public void UpdateUtilityAppendMultipleOperations() { var op = new UpdateOperationsUtility(); string addPath = "testPath1"; int addValue = 10; string replacePath = "testpath2"; int replaceValue = 20; op.AppendAddPropertyOp(addPath, addValue); op.AppendReplacePropertyOp(replacePath, replaceValue); string operations = op.Serialize(); // There should be two operations added. var jArray = JArray.Parse(operations); jArray.Count.Should().Be(2); // The patch operation added should have an "add" and a "replace" operation. var expectedOperations = new List <string> { Add, Replace }; var actualOperations = new List <string>(); foreach (JObject item in jArray) { actualOperations.Add(item.Value <string>(Op)); } actualOperations.Should().OnlyContain(item => expectedOperations.Contains(item)); }
public static string GetRelationshipUpdatePayload(string propertyName, bool propertyValue) { var uou = new UpdateOperationsUtility(); uou.AppendReplaceOp(propertyName, propertyValue); return(RemoveNewLines(uou.Serialize())); }
public void UpdateUtilityAppendsReplaceComponentOp() { var op = new UpdateOperationsUtility(); string path = "testPath"; string property = "someProperty"; int value = 10; op.AppendReplaceComponentOp(path, new Dictionary <string, object> { { property, value } }); string operations = op.Serialize(); // There should be a single operation added. var jArray = JArray.Parse(operations); jArray.Count.Should().Be(1); // The patch operation added should be a "replace" operation. JToken jObject = jArray.First; jObject.Value <string>(Op).Should().Be(Replace); // The value should have a "$metadata" : {} mapping. JObject patchValue = jObject.Value <JObject>(Value); patchValue[Metadata].Should().NotBeNull(); patchValue[Metadata].Should().BeEmpty(); }
public async void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log) { // After this is deployed, you need to turn the Managed Identity Status to "On", // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role // to this function identity in order for this function to be authorized on ADT APIs. //Authenticate with Digital Twins var credentials = new DefaultAzureCredential(); DigitalTwinsClient client = new DigitalTwinsClient( new Uri(adtServiceUrl), credentials, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpClient) }); log.LogInformation($"ADT service client connection created."); if (eventGridEvent != null && eventGridEvent.Data != null) { log.LogInformation(eventGridEvent.Data.ToString()); // Reading deviceId and temperature for IoT Hub JSON JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString()); string deviceId = (string)deviceMessage["systemProperties"]["iothub-connection-device-id"]; var temperature = deviceMessage["body"]["Temperature"]; log.LogInformation($"Device:{deviceId} Temperature is:{temperature}"); //Update twin using device temperature var uou = new UpdateOperationsUtility(); uou.AppendReplaceOp("/Temperature", temperature.Value <double>()); await client.UpdateDigitalTwinAsync(deviceId, uou.Serialize()); } }
public static string GetWifiComponentUpdatePayload() { var uou = new UpdateOperationsUtility(); uou.AppendReplaceOp("/Network", "New Network"); return(RemoveNewLines(uou.Serialize())); }
private async Task UpdateDigitalTwinComponentPropertyAsync() { // Choose a random value to assign to the targetTemperature property in thermostat1 component int desiredTargetTemperature = Random.Next(0, 100); const string targetTemperaturePropertyName = "targetTemperature"; var updateOperation = new UpdateOperationsUtility(); // First let's take a look at when the property was updated and what was it set to. HttpOperationResponse <TemperatureControllerTwin, DigitalTwinGetHeaders> getDigitalTwinResponse = await _digitalTwinClient .GetDigitalTwinAsync <TemperatureControllerTwin>(_digitalTwinId); ThermostatTwin thermostat1 = getDigitalTwinResponse.Body.Thermostat1; if (thermostat1 != null) { // Thermostat1 is present in the TemperatureController twin. We can add/replace the component-level property "targetTemperature" double?currentComponentTargetTemperature = getDigitalTwinResponse.Body.Thermostat1.TargetTemperature; if (currentComponentTargetTemperature != null) { DateTimeOffset targetTemperatureDesiredLastUpdateTime = getDigitalTwinResponse.Body.Thermostat1.Metadata.TargetTemperature.LastUpdateTime; _logger.LogDebug($"The property {targetTemperaturePropertyName} under component {Thermostat1Component} was last updated on `" + $"{targetTemperatureDesiredLastUpdateTime.ToLocalTime()} `" + $" with a value of {getDigitalTwinResponse.Body.Thermostat1.Metadata.TargetTemperature.DesiredValue}."); // The property path to be replaced should be prepended with a '/' updateOperation.AppendReplacePropertyOp($"/{Thermostat1Component}/{targetTemperaturePropertyName}", desiredTargetTemperature); } else { _logger.LogDebug($"The property {targetTemperaturePropertyName} under component {Thermostat1Component} `" + $"was never set on the {_digitalTwinId} digital twin."); // The property path to be added should be prepended with a '/' updateOperation.AppendAddPropertyOp($"/{Thermostat1Component}/{targetTemperaturePropertyName}", desiredTargetTemperature); } } else { // Thermostat1 is not present in the TemperatureController twin. We will add the component var componentProperty = new Dictionary <string, object> { { targetTemperaturePropertyName, desiredTargetTemperature }, { "$metadata", new object() } }; _logger.LogDebug($"The component {Thermostat1Component} does not exist on the {_digitalTwinId} digital twin."); // The property path to be replaced should be prepended with a '/' updateOperation.AppendAddComponentOp($"/{Thermostat1Component}", componentProperty); } _logger.LogDebug($"Update the {targetTemperaturePropertyName} property under component {Thermostat1Component} on the {_digitalTwinId} `" + $"digital twin to {desiredTargetTemperature}."); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> updateDigitalTwinResponse = await _digitalTwinClient .UpdateDigitalTwinAsync(_digitalTwinId, updateOperation.Serialize()); _logger.LogDebug($"Update {_digitalTwinId} digital twin response: {updateDigitalTwinResponse.Response.StatusCode}."); // Print the TemperatureController digital twin await GetAndPrintDigitalTwinAsync <TemperatureControllerTwin>(); }
public static async Task Run( [EventHubTrigger("deviceevents", Connection = "EVENTHUB_CONNECTIONSTRING")] EventData[] events, ILogger log) { // After this is deployed, you need to turn the Managed Identity Status to "On", // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role // to this function identity in order for this function to be authorized on ADT APIs. if (adtInstanceUrl == null) { log.LogError("Application setting \"ADT_SERVICE_URL\" not set"); } var exceptions = new List <Exception>(); foreach (EventData eventData in events) { try { // Get message body string messageBody = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count); // Create Digital Twin client var cred = new ManagedIdentityCredential("https://digitaltwins.azure.net"); var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpClient) }); // Reading Device ID from message headers JObject jbody = (JObject)JsonConvert.DeserializeObject(messageBody); string deviceId = eventData.SystemProperties["iothub-connection-device-id"].ToString(); string dtId = deviceId; // simple mapping // Extracting temperature from device telemetry double temperature = Convert.ToDouble(jbody["Temperature"].ToString()); // Update device Temperature property UpdateOperationsUtility uou = new UpdateOperationsUtility(); uou.AppendAddOp("/Temperature", temperature); await client.UpdateDigitalTwinAsync(dtId, uou.Serialize()); log.LogInformation($"Updated Temperature of device Twin '{dtId}' to: {temperature}"); } catch (Exception e) { // We need to keep processing the rest of the batch - capture this exception and continue. exceptions.Add(e); } } if (exceptions.Count > 1) { throw new AggregateException(exceptions); } if (exceptions.Count == 1) { throw exceptions.Single(); } }
public override async Task HandleMessageAsync(DeviceTelemetryMessage requestBody, RequestDetails requestDetails, RequestMessageHeaders headers, IExtensionGatewayClient client, ILogger log) { //write telemetry to statestore await client.PutDeviceTelemetryAsync(requestDetails.DeviceName, requestBody); // Create a secret client using the DefaultAzureCredential DefaultAzureCredential cred = new DefaultAzureCredential(); DigitalTwinsClient dtcli = new DigitalTwinsClient(new Uri("https://mobility-vss.api.wus2.digitaltwins.azure.net"), cred); DTUnit du = JsonSerializer.Deserialize <DTUnit>((string)requestBody.Payload); var updateOps = new UpdateOperationsUtility(); if (du.type == "boolean") { updateOps.AppendAddOp(du.path, bool.Parse(du.value)); } else if ((du.type == "date") || (du.type == "datetime") || (du.type == "time")) { updateOps.AppendAddOp(du.path, DateTime.Parse(du.value)); } else if (du.type == "double") { updateOps.AppendAddOp(du.path, double.Parse(du.value)); } else if (du.type == "float") { updateOps.AppendAddOp(du.path, float.Parse(du.value)); } else if (du.type == "integer") { updateOps.AppendAddOp(du.path, int.Parse(du.value)); } else if (du.type == "long") { updateOps.AppendAddOp(du.path, long.Parse(du.value)); } else { updateOps.AppendAddOp(du.path, du.value); } string patchPayload = updateOps.Serialize(); await dtcli.UpdateDigitalTwinAsync(du.dtID, patchPayload); // send stuff to the analytics pipeline var telemetryItem = new { VehicleId = requestDetails.VehicleId, TelemetryName = requestBody.TelemetryName, Time = requestBody.Time, Payload = patchPayload }; await client.SendToAnalyticsPipeline(telemetryItem); }
public static string GetRoomTwinUpdatePayload() { var uou = new UpdateOperationsUtility(); uou.AppendAddOp("/Humidity", 30); uou.AppendReplaceOp("/Temperature", 70); uou.AppendRemoveOp("/EmployeeId"); return(RemoveNewLines(uou.Serialize())); }
private static string generatePatchForTurbine(PowerValues powerValues) { UpdateOperationsUtility uou = new UpdateOperationsUtility(); uou.AppendReplaceOp("/powerObserved", powerValues.powerObserved); uou.AppendReplaceOp("/powerPM", powerValues.powerPM); uou.AppendReplaceOp("/powerDM", powerValues.powerDM); return(uou.Serialize()); }
public static async Task Run( [EventHubTrigger("deviceevents", Connection = "EVENTHUB_CONNECTIONSTRING")] EventData[] events, ILogger log) { var exceptions = new List <Exception>(); foreach (EventData eventData in events) { try { // Get message body string messageBody = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count); // Create Digital Twin client var cred = new ManagedIdentityCredential(adtAppId); var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpClient) }); // Reading Device ID from message headers JObject jbody = (JObject)JsonConvert.DeserializeObject(messageBody); string deviceId = eventData.SystemProperties["iothub-connection-device-id"].ToString(); string dtId = deviceId; // simple mapping // Extracting temperature from device telemetry double temperature = Convert.ToDouble(jbody["Temperature"].ToString()); // Update device Temperature property UpdateOperationsUtility uou = new UpdateOperationsUtility(); uou.AppendAddOp("/Temperature", temperature); await client.UpdateDigitalTwinAsync(dtId, uou.Serialize()); log.LogInformation($"Updated Temperature of device Twin '{dtId}' to: {temperature}"); } catch (Exception e) { // We need to keep processing the rest of the batch - capture this exception and continue. exceptions.Add(e); } } if (exceptions.Count > 1) { throw new AggregateException(exceptions); } if (exceptions.Count == 1) { throw exceptions.Single(); } }
public async Task Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log) { // After this is deployed, you need to turn the Managed Identity Status to "On", // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role // to this function identity in order for this function to be authorized on ADT APIs. if (adtInstanceUrl == null) { log.LogError("Application setting \"ADT_SERVICE_URL\" not set"); } try { //Authenticate with Digital Twins ManagedIdentityCredential cred = new ManagedIdentityCredential("https://digitaltwins.azure.net"); DigitalTwinsClient client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpClient) }); if (eventGridEvent != null && eventGridEvent.Data != null) { log.LogInformation(eventGridEvent.Data.ToString()); JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString()); byte[] body_byte = System.Convert.FromBase64String(deviceMessage["body"].ToString()); var body_value = System.Text.ASCIIEncoding.ASCII.GetString(body_byte); var body_json = (JObject)JsonConvert.DeserializeObject(body_value); //log.LogInformation($"Body {body_json}"); log.LogInformation(deviceMessage.ToString()); string deviceId = (string)deviceMessage["systemProperties"]["iothub-connection-device-id"]; var temperature = body_json["temperature_hts221"]; var humidity = body_json["humidity"]; log.LogInformation($"Device:{deviceId} Temperature is:{temperature} Humidity is:{humidity}"); //Update twin using device temperature var uou = new UpdateOperationsUtility(); uou.AppendReplaceOp("/Temperature", temperature.Value <double>()); uou.AppendReplaceOp("/HumidityLevel", humidity.Value <double>()); await client.UpdateDigitalTwinAsync(deviceId, uou.Serialize()); } } catch (Exception e) { log.LogError($"Error in ingest function: {e.Message}"); } }
public void UpdateOperationsUtility_BuildAdd() { // arrange const string addOp = "add"; const string replaceOp = "replace"; const string removeOp = "remove"; const string addPath = "/addComponentPath123"; const string addValue = "value123"; const string replacePath = "/replaceComponentPath123"; const string replaceValue = "value456"; const string removePath = "/removeComponentPath123"; var dtUpdateUtility = new UpdateOperationsUtility(); dtUpdateUtility.AppendAddOp(addPath, addValue); dtUpdateUtility.AppendReplaceOp(replacePath, replaceValue); dtUpdateUtility.AppendRemoveOp(removePath); // act string actual = dtUpdateUtility.Serialize(); // assert JsonDocument parsed = JsonDocument.Parse(actual); parsed.RootElement.ValueKind.Should().Be(JsonValueKind.Array, "operations should be nested in an array"); parsed.RootElement.GetArrayLength().Should().Be(3, "three operations were included"); JsonElement addElement = parsed.RootElement[0]; addElement.GetProperty("op").GetString().Should().Be(addOp); addElement.GetProperty("path").GetString().Should().Be(addPath); addElement.GetProperty("value").GetString().Should().Be(addValue); JsonElement replaceElement = parsed.RootElement[1]; replaceElement.GetProperty("op").GetString().Should().Be(replaceOp); replaceElement.GetProperty("path").GetString().Should().Be(replacePath); replaceElement.GetProperty("value").GetString().Should().Be(replaceValue); JsonElement removeElement = parsed.RootElement[2]; removeElement.GetProperty("op").GetString().Should().Be(removeOp); removeElement.GetProperty("path").GetString().Should().Be(removePath); removeElement.TryGetProperty("value", out _).Should().BeFalse(); }
private static string generatePatchForSensor(WTInfo info, TemperatureValues tempValues) { UpdateOperationsUtility uou = new UpdateOperationsUtility(); uou.AppendReplaceOp("/blade1PitchAngle", info.Blade1PitchPosition); uou.AppendReplaceOp("/blade2PitchAngle", info.Blade2PitchPosition); uou.AppendReplaceOp("/blade3PitchAngle", info.Blade3PitchPosition); uou.AppendReplaceOp("/yawPosition", info.YawPosition); uou.AppendReplaceOp("/windDirection", info.WindDir); uou.AppendReplaceOp("/windSpeed", info.WindSpeed); uou.AppendReplaceOp("/temperatureNacelle", tempValues.nacelle); uou.AppendReplaceOp("/temperatureGenerator", tempValues.generator); uou.AppendReplaceOp("/temperatureGearBox", tempValues.gearBox); return(uou.Serialize()); }
public static async Task UpdateTwinPropertyAsync(DigitalTwinsClient client, string twinId, string propertyPath, object value, ILogger log) { // If the twin does not exist, this will log an error try { var uou = new UpdateOperationsUtility(); uou.AppendReplaceOp(propertyPath, value); string patchPayload = uou.Serialize(); log.LogInformation($"UpdateTwinPropertyAsync sending {patchPayload}"); await client.UpdateDigitalTwinAsync(twinId, patchPayload); } catch (RequestFailedException exc) { log.LogInformation($"*** Error:{exc.Status}/{exc.Message}"); } }
private async Task UpdateCurrentTemperaturePropertyAsync() { // Choose a random value to assign to the currentTemperature property int currentTemperature = Random.Next(0, 100); const string currentTemperaturePropertyName = "currentTemperature"; var updateOperation = new UpdateOperationsUtility(); // First, add the property to the digital twin updateOperation.AppendAddPropertyOp($"/{currentTemperaturePropertyName}", currentTemperature); _logger.LogDebug($"Add the {currentTemperaturePropertyName} property on the {_digitalTwinId} digital twin " + $"with a value of {currentTemperature}."); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> addPropertyToDigitalTwinResponse = await _digitalTwinClient .UpdateDigitalTwinAsync(_digitalTwinId, updateOperation.Serialize()); _logger.LogDebug($"Update {_digitalTwinId} digital twin response: {addPropertyToDigitalTwinResponse.Response.StatusCode}."); // Print the Thermostat digital twin await GetAndPrintDigitalTwinAsync <ThermostatTwin>(); // Second, replace the property to a different value int newCurrentTemperature = Random.Next(0, 100); updateOperation.AppendReplacePropertyOp($"/{currentTemperaturePropertyName}", newCurrentTemperature); _logger.LogDebug($"Replace the {currentTemperaturePropertyName} property on the {_digitalTwinId} digital twin " + $"with a value of {newCurrentTemperature}."); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> replacePropertyInDigitalTwinResponse = await _digitalTwinClient .UpdateDigitalTwinAsync(_digitalTwinId, updateOperation.Serialize()); _logger.LogDebug($"Update {_digitalTwinId} digital twin response: {replacePropertyInDigitalTwinResponse.Response.StatusCode}."); // Print the Thermostat digital twin await GetAndPrintDigitalTwinAsync <ThermostatTwin>(); // Third, remove the currentTemperature property updateOperation.AppendRemoveOp($"/{currentTemperaturePropertyName}"); _logger.LogDebug($"Remove the {currentTemperaturePropertyName} property on the {_digitalTwinId} digital twin."); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> removePropertyInDigitalTwinResponse = await _digitalTwinClient .UpdateDigitalTwinAsync(_digitalTwinId, updateOperation.Serialize()); _logger.LogDebug($"Update {_digitalTwinId} digital twin response: {removePropertyInDigitalTwinResponse.Response.StatusCode}."); // Print the Thermostat digital twin await GetAndPrintDigitalTwinAsync <ThermostatTwin>(); }
public void UpdateUtilityAppendsRemoveOp() { var op = new UpdateOperationsUtility(); string path = "testPath"; op.AppendRemoveOp(path); string operations = op.Serialize(); // There should be a single operation added. var jArray = JArray.Parse(operations); jArray.Count.Should().Be(1); // The patch operation added should be a "remove" operation. JToken jObject = jArray.First; jObject.Value <string>(Op).Should().Be(Remove); }
public void UpdateUtilityAppendsAddPropertyOp() { var op = new UpdateOperationsUtility(); string path = "testPath"; int value = 10; op.AppendAddPropertyOp(path, value); string operations = op.Serialize(); // There should be a single operation added. var jArray = JArray.Parse(operations); jArray.Count.Should().Be(1); // The patch operation added should be an "add" operation. JToken jObject = jArray.First; jObject.Value <string>(Op).Should().Be(Add); }
private async Task UpdateTargetTemperaturePropertyAsync() { const string targetTemperaturePropertyName = "targetTemperature"; var updateOperation = new UpdateOperationsUtility(); // Choose a random value to assign to the targetTemperature property int desiredTargetTemperature = Random.Next(0, 100); // First let's take a look at when the property was updated and what was it set to. HttpOperationResponse <ThermostatTwin, DigitalTwinGetHeaders> getDigitalTwinResponse = await _digitalTwinClient .GetDigitalTwinAsync <ThermostatTwin>(_digitalTwinId); double?currentTargetTemperature = getDigitalTwinResponse.Body.TargetTemperature; if (currentTargetTemperature != null) { DateTimeOffset targetTemperatureDesiredLastUpdateTime = getDigitalTwinResponse.Body.Metadata.TargetTemperature.LastUpdateTime; _logger.LogDebug($"The property {targetTemperaturePropertyName} was last updated on " + $"{targetTemperatureDesiredLastUpdateTime.ToLocalTime()} `" + $" with a value of {getDigitalTwinResponse.Body.Metadata.TargetTemperature.DesiredValue}."); // The property path to be replaced should be prepended with a '/' updateOperation.AppendReplacePropertyOp($"/{targetTemperaturePropertyName}", desiredTargetTemperature); } else { _logger.LogDebug($"The property {targetTemperaturePropertyName} was never set on the ${_digitalTwinId} digital twin."); // The property path to be added should be prepended with a '/' updateOperation.AppendAddPropertyOp($"/{targetTemperaturePropertyName}", desiredTargetTemperature); } _logger.LogDebug($"Update the {targetTemperaturePropertyName} property on the " + $"{_digitalTwinId} digital twin to {desiredTargetTemperature}."); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> updateDigitalTwinResponse = await _digitalTwinClient .UpdateDigitalTwinAsync(_digitalTwinId, updateOperation.Serialize()); _logger.LogDebug($"Update {_digitalTwinId} digital twin response: {updateDigitalTwinResponse.Response.StatusCode}."); // Print the Thermostat digital twin await GetAndPrintDigitalTwinAsync <ThermostatTwin>(); }
private async Task UpdateDigitalTwinProperty(DigitalTwinsClient client, string deviceId, JToken body, string propertyName) { var propertyToken = body[propertyName]; if (propertyToken != null) { if (Constants.Telemetries.Contains(propertyName.ToUpper())) { var data = new Dictionary <string, double>(); data.Add(propertyName, propertyToken.Value <double>()); await client.PublishTelemetryAsync(deviceId, JsonConvert.SerializeObject(data)); } else { // Update twin using device property var uou = new UpdateOperationsUtility(); uou.AppendReplaceOp($"/{propertyName}", propertyToken.Value <double>()); await client.UpdateDigitalTwinAsync(deviceId, uou.Serialize()); } } }
private static void GetPatchPayload(string jsonInput, ref string dtid, ref string patchpayload) { var updateOps = new UpdateOperationsUtility(); DTUnit du = JsonSerializer.Deserialize <DTUnit>(jsonInput); dtid = du.dtID; if (du.type == "boolean") { updateOps.AppendAddOp(du.path, bool.Parse(du.value)); } else if ((du.type == "date") || (du.type == "datetime") || (du.type == "time")) { updateOps.AppendAddOp(du.path, DateTime.Parse(du.value)); } else if (du.type == "double") { updateOps.AppendAddOp(du.path, double.Parse(du.value)); } else if (du.type == "float") { updateOps.AppendAddOp(du.path, float.Parse(du.value)); } else if (du.type == "integer") { updateOps.AppendAddOp(du.path, int.Parse(du.value)); } else if (du.type == "long") { updateOps.AppendAddOp(du.path, long.Parse(du.value)); } else { updateOps.AppendAddOp(du.path, du.value); } patchpayload = updateOps.Serialize(); }
public async void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log) { if (adtInstanceUrl == null) { log.LogError("Application setting \"ADT_SERVICE_URL\" not set"); } try { //Authenticate with Digital Twins ManagedIdentityCredential cred = new ManagedIdentityCredential("https://digital-twin-demo-jc.api.wcus.digitaltwins.azure.net"); DigitalTwinsClient client = new DigitalTwinsClient( new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpClient) }); log.LogInformation($"ADT service client connection created."); if (eventGridEvent != null && eventGridEvent.Data != null) { log.LogInformation(eventGridEvent.Data.ToString()); // Reading deviceId, temperature, humidity, pressure, magnetometer, accelerometer and gyroscope for IoT Hub JSON JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString()); string deviceId = (string)deviceMessage["systemProperties"]["iothub-connection-device-id"]; byte[] body = System.Convert.FromBase64String(deviceMessage["body"].ToString()); var value = System.Text.ASCIIEncoding.ASCII.GetString(body); var bodyProperty = (JObject)JsonConvert.DeserializeObject(value); var temperature = bodyProperty["temperature"]; var humidity = bodyProperty["humidity"]; var pressure = bodyProperty["pressure"]; var magnetometer_x = bodyProperty["magnetometer_x"]; var magnetometer_y = bodyProperty["magnetometer_y"]; var magnetometer_z = bodyProperty["magnetometer_z"]; var accelerometer_x = bodyProperty["accelerometer_x"]; var accelerometer_y = bodyProperty["accelerometer_y"]; var accelerometer_z = bodyProperty["accelerometer_z"]; var gyroscope_x = bodyProperty["gyroscope_x"]; var gyroscope_y = bodyProperty["gyroscope_y"]; var gyroscope_z = bodyProperty["gyroscope_z"]; log.LogInformation($"Device:{deviceId} Temperature is: {temperature}"); //note: AppendReplaceOp only works if model properties are instantiated when twin created. var uou = new UpdateOperationsUtility(); if (temperature != null) //accounting for null values from I2C bus on MXChip dev kits { uou.AppendAddOp("/temperature", temperature.Value <double>()); } else { temperature = -1000; uou.AppendAddOp("/temperature", temperature.Value <double>()); } if (humidity != null) { uou.AppendAddOp("/humidity", humidity.Value <double>()); } else { humidity = -1000; uou.AppendAddOp("/humidity", humidity.Value <double>()); } if (pressure != null) { uou.AppendAddOp("/pressure", pressure.Value <double>()); } else { pressure = -1000; uou.AppendAddOp("/pressure", pressure.Value <double>()); } if (magnetometer_x != null) { uou.AppendAddOp("/magnetometer_x", magnetometer_x.Value <double>()); } else { magnetometer_x = -1000; uou.AppendAddOp("/magnetometer_x", magnetometer_x.Value <double>()); } if (magnetometer_y != null) { uou.AppendAddOp("/magnetometer_y", magnetometer_y.Value <double>()); } else { magnetometer_y = -1000; uou.AppendAddOp("/magnetometer_y", magnetometer_y.Value <double>()); } if (magnetometer_z != null) { uou.AppendAddOp("/magnetometer_z", magnetometer_z.Value <double>()); } else { magnetometer_z = -1000; uou.AppendAddOp("/magnetometer_z", magnetometer_z.Value <double>()); } if (accelerometer_x != null) { uou.AppendAddOp("/accelerometer_x", accelerometer_x.Value <double>()); } else { accelerometer_x = -1000; uou.AppendAddOp("/accelerometer_x", accelerometer_x.Value <double>()); } if (accelerometer_y != null) { uou.AppendAddOp("/accelerometer_y", accelerometer_y.Value <double>()); } else { accelerometer_y = -1000; uou.AppendAddOp("/accelerometer_y", accelerometer_y.Value <double>()); } if (accelerometer_z != null) { uou.AppendAddOp("/accelerometer_z", accelerometer_z.Value <double>()); } else { accelerometer_z = -1000; uou.AppendAddOp("/accelerometer_z", accelerometer_z.Value <double>()); } if (gyroscope_x != null) { uou.AppendAddOp("/gyroscope_x", gyroscope_x.Value <double>()); } else { gyroscope_x = -1000; uou.AppendAddOp("/gyroscope_x", gyroscope_x.Value <double>()); } if (gyroscope_y != null) { uou.AppendAddOp("/gyroscope_y", gyroscope_y.Value <double>()); } else { gyroscope_y = -1000; uou.AppendAddOp("/gyroscope_y", gyroscope_y.Value <double>()); } if (gyroscope_z != null) { uou.AppendAddOp("/gyroscope_z", gyroscope_z.Value <double>()); } else { gyroscope_z = -1000; uou.AppendAddOp("/gyroscope_z", gyroscope_z.Value <double>()); } await client.UpdateDigitalTwinAsync(deviceId, uou.Serialize()); log.LogInformation($"Device:{deviceId} Pressure is: {pressure}"); } } catch (Exception e) { log.LogError($"Error in ingest function: {e.Message}"); } }
public async static void Run([EventGridTrigger] EventGridEvent ev, ILogger log) { if (adtInstanceUrl == null) { log.LogError("Application setting \"ADT_SERVICE_URL\" not set"); } try { // Authenticate with Digital Twins ManagedIdentityCredential cred = new ManagedIdentityCredential("https://digitaltwins.azure.net"); DigitalTwinsClient client = new DigitalTwinsClient(new Uri(adtInstanceUrl), cred, new DigitalTwinsClientOptions { Transport = new HttpClientTransport(httpClient) }); log.LogInformation("ADT service client connection created."); if (ev != null && ev.Data != null) { // Extract JSON body from event JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(ev.Data.ToString()); byte[] data = System.Convert.FromBase64String((string)deviceMessage ["body"]); JObject body = (JObject)JsonConvert.DeserializeObject(System.Text.ASCIIEncoding.ASCII.GetString(data)); // Extract device twin id from message and digital twin id from system properties string deviceId = (string)deviceMessage ["systemProperties"]["iothub-connection-device-id"]; string twinId = (string)body ["twin_id"]; log.LogInformation($"Routing from device_id: {deviceId}"); log.LogInformation($"Routing to twin_id: {twinId}"); // Iterate set of readings and create change set for twin JObject readings = (JObject)body ["readings"]; var uou = new UpdateOperationsUtility(); foreach (var reading in readings) { string type = (string)reading.Value ["type"]; string key = (string)reading.Key; var value = reading.Value ["value"]; log.LogInformation($"key: {key} value: {value} type: {type}"); switch (type.ToLower()) { case "bool": uou.AppendReplaceOp($"/{key}", value.Value <bool>()); break; case "int8": uou.AppendReplaceOp($"/{key}", value.Value <SByte>()); break; case "int16": uou.AppendReplaceOp($"/{key}", value.Value <Int16>()); break; case "int32": uou.AppendReplaceOp($"/{key}", value.Value <Int32>()); break; case "uint8": uou.AppendReplaceOp($"/{key}", value.Value <Byte>()); break; case "uint16": uou.AppendReplaceOp($"/{key}", value.Value <UInt16>()); break; case "float32": uou.AppendReplaceOp($"/{key}", value.Value <float>()); break; case "float64": uou.AppendReplaceOp($"/{key}", value.Value <double>()); break; default: log.LogWarning($"{key} using {type} type isn't supported"); break; } } // Update digital twin string digitalTwinPatch = uou.Serialize(); log.LogInformation($"Updating twin: {twinId} with patch {digitalTwinPatch}"); await client.UpdateDigitalTwinAsync(twinId, digitalTwinPatch); } } catch (Exception e) { log.LogError(e.Message); } }
/// <summary> /// Creates a digital twin with Component and upates Component /// </summary> public async Task RunSamplesAsync() { PrintHeader("COMPONENT SAMPLE"); // For the purpose of this example we will create temporary models using a random model Ids. // We have to make sure these model Ids are unique within the DT instance. string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, DigitalTwinsClient).ConfigureAwait(false); string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, DigitalTwinsClient).ConfigureAwait(false); string twinId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, DigitalTwinsClient).ConfigureAwait(false); string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload .Replace(SamplesConstants.ComponentId, componentModelId); string newModelPayload = SamplesConstants.TemporaryModelPayload .Replace(SamplesConstants.ModelId, modelId) .Replace(SamplesConstants.ComponentId, componentModelId); // Then we create models await DigitalTwinsClient.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }).ConfigureAwait(false); Console.WriteLine($"Successfully created models with Ids: {componentModelId}, {modelId}"); // Create digital twin with Component payload string twinPayload = SamplesConstants.TemporaryTwinPayload .Replace(SamplesConstants.ModelId, modelId) .Replace(SamplesConstants.ComponentId, componentModelId); await DigitalTwinsClient.CreateDigitalTwinAsync(twinId, twinPayload).ConfigureAwait(false); Console.WriteLine($"Created digital twin {twinId}."); #region Snippet:DigitalTwinSampleUpdateComponent // Update Component with replacing property value string propertyPath = "/ComponentProp1"; string propValue = "New Value"; var componentUpdateUtility = new UpdateOperationsUtility(); componentUpdateUtility.AppendReplaceOp(propertyPath, propValue); Response <string> response = await DigitalTwinsClient.UpdateComponentAsync(twinId, SamplesConstants.ComponentPath, componentUpdateUtility.Serialize()); #endregion Snippet:DigitalTwinSampleUpdateComponent Console.WriteLine($"Updated component for digital twin {twinId}. Update response status: {response.GetRawResponse().Status}"); // Get Component #region Snippet:DigitalTwinSampleGetComponent response = await DigitalTwinsClient.GetComponentAsync(twinId, SamplesConstants.ComponentPath).ConfigureAwait(false); #endregion Snippet:DigitalTwinSampleGetComponent Console.WriteLine($"Get component for digital twin: \n{response.Value}. Get response status: {response.GetRawResponse().Status}"); // Now delete a Twin await DigitalTwinsClient.DeleteDigitalTwinAsync(twinId).ConfigureAwait(false); // Delete models try { await DigitalTwinsClient.DeleteModelAsync(modelId).ConfigureAwait(false); await DigitalTwinsClient.DeleteModelAsync(componentModelId).ConfigureAwait(false); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete models due to {ex}"); } }
public async Task DigitalTwinWithComponentOperationsAsync() { // Create a new test device instance. TestDevice testDevice = await TestDevice.GetTestDeviceAsync(Logger, _devicePrefix).ConfigureAwait(false); string deviceId = testDevice.Id; try { // Create a device client instance over Mqtt, initializing it with the "TemperatureController" model which has "Thermostat" components. var options = new ClientOptions { ModelId = TemperatureControllerModelId, }; using DeviceClient deviceClient = testDevice.CreateDeviceClient(Client.TransportType.Mqtt, options); // Call openAsync() to open the device's connection, so that the ModelId is sent over Mqtt CONNECT packet. await deviceClient.OpenAsync().ConfigureAwait(false); // Perform operations on the digital twin. using var digitalTwinClient = DigitalTwinClient.CreateFromConnectionString(s_connectionString); // Retrieve the digital twin. HttpOperationResponse <TemperatureControllerTwin, DigitalTwinGetHeaders> response = await digitalTwinClient.GetDigitalTwinAsync <TemperatureControllerTwin>(deviceId).ConfigureAwait(false); TemperatureControllerTwin twin = response.Body; twin.Metadata.ModelId.Should().Be(TemperatureControllerModelId); string componentName = "thermostat1"; // Set callback handler for receiving twin property updates. await deviceClient.SetDesiredPropertyUpdateCallbackAsync((patch, context) => { Logger.Trace($"{nameof(DigitalTwinWithComponentOperationsAsync)}: DesiredProperty update received: {patch}, {context}"); return(Task.FromResult(true)); }, deviceClient); // Update the property "targetTemperature" under component "thermostat1" on the digital twin. // NOTE: since this is the first operation on the digital twin, the component "thermostat1" doesn't exist on it yet. // So we will create a property patch that "adds" a component, and updates the property in it. string propertyName = "targetTemperature"; double propertyValue = new Random().Next(0, 100); var propertyValues = new Dictionary <string, object> { { propertyName, propertyValue } }; var ops = new UpdateOperationsUtility(); ops.AppendAddComponentOp($"/{componentName}", propertyValues); string patch = ops.Serialize(); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> updateResponse = await digitalTwinClient.UpdateDigitalTwinAsync(deviceId, patch); updateResponse.Response.StatusCode.Should().Be(HttpStatusCode.Accepted); // Set callbacks to handle command requests. int expectedCommandStatus = 200; // Set callback to handle root-level command invocation request. string rootCommandName = "reboot"; await deviceClient.SetMethodHandlerAsync(rootCommandName, (request, context) => { Logger.Trace($"{nameof(DigitalTwinWithComponentOperationsAsync)}: Digital twin command {request.Name} received."); string payload = JsonConvert.SerializeObject(request.Name); return(Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(payload), expectedCommandStatus))); }, null); // Invoke the root-level command "reboot" on the digital twin. int delay = 1; string rootCommandPayload = JsonConvert.SerializeObject(delay); HttpOperationResponse <DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders> rootCommandResponse = await digitalTwinClient.InvokeCommandAsync(deviceId, rootCommandName, rootCommandPayload).ConfigureAwait(false); rootCommandResponse.Body.Status.Should().Be(expectedCommandStatus); rootCommandResponse.Body.Payload.Should().Be(JsonConvert.SerializeObject(rootCommandName)); // Set callback to handle component-level command invocation request. // For a component-level command, the command name is in the format "<component-name>*<command-name>". string componentCommandName = "getMaxMinReport"; string componentCommandNamePnp = $"{componentName}*{componentCommandName}"; await deviceClient.SetMethodHandlerAsync(componentCommandNamePnp, (request, context) => { Logger.Trace($"{nameof(DigitalTwinWithComponentOperationsAsync)}: Digital twin command {request.Name} received."); string payload = JsonConvert.SerializeObject(request.Name); return(Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(payload), expectedCommandStatus))); }, null); // Invoke the command "getMaxMinReport" under component "thermostat1" on the digital twin. DateTimeOffset since = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(1)); string componentCommandPayload = JsonConvert.SerializeObject(since); HttpOperationResponse <DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders> componentCommandResponse = await digitalTwinClient.InvokeComponentCommandAsync(deviceId, componentName, componentCommandName, componentCommandPayload).ConfigureAwait(false); componentCommandResponse.Body.Status.Should().Be(expectedCommandStatus); componentCommandResponse.Body.Payload.Should().Be(JsonConvert.SerializeObject(componentCommandNamePnp)); } finally { // Delete the device. await testDevice.RemoveDeviceAsync().ConfigureAwait(false); } }
public async Task DigitalTwinWithOnlyRootComponentOperationsAsync() { // Create a new test device instance. TestDevice testDevice = await TestDevice.GetTestDeviceAsync(Logger, _devicePrefix).ConfigureAwait(false); string deviceId = testDevice.Id; try { // Create a device client instance over Mqtt, initializing it with the "Thermostat" model which has only a root component. var options = new ClientOptions { ModelId = ThermostatModelId, }; using DeviceClient deviceClient = testDevice.CreateDeviceClient(Client.TransportType.Mqtt, options); // Call openAsync() to open the device's connection, so that the ModelId is sent over Mqtt CONNECT packet. await deviceClient.OpenAsync().ConfigureAwait(false); // Perform operations on the digital twin. using var digitalTwinClient = DigitalTwinClient.CreateFromConnectionString(s_connectionString); // Retrieve the digital twin. HttpOperationResponse <ThermostatTwin, DigitalTwinGetHeaders> response = await digitalTwinClient.GetDigitalTwinAsync <ThermostatTwin>(deviceId).ConfigureAwait(false); ThermostatTwin twin = response.Body; twin.Metadata.ModelId.Should().Be(ThermostatModelId); // Set callback handler for receiving root-level twin property updates. await deviceClient.SetDesiredPropertyUpdateCallbackAsync((patch, context) => { Logger.Trace($"{nameof(DigitalTwinWithComponentOperationsAsync)}: DesiredProperty update received: {patch}, {context}"); return(Task.FromResult(true)); }, deviceClient); // Update the root-level property "targetTemperature". string propertyName = "targetTemperature"; double propertyValue = new Random().Next(0, 100); var ops = new UpdateOperationsUtility(); ops.AppendAddPropertyOp($"/{propertyName}", propertyValue); string patch = ops.Serialize(); HttpOperationHeaderResponse <DigitalTwinUpdateHeaders> updateResponse = await digitalTwinClient.UpdateDigitalTwinAsync(deviceId, patch); updateResponse.Response.StatusCode.Should().Be(HttpStatusCode.Accepted); // Set callback to handle root-level command invocation request. int expectedCommandStatus = 200; string commandName = "getMaxMinReport"; await deviceClient.SetMethodHandlerAsync(commandName, (request, context) => { Logger.Trace($"{nameof(DigitalTwinWithOnlyRootComponentOperationsAsync)}: Digital twin command received: {request.Name}."); string payload = JsonConvert.SerializeObject(request.Name); return(Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(payload), expectedCommandStatus))); }, null); // Invoke the root-level command "getMaxMinReport" on the digital twin. DateTimeOffset since = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(1)); string payload = JsonConvert.SerializeObject(since); HttpOperationResponse <DigitalTwinCommandResponse, DigitalTwinInvokeCommandHeaders> commandResponse = await digitalTwinClient.InvokeCommandAsync(deviceId, commandName, payload).ConfigureAwait(false); commandResponse.Body.Status.Should().Be(expectedCommandStatus); commandResponse.Body.Payload.Should().Be(JsonConvert.SerializeObject(commandName)); } finally { // Delete the device. await testDevice.RemoveDeviceAsync().ConfigureAwait(false); } }
/// <summary> /// Creates a digital twin with Component and upates Component /// </summary> public async Task RunSamplesAsync() { PrintHeader("COMPONENT SAMPLE"); // For the purpose of this example we will create temporary models using a random model Ids. // We have to make sure these model Ids are unique within the DT instance. string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, DigitalTwinsClient).ConfigureAwait(false); string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, DigitalTwinsClient).ConfigureAwait(false); string dtId1 = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, DigitalTwinsClient).ConfigureAwait(false); string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload .Replace(SamplesConstants.ComponentId, componentModelId); string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload .Replace(SamplesConstants.ModelId, modelId) .Replace(SamplesConstants.ComponentId, componentModelId); // Then we create models Response <IReadOnlyList <Models.ModelData> > createModelsResponse = await DigitalTwinsClient .CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }) .ConfigureAwait(false); Console.WriteLine($"Successfully created models Ids {componentModelId} and {modelId} with response {createModelsResponse.GetRawResponse().Status}."); #region Snippet:DigitalTwinsSampleCreateBasicTwin // Create digital twin with Component payload using the BasicDigitalTwin serialization helper var basicDigitalTwin = new BasicDigitalTwin { Id = dtId1 }; basicDigitalTwin.Metadata.ModelId = modelId; basicDigitalTwin.CustomProperties.Add("Prop1", "Value1"); basicDigitalTwin.CustomProperties.Add("Prop2", "Value2"); var componentMetadata = new ModelProperties(); componentMetadata.Metadata.ModelId = componentModelId; componentMetadata.CustomProperties.Add("ComponentProp1", "ComponentValue1"); componentMetadata.CustomProperties.Add("ComponentProp2", "ComponentValue2"); basicDigitalTwin.CustomProperties.Add("Component1", componentMetadata); string dt1Payload = JsonSerializer.Serialize(basicDigitalTwin); Response <string> createDt1Response = await DigitalTwinsClient.CreateDigitalTwinAsync(dtId1, dt1Payload).ConfigureAwait(false); Console.WriteLine($"Created digital twin {dtId1} with response {createDt1Response.GetRawResponse().Status}."); #endregion Snippet:DigitalTwinsSampleCreateBasicTwin #region Snippet:DigitalTwinsSampleCreateCustomTwin string dtId2 = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, DigitalTwinsClient).ConfigureAwait(false); var customDigitalTwin = new CustomDigitalTwin { Id = dtId2, Metadata = new CustomDigitalTwinMetadata { ModelId = modelId }, Prop1 = "Prop1 val", Prop2 = "Prop2 val", Component1 = new Component1 { Metadata = new Component1Metadata { ModelId = componentModelId }, ComponentProp1 = "Component prop1 val", ComponentProp2 = "Component prop2 val", } }; string dt2Payload = JsonSerializer.Serialize(customDigitalTwin); Response <string> createDt2Response = await DigitalTwinsClient.CreateDigitalTwinAsync(dtId2, dt2Payload).ConfigureAwait(false); Console.WriteLine($"Created digital twin {dtId2} with response {createDt2Response.GetRawResponse().Status}."); #endregion Snippet:DigitalTwinsSampleCreateCustomTwin #region Snippet:DigitalTwinsSampleUpdateComponent // Update Component1 by replacing the property ComponentProp1 value var componentUpdateUtility = new UpdateOperationsUtility(); componentUpdateUtility.AppendReplaceOp("/ComponentProp1", "Some new value"); string updatePayload = componentUpdateUtility.Serialize(); Response <string> response = await DigitalTwinsClient.UpdateComponentAsync(dtId1, "Component1", updatePayload); Console.WriteLine($"Updated component for digital twin {dtId1}. Update response status: {response.GetRawResponse().Status}"); #endregion Snippet:DigitalTwinsSampleUpdateComponent // Get Component #region Snippet:DigitalTwinsSampleGetComponent response = await DigitalTwinsClient.GetComponentAsync(dtId1, SamplesConstants.ComponentPath).ConfigureAwait(false); Console.WriteLine($"Get component for digital twin: \n{response.Value}. Get response status: {response.GetRawResponse().Status}"); #endregion Snippet:DigitalTwinsSampleGetComponent // Clean up try { await DigitalTwinsClient.DeleteDigitalTwinAsync(dtId1).ConfigureAwait(false); await DigitalTwinsClient.DeleteDigitalTwinAsync(dtId2).ConfigureAwait(false); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete digital twin due to {ex}"); } try { await DigitalTwinsClient.DeleteModelAsync(modelId).ConfigureAwait(false); await DigitalTwinsClient.DeleteModelAsync(componentModelId).ConfigureAwait(false); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete models due to {ex}"); } }
/// <summary> /// Creates a digital twin with Component and upates Component /// </summary> public async Task RunSamplesAsync(DigitalTwinsClient client) { PrintHeader("COMPONENT SAMPLE"); // For the purpose of this example we will create temporary models using a random model Ids. // We have to make sure these model Ids are unique within the DT instance. string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client); string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client); string basicDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client); string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload .Replace(SamplesConstants.ComponentId, componentModelId); string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload .Replace(SamplesConstants.ModelId, modelId) .Replace(SamplesConstants.ComponentId, componentModelId); // Then we create models Response <IReadOnlyList <Models.ModelData> > createModelsResponse = await client.CreateModelsAsync( new[] { newComponentModelPayload, newModelPayload }); Console.WriteLine($"Created models with Ids {componentModelId} and {modelId}. Response status: {createModelsResponse.GetRawResponse().Status}."); #region Snippet:DigitalTwinsSampleCreateBasicTwin // Create digital twin with component payload using the BasicDigitalTwin serialization helper var basicTwin = new BasicDigitalTwin { Id = basicDtId, // model Id of digital twin Metadata = { ModelId = modelId }, CustomProperties = { // digital twin properties { "Prop1", "Value1" }, { "Prop2", 987 }, // component { "Component1", new ModelProperties { // component properties CustomProperties = { { "ComponentProp1", "Component value 1" }, { "ComponentProp2", 123 }, }, } }, }, }; string basicDtPayload = JsonSerializer.Serialize(basicTwin); Response <string> createBasicDtResponse = await client.CreateDigitalTwinAsync(basicDtId, basicDtPayload); Console.WriteLine($"Created digital twin with Id {basicDtId}. Response status: {createBasicDtResponse.GetRawResponse().Status}."); #endregion Snippet:DigitalTwinsSampleCreateBasicTwin // You can also get a digital twin and deserialize it into a BasicDigitalTwin. // It works well for basic stuff, but as you can see it gets more difficult when delving into // more complex properties, like components. #region Snippet:DigitalTwinsSampleGetBasicDigitalTwin Response <string> getBasicDtResponse = await client.GetDigitalTwinAsync(basicDtId); if (getBasicDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) { BasicDigitalTwin basicDt = JsonSerializer.Deserialize <BasicDigitalTwin>(getBasicDtResponse.Value); // Must cast Component1 as a JsonElement and get its raw text in order to deserialize it as a dictionary string component1RawText = ((JsonElement)basicDt.CustomProperties["Component1"]).GetRawText(); IDictionary <string, object> component1 = JsonSerializer.Deserialize <IDictionary <string, object> >(component1RawText); Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id}:\n\t" + $"ETag: {basicDt.ETag}\n\t" + $"Prop1: {basicDt.CustomProperties["Prop1"]}\n\t" + $"Prop2: {basicDt.CustomProperties["Prop2"]}\n\t" + $"ComponentProp1: {component1["ComponentProp1"]}\n\t" + $"ComponentProp2: {component1["ComponentProp2"]}"); } #endregion Snippet:DigitalTwinsSampleGetBasicDigitalTwin string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client); // Alternatively, you can create your own custom data types to serialize and deserialize your digital twins. // By specifying your properties and types directly, it requires less code or knowledge of the type for // interaction. #region Snippet:DigitalTwinsSampleCreateCustomTwin var customTwin = new CustomDigitalTwin { Id = customDtId, Metadata = { ModelId = modelId }, Prop1 = "Prop1 val", Prop2 = 987, Component1 = new Component1 { ComponentProp1 = "Component prop1 val", ComponentProp2 = 123, } }; string dt2Payload = JsonSerializer.Serialize(customTwin); Response <string> createCustomDtResponse = await client.CreateDigitalTwinAsync(customDtId, dt2Payload); Console.WriteLine($"Created digital twin with Id {customDtId}. Response status: {createCustomDtResponse.GetRawResponse().Status}."); #endregion Snippet:DigitalTwinsSampleCreateCustomTwin // Getting and deserializing a digital twin into a custom data type is extremely easy. // Custom types provide the best possible experience. #region Snippet:DigitalTwinsSampleGetCustomDigitalTwin Response <string> getCustomDtResponse = await client.GetDigitalTwinAsync(customDtId); if (getCustomDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) { CustomDigitalTwin customDt = JsonSerializer.Deserialize <CustomDigitalTwin>(getCustomDtResponse.Value); Console.WriteLine($"Retrieved and deserialized digital twin {customDt.Id}:\n\t" + $"ETag: {customDt.ETag}\n\t" + $"Prop1: {customDt.Prop1}\n\t" + $"Prop2: {customDt.Prop2}\n\t" + $"ComponentProp1: {customDt.Component1.ComponentProp1}\n\t" + $"ComponentProp2: {customDt.Component1.ComponentProp2}"); } #endregion Snippet:DigitalTwinsSampleGetCustomDigitalTwin #region Snippet:DigitalTwinsSampleUpdateComponent // Update Component1 by replacing the property ComponentProp1 value var componentUpdateUtility = new UpdateOperationsUtility(); componentUpdateUtility.AppendReplaceOp("/ComponentProp1", "Some new value"); string updatePayload = componentUpdateUtility.Serialize(); Response <string> response = await client.UpdateComponentAsync(basicDtId, "Component1", updatePayload); Console.WriteLine($"Updated component for digital twin with Id {basicDtId}. Response status: {response.GetRawResponse().Status}"); #endregion Snippet:DigitalTwinsSampleUpdateComponent // Get Component #region Snippet:DigitalTwinsSampleGetComponent response = await client.GetComponentAsync(basicDtId, SamplesConstants.ComponentPath); Console.WriteLine($"Retrieved component for digital twin with Id {basicDtId}. Response status: {response.GetRawResponse().Status}"); #endregion Snippet:DigitalTwinsSampleGetComponent // Clean up try { await client.DeleteDigitalTwinAsync(basicDtId); await client.DeleteDigitalTwinAsync(customDtId); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete digital twin due to {ex}"); } try { await client.DeleteModelAsync(modelId); await client.DeleteModelAsync(componentModelId); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete models due to {ex}"); } }