From f9072f7d68aa7469031b5202eba0142ca193325b Mon Sep 17 00:00:00 2001 From: Abhipsa Misra Date: Tue, 29 Jun 2021 15:59:28 -0700 Subject: [PATCH 1/3] refactor(samples): Move preview samples to samples repository --- .../Models/DeviceInformation.json | 64 -- .../Models/TemperatureController.json | 83 --- .../Models/Thermostat.json | 89 --- .../Models/Thermostat2.json | 89 --- .../TemperatureController/Parameter.cs | 86 --- .../TemperatureController/Program.cs | 165 ----- .../Properties/launchSettings.template.json | 22 - .../SystemTextJsonPayloadConvention.cs | 19 - .../SystemTextJsonPayloadSerializer.cs | 67 -- .../SystemTextJsonWritablePropertyResponse.cs | 57 -- .../TemperatureController.csproj | 19 - .../TemperatureControllerSample.cs | 412 ------------- .../TemperatureReport.cs | 26 - .../Thermostat/Models/Thermostat.json | 89 --- .../Thermostat/Parameter.cs | 86 --- .../Thermostat/Program.cs | 162 ----- .../Properties/launchSettings.template.json | 22 - .../Thermostat/TemperatureReport.cs | 26 - .../Thermostat/Thermostat.csproj | 19 - .../Thermostat/ThermostatSample.cs | 205 ------- .../convention-based-samples/readme.md | 577 ------------------ iothub/device/samples/readme.md | 35 +- 22 files changed, 20 insertions(+), 2399 deletions(-) delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Models/DeviceInformation.json delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Models/TemperatureController.json delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat.json delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat2.json delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Parameter.cs delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Program.cs delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/Properties/launchSettings.template.json delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadConvention.cs delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadSerializer.cs delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonWritablePropertyResponse.cs delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/TemperatureController.csproj delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/TemperatureControllerSample.cs delete mode 100644 iothub/device/samples/convention-based-samples/TemperatureController/TemperatureReport.cs delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/Models/Thermostat.json delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/Parameter.cs delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/Program.cs delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/Properties/launchSettings.template.json delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/TemperatureReport.cs delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/Thermostat.csproj delete mode 100644 iothub/device/samples/convention-based-samples/Thermostat/ThermostatSample.cs delete mode 100644 iothub/device/samples/convention-based-samples/readme.md diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Models/DeviceInformation.json b/iothub/device/samples/convention-based-samples/TemperatureController/Models/DeviceInformation.json deleted file mode 100644 index 6d59180dc8..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Models/DeviceInformation.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "@id": "dtmi:azure:DeviceManagement:DeviceInformation;1", - "@type": "Interface", - "displayName": "Device Information", - "contents": [ - { - "@type": "Property", - "name": "manufacturer", - "displayName": "Manufacturer", - "schema": "string", - "description": "Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso." - }, - { - "@type": "Property", - "name": "model", - "displayName": "Device model", - "schema": "string", - "description": "Device model name or ID. Ex. Surface Book 2." - }, - { - "@type": "Property", - "name": "swVersion", - "displayName": "Software version", - "schema": "string", - "description": "Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45" - }, - { - "@type": "Property", - "name": "osName", - "displayName": "Operating system name", - "schema": "string", - "description": "Name of the operating system on the device. Ex. Windows 10 IoT Core." - }, - { - "@type": "Property", - "name": "processorArchitecture", - "displayName": "Processor architecture", - "schema": "string", - "description": "Architecture of the processor on the device. Ex. x64 or ARM." - }, - { - "@type": "Property", - "name": "processorManufacturer", - "displayName": "Processor manufacturer", - "schema": "string", - "description": "Name of the manufacturer of the processor on the device. Ex. Intel." - }, - { - "@type": "Property", - "name": "totalStorage", - "displayName": "Total storage", - "schema": "double", - "description": "Total available storage on the device in kilobytes. Ex. 2048000 kilobytes." - }, - { - "@type": "Property", - "name": "totalMemory", - "displayName": "Total memory", - "schema": "double", - "description": "Total available memory on the device in kilobytes. Ex. 256000 kilobytes." - } - ], - "@context": "dtmi:dtdl:context;2" -} \ No newline at end of file diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Models/TemperatureController.json b/iothub/device/samples/convention-based-samples/TemperatureController/Models/TemperatureController.json deleted file mode 100644 index 997b5cd34a..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Models/TemperatureController.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "@context": [ - "dtmi:iotcentral:context;2", - "dtmi:dtdl:context;2" - ], - "@id": "dtmi:com:example:TemperatureController;2", - "@type": "Interface", - "contents": [ - { - "@type": [ - "Telemetry", - "DataSize" - ], - "description": { - "en": "Current working set of the device memory in KiB." - }, - "displayName": { - "en": "Working Set" - }, - "name": "workingSet", - "schema": "double", - "unit": "kibibit" - }, - { - "@type": "Property", - "displayName": { - "en": "Serial Number" - }, - "name": "serialNumber", - "schema": "string", - "writable": false - }, - { - "@type": "Command", - "commandType": "synchronous", - "description": { - "en": "Reboots the device after waiting the number of seconds specified." - }, - "displayName": { - "en": "Reboot" - }, - "name": "reboot", - "request": { - "@type": "CommandPayload", - "description": { - "en": "Number of seconds to wait before rebooting the device." - }, - "displayName": { - "en": "Delay" - }, - "name": "delay", - "schema": "integer" - } - }, - { - "@type": "Component", - "displayName": { - "en": "thermostat1" - }, - "name": "thermostat1", - "schema": "dtmi:com:example:Thermostat;1" - }, - { - "@type": "Component", - "displayName": { - "en": "thermostat2" - }, - "name": "thermostat2", - "schema": "dtmi:com:example:Thermostat;2" - }, - { - "@type": "Component", - "displayName": { - "en": "DeviceInfo" - }, - "name": "deviceInformation", - "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1" - } - ], - "displayName": { - "en": "Temperature Controller" - } - } \ No newline at end of file diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat.json b/iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat.json deleted file mode 100644 index 46b21f85cb..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "@context": "dtmi:dtdl:context;2", - "@id": "dtmi:com:example:Thermostat;1", - "@type": "Interface", - "displayName": "Thermostat", - "description": "Reports current temperature and provides desired temperature control.", - "contents": [ - { - "@type": [ - "Telemetry", - "Temperature" - ], - "name": "temperature", - "displayName" : "Temperature", - "description" : "Temperature in degrees Celsius.", - "schema": "double", - "unit": "degreeCelsius" - }, - { - "@type": [ - "Property", - "Temperature" - ], - "name": "targetTemperature", - "schema": "double", - "displayName": "Target Temperature", - "description": "Allows to remotely specify the desired target temperature.", - "unit" : "degreeCelsius", - "writable": true - }, - { - "@type": [ - "Property", - "Temperature" - ], - "name": "maxTempSinceLastReboot", - "schema": "double", - "unit" : "degreeCelsius", - "displayName": "Max temperature since last reboot.", - "description": "Returns the max temperature since last device reboot." - }, - { - "@type": "Command", - "name": "getMaxMinReport", - "displayName": "Get Max-Min report.", - "description": "This command returns the max, min and average temperature from the specified time to the current time.", - "request": { - "name": "since", - "displayName": "Since", - "description": "Period to return the max-min report.", - "schema": "dateTime" - }, - "response": { - "name" : "tempReport", - "displayName": "Temperature Report", - "schema": { - "@type": "Object", - "fields": [ - { - "name": "maxTemp", - "displayName": "Max temperature", - "schema": "double" - }, - { - "name": "minTemp", - "displayName": "Min temperature", - "schema": "double" - }, - { - "name" : "avgTemp", - "displayName": "Average Temperature", - "schema": "double" - }, - { - "name" : "startTime", - "displayName": "Start Time", - "schema": "dateTime" - }, - { - "name" : "endTime", - "displayName": "End Time", - "schema": "dateTime" - } - ] - } - } - } - ] -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat2.json b/iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat2.json deleted file mode 100644 index 2309b4a5d4..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Models/Thermostat2.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "@context": "dtmi:dtdl:context;2", - "@id": "dtmi:com:example:Thermostat;2", - "@type": "Interface", - "displayName": "Thermostat", - "description": "Reports current temperature and provides desired temperature control.", - "contents": [ - { - "@type": [ - "Telemetry", - "Temperature" - ], - "name": "temperature", - "displayName" : "Temperature", - "description" : "Temperature in degrees Celsius.", - "schema": "double", - "unit": "degreeCelsius" - }, - { - "@type": [ - "Property", - "Temperature" - ], - "name": "targetTemperature", - "schema": "double", - "displayName": "Target Temperature", - "description": "Allows to remotely specify the desired target temperature.", - "unit" : "degreeCelsius", - "writable": true - }, - { - "@type": [ - "Property", - "Temperature" - ], - "name": "maxTempSinceLastReboot", - "schema": "double", - "unit" : "degreeCelsius", - "displayName": "Max temperature since last reboot.", - "description": "Returns the max temperature since last device reboot." - }, - { - "@type": "Command", - "name": "getMaxMinReport", - "displayName": "Get Max-Min report.", - "description": "This command returns the max, min and average temperature from the specified time to the current time.", - "request": { - "name": "since", - "displayName": "Since", - "description": "Period to return the max-min report.", - "schema": "dateTime" - }, - "response": { - "name" : "tempReport", - "displayName": "Temperature Report", - "schema": { - "@type": "Object", - "fields": [ - { - "name": "maxTemp", - "displayName": "Max temperature", - "schema": "double" - }, - { - "name": "minTemp", - "displayName": "Min temperature", - "schema": "double" - }, - { - "name" : "avgTemp", - "displayName": "Average Temperature", - "schema": "double" - }, - { - "name" : "startTime", - "displayName": "Start Time", - "schema": "dateTime" - }, - { - "name" : "endTime", - "displayName": "End Time", - "schema": "dateTime" - } - ] - } - } - } - ] -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Parameter.cs b/iothub/device/samples/convention-based-samples/TemperatureController/Parameter.cs deleted file mode 100644 index 9f8f5b99ff..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Parameter.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using CommandLine; -using Microsoft.Extensions.Logging; -using System; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - /// - /// Parameters for the application supplied via command line arguments. - /// If the parameter is not supplied via command line args, it will look for it in environment variables. - /// - internal class Parameters - { - [Option( - "DeviceSecurityType", - HelpText = "(Required) The flow that will be used for connecting the device for the sample. Possible case-insensitive values include: dps, connectionString." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_SECURITY_TYPE\".")] - public string DeviceSecurityType { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_SECURITY_TYPE"); - - [Option( - 'p', - "PrimaryConnectionString", - HelpText = "(Required if DeviceSecurityType is \"connectionString\"). \nThe primary connection string for the device to simulate." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_CONNECTION_STRING\".")] - public string PrimaryConnectionString { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONNECTION_STRING"); - - [Option( - 'e', - "DpsEndpoint", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe DPS endpoint to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_ENDPOINT\".")] - public string DpsEndpoint { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_ENDPOINT"); - - [Option( - 'i', - "DpsIdScope", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe DPS ID Scope to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_ID_SCOPE\".")] - public string DpsIdScope { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_ID_SCOPE"); - - [Option( - 'd', - "DeviceId", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe device registration Id to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_DEVICE_ID\".")] - public string DeviceId { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_DEVICE_ID"); - - [Option( - 'k', - "DeviceSymmetricKey", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe device symmetric key to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_DEVICE_KEY\".")] - public string DeviceSymmetricKey { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_DEVICE_KEY"); - - [Option( - 'r', - "Application running time (in seconds)", - Required = false, - HelpText = "The running time for this console application. Leave it unassigned to run the application until it is explicitly canceled using Control+C.")] - public double? ApplicationRunningTime { get; set; } - - public bool Validate(ILogger logger) - { - if (string.IsNullOrWhiteSpace(DeviceSecurityType)) - { - logger.LogWarning("Device provisioning type not set, please set the environment variable \"IOTHUB_DEVICE_SECURITY_TYPE\"" + - "or pass in \"-s | --DeviceSecurityType\" through command line. \nWill default to using \"dps\" flow."); - - DeviceSecurityType = "dps"; - } - - return (DeviceSecurityType.ToLowerInvariant()) switch - { - "dps" => !string.IsNullOrWhiteSpace(DpsEndpoint) - && !string.IsNullOrWhiteSpace(DpsIdScope) - && !string.IsNullOrWhiteSpace(DeviceId) - && !string.IsNullOrWhiteSpace(DeviceSymmetricKey), - "connectionstring" => !string.IsNullOrWhiteSpace(PrimaryConnectionString), - _ => throw new ArgumentException($"Unrecognized value for device provisioning received: {DeviceSecurityType}." + - $" It should be either \"dps\" or \"connectionString\" (case-insensitive)."), - }; - } - } -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Program.cs b/iothub/device/samples/convention-based-samples/TemperatureController/Program.cs deleted file mode 100644 index e2fcc0ba2e..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Program.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using CommandLine; -using Microsoft.Azure.Devices.Provisioning.Client; -using Microsoft.Azure.Devices.Provisioning.Client.PlugAndPlay; -using Microsoft.Azure.Devices.Provisioning.Client.Transport; -using Microsoft.Azure.Devices.Shared; -using Microsoft.Extensions.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - public class Program - { - // DTDL interface used: https://github.com/Azure/iot-plugandplay-models/blob/main/dtmi/com/example/temperaturecontroller-2.json - // The TemperatureController model contains 2 Thermostat components that implement different versions of Thermostat models. - // Both Thermostat models are identical in definition but this is done to allow IoT Central to handle - // TemperatureController model correctly. - private const string ModelId = "dtmi:com:example:TemperatureController;2"; - - private static ILogger s_logger; - - public static async Task Main(string[] args) - { - // Parse application parameters - Parameters parameters = null; - ParserResult result = Parser.Default.ParseArguments(args) - .WithParsed(parsedParams => - { - parameters = parsedParams; - }) - .WithNotParsed(errors => - { - Environment.Exit(1); - }); - - s_logger = InitializeConsoleDebugLogger(); - if (!parameters.Validate(s_logger)) - { - throw new ArgumentException("Required parameters are not set. Please recheck required variables by using \"--help\""); - } - - var runningTime = parameters.ApplicationRunningTime != null - ? TimeSpan.FromSeconds((double)parameters.ApplicationRunningTime) - : Timeout.InfiniteTimeSpan; - - s_logger.LogInformation("Press Control+C to quit the sample."); - using var cts = new CancellationTokenSource(runningTime); - Console.CancelKeyPress += (sender, eventArgs) => - { - eventArgs.Cancel = true; - cts.Cancel(); - s_logger.LogInformation("Sample execution cancellation requested; will exit."); - }; - - s_logger.LogDebug($"Set up the device client."); - using DeviceClient deviceClient = await SetupDeviceClientAsync(parameters, cts.Token); - var sample = new TemperatureControllerSample(deviceClient, s_logger); - await sample.PerformOperationsAsync(cts.Token); - - // PerformOperationsAsync is designed to run until cancellation has been explicitly requested, either through - // cancellation token expiration or by Console.CancelKeyPress. - // As a result, by the time the control reaches the call to close the device client, the cancellation token source would - // have already had cancellation requested. - // Hence, if you want to pass a cancellation token to any subsequent calls, a new token needs to be generated. - // For device client APIs, you can also call them without a cancellation token, which will set a default - // cancellation timeout of 4 minutes: https://github.com/Azure/azure-iot-sdk-csharp/blob/64f6e9f24371bc40ab3ec7a8b8accbfb537f0fe1/iothub/device/src/InternalClient.cs#L1922 - await deviceClient.CloseAsync(); - } - - private static ILogger InitializeConsoleDebugLogger() - { - ILoggerFactory loggerFactory = LoggerFactory.Create(builder => - { - builder - .AddFilter(level => level >= LogLevel.Debug) - .AddConsole(options => - { - options.TimestampFormat = "[MM/dd/yyyy HH:mm:ss]"; - }); - }); - - return loggerFactory.CreateLogger(); - } - - private static async Task SetupDeviceClientAsync(Parameters parameters, CancellationToken cancellationToken) - { - DeviceClient deviceClient; - switch (parameters.DeviceSecurityType.ToLowerInvariant()) - { - case "dps": - s_logger.LogDebug($"Initializing via DPS"); - DeviceRegistrationResult dpsRegistrationResult = await ProvisionDeviceAsync(parameters, cancellationToken); - var authMethod = new DeviceAuthenticationWithRegistrySymmetricKey(dpsRegistrationResult.DeviceId, parameters.DeviceSymmetricKey); - deviceClient = InitializeDeviceClient(dpsRegistrationResult.AssignedHub, authMethod); - break; - - case "connectionstring": - s_logger.LogDebug($"Initializing via IoT Hub connection string"); - deviceClient = InitializeDeviceClient(parameters.PrimaryConnectionString); - break; - - default: - throw new ArgumentException($"Unrecognized value for device provisioning received: {parameters.DeviceSecurityType}." + - $" It should be either \"dps\" or \"connectionString\" (case-insensitive)."); - } - return deviceClient; - } - - // Provision a device via DPS, by sending the PnP model Id as DPS payload. - private static async Task ProvisionDeviceAsync(Parameters parameters, CancellationToken cancellationToken) - { - SecurityProvider symmetricKeyProvider = new SecurityProviderSymmetricKey(parameters.DeviceId, parameters.DeviceSymmetricKey, null); - ProvisioningTransportHandler mqttTransportHandler = new ProvisioningTransportHandlerMqtt(); - ProvisioningDeviceClient pdc = ProvisioningDeviceClient.Create(parameters.DpsEndpoint, parameters.DpsIdScope, symmetricKeyProvider, mqttTransportHandler); - - var pnpPayload = new ProvisioningRegistrationAdditionalData - { - JsonData = PnpConvention.CreateDpsPayload(ModelId), - }; - return await pdc.RegisterAsync(pnpPayload, cancellationToken); - } - - // Initialize the device client instance using connection string based authentication, over Mqtt protocol (TCP, with fallback over Websocket) and - // setting the ModelId into ClientOptions.This method also sets a connection status change callback, that will get triggered any time the device's - // connection status changes. - private static DeviceClient InitializeDeviceClient(string deviceConnectionString) - { - // Specify a custom System.Text.Json based PayloadConvention to be used. - var options = new ClientOptions(SystemTextJsonPayloadConvention.Instance) - { - ModelId = ModelId, - }; - - DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Mqtt, options); - deviceClient.SetConnectionStatusChangesHandler((status, reason) => - { - s_logger.LogDebug($"Connection status change registered - status={status}, reason={reason}."); - }); - - return deviceClient; - } - - // Initialize the device client instance using symmetric key based authentication, over Mqtt protocol (TCP, with fallback over Websocket) - // and setting the ModelId into ClientOptions. This method also sets a connection status change callback, that will get triggered any time the device's connection status changes. - private static DeviceClient InitializeDeviceClient(string hostname, IAuthenticationMethod authenticationMethod) - { - var options = new ClientOptions - { - ModelId = ModelId, - }; - - DeviceClient deviceClient = DeviceClient.Create(hostname, authenticationMethod, TransportType.Mqtt, options); - deviceClient.SetConnectionStatusChangesHandler((status, reason) => - { - s_logger.LogDebug($"Connection status change registered - status={status}, reason={reason}."); - }); - - return deviceClient; - } - } -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/Properties/launchSettings.template.json b/iothub/device/samples/convention-based-samples/TemperatureController/Properties/launchSettings.template.json deleted file mode 100644 index 6ae8d6e736..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/Properties/launchSettings.template.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "profiles": { - "Hub": { - "commandName": "Project", - "environmentVariables": { - "IOTHUB_DEVICE_SECURITY_TYPE": "connectionString", - "IOTHUB_DEVICE_CONNECTION_STRING": "" - } - }, - "DPS": { - "commandName": "Project", - "environmentVariables": { - "IOTHUB_DEVICE_SECURITY_TYPE": "dps", - "IOTHUB_DEVICE_DPS_ID_SCOPE": "", - "IOTHUB_DEVICE_DPS_DEVICE_ID": "", - "IOTHUB_DEVICE_DPS_DEVICE_KEY": "", - "IOTHUB_DEVICE_DPS_ENDPOINT": "global.azure-devices-provisioning.net" - }, - "sqlDebugging": false - } - } -} \ No newline at end of file diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadConvention.cs b/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadConvention.cs deleted file mode 100644 index 02cced0002..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadConvention.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.Azure.Devices.Shared; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - /// - /// A that uses . - /// - public class SystemTextJsonPayloadConvention : PayloadConvention - { - public static readonly SystemTextJsonPayloadConvention Instance = new SystemTextJsonPayloadConvention(); - - public override PayloadSerializer PayloadSerializer { get; } = SystemTextJsonPayloadSerializer.Instance; - - public override PayloadEncoder PayloadEncoder { get; } = Utf8PayloadEncoder.Instance; - } -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadSerializer.cs b/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadSerializer.cs deleted file mode 100644 index c3cad86935..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonPayloadSerializer.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Text.Json; -using Microsoft.Azure.Devices.Shared; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - /// - /// A implementation. - /// - public class SystemTextJsonPayloadSerializer : PayloadSerializer - { - /// - /// The Content Type string. - /// - internal const string ApplicationJson = "application/json"; - - /// - /// The default instance of this class. - /// - public static readonly SystemTextJsonPayloadSerializer Instance = new SystemTextJsonPayloadSerializer(); - - /// - public override string ContentType => ApplicationJson; - - /// - public override string SerializeToString(object objectToSerialize) - { - return JsonSerializer.Serialize(objectToSerialize); - } - - /// - public override T DeserializeToType(string stringToDeserialize) - { - return JsonSerializer.Deserialize(stringToDeserialize); - } - - /// - public override T ConvertFromObject(object objectToConvert) - { - return DeserializeToType(SerializeToString(objectToConvert)); - } - - /// - public override bool TryGetNestedObjectValue(object nestedObject, string propertyName, out T outValue) - { - outValue = default; - if (nestedObject == null || string.IsNullOrEmpty(propertyName)) - { - return false; - } - if (((JsonElement)nestedObject).TryGetProperty(propertyName, out JsonElement element)) - { - outValue = DeserializeToType(element.GetRawText()); - return true; - } - return false; - } - - /// - public override IWritablePropertyResponse CreateWritablePropertyResponse(object value, int statusCode, long version, string description = null) - { - return new SystemTextJsonWritablePropertyResponse(value, statusCode, version, description); - } - } -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonWritablePropertyResponse.cs b/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonWritablePropertyResponse.cs deleted file mode 100644 index 97a8a84d64..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/SystemTextJsonWritablePropertyResponse.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Text.Json.Serialization; -using Microsoft.Azure.Devices.Shared; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - /// - /// An optional, helper class for constructing a writable property response. - /// - /// - /// This helper class will only work with . - /// It uses based to define the JSON property names. - /// - public sealed class SystemTextJsonWritablePropertyResponse : IWritablePropertyResponse - { - /// - /// Convenience constructor for specifying the properties. - /// - /// The unserialized property value. - /// The acknowledgment code, usually an HTTP Status Code e.g. 200, 400. - /// The acknowledgment version, as supplied in the property update request. - /// The acknowledgment description, an optional, human-readable message about the result of the property update. - public SystemTextJsonWritablePropertyResponse(object value, int ackCode, long ackVersion, string ackDescription = default) - { - Value = value; - AckCode = ackCode; - AckVersion = ackVersion; - AckDescription = ackDescription; - } - - /// - /// The unserialized property value. - /// - [JsonPropertyName(ConventionBasedConstants.ValuePropertyName)] - public object Value { get; set; } - - /// - /// The acknowledgment code, usually an HTTP Status Code e.g. 200, 400. - /// - [JsonPropertyName(ConventionBasedConstants.AckCodePropertyName)] - public int AckCode { get; set; } - - /// - /// The acknowledgment version, as supplied in the property update request. - /// - [JsonPropertyName(ConventionBasedConstants.AckVersionPropertyName)] - public long AckVersion { get; set; } - - /// - /// The acknowledgment description, an optional, human-readable message about the result of the property update. - /// - [JsonPropertyName(ConventionBasedConstants.AckDescriptionPropertyName)] - public string AckDescription { get; set; } - } -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureController.csproj b/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureController.csproj deleted file mode 100644 index d0fbcbc34a..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureController.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - netcoreapp3.1 - $(MSBuildProjectDirectory)\..\..\..\..\.. - - - - - - - - - - - - - diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureControllerSample.cs b/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureControllerSample.cs deleted file mode 100644 index 041adeffb3..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureControllerSample.cs +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Azure.Devices.Shared; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - public class TemperatureControllerSample - { - private const string Thermostat1 = "thermostat1"; - private const string Thermostat2 = "thermostat2"; - - private static readonly Random s_random = new Random(); - private static readonly TimeSpan s_sleepDuration = TimeSpan.FromSeconds(5); - - private readonly DeviceClient _deviceClient; - private readonly ILogger _logger; - - // Dictionary to hold the temperature updates sent over each "Thermostat" component. - // NOTE: Memory constrained devices should leverage storage capabilities of an external service to store this - // information and perform computation. - // See https://docs.microsoft.com/en-us/azure/event-grid/compare-messaging-services for more details. - private readonly Dictionary> _temperatureReadingsDateTimeOffset = - new Dictionary>(); - - // Dictionary to hold the current temperature for each "Thermostat" component. - private readonly Dictionary _temperature = new Dictionary(); - - // Dictionary to hold the max temperature since last reboot, for each "Thermostat" component. - private readonly Dictionary _maxTemp = new Dictionary(); - - public TemperatureControllerSample(DeviceClient deviceClient, ILogger logger) - { - _deviceClient = deviceClient ?? throw new ArgumentNullException($"{nameof(deviceClient)} cannot be null."); - _logger = logger ?? LoggerFactory.Create(builer => builer.AddConsole()).CreateLogger(); - } - - public async Task PerformOperationsAsync(CancellationToken cancellationToken) - { - // Set handler to receive and respond to writable property update requests. - _logger.LogDebug("Subscribe to writable property updates."); - await _deviceClient.SubscribeToWritablePropertiesEventAsync(HandlePropertyUpdatesAsync, null, cancellationToken); - - // Set handler to receive and respond to commands. - _logger.LogDebug($"Subscribe to commands."); - await _deviceClient.SubscribeToCommandsAsync(HandleCommandsAsync, null, cancellationToken); - - // Report device information on "deviceInformation" component. - // This is a component-level property update call. - await UpdateDeviceInformationPropertyAsync(cancellationToken); - - // Verify if the device has previously reported the current value for property "serialNumber". - // If the expected value has not been previously reported then send device serial number over property update. - // This is a top-level property update call. - await SendDeviceSerialNumberPropertyIfNotCurrentAsync(cancellationToken); - - bool temperatureReset = true; - _maxTemp[Thermostat1] = 0d; - _maxTemp[Thermostat2] = 0d; - - // Periodically send "temperature" over telemetry - on "Thermostat" components. - // Send "maxTempSinceLastReboot" over property update, when a new max temperature is reached - on "Thermostat" components. - while (!cancellationToken.IsCancellationRequested) - { - if (temperatureReset) - { - // Generate a random value between 5.0°C and 45.0°C for the current temperature reading for each "Thermostat" component. - _temperature[Thermostat1] = GenerateTemperatureWithinRange(45, 5); - _temperature[Thermostat2] = GenerateTemperatureWithinRange(45, 5); - } - - // Send temperature updates over telemetry and the value of max temperature since last reboot over property update. - // Both of these are component-level calls. - await SendTemperatureAsync(Thermostat1, cancellationToken); - await SendTemperatureAsync(Thermostat2, cancellationToken); - - // Send working set of device memory over telemetry. - // This is a top-level telemetry call. - await SendDeviceMemoryTelemetryAsync(cancellationToken); - - temperatureReset = _temperature[Thermostat1] == 0 && _temperature[Thermostat2] == 0; - await Task.Delay(s_sleepDuration); - } - } - - // The callback to handle property update requests. - private async Task HandlePropertyUpdatesAsync(ClientPropertyCollection writableProperties, object userContext) - { - foreach (KeyValuePair writableProperty in writableProperties) - { - // The dispatcher key will be either a top-level property name or a component name. - switch (writableProperty.Key) - { - case Thermostat1: - case Thermostat2: - const string targetTemperatureProperty = "targetTemperature"; - if (writableProperties.TryGetValue(writableProperty.Key, targetTemperatureProperty, out double targetTemperatureRequested)) - { - await HandleTargetTemperatureUpdateRequestAsync(writableProperty.Key, targetTemperatureRequested, writableProperties.Version, userContext); - break; - } - else - { - _logger.LogWarning($"Property: Received an unrecognized property update from service for component {writableProperty.Key}:" + - $"\n[ {writableProperty.Value} ]."); - break; - } - - default: - _logger.LogWarning($"Property: Received an unrecognized property update from service:" + - $"\n[ {writableProperty.Key}: {writableProperty.Value} ]."); - break; - } - } - } - - // The callback to handle target temperature property update requests for a component. - private async Task HandleTargetTemperatureUpdateRequestAsync(string componentName, double targetTemperature, long version, object userContext) - { - const string targetTemperatureProperty = "targetTemperature"; - _logger.LogDebug($"Property: Received - component=\"{componentName}\", [ \"{targetTemperatureProperty}\": {targetTemperature}°C ]."); - - _temperature[componentName] = targetTemperature; - IWritablePropertyResponse writableResponse = _deviceClient - .PayloadConvention - .PayloadSerializer - .CreateWritablePropertyResponse(_temperature[componentName], CommonClientResponseCodes.OK, version, "Successfully updated target temperature."); - - var reportedProperty = new ClientPropertyCollection(); - reportedProperty.AddComponentProperty(componentName, targetTemperatureProperty, writableResponse); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(reportedProperty); - - _logger.LogDebug($"Property: Update - component=\"{componentName}\", {reportedProperty.GetSerializedString()} is {nameof(CommonClientResponseCodes.OK)} " + - $"with a version of {updateResponse.Version}."); - } - - // The callback to handle command invocation requests. - private Task HandleCommandsAsync(CommandRequest commandRequest, object userContext) - { - // In this approach, we'll first switch through the component name returned and handle each component-level command. - // For the "default" case, we'll first check if the component name is null. - // If null, then this would be a top-level command request, so we'll switch through each top-level command. - // If not null, then this is a component-level command that has not been implemented. - - // Switch through CommandRequest.ComponentName to handle all component-level commands. - switch (commandRequest.ComponentName) - { - case Thermostat1: - case Thermostat2: - // For each component, switch through CommandRequest.CommandName to handle the specific component-level command. - switch (commandRequest.CommandName) - { - case "getMaxMinReport": - return HandleMaxMinReportCommandAsync(commandRequest, userContext); - - default: - _logger.LogWarning($"Received a command request that isn't" + - $" implemented - component name = {commandRequest.ComponentName}, command name = {commandRequest.CommandName}"); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - - // For the default case, first check if CommandRequest.ComponentName is null. - default: - // If CommandRequest.ComponentName is null, then this is a top-level command request. - if (commandRequest.ComponentName == null) - { - // Switch through CommandRequest.CommandName to handle all top-level commands. - switch (commandRequest.CommandName) - { - case "reboot": - return HandleRebootCommandAsync(commandRequest, userContext); - - default: - _logger.LogWarning($"Received a command request that isn't" + - $" implemented - command name = {commandRequest.CommandName}"); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - } - else - { - _logger.LogWarning($"Received a command request that isn't" + - $" implemented - component name = {commandRequest.ComponentName}, command name = {commandRequest.CommandName}"); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - } - } - - // The callback to handle top-level "reboot" command. - // This method will send a temperature update (of 0°C) over telemetry for both associated components. - private async Task HandleRebootCommandAsync(CommandRequest commandRequest, object userContext) - { - try - { - int delay = commandRequest.GetData(); - - _logger.LogDebug($"Command: Received - Rebooting thermostat (resetting temperature reading to 0°C after {delay} seconds)."); - await Task.Delay(delay * 1000); - - _temperature[Thermostat1] = _maxTemp[Thermostat1] = 0; - _temperature[Thermostat2] = _maxTemp[Thermostat2] = 0; - - _temperatureReadingsDateTimeOffset.Clear(); - _logger.LogDebug($"Command: Reboot completed."); - - return new CommandResponse(CommonClientResponseCodes.OK); - } - catch (JsonReaderException ex) - { - _logger.LogDebug($"Command input for {commandRequest.CommandName} is invalid: {ex.Message}."); - return new CommandResponse(CommonClientResponseCodes.BadRequest); - } - } - - // The callback to handle component-level "getMaxMinReport" command. - // This method will returns the max, min and average temperature from the specified time to the current time. - private Task HandleMaxMinReportCommandAsync(CommandRequest commandRequest, object userContext) - { - try - { - DateTimeOffset sinceInUtc = commandRequest.GetData(); - _logger.LogDebug($"Command: Received - Generating max, min and avg temperature report since " + - $"{sinceInUtc.LocalDateTime}."); - - if (_temperatureReadingsDateTimeOffset.ContainsKey(commandRequest.ComponentName)) - { - Dictionary allReadings = _temperatureReadingsDateTimeOffset[commandRequest.ComponentName]; - Dictionary filteredReadings = allReadings.Where(i => i.Key > sinceInUtc) - .ToDictionary(i => i.Key, i => i.Value); - - if (filteredReadings != null && filteredReadings.Any()) - { - var report = new TemperatureReport - { - MaximumTemperature = filteredReadings.Values.Max(), - MinimumTemperature = filteredReadings.Values.Min(), - AverageTemperature = filteredReadings.Values.Average(), - StartTime = filteredReadings.Keys.Min(), - EndTime = filteredReadings.Keys.Max(), - }; - - _logger.LogDebug($"Command: component=\"{commandRequest.ComponentName}\", MaxMinReport since {sinceInUtc.LocalDateTime}:" + - $" maxTemp={report.MaximumTemperature}, minTemp={report.MinimumTemperature}, avgTemp={report.AverageTemperature}, " + - $"startTime={report.StartTime.LocalDateTime}, endTime={report.EndTime.LocalDateTime}"); - - return Task.FromResult(new CommandResponse(report, CommonClientResponseCodes.OK)); - } - - _logger.LogDebug($"Command: component=\"{commandRequest.ComponentName}\"," + - $" no relevant readings found since {sinceInUtc.LocalDateTime}, cannot generate any report."); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - - _logger.LogDebug($"Command: component=\"{commandRequest.ComponentName}\", no temperature readings sent yet," + - $" cannot generate any report."); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - catch (JsonReaderException ex) - { - _logger.LogError($"Command input for {commandRequest.CommandName} is invalid: {ex.Message}."); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.BadRequest)); - } - } - - // Report the property values on "deviceInformation" component. - // This is a component-level property update call. - private async Task UpdateDeviceInformationPropertyAsync(CancellationToken cancellationToken) - { - const string componentName = "deviceInformation"; - var deviceInformationProperties = new Dictionary - { - { "manufacturer", "element15" }, - { "model", "ModelIDxcdvmk" }, - { "swVersion", "1.0.0" }, - { "osName", "Windows 10" }, - { "processorArchitecture", "64-bit" }, - { "processorManufacturer", "Intel" }, - { "totalStorage", 256 }, - { "totalMemory", 1024 }, - }; - var deviceInformation = new ClientPropertyCollection(); - deviceInformation.AddComponentProperties(componentName, deviceInformationProperties); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(deviceInformation, cancellationToken); - - _logger.LogDebug($"Property: Update - component = '{componentName}', properties update is complete " + - $"with a version of {updateResponse.Version}."); - } - - // Send working set of device memory over telemetry. - // This is a top-level telemetry call. - private async Task SendDeviceMemoryTelemetryAsync(CancellationToken cancellationToken) - { - const string workingSetName = "workingSet"; - long workingSet = Process.GetCurrentProcess().PrivateMemorySize64 / 1024; - using var telemetryMessage = new TelemetryMessage - { - Telemetry = { [workingSetName] = workingSet }, - }; - - await _deviceClient.SendTelemetryAsync(telemetryMessage, cancellationToken); - - _logger.LogDebug($"Telemetry: Sent - {telemetryMessage.Telemetry.GetSerializedString()} in KB."); - } - - // Verify if the device has previously reported the current value for property "serialNumber". - // If the expected value has not been previously reported then send device serial number over property update. - // This is a top-level property update call. - private async Task SendDeviceSerialNumberPropertyIfNotCurrentAsync(CancellationToken cancellationToken) - { - const string serialNumber = "serialNumber"; - const string currentSerialNumber = "SR-123456"; - - // Verify if the device has previously reported the current value for property "serialNumber". - // If the expected value has not been previously reported then report it. - - // Retrieve the device's properties. - ClientProperties properties = await _deviceClient.GetClientPropertiesAsync(cancellationToken); - - if (!properties.TryGetValue(serialNumber, out string serialNumberReported) - || serialNumberReported != currentSerialNumber) - { - var reportedProperties = new ClientPropertyCollection(); - reportedProperties.AddRootProperty(serialNumber, currentSerialNumber); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(reportedProperties, cancellationToken); - - _logger.LogDebug($"Property: Update - {reportedProperties.GetSerializedString()} is complete " + - $"with a version of {updateResponse.Version}."); - } - } - - // Send temperature updates over telemetry. - // This also sends the value of max temperature since last reboot over property update. - private async Task SendTemperatureAsync(string componentName, CancellationToken cancellationToken) - { - await SendTemperatureTelemetryAsync(componentName, cancellationToken); - - double maxTemp = _temperatureReadingsDateTimeOffset[componentName].Values.Max(); - if (maxTemp > _maxTemp[componentName]) - { - _maxTemp[componentName] = maxTemp; - await UpdateMaxTemperatureSinceLastRebootAsync(componentName, cancellationToken); - } - } - - // Send temperature update over telemetry. - // This is a component-level telemetry call. - private async Task SendTemperatureTelemetryAsync(string componentName, CancellationToken cancellationToken) - { - const string telemetryName = "temperature"; - double currentTemperature = _temperature[componentName]; - - using var telemtryMessage = new TelemetryMessage(componentName) - { - Telemetry = { [telemetryName] = currentTemperature }, - }; - - await _deviceClient.SendTelemetryAsync(telemtryMessage, cancellationToken); - - _logger.LogDebug($"Telemetry: Sent - component=\"{componentName}\", {telemtryMessage.Telemetry.GetSerializedString()} in °C."); - - if (_temperatureReadingsDateTimeOffset.ContainsKey(componentName)) - { - _temperatureReadingsDateTimeOffset[componentName].TryAdd(DateTimeOffset.UtcNow, currentTemperature); - } - else - { - _temperatureReadingsDateTimeOffset.TryAdd( - componentName, - new Dictionary - { - { DateTimeOffset.UtcNow, currentTemperature }, - }); - } - } - - // Send temperature over reported property update. - // This is a component-level property update. - private async Task UpdateMaxTemperatureSinceLastRebootAsync(string componentName, CancellationToken cancellationToken) - { - const string propertyName = "maxTempSinceLastReboot"; - double maxTemp = _maxTemp[componentName]; - var reportedProperties = new ClientPropertyCollection(); - reportedProperties.AddComponentProperty(componentName, propertyName, maxTemp); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(reportedProperties, cancellationToken); - - _logger.LogDebug($"Property: Update - component=\"{componentName}\", {reportedProperties.GetSerializedString()}" + - $" in °C is complete with a version of {updateResponse.Version}."); - } - - private static double GenerateTemperatureWithinRange(int max = 50, int min = 0) - { - return Math.Round(s_random.NextDouble() * (max - min) + min, 1); - } - } -} diff --git a/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureReport.cs b/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureReport.cs deleted file mode 100644 index f7b25e9ec7..0000000000 --- a/iothub/device/samples/convention-based-samples/TemperatureController/TemperatureReport.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Text.Json.Serialization; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - public class TemperatureReport - { - [JsonPropertyName("maxTemp")] - public double MaximumTemperature { get; set; } - - [JsonPropertyName("minTemp")] - public double MinimumTemperature { get; set; } - - [JsonPropertyName("avgTemp")] - public double AverageTemperature { get; set; } - - [JsonPropertyName("startTime")] - public DateTimeOffset StartTime { get; set; } - - [JsonPropertyName("endTime")] - public DateTimeOffset EndTime { get; set; } - } -} diff --git a/iothub/device/samples/convention-based-samples/Thermostat/Models/Thermostat.json b/iothub/device/samples/convention-based-samples/Thermostat/Models/Thermostat.json deleted file mode 100644 index 46b21f85cb..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/Models/Thermostat.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "@context": "dtmi:dtdl:context;2", - "@id": "dtmi:com:example:Thermostat;1", - "@type": "Interface", - "displayName": "Thermostat", - "description": "Reports current temperature and provides desired temperature control.", - "contents": [ - { - "@type": [ - "Telemetry", - "Temperature" - ], - "name": "temperature", - "displayName" : "Temperature", - "description" : "Temperature in degrees Celsius.", - "schema": "double", - "unit": "degreeCelsius" - }, - { - "@type": [ - "Property", - "Temperature" - ], - "name": "targetTemperature", - "schema": "double", - "displayName": "Target Temperature", - "description": "Allows to remotely specify the desired target temperature.", - "unit" : "degreeCelsius", - "writable": true - }, - { - "@type": [ - "Property", - "Temperature" - ], - "name": "maxTempSinceLastReboot", - "schema": "double", - "unit" : "degreeCelsius", - "displayName": "Max temperature since last reboot.", - "description": "Returns the max temperature since last device reboot." - }, - { - "@type": "Command", - "name": "getMaxMinReport", - "displayName": "Get Max-Min report.", - "description": "This command returns the max, min and average temperature from the specified time to the current time.", - "request": { - "name": "since", - "displayName": "Since", - "description": "Period to return the max-min report.", - "schema": "dateTime" - }, - "response": { - "name" : "tempReport", - "displayName": "Temperature Report", - "schema": { - "@type": "Object", - "fields": [ - { - "name": "maxTemp", - "displayName": "Max temperature", - "schema": "double" - }, - { - "name": "minTemp", - "displayName": "Min temperature", - "schema": "double" - }, - { - "name" : "avgTemp", - "displayName": "Average Temperature", - "schema": "double" - }, - { - "name" : "startTime", - "displayName": "Start Time", - "schema": "dateTime" - }, - { - "name" : "endTime", - "displayName": "End Time", - "schema": "dateTime" - } - ] - } - } - } - ] -} diff --git a/iothub/device/samples/convention-based-samples/Thermostat/Parameter.cs b/iothub/device/samples/convention-based-samples/Thermostat/Parameter.cs deleted file mode 100644 index 9f8f5b99ff..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/Parameter.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using CommandLine; -using Microsoft.Extensions.Logging; -using System; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - /// - /// Parameters for the application supplied via command line arguments. - /// If the parameter is not supplied via command line args, it will look for it in environment variables. - /// - internal class Parameters - { - [Option( - "DeviceSecurityType", - HelpText = "(Required) The flow that will be used for connecting the device for the sample. Possible case-insensitive values include: dps, connectionString." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_SECURITY_TYPE\".")] - public string DeviceSecurityType { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_SECURITY_TYPE"); - - [Option( - 'p', - "PrimaryConnectionString", - HelpText = "(Required if DeviceSecurityType is \"connectionString\"). \nThe primary connection string for the device to simulate." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_CONNECTION_STRING\".")] - public string PrimaryConnectionString { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONNECTION_STRING"); - - [Option( - 'e', - "DpsEndpoint", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe DPS endpoint to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_ENDPOINT\".")] - public string DpsEndpoint { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_ENDPOINT"); - - [Option( - 'i', - "DpsIdScope", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe DPS ID Scope to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_ID_SCOPE\".")] - public string DpsIdScope { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_ID_SCOPE"); - - [Option( - 'd', - "DeviceId", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe device registration Id to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_DEVICE_ID\".")] - public string DeviceId { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_DEVICE_ID"); - - [Option( - 'k', - "DeviceSymmetricKey", - HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe device symmetric key to use during device provisioning." + - "\nDefaults to environment variable \"IOTHUB_DEVICE_DPS_DEVICE_KEY\".")] - public string DeviceSymmetricKey { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_DPS_DEVICE_KEY"); - - [Option( - 'r', - "Application running time (in seconds)", - Required = false, - HelpText = "The running time for this console application. Leave it unassigned to run the application until it is explicitly canceled using Control+C.")] - public double? ApplicationRunningTime { get; set; } - - public bool Validate(ILogger logger) - { - if (string.IsNullOrWhiteSpace(DeviceSecurityType)) - { - logger.LogWarning("Device provisioning type not set, please set the environment variable \"IOTHUB_DEVICE_SECURITY_TYPE\"" + - "or pass in \"-s | --DeviceSecurityType\" through command line. \nWill default to using \"dps\" flow."); - - DeviceSecurityType = "dps"; - } - - return (DeviceSecurityType.ToLowerInvariant()) switch - { - "dps" => !string.IsNullOrWhiteSpace(DpsEndpoint) - && !string.IsNullOrWhiteSpace(DpsIdScope) - && !string.IsNullOrWhiteSpace(DeviceId) - && !string.IsNullOrWhiteSpace(DeviceSymmetricKey), - "connectionstring" => !string.IsNullOrWhiteSpace(PrimaryConnectionString), - _ => throw new ArgumentException($"Unrecognized value for device provisioning received: {DeviceSecurityType}." + - $" It should be either \"dps\" or \"connectionString\" (case-insensitive)."), - }; - } - } -} diff --git a/iothub/device/samples/convention-based-samples/Thermostat/Program.cs b/iothub/device/samples/convention-based-samples/Thermostat/Program.cs deleted file mode 100644 index 69dff54071..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/Program.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using CommandLine; -using Microsoft.Azure.Devices.Provisioning.Client; -using Microsoft.Azure.Devices.Provisioning.Client.Transport; -using Microsoft.Azure.Devices.Shared; -using Microsoft.Extensions.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - public class Program - { - // DTDL interface used: https://github.com/Azure/iot-plugandplay-models/blob/main/dtmi/com/example/thermostat-1.json - private const string ModelId = "dtmi:com:example:Thermostat;1"; - - private static ILogger s_logger; - - public static async Task Main(string[] args) - { - // Parse application parameters - Parameters parameters = null; - ParserResult result = Parser.Default.ParseArguments(args) - .WithParsed(parsedParams => - { - parameters = parsedParams; - }) - .WithNotParsed(errors => - { - Environment.Exit(1); - }); - - s_logger = InitializeConsoleDebugLogger(); - if (!parameters.Validate(s_logger)) - { - throw new ArgumentException("Required parameters are not set. Please recheck required variables by using \"--help\""); - } - - var runningTime = parameters.ApplicationRunningTime != null - ? TimeSpan.FromSeconds((double)parameters.ApplicationRunningTime) - : Timeout.InfiniteTimeSpan; - - s_logger.LogInformation("Press Control+C to quit the sample."); - using var cts = new CancellationTokenSource(runningTime); - Console.CancelKeyPress += (sender, eventArgs) => - { - eventArgs.Cancel = true; - cts.Cancel(); - s_logger.LogInformation("Sample execution cancellation requested; will exit."); - }; - - s_logger.LogDebug($"Set up the device client."); - using DeviceClient deviceClient = await SetupDeviceClientAsync(parameters, cts.Token); - var sample = new ThermostatSample(deviceClient, s_logger); - await sample.PerformOperationsAsync(cts.Token); - - // PerformOperationsAsync is designed to run until cancellation has been explicitly requested, either through - // cancellation token expiration or by Console.CancelKeyPress. - // As a result, by the time the control reaches the call to close the device client, the cancellation token source would - // have already had cancellation requested. - // Hence, if you want to pass a cancellation token to any subsequent calls, a new token needs to be generated. - // For device client APIs, you can also call them without a cancellation token, which will set a default - // cancellation timeout of 4 minutes: https://github.com/Azure/azure-iot-sdk-csharp/blob/64f6e9f24371bc40ab3ec7a8b8accbfb537f0fe1/iothub/device/src/InternalClient.cs#L1922 - await deviceClient.CloseAsync(); - } - - private static ILogger InitializeConsoleDebugLogger() - { - ILoggerFactory loggerFactory = LoggerFactory.Create(builder => - { - builder - .AddFilter(level => level >= LogLevel.Debug) - .AddConsole(options => - { - options.TimestampFormat = "[MM/dd/yyyy HH:mm:ss]"; - }); - }); - - return loggerFactory.CreateLogger(); - } - - private static async Task SetupDeviceClientAsync(Parameters parameters, CancellationToken cancellationToken) - { - DeviceClient deviceClient; - switch (parameters.DeviceSecurityType.ToLowerInvariant()) - { - case "dps": - s_logger.LogDebug($"Initializing via DPS"); - DeviceRegistrationResult dpsRegistrationResult = await ProvisionDeviceAsync(parameters, cancellationToken); - var authMethod = new DeviceAuthenticationWithRegistrySymmetricKey(dpsRegistrationResult.DeviceId, parameters.DeviceSymmetricKey); - deviceClient = InitializeDeviceClient(dpsRegistrationResult.AssignedHub, authMethod); - break; - - case "connectionstring": - s_logger.LogDebug($"Initializing via IoT Hub connection string"); - deviceClient = InitializeDeviceClient(parameters.PrimaryConnectionString); - break; - - default: - throw new ArgumentException($"Unrecognized value for device provisioning received: {parameters.DeviceSecurityType}." + - $" It should be either \"dps\" or \"connectionString\" (case-insensitive)."); - } - - return deviceClient; - } - - // Provision a device via DPS, by sending the PnP model Id as DPS payload. - private static async Task ProvisionDeviceAsync(Parameters parameters, CancellationToken cancellationToken) - { - SecurityProvider symmetricKeyProvider = new SecurityProviderSymmetricKey(parameters.DeviceId, parameters.DeviceSymmetricKey, null); - ProvisioningTransportHandler mqttTransportHandler = new ProvisioningTransportHandlerMqtt(); - ProvisioningDeviceClient pdc = ProvisioningDeviceClient.Create(parameters.DpsEndpoint, parameters.DpsIdScope, - symmetricKeyProvider, mqttTransportHandler); - - var pnpPayload = new ProvisioningRegistrationAdditionalData - { - JsonData = $"{{ \"modelId\": \"{ModelId}\" }}", - }; - return await pdc.RegisterAsync(pnpPayload, cancellationToken); - } - - // Initialize the device client instance using connection string based authentication, over Mqtt protocol (TCP, with fallback over Websocket) - // and setting the ModelId into ClientOptions. - // This method also sets a connection status change callback, that will get triggered any time the device's connection status changes. - private static DeviceClient InitializeDeviceClient(string deviceConnectionString) - { - var options = new ClientOptions - { - ModelId = ModelId, - }; - - DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Mqtt, options); - deviceClient.SetConnectionStatusChangesHandler((status, reason) => - { - s_logger.LogDebug($"Connection status change registered - status={status}, reason={reason}."); - }); - - return deviceClient; - } - - // Initialize the device client instance using symmetric key based authentication, over Mqtt protocol (TCP, with fallback over Websocket) and setting the ModelId into ClientOptions. - // This method also sets a connection status change callback, that will get triggered any time the device's connection status changes. - private static DeviceClient InitializeDeviceClient(string hostname, IAuthenticationMethod authenticationMethod) - { - var options = new ClientOptions - { - ModelId = ModelId, - }; - - DeviceClient deviceClient = DeviceClient.Create(hostname, authenticationMethod, TransportType.Mqtt, options); - deviceClient.SetConnectionStatusChangesHandler((status, reason) => - { - s_logger.LogDebug($"Connection status change registered - status={status}, reason={reason}."); - }); - - return deviceClient; - } - } -} diff --git a/iothub/device/samples/convention-based-samples/Thermostat/Properties/launchSettings.template.json b/iothub/device/samples/convention-based-samples/Thermostat/Properties/launchSettings.template.json deleted file mode 100644 index 6ae8d6e736..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/Properties/launchSettings.template.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "profiles": { - "Hub": { - "commandName": "Project", - "environmentVariables": { - "IOTHUB_DEVICE_SECURITY_TYPE": "connectionString", - "IOTHUB_DEVICE_CONNECTION_STRING": "" - } - }, - "DPS": { - "commandName": "Project", - "environmentVariables": { - "IOTHUB_DEVICE_SECURITY_TYPE": "dps", - "IOTHUB_DEVICE_DPS_ID_SCOPE": "", - "IOTHUB_DEVICE_DPS_DEVICE_ID": "", - "IOTHUB_DEVICE_DPS_DEVICE_KEY": "", - "IOTHUB_DEVICE_DPS_ENDPOINT": "global.azure-devices-provisioning.net" - }, - "sqlDebugging": false - } - } -} \ No newline at end of file diff --git a/iothub/device/samples/convention-based-samples/Thermostat/TemperatureReport.cs b/iothub/device/samples/convention-based-samples/Thermostat/TemperatureReport.cs deleted file mode 100644 index 44996a7961..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/TemperatureReport.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Newtonsoft.Json; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - public class TemperatureReport - { - [JsonProperty("maxTemp")] - public double MaximumTemperature { get; set; } - - [JsonProperty("minTemp")] - public double MinimumTemperature { get; set; } - - [JsonProperty("avgTemp")] - public double AverageTemperature { get; set; } - - [JsonProperty("startTime")] - public DateTimeOffset StartTime { get; set; } - - [JsonProperty("endTime")] - public DateTimeOffset EndTime { get; set; } - } -} diff --git a/iothub/device/samples/convention-based-samples/Thermostat/Thermostat.csproj b/iothub/device/samples/convention-based-samples/Thermostat/Thermostat.csproj deleted file mode 100644 index d0fbcbc34a..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/Thermostat.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - netcoreapp3.1 - $(MSBuildProjectDirectory)\..\..\..\..\.. - - - - - - - - - - - - - diff --git a/iothub/device/samples/convention-based-samples/Thermostat/ThermostatSample.cs b/iothub/device/samples/convention-based-samples/Thermostat/ThermostatSample.cs deleted file mode 100644 index d4977479d0..0000000000 --- a/iothub/device/samples/convention-based-samples/Thermostat/ThermostatSample.cs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Azure.Devices.Shared; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; - -namespace Microsoft.Azure.Devices.Client.Samples -{ - public class ThermostatSample - { - private static readonly Random s_random = new Random(); - private static readonly TimeSpan s_sleepDuration = TimeSpan.FromSeconds(5); - - private double _temperature = 0d; - private double _maxTemp = 0d; - - // Dictionary to hold the temperature updates sent over. - // NOTE: Memory constrained devices should leverage storage capabilities of an external service to store this information and perform computation. - // See https://docs.microsoft.com/en-us/azure/event-grid/compare-messaging-services for more details. - private readonly Dictionary _temperatureReadingsDateTimeOffset = new Dictionary(); - - private readonly DeviceClient _deviceClient; - private readonly ILogger _logger; - - public ThermostatSample(DeviceClient deviceClient, ILogger logger) - { - _deviceClient = deviceClient ?? throw new ArgumentNullException($"{nameof(deviceClient)} cannot be null."); - _logger = logger ?? LoggerFactory.Create(builer => builer.AddConsole()).CreateLogger(); - } - - public async Task PerformOperationsAsync(CancellationToken cancellationToken) - { - // Set handler to receive and respond to writable property update requests. - _logger.LogDebug($"Subscribe to writable property updates."); - await _deviceClient.SubscribeToWritablePropertiesEventAsync(HandlePropertyUpdatesAsync, null, cancellationToken); - - // Set handler to receive and respond to commands. - _logger.LogDebug($"Subscribe to commands."); - await _deviceClient.SubscribeToCommandsAsync(HandleCommandsAsync, null, cancellationToken); - - bool temperatureReset = true; - - // Periodically send "temperature" over telemetry. - // Send "maxTempSinceLastReboot" over property update, when a new max temperature is reached. - while (!cancellationToken.IsCancellationRequested) - { - if (temperatureReset) - { - // Generate a random value between 5.0°C and 45.0°C for the current temperature reading. - _temperature = GenerateTemperatureWithinRange(45, 5); - temperatureReset = false; - } - - // Send temperature updates over telemetry and the value of max temperature since last reboot over property update. - await SendTemperatureAsync(); - - await Task.Delay(s_sleepDuration); - } - } - - // The callback to handle property update requests. - private async Task HandlePropertyUpdatesAsync(ClientPropertyCollection writableProperties, object userContext) - { - foreach (KeyValuePair writableProperty in writableProperties) - { - switch (writableProperty.Key) - { - case "targetTemperature": - const string targetTemperatureProperty = "targetTemperature"; - double targetTemperatureRequested = Convert.ToDouble(writableProperty.Value); - _logger.LogDebug($"Property: Received - [ \"{targetTemperatureProperty}\": {targetTemperatureRequested}°C ]."); - - _temperature = targetTemperatureRequested; - IWritablePropertyResponse writableResponse = _deviceClient - .PayloadConvention - .PayloadSerializer - .CreateWritablePropertyResponse(_temperature, CommonClientResponseCodes.OK, writableProperties.Version, "Successfully updated target temperature"); - - var reportedProperty = new ClientPropertyCollection(); - reportedProperty.AddRootProperty(targetTemperatureProperty, writableResponse); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(reportedProperty); - - _logger.LogDebug($"Property: Update - {reportedProperty.GetSerializedString()} is {nameof(CommonClientResponseCodes.OK)} " + - $"with a version of {updateResponse.Version}."); - - break; - - default: - _logger.LogWarning($"Property: Received an unrecognized property update from service:\n[ {writableProperty.Key}: {writableProperty.Value} ]."); - break; - } - } - } - - // The callback to handle command invocation requests. - private Task HandleCommandsAsync(CommandRequest commandRequest, object userContext) - { - // In this approach, we'll switch through the command name returned and handle each top-level command. - switch (commandRequest.CommandName) - { - case "getMaxMinReport": - try - { - DateTimeOffset sinceInUtc = commandRequest.GetData(); - _logger.LogDebug($"Command: Received - Generating max, min and avg temperature report since " + - $"{sinceInUtc.LocalDateTime}."); - - Dictionary filteredReadings = _temperatureReadingsDateTimeOffset - .Where(i => i.Key > sinceInUtc) - .ToDictionary(i => i.Key, i => i.Value); - - if (filteredReadings != null && filteredReadings.Any()) - { - var report = new TemperatureReport - { - MaximumTemperature = filteredReadings.Values.Max(), - MinimumTemperature = filteredReadings.Values.Min(), - AverageTemperature = filteredReadings.Values.Average(), - StartTime = filteredReadings.Keys.Min(), - EndTime = filteredReadings.Keys.Max(), - }; - - _logger.LogDebug($"Command: MaxMinReport since {sinceInUtc.LocalDateTime}:" + - $" maxTemp={report.MaximumTemperature}, minTemp={report.MinimumTemperature}, avgTemp={report.AverageTemperature}, " + - $"startTime={report.StartTime.LocalDateTime}, endTime={report.EndTime.LocalDateTime}"); - - return Task.FromResult(new CommandResponse(report, CommonClientResponseCodes.OK)); - } - - _logger.LogDebug($"Command: No relevant readings found since {sinceInUtc.LocalDateTime}, cannot generate any report."); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - catch (JsonReaderException ex) - { - _logger.LogError($"Command input for {commandRequest.CommandName} is invalid: {ex.Message}."); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.BadRequest)); - } - - default: - _logger.LogWarning($"Received a command request that isn't" + - $" implemented - command name = {commandRequest.CommandName}"); - - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - } - - // Send temperature updates over telemetry. - // This also sends the value of max temperature since last reboot over property update. - private async Task SendTemperatureAsync() - { - await SendTemperatureTelemetryAsync(); - - double maxTemp = _temperatureReadingsDateTimeOffset.Values.Max(); - if (maxTemp > _maxTemp) - { - _maxTemp = maxTemp; - await UpdateMaxTemperatureSinceLastRebootPropertyAsync(); - } - } - - // Send temperature update over telemetry. - private async Task SendTemperatureTelemetryAsync() - { - const string telemetryName = "temperature"; - - using var telemetryMessage = new TelemetryMessage - { - Telemetry = { [telemetryName] = _temperature } - }; - await _deviceClient.SendTelemetryAsync(telemetryMessage); - - _logger.LogDebug($"Telemetry: Sent - {telemetryMessage.Telemetry.GetSerializedString()}."); - _temperatureReadingsDateTimeOffset.Add(DateTimeOffset.Now, _temperature); - } - - // Send temperature over reported property update. - private async Task UpdateMaxTemperatureSinceLastRebootPropertyAsync() - { - const string propertyName = "maxTempSinceLastReboot"; - var reportedProperties = new ClientPropertyCollection(); - reportedProperties.AddRootProperty(propertyName, _maxTemp); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(reportedProperties); - - _logger.LogDebug($"Property: Update - {reportedProperties.GetSerializedString()} is {nameof(CommonClientResponseCodes.OK)} " + - $"with a version of {updateResponse.Version}."); - } - - private static double GenerateTemperatureWithinRange(int max = 50, int min = 0) - { - return Math.Round(s_random.NextDouble() * (max - min) + min, 1); - } - } -} diff --git a/iothub/device/samples/convention-based-samples/readme.md b/iothub/device/samples/convention-based-samples/readme.md deleted file mode 100644 index de7263a860..0000000000 --- a/iothub/device/samples/convention-based-samples/readme.md +++ /dev/null @@ -1,577 +0,0 @@ ---- -page_type: sample -description: "A set of samples that show how a device that uses the IoT Plug and Play conventions interacts with either IoT Hub or IoT Central." -languages: -- csharp -products: -- azure -- azure-iot-hub -- azure-iot-central -- azure-iot-pnp -- dotnet -urlFragment: azure-iot-pnp-device-samples-for-csharp-net ---- - -# IoT Plug And Play (PnP) device/module APIs - -Device(s)/module(s) connecting to IoT Hub that announce their DTDL model ID during initialization can now perform convention-based operations. One such convention supported is [IoT Plug and Play][pnp-convention]. - -These devices/modules can now use the native PnP APIs in the Azure IoT device SDKs to directly exchange messages with an IoT Hub, without having to manually format these messages to follow the PnP convention. - -## Table of Contents - -- [Client initialization](#client-initialization) - - [Announce model ID during client initialization (same as in latest `master` release)](#announce-model-ID-during-client-initialization-same-as-in-latest-master-release) - - [Define the serialization and encoding convention that the client follows (newly introduced in `preview`)](#define-the-serialization-and-encoding-convention-that-the-client-follows-newly-introduced-in-preview) -- [Terms used](#terms-used) -- [Comparison of API calls - non-convention-aware APIs (old) vs convention-aware APIs (new):](#comparison-of-api-calls---non-convention-aware-apis-old-vs-convention-aware-apis-new) - - [Telemetry](#telemetry) - - [Commands](#commands) - - [Properties](#properties) -- [IoT Plug And Play device samples](#iot-plug-and-play-device-samples) - -## Client initialization - -### Announce model ID during client initialization (same as in latest [`master`][latest-master-release] release) - -```csharp -var options = new ClientOptions -{ - ModelId = ModelId, -}; - -DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Mqtt, options); -``` - -### Define the serialization and encoding convention that the client follows (newly introduced in [`preview`][latest-preview-release]) - -```csharp -// Specify a custom System.Text.Json serialization and Utf8 encoding based PayloadConvention to be used. -// If not specified, the library defaults to a convention that uses Newtonsoft.Json-based serializer and Utf8-based encoder. -var options = new ClientOptions(SystemTextJsonPayloadConvention.Instance) -{ - ModelId = ModelId, -}; - -DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Mqtt, options); -``` - -## Terms used: -Telemetry, commands, properties and components can all be defined in the contents section of the main interface of a DTDL v2 model. Components enable interfaces to be composed of other interfaces. - -In DTDL v2, a component cannot contain another component. The maximum depth of components is 1. - -- Top-level telemetry/commands/properties - - These refer to the telemetry, commands and properties that are defined directly in the contents section of the main interface of a DTDL v2 model. In case of a model with no components, the main interface refers to the default component. - - When working with this category of telemetry, commands and properties, you do not need to specify any component name. -- Component-level telemetry/commands/properties - - These refer to the telemetry, commands and properties that are defined in the contents section of an interface, which itself is defined as a component within the main interface. - - When working with this category of telemetry, commands and properties, you need to specify the name of the component that these contents belong to. - -## Comparison of API calls - non-convention-aware APIs (old) vs convention-aware APIs (new): - -The following section provides a comparison between the older non-convention-aware APIs (as per latest [`master`][latest-master-release] release) and the newly introduced convention-aware APIs (as per latest [`preview`][latest-preview-release] release). - -## Telemetry - -### Send top-level telemetry: - -#### Using non-convention-aware API (old): - -```csharp -// Send telemetry "serialNumber". -string serialNumber = "SR-1234"; -var telemetry = new Dictionary -{ - ["serialNumber"] = serialNumber, -}; - -using var message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(telemetry))) -{ - MessageId = s_random.Next().ToString(), - ContentEncoding = "utf-8", - ContentType = "application/json", -}; -await _deviceClient.SendEventAsync(message, cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Send telemetry "serialNumber". -string serialNumber = "SR-1234"; -using var telemetryMessage = new TelemetryMessage -{ - MessageId = Guid.NewGuid().ToString(), - Telemetry = { ["serialNumber"] = serialNumber }, -}; - -await _deviceClient.SendTelemetryAsync(telemetryMessage, cancellationToken); -``` - -### Send component-level telemetry: - -#### Using non-convention-aware API (old): - -```csharp -// Send telemetry "serialNumber" under component "thermostat1". -string serialNumber = "SR-1234"; -var telemetry = new Dictionary() -{ - ["serialNumber"] = serialNumber, -}; - -using var message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(telemetry))) -{ - MessageId = s_random.Next().ToString(), - ContentEncoding = "utf-8", - ContentType = "application/json", - ComponentName = "thermostat1", -}; -await _deviceClient.SendEventAsync(message, cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Send telemetry "serialNumber" under component "thermostat1". -string serialNumber = "SR-1234"; -using var telemtryMessage = new TelemetryMessage("thermostat1") -{ - MessageId = Guid.NewGuid().ToString(), - Telemetry = { ["serialNumber"] = serialNumber }, -}; - -await _deviceClient.SendTelemetryAsync(telemtryMessage, cancellationToken); -``` - -## Commands - -### Respond to top-level commands: - -#### Using non-convention-aware API (old): - -```csharp -// Subscribe and respond to command "reboot". -await _deviceClient.SetMethodHandlerAsync( - "reboot", - async (methodRequest, userContext) => - { - try - { - int delay = JsonConvert.DeserializeObject(methodRequest.DataAsJson); - await Task.Delay(TimeSpan.FromSeconds(delay)); - - // Application code ... - - return new MethodResponse(CommonClientResponseCodes.OK); - } - catch (JsonReaderException) - { - return new MethodResponse(CommonClientResponseCodes.BadRequest); - } - }, - null, - cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Subscribe and respond to command "reboot". -await _deviceClient.SubscribeToCommandsAsync( - async (commandRequest, userContext) => - { - // This API does not support setting command-level callbacks. - // For this reason we'll need to inspect the commandRequest.CommandName for the request command and perform the actions accordingly. - // Refer to the ThermostatSample.cs for a complete sample implementation. - - if (commandRequest.CommandName == "reboot") - { - try - { - int delay = commandRequest.GetData(); - await Task.Delay(delay * 1000); - - // Application code ... - - return new CommandResponse(CommonClientResponseCodes.OK); - } - catch (JsonReaderException) - { - return new CommandResponse(CommonClientResponseCodes.BadRequest); - } - } - else - { - return new CommandResponse(CommonClientResponseCodes.NotFound); - } - }, - null, - cancellationToken); -``` - -### Respond to component-level commands: - -#### Using non-convention-aware API (old): - -```csharp -// Subscribe and respond to command "getMaxMinReport" under component "thermostat1". -// The method that the application subscribes to is in the format {componentName}*{commandName}. -await _deviceClient.SetMethodHandlerAsync( - "thermostat1*getMaxMinReport", - (commandRequest, userContext) => - { - try - { - DateTimeOffset sinceInUtc = JsonConvert.DeserializeObject(commandRequest.DataAsJson); - - // Application code ... - Report report = GetMaxMinReport(sinceInUtc); - - return Task.FromResult( - new MethodResponse( - Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(report)), - CommonClientResponseCodes.OK)); - } - catch (JsonReaderException) - { - return Task.FromResult(new MethodResponse(CommonClientResponseCodes.BadRequest)); - } - }, - null, - cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Subscribe and respond to command "getMaxMinReport" under component "thermostat1". -await _deviceClient.SubscribeToCommandsAsync( - (commandRequest, userContext) => - { - // This API does not support setting command-level callbacks. - // For this reason we'll need to inspect both commandRequest.ComponentName and commandRequest.CommandName, and perform the actions accordingly. - // Refer to the TemperatureControllerSample.cs for a complete sample implementation. - - if (commandRequest.ComponentName == "thermostat1" - && commandRequest.CommandName == "getMaxMinReport") - { - try - { - DateTimeOffset sinceInUtc = commandRequest.GetData(); - - // Application code ... - Report report = GetMaxMinReport(sinceInUtc); - - return Task.FromResult(new CommandResponse(report, CommonClientResponseCodes.OK)); - } - catch (JsonReaderException) - { - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.BadRequest)); - } - } - else - { - return Task.FromResult(new CommandResponse(CommonClientResponseCodes.NotFound)); - } - } -); -``` - -## Properties - -### Retrive top-level client properties: - -#### Using non-convention-aware API (old): - -```csharp -// Retrieve the client's properties. -Twin properties = await _deviceClient.GetTwinAsync(cancellationToken); - -// To fetch the value of client reported property "serialNumber". -bool isSerialNumberReported = properties.Properties.Reported.Contains("serialNumber"); -if (isSerialNumberReported) -{ - string serialNumberReported = properties.Properties.Reported["serialNumber"]; -} - -// To fetch the value of service requested "targetTemperature" value. -bool isTargetTemperatureUpdateRequested = properties.Properties.Desired.Contains("targetTemperature"); -if (isTargetTemperatureUpdateRequested) -{ - double targetTemperatureUpdateRequest = properties.Properties.Desired["targetTemperature"]; -} -``` - -#### Using convention-aware API (new): - -```csharp -// Retrieve the client's properties. - ClientProperties properties = await _deviceClient.GetClientPropertiesAsync(cancellationToken); - -// To fetch the value of client reported property "serialNumber". -bool isSerialNumberReported = properties.TryGetValue("serialNumber", out string serialNumberReported); - - -// To fetch the value of service requested "targetTemperature" value. -bool isTargetTemperatureUpdateRequested = properties.Writable.TryGetValue("targetTemperature", out double targetTemperatureUpdateRequest); -``` - -### Retrive component-level client properties: - -#### Using non-convention-aware API (old): - -```csharp -// Retrieve the client's properties. -Twin properties = await _deviceClient.GetTwinAsync(cancellationToken); - -// To fetch the value of client reported property "serialNumber" under component "thermostat1". -JToken serialNumberJToken = null; -bool isSerialNumberReported = properties.Properties.Reported.Contains("thermostat1") - && ((JObject)properties.Properties.Reported["thermostat1"]).TryGetValue("serialNumber", out serialNumberJToken); - -if (isSerialNumberReported) -{ - string serialNumberReported = serialNumberJToken?.ToObject(); -} - -// To fetch the value of service requested "targetTemperature" value under component "thermostat1". -JToken targetTemperatureUpdateRequestJToken = null; -bool isTargetTemperatureUpdateRequested = properties.Properties.Desired.Contains("thermostat1") - && ((JObject)properties.Properties.Desired["thermostat1"]).TryGetValue("targetTemperature", out targetTemperatureUpdateRequestJToken); - -if (isTargetTemperatureUpdateRequested) -{ - double targetTemperatureUpdateRequest = (double)(targetTemperatureUpdateRequestJToken?.ToObject()); -} -``` - -#### Using convention-aware API (new): - -```csharp -// Retrieve the client's properties. - ClientProperties properties = await _deviceClient.GetClientPropertiesAsync(cancellationToken); - -// To fetch the value of client reported property "serialNumber" under component "thermostat1". -bool isSerialNumberReported = properties.TryGetValue("thermostat1", "serialNumber", out string serialNumberReported); - - -// To fetch the value of service requested "targetTemperature" value under component "thermostat1". -bool isTargetTemperatureUpdateRequested = properties.Writable.TryGetValue("thermostat1", "targetTemperature", out double targetTemperatureUpdateRequest); -``` - -### Update top-level property: - -#### Using non-convention-aware API (old): - -```csharp -// Update the property "serialNumber". -var propertiesToBeUpdated = new TwinCollection -{ - ["serialNumber"] = "SR-1234", -}; -await _deviceClient.UpdateReportedPropertiesAsync(propertiesToBeUpdated, cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Update the property "serialNumber". -var propertiesToBeUpdated = new ClientPropertyCollection -{ - ["serialNumber"] = "SR-1234", -}; -ClientPropertiesUpdateResponse updateResponse = await _deviceClient - .UpdateClientPropertiesAsync(propertiesToBeUpdated, cancellationToken); -long updatedVersion = updateResponse.Version; -``` - -### Update component-level properties: - -#### Using non-convention-aware API (old): - -```csharp -// Update the property "serialNumber" under component "thermostat1". -// When calling the UpdateReportedPropertiesAsync API the component-level property update requests must -// include the {"__t": "c"} marker to indicate that the element refers to a component. -var thermostatProperties = new TwinCollection -{ - ["__t"] = "c", - ["serialNumber"] = "SR-1234", -}; -var propertiesToBeUpdated = new TwinCollection -{ - ["thermostat1"] = thermostatProperties -}; -await _deviceClient.UpdateReportedPropertiesAsync(propertiesToBeUpdated, cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Update the property "serialNumber" under component "thermostat1". -var propertiesToBeUpdated = new ClientPropertyCollection(); -propertiesToBeUpdated.AddComponentProperty("thermostat1", "serialNumber", "SR-1234"); - -ClientPropertiesUpdateResponse updateResponse = await _deviceClient - .UpdateClientPropertiesAsync(propertiesToBeUpdated, cancellationToken); -long updatedVersion = updateResponse.Version; -``` - -### Respond to top-level property update requests: - -#### Using non-convention-aware API (old): - -```csharp -// Subscribe and respond to event for writable property "targetTemperature". -// This writable property update response should follow the format specified here: https://docs.microsoft.com/azure/iot-pnp/concepts-convention#writable-properties. -await _deviceClient.SetDesiredPropertyUpdateCallbackAsync( - async (desired, userContext) => - { - if (desired.Contains("targetTemperature")) - { - double targetTemperature = desired["targetTemperature"]; - - var targetTemperatureUpdateResponse = new TwinCollection - { - ["value"] = targetTemperature, - ["ac"] = CommonClientResponseCodes.OK, - ["av"] = desired.Version, - ["ad"] = "The operation completed successfully." - }; - var propertiesToBeUpdated = new TwinCollection() - { - ["targetTemperature"] = targetTemperatureUpdateResponse, - }; - - await _deviceClient.UpdateReportedPropertiesAsync(propertiesToBeUpdated, cancellationToken); - } - }, - null, - cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Subscribe and respond to event for writable property "targetTemperature". -// This writable property update response should follow the format specified here: https://docs.microsoft.com/azure/iot-pnp/concepts-convention#writable-properties. -await _deviceClient.SubscribeToWritablePropertiesEventAsync( - async (writableProperties, userContext) => - { - if (writableProperties.TryGetValue("targetTemperature", out double targetTemperature)) - { - IWritablePropertyResponse writableResponse = _deviceClient - .PayloadConvention - .PayloadSerializer - .CreateWritablePropertyResponse(targetTemperature, CommonClientResponseCodes.OK, writableProperties.Version, "The operation completed successfully."); - - var propertiesToBeUpdated = new ClientPropertyCollection(); - propertiesToBeUpdated.AddRootProperty("targetTemperature", writableResponse); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(propertiesToBeUpdated, cancellationToken); - } - }, - null, - cancellationToken); -``` - -### Respond to component-level property update requests: - -#### Using non-convention-aware API (old): - -```csharp -// Subscribe and respond to event for writable property "targetTemperature" -// under component "thermostat1". -// This writable property update response should follow the format specified here: https://docs.microsoft.com/azure/iot-pnp/concepts-convention#writable-properties. -// When calling the UpdateReportedPropertiesAsync API the component-level property update requests must -// include the {"__t": "c"} marker to indicate that the element refers to a component. -await _deviceClient.SetDesiredPropertyUpdateCallbackAsync( - async (desired, userContext) => - { - if (desired.Contains("thermostat1") - && ((JObject)desired["thermostat1"]) - .TryGetValue("targetTemperature", out JToken targetTemperatureRequested)) - { - double targetTemperature = targetTemperatureRequested - .ToObject(); - - var targetTemperatureUpdateResponse = new TwinCollection - { - ["value"] = targetTemperature, - ["ac"] = CommonClientResponseCodes.OK, - ["av"] = desired.Version, - ["ad"] = "The operation completed successfully." - }; - var thermostatProperties = new TwinCollection() - { - ["__t"] = "c", - ["targetTemperature"] = targetTemperatureUpdateResponse, - }; - var propertiesToBeUpdated = new TwinCollection() - { - ["thermostat1"] = thermostatProperties, - }; - - await _deviceClient.UpdateReportedPropertiesAsync(propertiesToBeUpdated, cancellationToken); - } - }, - null, - cancellationToken); -``` - -#### Using convention-aware API (new): - -```csharp -// Subscribe and respond to event for writable property "targetTemperature" -// under component "thermostat1". -// This writable property update response should follow the format specified here: https://docs.microsoft.com/azure/iot-pnp/concepts-convention#writable-properties. -await _deviceClient.SubscribeToWritablePropertiesEventAsync( - async (writableProperties, userContext) => - { - if (writableProperties.TryGetValue("thermostat1", "targetTemperature", out double targetTemperature)) - { - IWritablePropertyResponse writableResponse = _deviceClient - .PayloadConvention - .PayloadSerializer - .CreateWritablePropertyResponse(targetTemperature, CommonClientResponseCodes.OK, writableProperties.Version, "The operation completed successfully."); - - var propertiesToBeUpdated = new ClientPropertyCollection(); - propertiesToBeUpdated.AddComponentProperty("thermostat1", "targetTemperature", writableResponse); - - ClientPropertiesUpdateResponse updateResponse = await _deviceClient.UpdateClientPropertiesAsync(propertiesToBeUpdated, cancellationToken); - } - }, - null, - cancellationToken); -``` - -# IoT Plug And Play device samples - -These samples demonstrate how a device that follows the [IoT Plug and Play conventions][pnp-convention] interacts with IoT Hub or IoT Central, to: - -- Send telemetry. -- Update client properties and be notified of service requested property update requests. -- Respond to command invocation. - -The samples demonstrate two scenarios: - -- An IoT Plug and Play device that implements the [Thermostat][d-thermostat] model. This model has a single interface (the default component) that defines telemetry, properties and commands. -- An IoT Plug and Play device that implements the [Temperature controller][d-temperature-controller] model. This model defines multiple interfaces: - - The top-level interface defines telemetry, properties and commands. - - The model includes two [Thermostat][thermostat-model] components, and a [device information][d-device-info] component. - -> NOTE: These samples are only meant to demonstrate the usage of Plug and Play APIs. If you are looking for a good device sample to get started with, please see the [device reconnection sample][device-reconnection-sample]. It shows how to connect a device, handle disconnect events, cases to handle when making calls, and when to re-initialize the `DeviceClient`. - -[pnp-convention]: https://docs.microsoft.com/azure/iot-pnp/concepts-convention -[d-thermostat]: ./Thermostat -[d-temperature-controller]: ./TemperatureController -[thermostat-model]: /iot-hub/Samples/device/convention-based-samples/Thermostat/Models/Thermostat.json -[d-device-info]: https://devicemodels.azure.com/dtmi/azure/devicemanagement/deviceinformation-1.json -[thermostat-hub-qs]: https://docs.microsoft.com/azure/iot-pnp/quickstart-connect-device?pivots=programming-language-csharp -[temp-controller-hub-tutorial]: https://docs.microsoft.com/azure/iot-pnp/tutorial-multiple-components?pivots=programming-language-csharp -[temp-controller-central-tutorial]: https://docs.microsoft.com/azure/iot-central/core/tutorial-connect-device?pivots=programming-language-csharp -[device-reconnection-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/DeviceReconnectionSample -[latest-master-release]: https://github.com/Azure/azure-iot-sdk-csharp/tree/2021-05-13 -[latest-preview-release]: https://github.com/Azure/azure-iot-sdk-csharp/tree/preview_2021-6-8 \ No newline at end of file diff --git a/iothub/device/samples/readme.md b/iothub/device/samples/readme.md index 3908583189..82bbe02610 100644 --- a/iothub/device/samples/readme.md +++ b/iothub/device/samples/readme.md @@ -1,5 +1,10 @@ -This folder contains simple samples showing how to use the various features of Microsoft Azure IoT Hub service, from a device running C# code. +This folder contains simple samples showing how to use the various preview features of Microsoft Azure IoT Hub .NET SDK. + +The following features are currently in preview: +- .NET 5.0 support. +- Support for convention-based operations. +- Device Streaming. ### [Device samples][device-samples] @@ -12,8 +17,8 @@ This folder contains simple samples showing how to use the various features of M - [File upload sample][d-file-upload-sample] - [Import/export devices sample][d-import-export-devices-sample] - [Connect with X509 certificate sample][d-x509-cert-sample] -- [Plug and Play device samples][d-pnp-sample] -- [Xamarin sample][d-xamarin-sample] +- [Convention based operations samples][d-convention-based-operations-sample] +- [Device streaming sample][d-device-streaming-sample] ### Module sample @@ -65,18 +70,18 @@ You need to clone the repository or download the sample (the one you want to try dotnet run ``` -[device-samples]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device -[d-message-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/DeviceReconnectionSample -[d-receive-message-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/MessageReceiveSample -[d-method-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/MethodSample -[d-twin-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/TwinSample -[d-file-upload-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/FileUploadSample -[d-x509-cert-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/X509DeviceCertWithChainSample -[d-import-export-devices-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/ImportExportDevicesSample -[d-pnp-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/PnpDeviceSamples -[d-xamarin-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/XamarinSample - -[m-message-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/module/ModuleSample +[device-samples]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device +[d-message-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/DeviceReconnectionSample +[d-receive-message-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/MessageReceiveSample +[d-method-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/MethodSample +[d-twin-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/TwinSample +[d-file-upload-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/FileUploadSample +[d-x509-cert-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/X509DeviceCertWithChainSample +[d-import-export-devices-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/ImportExportDevicesSample +[d-convention-based-operations-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/ConventionBasedOperations +[d-device-streaming-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/DeviceStreamingSample + +[m-message-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/module/ModuleSample [lnk-setup-iot-hub]: https://aka.ms/howtocreateazureiothub [lnk-manage-iot-device]: https://github.com/Azure/azure-iot-device-ecosystem/blob/master/setup_iothub.md#create-new-device-in-the-iot-hub-device-identity-registry \ No newline at end of file From c8c3943ceefc83e7740b8027fa6af18559d6c27e Mon Sep 17 00:00:00 2001 From: Abhipsa Misra Date: Wed, 30 Jun 2021 14:48:23 -0700 Subject: [PATCH 2/3] remove import export device sample --- iothub/device/samples/readme.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/iothub/device/samples/readme.md b/iothub/device/samples/readme.md index 82bbe02610..0fd55b6269 100644 --- a/iothub/device/samples/readme.md +++ b/iothub/device/samples/readme.md @@ -15,7 +15,6 @@ The following features are currently in preview: - [Receive message sample][d-receive-message-sample] - [Twin sample][d-twin-sample] - [File upload sample][d-file-upload-sample] -- [Import/export devices sample][d-import-export-devices-sample] - [Connect with X509 certificate sample][d-x509-cert-sample] - [Convention based operations samples][d-convention-based-operations-sample] - [Device streaming sample][d-device-streaming-sample] @@ -77,7 +76,6 @@ You need to clone the repository or download the sample (the one you want to try [d-twin-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/TwinSample [d-file-upload-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/FileUploadSample [d-x509-cert-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/X509DeviceCertWithChainSample -[d-import-export-devices-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/ImportExportDevicesSample [d-convention-based-operations-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/ConventionBasedOperations [d-device-streaming-sample]: https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/preview/iot-hub/Samples/device/DeviceStreamingSample From 4fd62cad370663fc558474d8dba18fa54627fb3f Mon Sep 17 00:00:00 2001 From: Abhipsa Misra Date: Wed, 30 Jun 2021 17:01:21 -0700 Subject: [PATCH 3/3] fix --- azureiot.sln | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/azureiot.sln b/azureiot.sln index 5b4d4d37ae..3b894997b8 100644 --- a/azureiot.sln +++ b/azureiot.sln @@ -79,12 +79,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Devices.Sha EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{2368415A-9C09-4F47-9636-FDCA4B85C88C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "convention-based-samples", "convention-based-samples", "{22318FE4-1453-41BF-A38D-9401C4F16023}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thermostat", "iothub\device\samples\convention-based-samples\Thermostat\Thermostat.csproj", "{5658A5DF-EDEF-4561-9F0B-A37EEABC8135}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemperatureController", "iothub\device\samples\convention-based-samples\TemperatureController\TemperatureController.csproj", "{B557FCFE-015C-4A65-81B6-B4987E07BFB7}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -158,14 +152,6 @@ Global {CEEE435F-32FC-4DE5-8735-90F6AC950A01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CEEE435F-32FC-4DE5-8735-90F6AC950A01}.Debug|Any CPU.Build.0 = Debug|Any CPU {CEEE435F-32FC-4DE5-8735-90F6AC950A01}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5658A5DF-EDEF-4561-9F0B-A37EEABC8135}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5658A5DF-EDEF-4561-9F0B-A37EEABC8135}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5658A5DF-EDEF-4561-9F0B-A37EEABC8135}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5658A5DF-EDEF-4561-9F0B-A37EEABC8135}.Release|Any CPU.Build.0 = Release|Any CPU - {B557FCFE-015C-4A65-81B6-B4987E07BFB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B557FCFE-015C-4A65-81B6-B4987E07BFB7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B557FCFE-015C-4A65-81B6-B4987E07BFB7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B557FCFE-015C-4A65-81B6-B4987E07BFB7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -201,9 +187,6 @@ Global {8E25CDE3-992D-4942-8C38-51A0D8E8EB70} = {9C260BF0-1CCA-45A2-AAB8-6419291B8B88} {CEEE435F-32FC-4DE5-8735-90F6AC950A01} = {3AA089A9-A035-439E-BAF6-C3975A334379} {2368415A-9C09-4F47-9636-FDCA4B85C88C} = {A48437BA-3C5B-431E-9B2F-96C850E9E1A5} - {22318FE4-1453-41BF-A38D-9401C4F16023} = {2368415A-9C09-4F47-9636-FDCA4B85C88C} - {5658A5DF-EDEF-4561-9F0B-A37EEABC8135} = {22318FE4-1453-41BF-A38D-9401C4F16023} - {B557FCFE-015C-4A65-81B6-B4987E07BFB7} = {22318FE4-1453-41BF-A38D-9401C4F16023} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AF61665D-340A-494B-9705-571456BDC752}