// The desired property update callback, which receives the target temperature as a desired property update,
        // and updates the current temperature value over telemetry and property update.
        private async Task TargetTemperatureUpdateCallbackAsync(TwinCollection desiredProperties, object userContext)
        {
            string componentName = (string)userContext;

            bool targetTempUpdateReceived = PnpConvention.TryGetPropertyFromTwin(
                desiredProperties,
                TargetTemperatureProperty,
                out double targetTemperature,
                componentName);

            if (!targetTempUpdateReceived)
            {
                _logger.LogDebug($"Property: Update - component=\"{componentName}\", received an update which is not associated with a valid property.\n{desiredProperties.ToJson()}");
                return;
            }

            _logger.LogDebug($"Property: Received - component=\"{componentName}\", {{ \"{TargetTemperatureProperty}\": {targetTemperature}°C }}.");

            s_localWritablePropertiesVersion = desiredProperties.Version;

            TwinCollection pendingReportedProperty = PnpConvention.CreateComponentWritablePropertyResponse(
                componentName,
                TargetTemperatureProperty,
                targetTemperature,
                (int)StatusCode.InProgress,
                desiredProperties.Version,
                "In progress - reporting current temperature");

            await _deviceClient.UpdateReportedPropertiesAsync(pendingReportedProperty);

            _logger.LogDebug($"Property: Update - component=\"{componentName}\", {{\"{TargetTemperatureProperty}\": {targetTemperature} }} in °C is {StatusCode.InProgress}.");

            // Update Temperature in 2 steps
            double step = (targetTemperature - _temperature[componentName]) / 2d;

            for (int i = 1; i <= 2; i++)
            {
                _temperature[componentName] = Math.Round(_temperature[componentName] + step, 1);
                await Task.Delay(6 * 1000);
            }

            TwinCollection completedReportedProperty = PnpConvention.CreateComponentWritablePropertyResponse(
                componentName,
                TargetTemperatureProperty,
                _temperature[componentName],
                (int)StatusCode.Completed,
                desiredProperties.Version,
                "Successfully updated target temperature");

            await _deviceClient.UpdateReportedPropertiesAsync(completedReportedProperty);

            _logger.LogDebug($"Property: Update - component=\"{componentName}\", {{\"{TargetTemperatureProperty}\": {_temperature[componentName]} }} in °C is {StatusCode.Completed}");
        }
        private async Task ReportInitialPropertyAsync(string componentName, string propertyName, CancellationToken cancellationToken)
        {
            // If the device properties are empty, report the default value with ACK(ac=203, av=0) as part of the PnP convention.
            // "DefaultPropertyValue" is set from the device when the desired property is not set via the hub.
            TwinCollection reportedProperties = PnpConvention.CreateComponentWritablePropertyResponse(
                componentName,
                propertyName,
                DefaultPropertyValue,
                (int)StatusCode.ReportDeviceInitialProperty,
                DefaultAckVersion,
                "Initialized with default value");

            await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties, cancellationToken);

            _logger.LogDebug($"Report the default values for \"{componentName}\".\nProperty: Update - {reportedProperties.ToJson()} is complete.");
        }