コード例 #1
0
        /// <summary>
        /// Create patch twin model to upload
        /// </summary>
        /// <param name="existing"></param>
        /// <param name="update"></param>
        public static DeviceTwinModel Patch(this GatewayRegistration existing,
                                            GatewayRegistration update)
        {
            var twin = new DeviceTwinModel {
                Etag       = existing?.Etag,
                Tags       = new Dictionary <string, VariantValue>(),
                Properties = new TwinPropertiesModel {
                    Desired = new Dictionary <string, VariantValue>()
                }
            };

            // Tags

            if (update?.IsDisabled != null && update.IsDisabled != existing?.IsDisabled)
            {
                twin.Tags.Add(nameof(GatewayRegistration.IsDisabled), (update?.IsDisabled ?? false) ?
                              true : (bool?)null);
                twin.Tags.Add(nameof(GatewayRegistration.NotSeenSince), (update?.IsDisabled ?? false) ?
                              DateTime.UtcNow : (DateTime?)null);
            }

            if (update?.SiteId != existing?.SiteId)
            {
                twin.Tags.Add(TwinProperty.SiteId, update?.SiteId);
            }

            twin.Tags.Add(nameof(GatewayRegistration.DeviceType), update?.DeviceType);
            twin.Id = update?.DeviceId ?? existing?.DeviceId;
            return(twin);
        }
コード例 #2
0
        /// <summary>
        /// Make sure to get the registration information from the right place.
        /// Reported (truth) properties take precedence over desired. However,
        /// if there is nothing reported, it means the endpoint is not currently
        /// serviced, thus we use desired as if they are attributes of the
        /// endpoint.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="onlyServerState">Only desired endpoint should be returned
        /// this means that you will look at stale information.</param>
        /// <returns></returns>
        public static EndpointRegistration FromTwin(DeviceTwinModel twin,
                                                    bool onlyServerState)
        {
            if (twin == null)
            {
                return(null);
            }
            if (twin.Tags == null)
            {
                twin.Tags = new Dictionary <string, JToken>();
            }

            var consolidated =
                FromTwin(twin, twin.GetConsolidatedProperties());
            var desired = (twin.Properties?.Desired == null) ? null :
                          FromTwin(twin, twin.Properties.Desired);

            if (!onlyServerState)
            {
                consolidated.MarkAsInSyncWith(desired);
                return(consolidated);
            }
            desired?.MarkAsInSyncWith(consolidated);
            return(desired);
        }
コード例 #3
0
        /// <summary>
        /// Decode tags and property into registration object
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public static GatewayRegistration ToGatewayRegistration(this DeviceTwinModel twin,
                                                                Dictionary <string, VariantValue> properties)
        {
            if (twin == null)
            {
                return(null);
            }

            var tags = twin.Tags ?? new Dictionary <string, VariantValue>();

            var registration = new GatewayRegistration {
                // Device

                DeviceId = twin.Id,
                Etag     = twin.Etag,

                // Connected
                Connected = twin.IsConnected() ?? false,

                // Tags

                IsDisabled =
                    tags.GetValueOrDefault <bool>(nameof(GatewayRegistration.IsDisabled), null),
                NotSeenSince =
                    tags.GetValueOrDefault <DateTime>(nameof(GatewayRegistration.NotSeenSince), null),
                Type =
                    tags.GetValueOrDefault <string>(TwinProperty.Type, null),
                SiteId =
                    tags.GetValueOrDefault <string>(TwinProperty.SiteId, null),

                // Properties
            };

            return(registration);
        }
コード例 #4
0
        /// <summary>
        /// Make sure to get the registration information from the right place.
        /// Reported (truth) properties take precedence over desired. However,
        /// if there is nothing reported, it means the endpoint is not currently
        /// serviced, thus we use desired as if they are attributes of the
        /// endpoint.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="onlyServerState">Only desired endpoint should be returned
        /// this means that you will look at stale information.</param>
        /// <returns></returns>
        public static EndpointRegistration ToEndpointRegistration(this DeviceTwinModel twin,
                                                                  bool onlyServerState)
        {
            if (twin == null)
            {
                return(null);
            }
            if (twin.Tags == null)
            {
                twin.Tags = new Dictionary <string, JToken>();
            }

            var consolidated =
                ToEndpointRegistration(twin, twin.GetConsolidatedProperties());
            var desired = (twin.Properties?.Desired == null) ? null :
                          ToEndpointRegistration(twin, twin.Properties.Desired);

            if (!onlyServerState)
            {
                consolidated._isInSync = consolidated.IsInSyncWith(desired);
                return(consolidated);
            }
            if (desired != null)
            {
                desired._isInSync = desired.IsInSyncWith(consolidated);
            }
            return(desired);
        }
コード例 #5
0
        /// <inheritdoc/>
        public async Task OnJobCreatingAsync(IJobService manager, JobInfoModel job)
        {
            var jobDeviceId = GetJobDeviceId(job);

            try {
                var deviceTwin = await _ioTHubTwinServices.GetAsync(jobDeviceId);

                if (deviceTwin == null)
                {
                    deviceTwin = new DeviceTwinModel {
                        Id = jobDeviceId
                    };
                    await _ioTHubTwinServices.CreateAsync(deviceTwin);
                }
                var cs = await _ioTHubTwinServices.GetConnectionStringAsync(deviceTwin.Id);

                if (job.JobConfiguration?.Type == JTokenType.Object &&
                    job.JobConfiguration is JObject o)
                {
                    var connectionString = JToken.FromObject(cs.ToString());
                    if (o.ContainsKey(TwinProperties.ConnectionString))
                    {
                        o[TwinProperties.ConnectionString] = connectionString;
                    }
                    else
                    {
                        o.Add(TwinProperties.ConnectionString, connectionString);
                    }
                    _logger.Debug("Added connection string to job {id}", jobDeviceId);
                }
            }
            catch (Exception ex) {
                _logger.Error(ex, "Error while creating IoT Device.");
            }
        }
コード例 #6
0
        /// <summary>
        /// Make sure to get the registration information from the right place.
        /// Reported (truth) properties take precedence over desired. However,
        /// if there is nothing reported, it means the endpoint is not currently
        /// serviced, thus we use desired as if they are attributes of the
        /// endpoint.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="connected"></param>
        /// <returns></returns>
        public static GatewayRegistration ToGatewayRegistration(this DeviceTwinModel twin,
                                                                out bool connected)
        {
            if (twin == null)
            {
                connected = false;
                return(null);
            }
            if (twin.Tags == null)
            {
                twin.Tags = new Dictionary <string, JToken>();
            }

            var consolidated =
                ToGatewayRegistration(twin, twin.GetConsolidatedProperties());
            var desired = (twin.Properties?.Desired == null) ? null :
                          ToGatewayRegistration(twin, twin.Properties.Desired);

            connected = consolidated.Connected;
            if (desired != null)
            {
                desired.Connected = connected;
                if (desired.SiteId == null && consolidated.SiteId != null)
                {
                    // Not set by user, but by config, so fake user desiring it.
                    desired.SiteId = consolidated.SiteId;
                }
            }
            return(desired);
        }
コード例 #7
0
        /// <inheritdoc/>
        public async Task OnJobCreatingAsync(IJobService manager, JobInfoModel job)
        {
            if (job.JobConfiguration?.IsObject != true)
            {
                return;
            }
            try {
                var jobDeviceId = GetJobDeviceId(job);
                var deviceTwin  = await _ioTHubTwinServices.FindAsync(jobDeviceId);

                if (deviceTwin == null)
                {
                    deviceTwin = new DeviceTwinModel {
                        Id = jobDeviceId
                    };
                    await _ioTHubTwinServices.CreateOrUpdateAsync(deviceTwin, true);
                }
                var cs = await _ioTHubTwinServices.GetConnectionStringAsync(deviceTwin.Id);

                job.JobConfiguration[TwinProperties.ConnectionString].AssignValue(cs.ToString());
                _logger.Debug("Added connection string to job {id}", jobDeviceId);
            }
            catch (Exception ex) {
                _logger.Error(ex, "Error while creating IoT Device.");
            }
        }
コード例 #8
0
 /// <inheritdoc/>
 public async Task <DeviceTwinModel> PatchAsync(DeviceTwinModel twin,
                                                bool force, CancellationToken ct)
 {
     try {
         Twin update;
         // Then update twin assuming it now exists. If fails, retry...
         var etag = string.IsNullOrEmpty(twin.Etag) || force ? "*" : twin.Etag;
         if (!string.IsNullOrEmpty(twin.ModuleId))
         {
             update = await _registry.UpdateTwinAsync(twin.Id, twin.ModuleId,
                                                      twin.ToTwin(true), etag, ct);
         }
         else
         {
             // Patch device
             update = await _registry.UpdateTwinAsync(twin.Id,
                                                      twin.ToTwin(true), etag, ct);
         }
         return(update.ToModel());
     }
     catch (Exception e) {
         _logger.Verbose(e, "Create or update failed ");
         throw e.Rethrow();
     }
 }
コード例 #9
0
        /// <summary>
        /// Convert twin to registration information.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="onlyServerState"></param>
        /// <returns></returns>
        public static BaseRegistration ToRegistration(DeviceTwinModel twin,
                                                      bool onlyServerState = false)
        {
            if (twin == null)
            {
                return(null);
            }
            var type = twin.Tags.GetValueOrDefault <string>(nameof(DeviceType), null);

            if (string.IsNullOrEmpty(type) && twin.Properties.Reported != null)
            {
                type = twin.Properties.Reported.GetValueOrDefault <string>(TwinProperty.kType, null);
            }
            switch (type?.ToLowerInvariant() ?? "")
            {
            case "endpoint":
                return(EndpointRegistration.FromTwin(twin, onlyServerState));

            case "application":
                return(ApplicationRegistration.FromTwin(twin));

            case "supervisor":
                return(SupervisorRegistration.FromTwin(twin, onlyServerState));
            }
            return(null);
        }
コード例 #10
0
    public async Task get_iotHub_update_device_twin()
    {
        DeviceTwinRepository repo = new DeviceTwinRepository(iotHubConnectionString);
        var tags = new DeviceTwinTagsModel()
        {
            ProductFamily    = "ProductFamilyTest",
            ProductName      = "ProductNameTest",
            RetailerName     = "RetailerTest",
            ManufacturedDate = DateTime.Now,
            ShippedDate      = DateTime.Now,
            RetailerRegion   = "Chicago"
        };
        var device = await repo.CreateAndInitializeDeviceTwin("unittestdevice", tags);

        Assert.Equal("unittestdevice", device.Id);

        // get device twin
        var deviceTwin = await repo.GetDeviceTwinAsync(device.Id);

        Assert.NotNull(deviceTwin);

        var deviceTwinModel = new DeviceTwinModel()
        {
            DeviceId = "unittestdevice",

            /*Location = new DeviceLocation()
             * {
             *  AddressLine1 = "1100, S King Drive",
             *  City = "Chicago",
             *  State = "IL",
             *  ZipCode = "50630",
             *  Country = "US",
             *  AdditionalNotes="Test Notes"
             * },
             * Features = new List<DeviceFeature>()
             * {
             *  new DeviceFeature(){ Name = "Just Test Feature",
             *  Value = true }
             *
             * },
             * ActivationDate = DateTime.Now,
             * ShipDate = DateTime.Now.AddDays(2)*/
        };

        //await repo.UpdateDeviceTwinTagsAsync(deviceTwinModel);
        await repo.InitializeDeviceTwinDesiredFeaturesAsync(new DeviceTwinDesiredFeaturesModel()
        {
            DeviceId = device.Id                                                                                            /*, ActivatedFeatures = deviceTwinModel.Features*/
        });

        // get device twin
        deviceTwin = await repo.GetDeviceTwinAsync(device.Id);

        //Assert.Equal(1,deviceTwin.Tags.Count);
        //Assert.True(deviceTwin.Tags.Contains("location"));

        //Assert.Equal(1, deviceTwin.Properties.Desired.Count);
        //Assert.True(deviceTwin.Properties.Desired.Contains("features"));
    }
コード例 #11
0
        /// <summary>
        /// Create patch twin model to upload
        /// </summary>
        /// <param name="existing"></param>
        /// <param name="update"></param>
        public static DeviceTwinModel Patch(this SupervisorRegistration existing,
                                            SupervisorRegistration update)
        {
            var twin = new DeviceTwinModel {
                Etag       = existing?.Etag,
                Tags       = new Dictionary <string, JToken>(),
                Properties = new TwinPropertiesModel {
                    Desired = new Dictionary <string, JToken>()
                }
            };

            // Tags

            if (update?.IsDisabled != null && update.IsDisabled != existing?.IsDisabled)
            {
                twin.Tags.Add(nameof(SupervisorRegistration.IsDisabled), (update?.IsDisabled ?? false) ?
                              true : (bool?)null);
                twin.Tags.Add(nameof(SupervisorRegistration.NotSeenSince), (update?.IsDisabled ?? false) ?
                              DateTime.UtcNow : (DateTime?)null);
            }

            if (update?.SiteOrGatewayId != existing?.SiteOrGatewayId)
            {
                twin.Tags.Add(nameof(SupervisorRegistration.SiteOrGatewayId),
                              update?.SiteOrGatewayId);
            }

            // Settings

            var certUpdate = update?.Certificate?.DecodeAsByteArray()?.SequenceEqualsSafe(
                existing?.Certificate.DecodeAsByteArray());

            if (!(certUpdate ?? true))
            {
                twin.Properties.Desired.Add(nameof(SupervisorRegistration.Certificate),
                                            update?.Certificate == null ?
                                            null : JToken.FromObject(update.Certificate));
                twin.Tags.Add(nameof(SupervisorRegistration.Thumbprint),
                              update?.Certificate?.DecodeAsByteArray()?.ToSha1Hash());
            }

            if (update?.LogLevel != existing?.LogLevel)
            {
                twin.Properties.Desired.Add(nameof(SupervisorRegistration.LogLevel),
                                            update?.LogLevel == null ?
                                            null : JToken.FromObject(update.LogLevel));
            }

            if (update?.SiteId != existing?.SiteId)
            {
                twin.Properties.Desired.Add(TwinProperty.SiteId, update?.SiteId);
            }

            twin.Tags.Add(nameof(SupervisorRegistration.DeviceType), update?.DeviceType);
            twin.Id       = update?.DeviceId ?? existing?.DeviceId;
            twin.ModuleId = update?.ModuleId ?? existing?.ModuleId;
            return(twin);
        }
コード例 #12
0
        /// <summary>
        /// Create patch twin model to upload
        /// </summary>
        /// <param name="existing"></param>
        /// <param name="update"></param>
        protected static DeviceTwinModel Patch(
            BaseRegistration existing, BaseRegistration update)
        {
            var twin = new DeviceTwinModel {
                Etag       = existing?.Etag,
                Tags       = new Dictionary <string, JToken>(),
                Properties = new TwinPropertiesModel {
                    Desired = new Dictionary <string, JToken>()
                }
            };

            // Tags

            if (update?.ApplicationId != null &&
                update.ApplicationId != existing?.ApplicationId)
            {
                twin.Tags.Add(nameof(ApplicationId), update.ApplicationId);
            }

            if (update?.IsDisabled != null &&
                update.IsDisabled != existing?.IsDisabled)
            {
                twin.Tags.Add(nameof(IsDisabled), (update?.IsDisabled ?? false) ?
                              true : (bool?)null);
                twin.Tags.Add(nameof(NotSeenSince), (update?.IsDisabled ?? false) ?
                              DateTime.UtcNow : (DateTime?)null);
            }

            if (update?.SiteOrSupervisorId != existing?.SiteOrSupervisorId)
            {
                twin.Tags.Add(nameof(SiteOrSupervisorId), update?.SiteOrSupervisorId);
            }

            if (update?.SupervisorId != existing?.SupervisorId)
            {
                twin.Tags.Add(nameof(SupervisorId), update?.SupervisorId);
            }

            if (update?.SiteId != existing?.SiteId)
            {
                twin.Tags.Add(nameof(SiteId), update?.SiteId);
            }

            var certUpdate = update?.Certificate.DecodeAsByteArray().SequenceEqualsSafe(
                existing?.Certificate.DecodeAsByteArray());

            if (!(certUpdate ?? true))
            {
                twin.Tags.Add(nameof(Certificate), update?.Certificate == null ?
                              null : JToken.FromObject(update.Certificate));
                twin.Tags.Add(nameof(Thumbprint),
                              update?.Certificate?.DecodeAsByteArray()?.ToSha1Hash());
            }

            twin.Tags.Add(nameof(DeviceType), update?.DeviceType);
            return(twin);
        }
コード例 #13
0
        /// <summary>
        /// Get identity of device twin
        /// </summary>
        /// <param name="deviceTwin"></param>
        /// <returns></returns>
        private static string GetIdentity(DeviceTwinModel deviceTwin)
        {
            var identity = deviceTwin.Id;

            if (!string.IsNullOrEmpty(deviceTwin.ModuleId))
            {
                identity += $"/{deviceTwin.ModuleId}";
            }
            return(identity);
        }
コード例 #14
0
        /// <summary>
        /// Create or update a device
        /// </summary>
        /// <param name="deviceTwinObj">DeviceTwinModel</param>
        /// <returns>DeviceModel</returns>
        public async Task <DeviceModel> CreateOrUpdateDevice(DeviceTwinModel deviceTwinObj)
        {
            if (deviceTwinObj.DeviceId == Guid.Empty)
            {
                throw new Exception($"No device found that matches DeviceId: {deviceTwinObj.DeviceId}");
            }

            DeviceDAO deviceDAO = await _repoDevices.GetItemAsync(deviceTwinObj.DeviceId);

            //Create
            if (deviceDAO == null)
            {
                return(await CreateDevice(deviceTwinObj));
            }

            //Update
            deviceDAO.IoTDevice = true;
            if (deviceTwinObj.Properties?.Desired != null)
            {
                deviceDAO.Desired = deviceTwinObj.Properties.Desired;
            }
            if (deviceTwinObj.Properties?.Reported != null)
            {
                deviceDAO.Reported = deviceTwinObj.Properties.Reported;
            }
            if (deviceTwinObj.Tags != null)
            {
                deviceDAO.DeviceType  = deviceTwinObj.Tags.DeviceType;
                deviceDAO.Enabled     = deviceTwinObj.Tags.Enabled;
                deviceDAO.Custom      = deviceTwinObj.Tags.Custom;
                deviceDAO.Name        = deviceTwinObj.Tags.Name;
                deviceDAO.Location1   = deviceTwinObj.Tags.Location1;
                deviceDAO.Location2   = deviceTwinObj.Tags.Location2;
                deviceDAO.Location3   = deviceTwinObj.Tags.Location3;
                deviceDAO.SSID        = deviceTwinObj.Tags.SSID;
                deviceDAO.Sensor      = deviceTwinObj.Tags.Sensor;
                deviceDAO.Geolocation = _mapper.Map <GeolocationDAOObject>(deviceTwinObj.Tags.Geolocation);
            }

            try
            {
                await _repoDevices.UpdateItemAsync(deviceDAO);
            }
            catch (DocumentClientException e)
            {
                //Update concurrency issue, retrying
                if (e.StatusCode == HttpStatusCode.PreconditionFailed)
                {
                    return(await CreateOrUpdateDevice(deviceTwinObj));
                }
                throw e;
            }

            return(_mapper.Map <DeviceModel>(deviceDAO));
        }
コード例 #15
0
 /// <inheritdoc/>
 public Task <DeviceTwinModel> CreateAsync(DeviceTwinModel twin, bool force,
                                           CancellationToken ct)
 {
     if (twin == null)
     {
         throw new ArgumentNullException(nameof(twin));
     }
     if (string.IsNullOrEmpty(twin.Id))
     {
         throw new ArgumentNullException(nameof(twin.Id));
     }
     // Retry transient errors
     return(Retry.WithExponentialBackoff(_logger, ct, async() => {
         // First try create device
         try {
             var device = NewRequest($"/devices/{twin.Id}");
             device.SetContent(new {
                 deviceId = twin.Id,
                 capabilities = twin.Capabilities
             });
             var response = await _httpClient.PutAsync(device, ct);
             response.Validate();
         }
         catch (ConflictingResourceException)
             when(!string.IsNullOrEmpty(twin.ModuleId) || force)
             {
                 // Continue onward
             }
         catch (Exception e) {
             _logger.Debug(e, "Create device failed in CreateOrUpdate");
         }
         if (!string.IsNullOrEmpty(twin.ModuleId))
         {
             // Try create module
             try {
                 var module = NewRequest(
                     $"/devices/{twin.Id}/modules/{twin.ModuleId}");
                 module.SetContent(new {
                     deviceId = twin.Id,
                     moduleId = twin.ModuleId
                 });
                 var response = await _httpClient.PutAsync(module, ct);
                 response.Validate();
             }
             catch (ConflictingResourceException)
                 when(force)
                 {
                 }
             catch (Exception e) {
                 _logger.Debug(e, "Create module failed in CreateOrUpdate");
             }
         }
         return await PatchAsync(twin, true, ct);  // Force update of twin
     }, kMaxRetryCount));
 }
コード例 #16
0
        /// <summary>
        /// Decode tags and property into registration object
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public static PublisherRegistration ToPublisherRegistration(this DeviceTwinModel twin,
                                                                    Dictionary <string, JToken> properties)
        {
            if (twin == null)
            {
                return(null);
            }

            var tags      = twin.Tags ?? new Dictionary <string, JToken>();
            var connected = twin.IsConnected();

            var registration = new PublisherRegistration {
                // Device

                DeviceId = twin.Id,
                ModuleId = twin.ModuleId,
                Etag     = twin.Etag,

                // Tags

                IsDisabled =
                    tags.GetValueOrDefault <bool>(nameof(PublisherRegistration.IsDisabled), null),
                NotSeenSince =
                    tags.GetValueOrDefault <DateTime>(nameof(PublisherRegistration.NotSeenSince), null),
                Thumbprint =
                    tags.GetValueOrDefault <string>(nameof(PublisherRegistration.Thumbprint), null),

                // Properties

                Certificate =
                    properties.GetValueOrDefault <Dictionary <string, string> >(nameof(PublisherRegistration.Certificate), null),
                LogLevel =
                    properties.GetValueOrDefault <TraceLogLevel>(nameof(PublisherRegistration.LogLevel), null),
                JobOrchestratorUrl =
                    properties.GetValueOrDefault <string>(nameof(PublisherRegistration.JobOrchestratorUrl), null),
                JobCheckInterval =
                    properties.GetValueOrDefault <TimeSpan>(nameof(PublisherRegistration.JobCheckInterval), null),
                MaxWorkers =
                    properties.GetValueOrDefault <int>(nameof(PublisherRegistration.MaxWorkers), null),
                HeartbeatInterval =
                    properties.GetValueOrDefault <TimeSpan>(nameof(PublisherRegistration.HeartbeatInterval), null),
                Capabilities =
                    properties.GetValueOrDefault <Dictionary <string, string> >(nameof(PublisherRegistration.Capabilities), null),

                SiteId =
                    properties.GetValueOrDefault <string>(TwinProperty.SiteId, null),
                Connected = connected ??
                            properties.GetValueOrDefault(TwinProperty.Connected, false),
                Type =
                    properties.GetValueOrDefault <string>(TwinProperty.Type, null)
            };

            return(registration);
        }
コード例 #17
0
        /// <inheritdoc/>
        public async Task <DeviceTwinModel> CreateOrUpdateAsync(DeviceTwinModel twin,
                                                                bool forceUpdate)
        {
            if (string.IsNullOrEmpty(twin.Etag))
            {
                // First try create device
                try {
                    var device = await _registry.AddDeviceAsync(twin.ToDevice());
                }
                catch (DeviceAlreadyExistsException) {
                    // Expected for update
                }
                catch (Exception e) {
                    _logger.Debug(e, "Create device failed in CreateOrUpdate");
                }
            }

            try {
                Twin update;
                // Then update twin assuming it now exists. If fails, retry...
                var etag = string.IsNullOrEmpty(twin.Etag) || forceUpdate ? "*" : twin.Etag;
                if (!string.IsNullOrEmpty(twin.ModuleId))
                {
                    if (string.IsNullOrEmpty(twin.Etag))
                    {
                        // Try create module
                        try {
                            var module = await _registry.AddModuleAsync(twin.ToModule());
                        }
                        catch (DeviceAlreadyExistsException) {
                            // Expected for update
                        }
                        catch (Exception e) {
                            _logger.Debug(e, "Create module failed in CreateOrUpdate");
                        }
                    }

                    update = await _registry.UpdateTwinAsync(twin.Id, twin.ModuleId,
                                                             twin.ToTwin(true), etag);
                }
                else
                {
                    // Patch device
                    update = await _registry.UpdateTwinAsync(twin.Id,
                                                             twin.ToTwin(true), etag);
                }
                return(update.ToModel());
            }
            catch (Exception e) {
                _logger.Debug(e, "Create or update failed ");
                throw;
            }
        }
コード例 #18
0
 private void SetTagPropertiesThatExist(IDictionary <string, object> providedData,
                                        DeviceModel existingModel,
                                        DeviceTwinModel updateModel)
 {
     updateModel.Tags.DeviceType = GetValueIfProvided("DeviceType", dm => dm.DeviceType, providedData, existingModel);
     updateModel.Tags.Enabled    = GetValueIfProvided("Enabled", dm => dm.Enabled, providedData, existingModel);
     updateModel.Tags.Location1  = GetValueIfProvided("Location1", dm => dm.Location1, providedData, existingModel);
     updateModel.Tags.Location2  = GetValueIfProvided("Location2", dm => dm.Location2, providedData, existingModel);
     updateModel.Tags.Location3  = GetValueIfProvided("Location3", dm => dm.Location3, providedData, existingModel);
     updateModel.Tags.Name       = GetValueIfProvided("Name", dm => dm.Name, providedData, existingModel);
     updateModel.Tags.Sensor     = GetValueIfProvided("Sensor", dm => dm.Sensor, providedData, existingModel);
     updateModel.Tags.SSID       = GetValueIfProvided("SSID", dm => dm.SSID, providedData, existingModel);
 }
コード例 #19
0
 /// <summary>
 /// Update twin
 /// </summary>
 /// <param name="twin"></param>
 public void UpdateTwin(DeviceTwinModel twin)
 {
     Twin.Tags = Merge(Twin.Tags, twin.Tags);
     if (Twin.Properties == null)
     {
         Twin.Properties = new TwinPropertiesModel();
     }
     Twin.Properties.Desired = Merge(
         Twin.Properties.Desired, twin.Properties?.Desired);
     Twin.Properties.Reported = Merge(
         Twin.Properties.Reported, twin.Properties?.Reported);
     Twin.LastActivityTime = DateTime.UtcNow;
     Twin.Etag             = Device.Etag = Guid.NewGuid().ToString();
 }
コード例 #20
0
 /// <inheritdoc/>
 public Task <DeviceTwinModel> PatchAsync(DeviceTwinModel twin, bool force, CancellationToken ct)
 {
     if (twin == null)
     {
         throw new ArgumentNullException(nameof(twin));
     }
     if (string.IsNullOrEmpty(twin.Id))
     {
         throw new ArgumentNullException(nameof(twin.Id));
     }
     return(Retry.WithExponentialBackoff(_logger, ct, async() => {
         // Then update twin assuming it now exists. If fails, retry...
         var patch = NewRequest(
             $"/twins/{ToResourceId(twin.Id, twin.ModuleId)}");
         patch.Headers.Add("If-Match",
                           $"\"{(string.IsNullOrEmpty(twin.Etag) || force ? "*" : twin.Etag)}\"");
         if (!string.IsNullOrEmpty(twin.ModuleId))
         {
             // Patch module
             patch.SetContent(new {
                 deviceId = twin.Id,
                 moduleId = twin.ModuleId,
                 tags = twin.Tags ?? new Dictionary <string, JToken>(),
                 properties = new {
                     desired = twin.Properties?.Desired ?? new Dictionary <string, JToken>()
                 }
             });
         }
         else
         {
             // Patch device
             patch.SetContent(new {
                 deviceId = twin.Id,
                 tags = twin.Tags ?? new Dictionary <string, JToken>(),
                 properties = new {
                     desired = twin.Properties?.Desired ?? new Dictionary <string, JToken>()
                 }
             });
         }
         {
             var response = await _httpClient.PatchAsync(patch, ct);
             response.Validate();
             var result = response.GetContent <DeviceTwinModel>();
             _logger.Information(
                 "{id} ({moduleId}) created or updated ({twinEtag} -> {resultEtag})",
                 twin.Id, twin.ModuleId ?? string.Empty, twin.Etag ?? "*", result.Etag);
             return result;
         }
     }, kMaxRetryCount));
 }
コード例 #21
0
        /// <summary>
        /// Create a device
        /// </summary>
        /// <param name="deviceTwinObj">DeviceTwinModel</param>
        /// <returns>DeviceModel</returns>
        public async Task <DeviceModel> CreateDevice(DeviceTwinModel deviceTwinObj)
        {
            //If device doesn't exist, throw exception
            DeviceDAO deviceEntity = _mapper.Map <DeviceDAO>(deviceTwinObj);

            deviceEntity.Id = await _repoDevices.CreateItemAsync(deviceEntity);

            if (_repoDevices.IsDocumentKeyNull(deviceEntity))
            {
                throw new Exception($"An error occured when creating a new device: {deviceTwinObj.DeviceId}");
            }

            return(_mapper.Map <DeviceModel>(deviceEntity));
        }
コード例 #22
0
        /// <summary>
        /// Convert twin to module model
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        private static DiscoveredModuleModel ToDiscoveredModuleModel(DeviceTwinModel t)
        {
            if (t == null)
            {
                return(null);
            }
            var model = new DiscoveredModuleModel {
                Id        = t.ModuleId,
                ImageName = t.ModuleId,
                ImageHash = null,
                Version   = t.Version?.ToString(),
                Status    = t.Status
            };

            return(model);
        }
コード例 #23
0
        /// <inheritdoc/>
        public async Task OnJobAssignmentAsync(IJobService manager, JobInfoModel job, string workerId)
        {
            if (job.JobConfiguration?.IsObject != true)
            {
                return;
            }
            if (string.IsNullOrEmpty(workerId))
            {
                throw new ArgumentNullException("empty WorkerId provided");
            }
            try {
                var edgeDeviceTwin = await _ioTHubTwinServices.FindAsync(workerId.Split("_publisher")[0]);

                if (edgeDeviceTwin == null)
                {
                    _logger.Error("IoT Edge Device not found.");
                    return;
                }

                var jobDeviceId = GetJobDeviceId(job);
                var deviceTwin  = await _ioTHubTwinServices.FindAsync(jobDeviceId);

                if (deviceTwin == null)
                {
                    deviceTwin = new DeviceTwinModel {
                        Id          = jobDeviceId,
                        DeviceScope = edgeDeviceTwin.DeviceScope
                    };
                    await _ioTHubTwinServices.CreateOrUpdateAsync(deviceTwin, true);
                }
                else
                {
                    if (deviceTwin.DeviceScope != edgeDeviceTwin.DeviceScope)
                    {
                        deviceTwin.DeviceScope = edgeDeviceTwin.DeviceScope;
                        await _ioTHubTwinServices.CreateOrUpdateAsync(deviceTwin, true);
                    }
                }
                var cs = await _ioTHubTwinServices.GetConnectionStringAsync(deviceTwin.Id);

                job.JobConfiguration[TwinProperties.ConnectionString].AssignValue(cs.ToString());
                _logger.Debug("Added connection string to job {id}", jobDeviceId);
            }
            catch (Exception ex) {
                _logger.Error(ex, "Error while assigning the Job's IoT Device.");
            }
        }
コード例 #24
0
        /// <summary>
        /// Make sure to get the registration information from the right place.
        /// Reported (truth) properties take precedence over desired. However,
        /// if there is nothing reported, it means the endpoint is not currently
        /// serviced, thus we use desired as if they are attributes of the
        /// endpoint.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="onlyServerState">Only desired endpoint should be returned
        /// this means that you will look at stale information.</param>
        /// <param name="connected"></param>
        /// <returns></returns>
        public static SupervisorRegistration ToSupervisorRegistration(this DeviceTwinModel twin,
                                                                      bool onlyServerState, out bool connected)
        {
            if (twin == null)
            {
                connected = false;
                return(null);
            }
            if (twin.Tags == null)
            {
                twin.Tags = new Dictionary <string, VariantValue>();
            }

            var consolidated =
                ToSupervisorRegistration(twin, twin.GetConsolidatedProperties());
            var desired = (twin.Properties?.Desired == null) ? null :
                          ToSupervisorRegistration(twin, twin.Properties.Desired);

            connected = consolidated.Connected;
            if (desired != null)
            {
                desired.Connected = connected;
                if (desired.SiteId == null && consolidated.SiteId != null)
                {
                    // Not set by user, but by config, so fake user desiring it.
                    desired.SiteId = consolidated.SiteId;
                }
                if (desired.LogLevel == null && consolidated.LogLevel != null)
                {
                    // Not set by user, but reported, so set as desired
                    desired.LogLevel = consolidated.LogLevel;
                }
                desired.Version = consolidated.Version;
            }

            if (!onlyServerState)
            {
                consolidated._isInSync = consolidated.IsInSyncWith(desired);
                return(consolidated);
            }
            if (desired != null)
            {
                desired._isInSync = desired.IsInSyncWith(consolidated);
            }
            return(desired);
        }
コード例 #25
0
        /// <summary>
        /// Create patch twin model to upload
        /// </summary>
        /// <param name="existing"></param>
        /// <param name="update"></param>
        /// <param name="serializer"></param>
        public static DeviceTwinModel Patch(this SupervisorRegistration existing,
                                            SupervisorRegistration update, IJsonSerializer serializer)
        {
            var twin = new DeviceTwinModel {
                Etag       = existing?.Etag,
                Tags       = new Dictionary <string, VariantValue>(),
                Properties = new TwinPropertiesModel {
                    Desired = new Dictionary <string, VariantValue>()
                }
            };

            // Tags

            if (update?.IsDisabled != null && update.IsDisabled != existing?.IsDisabled)
            {
                twin.Tags.Add(nameof(SupervisorRegistration.IsDisabled), (update?.IsDisabled ?? false) ?
                              true : (bool?)null);
                twin.Tags.Add(nameof(SupervisorRegistration.NotSeenSince), (update?.IsDisabled ?? false) ?
                              DateTime.UtcNow : (DateTime?)null);
            }

            if (update?.SiteOrGatewayId != existing?.SiteOrGatewayId)
            {
                twin.Tags.Add(nameof(SupervisorRegistration.SiteOrGatewayId),
                              update?.SiteOrGatewayId);
            }

            // Settings

            if (update?.LogLevel != existing?.LogLevel)
            {
                twin.Properties.Desired.Add(nameof(SupervisorRegistration.LogLevel),
                                            update?.LogLevel == null ?
                                            null : serializer.FromObject(update.LogLevel.ToString()));
            }

            if (update?.SiteId != existing?.SiteId)
            {
                twin.Properties.Desired.Add(TwinProperty.SiteId, update?.SiteId);
            }

            twin.Tags.Add(nameof(SupervisorRegistration.DeviceType), update?.DeviceType);
            twin.Id       = update?.DeviceId ?? existing?.DeviceId;
            twin.ModuleId = update?.ModuleId ?? existing?.ModuleId;
            return(twin);
        }
コード例 #26
0
        public async Task <DeviceModel> CreateOrUpdateDevice(DeviceTwinModel deviceObj)
        {
            RestRequest request = await PrepareQuery("Devices", Method.POST);

            request.AddParameter("application/json", JsonConvert.SerializeObject(deviceObj), ParameterType.RequestBody);
            var queryResult = await _client.ExecuteTaskAsync <DeviceModel>(request);

            if (queryResult.IsSuccessful)
            {
                return(queryResult.Data);
            }
            else
            {
                _logger.LogError($"CreationModel: Error while adding a device: {queryResult.StatusCode}");
            }
            return(null);
        }
コード例 #27
0
        /// <summary>
        /// Convert device twin registration property to registration model
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="onlyServerState">Only desired should be returned
        /// this means that you will look at stale information.</param>
        /// <param name="skipInvalid"></param>
        /// <returns></returns>
        private static EndpointInfoModel TwinModelToEndpointRegistrationModel(
            DeviceTwinModel twin, bool onlyServerState, bool skipInvalid)
        {
            // Convert to twin registration
            var registration = twin.ToEntityRegistration(onlyServerState) as EndpointRegistration;

            if (registration == null)
            {
                if (skipInvalid)
                {
                    return(null);
                }
                throw new ResourceNotFoundException(
                          $"{twin.Id} is not a registered opc ua endpoint.");
            }
            return(registration.ToServiceModel());
        }
コード例 #28
0
        /// <summary>
        /// Decode tags and property into registration object
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public static SupervisorRegistration ToSupervisorRegistration(this DeviceTwinModel twin,
                                                                      Dictionary <string, JToken> properties)
        {
            if (twin == null)
            {
                return(null);
            }

            var tags      = twin.Tags ?? new Dictionary <string, JToken>();
            var connected = twin.IsConnected();

            var registration = new SupervisorRegistration {
                // Device

                DeviceId = twin.Id,
                ModuleId = twin.ModuleId,
                Etag     = twin.Etag,

                // Tags

                IsDisabled =
                    tags.GetValueOrDefault <bool>(nameof(SupervisorRegistration.IsDisabled), null),
                NotSeenSince =
                    tags.GetValueOrDefault <DateTime>(nameof(SupervisorRegistration.NotSeenSince), null),
                Thumbprint =
                    tags.GetValueOrDefault <string>(nameof(SupervisorRegistration.Thumbprint), null),

                // Properties

                Certificate =
                    properties.GetValueOrDefault <Dictionary <string, string> >(nameof(SupervisorRegistration.Certificate), null),
                LogLevel =
                    properties.GetValueOrDefault <TraceLogLevel>(nameof(SupervisorRegistration.LogLevel), null),

                SiteId =
                    properties.GetValueOrDefault <string>(TwinProperty.SiteId, null),
                Connected = connected ??
                            properties.GetValueOrDefault(TwinProperty.Connected, false),
                Type =
                    properties.GetValueOrDefault <string>(TwinProperty.Type, null)
            };

            return(registration);
        }
コード例 #29
0
        /// <summary>
        /// Convert twin to registration information.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="onlyServerState"></param>
        /// <returns></returns>
        public static EntityRegistration ToEntityRegistration(this DeviceTwinModel twin,
                                                              bool onlyServerState = false)
        {
            if (twin == null)
            {
                return(null);
            }
            var type = twin.Tags.GetValueOrDefault <string>(nameof(EntityRegistration.DeviceType), null);

            if (string.IsNullOrEmpty(type) && twin.Properties.Reported != null)
            {
                type = twin.Properties.Reported.GetValueOrDefault <string>(TwinProperty.Type, null);
                if (string.IsNullOrEmpty(type))
                {
                    type = twin.Tags.GetValueOrDefault <string>(TwinProperty.Type, null);
                }
            }
            if (IdentityType.Gateway.EqualsIgnoreCase(type))
            {
                return(twin.ToGatewayRegistration());
            }
            if (IdentityType.Application.EqualsIgnoreCase(type))
            {
                return(twin.ToApplicationRegistration());
            }
            if (IdentityType.Endpoint.EqualsIgnoreCase(type))
            {
                return(twin.ToEndpointRegistration(onlyServerState));
            }
            if (IdentityType.Supervisor.EqualsIgnoreCase(type))
            {
                return(twin.ToSupervisorRegistration(onlyServerState));
            }
            if (IdentityType.Publisher.EqualsIgnoreCase(type))
            {
                return(twin.ToPublisherRegistration(onlyServerState));
            }
            if (IdentityType.Discoverer.EqualsIgnoreCase(type))
            {
                return(twin.ToDiscovererRegistration(onlyServerState));
            }
            // ...
            return(null);
        }
コード例 #30
0
        /// <summary>
        /// Make sure to get the registration information from the right place.
        /// Reported (truth) properties take precedence over desired. However,
        /// if there is nothing reported, it means the endpoint is not currently
        /// serviced, thus we use desired as if they are attributes of the
        /// endpoint.
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="connected"></param>
        /// <returns></returns>
        public static GatewayRegistration ToGatewayRegistration(this DeviceTwinModel twin,
                                                                out bool connected)
        {
            if (twin == null)
            {
                connected = false;
                return(null);
            }
            if (twin.Tags == null)
            {
                twin.Tags = new Dictionary <string, VariantValue>();
            }

            var consolidated =
                ToGatewayRegistration(twin, twin.GetConsolidatedProperties());

            connected = consolidated.Connected;
            return(consolidated);
        }