Ejemplo n.º 1
0
        private static async Task SendTelemetry(CancellationTokenSource cts) {
            while (!cts.Token.IsCancellationRequested) {
                // Flag used when we need to pause telemetry send due to needdd reindexing
                bool breakForReindexing = false;


                RecEdgeMessage recEdgeMessage = new RecEdgeMessage() { 
                    deviceId = ioTEdgeDeviceId,
                    observations = new List<Observation>()
                };

                // Iterate over all previously indexed sensors
                foreach(KeyValuePair<HueDeviceDescription, HueClientDescription> sensorDescriptionEntry in hueSensors)
                {
                    // Extract sensor and client metadata
                    HueDeviceDescription sensorDescription = sensorDescriptionEntry.Key;
                    HueClientDescription clientDescription = sensorDescriptionEntry.Value;
                    LocalHueClient client = clientDescription.client;

                    // Query for current sensor state
                    Sensor sensor = await client.GetSensorAsync(sensorDescription.id);

                    // Verify that the indexed sensor is still correct; if not, 
                    // some change to the underlying Hue environment has occured; 
                    // if so, return and trigger reindexing
                    if (sensor.UniqueId != sensorDescription.uniqueId) {
                        breakForReindexing = true;
                        break;
                    }
                    
                    // Extract sensor state; set up a new observation using either 
                    // the last updated value from sensor state, or if that is missing, right now
                    SensorState sensorState = sensor.State;
                    Observation sensorObservation = new Observation();
                    if (sensorState.Lastupdated.HasValue) {
                        sensorObservation.observationTime = sensorState.Lastupdated.Value;
                    }
                    else {
                        sensorObservation.observationTime = DateTime.Now;
                    }
                    
                    // Defined sensor URI based on local bridge IP and sensor unique id
                    // TODO: Make sensor URI prefix configurable through Module Twin
                    sensorObservation.sensorId = new Uri($"http://{clientDescription.ip}/{sensor.UniqueId}");

                    // Depending on the type of sensor, set the quantity kind and extract values accordingly
                    // TODO: Figure out quantity kind for boolean, i.e., ZLLPresence
                    // TODO: Connect this switch statement to the sensorType enum for future maintainability
                    switch (sensor.Type) {
                        case "ZLLTemperature":
                            if (sensorState.Temperature.HasValue) {
                                sensorObservation.numericValue = ((double)sensorState.Temperature.Value / (double)100);
                                sensorObservation.quantityKind = new Uri("http://qudt.org/vocab/quantitykind/Temperature");
                            }
                            break;
                        case "ZLLLightLevel":
                            if (sensorState.LightLevel.HasValue) {
                                // Parse measurement data (expressed on log scale) into Lux; 
                                // see https://developers.meethue.com/develop/hue-api/supported-devices/#supportred-sensors for details
                                double luxValue = Math.Pow(10,(((double)sensorState.LightLevel.Value-1.0)/10000.0));
                                sensorObservation.numericValue = luxValue;
                                sensorObservation.quantityKind = new Uri("http://qudt.org/vocab/quantitykind/Illuminance");
                            }
                            break;
                        case "ZLLPresence":
                            if (sensorState.Presence.HasValue) {
                                sensorObservation.booleanValue = sensorState.Presence.Value;
                            }
                            break;
                    }

                    recEdgeMessage.observations.Add(sensorObservation);
                }
                
                if (breakForReindexing) {
                    // If we broke out of last loop due to sensor index inconsistency, reindex before proceeding in next SendTelemetry iteration
                    Twin moduleTwin = await ioTHubModuleClient.GetTwinAsync();
                    await IndexHueBridges(moduleTwin.Properties.Desired);
                    breakForReindexing = false;
                }
                else {
                    // Otherwise, serialize the REC Edge Message into JSON, built an IoT Edge message, and pass it to the IoT Hub
                    JsonSerializerSettings serializerSettings = new JsonSerializerSettings {
                        NullValueHandling = NullValueHandling.Ignore
                    };
                    string recEdgeMessageJson = JsonConvert.SerializeObject(recEdgeMessage, Formatting.None, serializerSettings);
                    Message telemetryMessage = new Message(Encoding.ASCII.GetBytes(recEdgeMessageJson)) {
                        ContentType = "application/json",
                        ContentEncoding = "utf-8"
                    };
                    Console.WriteLine($"Sending message: {recEdgeMessageJson}");
                    await ioTHubModuleClient.SendEventAsync(telemetryMessage);
                }
                
                await Task.Delay(telemetryInterval, cts.Token);
            }
        }
Ejemplo n.º 2
0
        static async Task IndexHueBridges(TwinCollection desiredProperties) {
            // Only proceed if the module twin contains a hueBridges key
            // TODO: exception handling in case of malformed JSON?
            if (desiredProperties.Contains("hueBridges")) {

                // Reset previous lists of sensors and lights
                hueSensors.Clear();
                hueLights.Clear();

                // Naive lookup through https://discovery.meethue.com
                IBridgeLocator locator = new HttpBridgeLocator();
                IEnumerable<LocatedBridge> locatedLocalBridges  = await locator.LocateBridgesAsync(TimeSpan.FromSeconds(5));

                // Iterate over the bridge IDs and corresponding app key credentials provided in the module twin
                JArray moduleTwinBridges = desiredProperties["hueBridges"];
                foreach (JObject bridge in moduleTwinBridges.Children()) {
                    string moduleTwinBridgeId = bridge.GetValue("id").ToString();
                    string moduleTwinAppKey = bridge.GetValue("appKey").ToString();

                    // If a locally found bridge corresponds with a set of such credentials from the module twin, index it for sensors and lights
                    IEnumerable<LocatedBridge> locatedBridgesInModuleTwinProperties = locatedLocalBridges.Where(locatedBridge => locatedBridge.BridgeId == moduleTwinBridgeId);
                    if (locatedBridgesInModuleTwinProperties.Count() == 1) {
                        LocatedBridge bridgeToIndex = locatedBridgesInModuleTwinProperties.First();
                        Console.WriteLine($"Will index Hue bridge with ID = {moduleTwinBridgeId} at IP {bridgeToIndex.IpAddress}, using App Key = {moduleTwinAppKey}");

                        LocalHueClient client = new LocalHueClient(bridgeToIndex.IpAddress, moduleTwinAppKey);

                        try {
                            // Index sensors
                            IReadOnlyCollection<Sensor> sensors = await client.GetSensorsAsync();
                            foreach(Sensor sensor in sensors) {
                                if (Enum.IsDefined(typeof(SensorType), sensor.Type)) {
                                    HueDeviceDescription sensorDescription = new HueDeviceDescription() {
                                        id = sensor.Id,
                                        uniqueId = sensor.UniqueId,
                                    };
                                    hueSensors.Add(sensorDescription, new HueClientDescription(){client = client, ip = bridgeToIndex.IpAddress});
                                    Console.WriteLine($"Found sensor: {sensor.Name} ({sensor.UniqueId})");
                                }
                            }
                        
                            // Index lights
                            IEnumerable<Light> lights = await client.GetLightsAsync();
                            foreach(Light light in lights) {
                                hueLights.Add(light.Name);
                                Console.WriteLine($"Found light: {light.Name} ({light.UniqueId})");
                            }
                        }
                        catch (Exception ex) 
                        {
                            Console.Error.WriteLine(ex.Message);
                            Console.Error.WriteLine(ex.StackTrace);
                        }
                    }
                }

                // Report back the results of the indexing; the unique ID:s of each detected Hue device
                TwinCollection reportedProperties = new TwinCollection
                {
                    ["Sensors"] = hueSensors.Keys.Select(sensorDescription => sensorDescription.uniqueId),
                    ["Lights"] = hueLights
                };
                await ioTHubModuleClient.UpdateReportedPropertiesAsync(reportedProperties).ConfigureAwait(false);
            }
        }