Tutorial: Erstellen einer Clientanwendung und Verbinden dieser Anwendung mit Ihrer Azure IoT Central-Anwendung

In diesem Tutorial erfahren Sie, wie Sie eine Clientanwendung mit Ihrer Azure IoT Central-Anwendung verbinden. Die Anwendung simuliert das Verhalten eines Thermostatsgerät. Wenn die Anwendung eine Verbindung mit IoT Central herstellt, sendet sie die Modell-ID des Thermostatgerätemodells. IoT Central verwendet die Modell-ID, um das Gerätemodell abzurufen und eine Gerätevorlage für Sie zu erstellen. Sie fügen der Gerätevorlage Ansichten hinzu, um einem Bediener die Interaktion mit einem Gerät zu ermöglichen.

In diesem Tutorial lernen Sie Folgendes:

  • Erstellen und Ausführen des Gerätecodes und Verfolgen der Verbindungsherstellung mit Ihrer IoT Central-Anwendung
  • Zeigen Sie die simulierten Telemetriedaten an, die vom Gerät gesendet werden.
  • Hinzufügen von benutzerdefinierten Ansichten zu einer Gerätevorlage
  • Veröffentlichen der Gerätevorlage
  • Verwalten von Geräteeigenschaften mithilfe einer Ansicht
  • Aufrufen eines Befehls zum Steuern des Geräts

Browse code

Voraussetzungen

Zum Durchführen der Schritte in diesem Tutorial benötigen Sie Folgendes:

Sie können dieses Tutorial unter Linux oder Windows durcharbeiten. Die Shellbefehle in diesem Tutorial entsprechen der Linux-Konvention für die Pfadtrennzeichen /. Wenn Sie den Anleitungen unter Windows folgen, sollten Sie diese Trennzeichen durch \ ersetzen.

Die Voraussetzungen sind je nach Betriebssystem unterschiedlich:

Linux

In diesem Tutorial wird davon ausgegangen, dass Sie Ubuntu Linux nutzen. Die Schritte in diesem Tutorial wurden unter Ubuntu 18.04 getestet.

Installieren Sie die folgende Software in Ihrer lokalen Linux-Umgebung, um dieses Tutorial unter Linux durchzuarbeiten:

Installieren Sie GCC, Git, cmake und alle erforderlichen Abhängigkeiten mit dem Befehl apt-get:

sudo apt-get update
sudo apt-get install -y git cmake build-essential curl libcurl4-openssl-dev libssl-dev uuid-dev

Stellen Sie sicher, dass die Version von cmake höher als 2.8.12 und die Version von GCC höher als 4.4.7 ist.

cmake --version
gcc --version

Windows

Installieren Sie die folgende Software in Ihrer lokalen Windows-Umgebung, um dieses Tutorial unter Windows ausführen zu können:

Laden Sie den Code herunter.

In diesem Tutorial wird eine Entwicklungsumgebung vorbereitet, die Sie zum Klonen und Erstellen des Azure IoT Hub-Geräte-SDK für C verwenden können.

Öffnen Sie eine Eingabeaufforderung in einem Verzeichnis Ihrer Wahl. Führen Sie den folgenden Befehl zum Klonen des GitHub-Repositorys für das Azure IoT-C-SDK und die zugehörigen Bibliotheken an diesem Speicherort aus:

git clone https://github.com/Azure/azure-iot-sdk-c.git
cd azure-iot-sdk-c
git submodule update --init

Sie sollten damit rechnen, dass die Ausführung dieses Vorgangs mehrere Minuten in Anspruch nimmt.

Überprüfen des Codes

Öffnen Sie in der Kopie des zuvor heruntergeladenen Microsoft Azure IoT SDK für C die Dateien azure-iot-sdk-c/iothub_client/samples/pnp/pnp_temperature_controller/pnp_temperature_controller.c und azure-iot-sdk-c/iothub_client/samples/pnp/pnp_temperature_controller/pnp_thermostat_component.c in einem Text-Editor.

Im Beispiel wird das Temperaturcontroller-Sprachmodell mit mehreren Komponenten der Definition von digitalen Zwillingen implementiert.

Wenn Sie das Beispiel ausführen, um eine Verbindung mit IoT Central herzustellen, wird Device Provisioning Service (DPS) zum Registrieren des Geräts und zum Generieren einer Verbindungszeichenfolge verwendet. Das Beispiel ruft die erforderlichen DPS-Verbindungsinformationen aus der Befehlszeilenumgebung ab.

In pnp_temperature_controller.c ruft die main-Funktion zunächst CreateDeviceClientAndAllocateComponents für folgende Aktionen auf:

  • Festlegen der Modell-ID dtmi:com:example:Thermostat;1 IoT Central verwendet die Modell-ID zum Identifizieren oder Generieren der Gerätevorlage für dieses Gerät. Weitere Informationen finden Sie unter Zuweisen eines Geräts zu einer Gerätevorlage.
  • Verwenden von DPS zum Bereitstellen und Registrieren des Geräts
  • Erstellen eines Geräteclienthandlers und Herstellen einer Verbindung mit der IoT Central-Anwendung
  • Erstellen eines Handlers für Befehle in der Temperaturreglerkomponente
  • Erstellen eines Handlers für Eigenschaftsaktualisierungen in der Temperaturreglerkomponente
  • Erstellen der beiden Thermostatkomponenten

Als Nächstes werden von der main-Funktion folgende Aktionen ausgeführt:

  • Melden einiger Eigenschaftsanfangswerte für alle Komponenten
  • Starten einer Schleife, um Telemetriedaten von allen Komponenten zu senden

Die main-Funktion startet dann einen Thread, um in regelmäßigen Abständen Telemetriedaten zu senden.

int main(void)
{
    IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient = NULL;

    g_pnpDeviceConfiguration.modelId = g_temperatureControllerModelId;
    g_pnpDeviceConfiguration.enableTracing = g_hubClientTraceEnabled;

    // First determine the IoT Hub / credentials / device to use.
    if (GetConnectionSettingsFromEnvironment(&g_pnpDeviceConfiguration) == false)
    {
        LogError("Cannot read required environment variable(s)");
    }
    // Creates the thermostat subcomponents defined by this model.  Since everything
    // is simulated, this setup stage just creates simulated objects in memory.
    else if (AllocateThermostatComponents() == false)
    {
        LogError("Failure allocating thermostat components");
    }
    // Create a handle to device client handle.  Note that this call may block
    // for extended periods of time when using DPS.
    else if ((deviceClient = CreateAndConfigureDeviceClientHandleForPnP()) == NULL)
    {
        LogError("Failure creating Iot Hub device client");
        PnP_ThermostatComponent_Destroy(g_thermostatHandle1);
        PnP_ThermostatComponent_Destroy(g_thermostatHandle2);
    }
    else
    {
        LogInfo("Successfully created device client.  Hit Control-C to exit program\n");

        int numberOfIterations = 0;

        // During startup, send what DTDLv2 calls "read-only properties" to indicate initial device state.
        PnP_TempControlComponent_ReportSerialNumber_Property(deviceClient);
        PnP_DeviceInfoComponent_Report_All_Properties(g_deviceInfoComponentName, deviceClient);
        PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(g_thermostatHandle1, deviceClient);
        PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(g_thermostatHandle2, deviceClient);

        while (true)
        {
            // Wake up periodically to poll.  Even if we do not plan on sending telemetry, we still need to poll periodically in order to process
            // incoming requests from the server and to do connection keep alives.
            if ((numberOfIterations % g_sendTelemetryPollInterval) == 0)
            {
                PnP_TempControlComponent_SendWorkingSet(deviceClient);
                PnP_ThermostatComponent_SendCurrentTemperature(g_thermostatHandle1, deviceClient);
                PnP_ThermostatComponent_SendCurrentTemperature(g_thermostatHandle2, deviceClient);
            }

            IoTHubDeviceClient_LL_DoWork(deviceClient);
            ThreadAPI_Sleep(g_sleepBetweenPollsMs);
            numberOfIterations++;
        }

        // The remainder of the code is used for cleaning up our allocated resources. It won't be executed in this 
        // sample (because the loop above is infinite and is only broken out of by Control-C of the program), but 
        // it is included for reference.

        // Free the memory allocated to track simulated thermostat.
        PnP_ThermostatComponent_Destroy(g_thermostatHandle1);
        PnP_ThermostatComponent_Destroy(g_thermostatHandle2);

        // Clean up the IoT Hub SDK handle.
        IoTHubDeviceClient_LL_Destroy(deviceClient);
        // Free all IoT Hub subsystem.
        IoTHub_Deinit();
    }

    return 0;
}

In pnp_thermostat_component.c zeigt die Funktion PnP_ThermostatComponent_SendCurrentTemperature, wie das Gerät Temperaturtelemetriedaten von einer Komponente an IoT Central sendet:

void PnP_ThermostatComponent_SendCurrentTemperature(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient)
{
    PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
    IOTHUB_MESSAGE_HANDLE messageHandle = NULL;
    IOTHUB_MESSAGE_RESULT messageResult;
    IOTHUB_CLIENT_RESULT iothubClientResult;

    char temperatureStringBuffer[CURRENT_TEMPERATURE_BUFFER_SIZE];

    // Create the telemetry message body to send.
    if (snprintf(temperatureStringBuffer, sizeof(temperatureStringBuffer), g_temperatureTelemetryBodyFormat, pnpThermostatComponent->currentTemperature) < 0)
    {
        LogError("snprintf of current temperature telemetry failed");
    }
    // Create the message handle and specify its metadata.
    else if ((messageHandle = IoTHubMessage_CreateFromString(temperatureStringBuffer)) == NULL)
    {
        LogError("IoTHubMessage_PnP_CreateFromString failed");
    }
    else if ((messageResult = IoTHubMessage_SetContentTypeSystemProperty(messageHandle, g_jsonContentType)) != IOTHUB_MESSAGE_OK)
    {
        LogError("IoTHubMessage_SetContentTypeSystemProperty failed, error=%d", messageResult);
    }
    else if ((messageResult = IoTHubMessage_SetContentEncodingSystemProperty(messageHandle, g_utf8EncodingType)) != IOTHUB_MESSAGE_OK)
    {
        LogError("IoTHubMessage_SetContentEncodingSystemProperty failed, error=%d", messageResult);
    }
    else if ((messageResult = IoTHubMessage_SetComponentName(messageHandle, pnpThermostatComponent->componentName)) != IOTHUB_MESSAGE_OK)
    {
        LogError("IoTHubMessage_SetContentEncodingSystemProperty failed, error=%d", messageResult);
    }
    // Send the telemetry message.
    else if ((iothubClientResult = IoTHubDeviceClient_LL_SendTelemetryAsync(deviceClient, messageHandle, NULL, NULL)) != IOTHUB_CLIENT_OK)
    {
        LogError("Unable to send telemetry message, error=%d", iothubClientResult);
    }

    IoTHubMessage_Destroy(messageHandle);
}

In pnp_thermostat_component.c sendet die Funktion PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property eine Aktualisierung der Eigenschaft maxTempSinceLastReboot von der Komponente an IoT Central:

void PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient)
{
    PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
    char maximumTemperatureAsString[MAX_TEMPERATURE_SINCE_REBOOT_BUFFER_SIZE];
    IOTHUB_CLIENT_RESULT iothubClientResult;

    if (snprintf(maximumTemperatureAsString, sizeof(maximumTemperatureAsString), g_maxTempSinceLastRebootPropertyFormat, pnpThermostatComponent->maxTemperature) < 0)
    {
        LogError("Unable to create max temp since last reboot string for reporting result");
    }
    else
    {
        IOTHUB_CLIENT_PROPERTY_REPORTED maxTempProperty;
        maxTempProperty.structVersion = IOTHUB_CLIENT_PROPERTY_REPORTED_STRUCT_VERSION_1;
        maxTempProperty.name = g_maxTempSinceLastRebootPropertyName;
        maxTempProperty.value =  maximumTemperatureAsString;

        unsigned char* propertySerialized = NULL;
        size_t propertySerializedLength;

        // The first step of reporting properties is to serialize IOTHUB_CLIENT_PROPERTY_WRITABLE_RESPONSE into JSON for sending.
        if ((iothubClientResult = IoTHubClient_Properties_Serializer_CreateReported(&maxTempProperty, 1, pnpThermostatComponent->componentName, &propertySerialized, &propertySerializedLength)) != IOTHUB_CLIENT_OK)
        {
            LogError("Unable to serialize reported state, error=%d", iothubClientResult);
        }
        // The output of IoTHubClient_Properties_Serializer_CreateReported is sent to IoTHubDeviceClient_LL_SendPropertiesAsync to perform network I/O.
        else if ((iothubClientResult = IoTHubDeviceClient_LL_SendPropertiesAsync(deviceClient, propertySerialized, propertySerializedLength,  NULL, NULL)) != IOTHUB_CLIENT_OK)
        {
            LogError("Unable to send reported state, error=%d", iothubClientResult);
        }
        else
        {
            LogInfo("Sending %s property to IoTHub for component %s", g_maxTempSinceLastRebootPropertyName, pnpThermostatComponent->componentName);
        }
        IoTHubClient_Properties_Serializer_Destroy(propertySerialized);
    }
}

In pnp_thermostat_component.c verarbeitet die Funktion PnP_ThermostatComponent_ProcessPropertyUpdate schreibbare Eigenschaftsaktualisierungen aus IoT Central:

void PnP_ThermostatComponent_ProcessPropertyUpdate(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, IOTHUB_DEVICE_CLIENT_LL_HANDLE deviceClient, const char* propertyName, const char* propertyValue, int version)
{
    PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;

    if (strcmp(propertyName, g_targetTemperaturePropertyName) != 0)
    {
        LogError("Property %s was requested to be changed but is not part of the thermostat interface definition", propertyName);
    }
    else
    {
        char* next;
        double targetTemperature = strtod(propertyValue, &next);
        if ((propertyValue == next) || (targetTemperature == HUGE_VAL) || (targetTemperature == (-1*HUGE_VAL)))
        {
            LogError("Property %s is not a valid number", propertyValue);
            SendTargetTemperatureResponse(pnpThermostatComponent, deviceClient, propertyValue, PNP_STATUS_BAD_FORMAT, version, g_temperaturePropertyResponseDescriptionNotInt);
        }
        else
        {
            LogInfo("Received targetTemperature %f for component %s", targetTemperature, pnpThermostatComponent->componentName);
            
            bool maxTempUpdated = false;
            UpdateTemperatureAndStatistics(pnpThermostatComponent, targetTemperature, &maxTempUpdated);

            // The device needs to let the service know that it has received the targetTemperature desired property.
            SendTargetTemperatureResponse(pnpThermostatComponent, deviceClient, propertyValue, PNP_STATUS_SUCCESS, version, NULL);
            
            if (maxTempUpdated)
            {
                // If the maximum temperature has been updated, we also report this as a property.
                PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property(pnpThermostatComponent, deviceClient);
            }
        }
    }
}

In pnp_thermostat_component.c verarbeitet die Funktion PnP_ThermostatComponent_ProcessCommand über IoT Central aufgerufene Befehle:

void PnP_ThermostatComponent_ProcessCommand(PNP_THERMOSTAT_COMPONENT_HANDLE pnpThermostatComponentHandle, const char *pnpCommandName, JSON_Value* commandJsonValue, IOTHUB_CLIENT_COMMAND_RESPONSE* commandResponse)
{
    PNP_THERMOSTAT_COMPONENT* pnpThermostatComponent = (PNP_THERMOSTAT_COMPONENT*)pnpThermostatComponentHandle;
    const char* sinceStr;

    if (strcmp(pnpCommandName, g_getMaxMinReportCommandName) != 0)
    {
        LogError("Command %s is not supported on thermostat component", pnpCommandName);
        commandResponse->statusCode = PNP_STATUS_NOT_FOUND;
    }
    // See caveats section in ../readme.md; we don't actually respect this sinceStr to keep the sample simple,
    // but want to demonstrate how to parse out in any case.
    else if ((sinceStr = json_value_get_string(commandJsonValue)) == NULL)
    {
        LogError("Cannot retrieve JSON string for command");
        commandResponse->statusCode = PNP_STATUS_BAD_FORMAT;
    }
    else if (BuildMaxMinCommandResponse(pnpThermostatComponent, commandResponse) == false)
    {
        LogError("Unable to build response for component %s", pnpThermostatComponent->componentName);
        commandResponse->statusCode = PNP_STATUS_INTERNAL_ERROR;
    }
    else
    {
        LogInfo("Returning success from command request for component %s", pnpThermostatComponent->componentName);
        commandResponse->statusCode = PNP_STATUS_SUCCESS;
    }
}

Erstellen des Codes

Sie verwenden das Geräte-SDK, um den enthaltenen Beispielcode zu erstellen:

  1. Erstellen Sie im Stammordner des Geräte-SDK den Unterordner cmake, und navigieren Sie zu diesem Ordner:

    cd azure-iot-sdk-c
    mkdir cmake
    cd cmake
    
  2. Führen Sie die folgenden Befehle aus, um das SDK und die Beispiele zu erstellen:

    cmake -Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF ..
    cmake --build .
    

Abrufen von Verbindungsinformationen

Wenn Sie die Beispielgeräteanwendung später in diesem Tutorial ausführen, benötigen Sie die folgenden Konfigurationswerte:

  • ID-Bereich: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen. Notieren Sie sich den Wert für ID-Bereich.
  • Gruppenprimärschlüssel: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen > SAS-IoT-Devices. Notieren Sie sich den Wert für den SAS-Primärschlüssel (Shared Access Signature).

Verwenden Sie Azure Cloud Shell, um einen Geräteschlüssel auf der Grundlage des von Ihnen abgerufenen Gruppenprimärschlüssels zu generieren:

az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>

Notieren Sie sich den generierten Geräteschlüssel. Sie verwenden ihn später in diesem Tutorial.

Hinweis

Um dieses Beispiel auszuführen, müssen Sie das Gerät nicht im Voraus in Ihrer IoT Central-Anwendung registrieren. Im Beispiel wird die IoT Central-Funktion verwendet, um Geräte automatisch zu registrieren, wenn sie zum ersten Mal eine Verbindung herstellen.

Ausführen des Codes

Öffnen Sie zum Ausführen der Beispielanwendung eine Befehlszeilenumgebung, und navigieren Sie zum Ordner azure-iot-sdk-c\cmake.

Legen Sie die Umgebungsvariablen zum Konfigurieren des Beispiels fest. Der folgende Ausschnitt zeigt, wie Sie die Umgebungsvariablen in der Windows-Eingabeaufforderung festlegen. Ersetzen Sie bei Verwendung einer Bash-Shell die set-Befehle durch export-Befehle:

set IOTHUB_DEVICE_SECURITY_TYPE=DPS
set IOTHUB_DEVICE_DPS_ID_SCOPE=<The ID scope you made a note of previously>
set IOTHUB_DEVICE_DPS_DEVICE_ID=sample-device-01
set IOTHUB_DEVICE_DPS_DEVICE_KEY=<The generated device key you made a note of previously>
set IOTHUB_DEVICE_DPS_ENDPOINT=global.azure-devices-provisioning.net

So führen Sie das Beispiel aus:

# Bash
cd iothub_client/samples/pnp/pnp_temperature_controller/
./pnp_temperature_controller
REM Windows
cd iothub_client\samples\pnp\pnp_temperature_controller\Debug
.\pnp_temperature_controller.exe

Die folgende Ausgabe zeigt, wie das Gerät registriert und eine Verbindung mit IoT Central hergestellt wird. Das Beispiel beginnt mit dem Senden von Telemetriedaten:

Info: Initiating DPS client to retrieve IoT Hub connection information
-> 09:43:27 CONNECT | VER: 4 | KEEPALIVE: 0 | FLAGS: 194 | USERNAME: 0ne0026656D/registrations/sample-device-01/api-version=2019-03-31&ClientVersion=1.6.0 | PWD: XXXX | CLEAN: 1
<- 09:43:28 CONNACK | SESSION_PRESENT: false | RETURN_CODE: 0x0
-> 09:43:29 SUBSCRIBE | PACKET_ID: 1 | TOPIC_NAME: $dps/registrations/res/# | QOS: 1
<- 09:43:30 SUBACK | PACKET_ID: 1 | RETURN_CODE: 1
-> 09:43:30 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_MOST_ONCE | TOPIC_NAME: $dps/registrations/PUT/iotdps-register/?$rid=1 | PAYLOAD_LEN: 102
<- 09:43:31 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_LEAST_ONCE | TOPIC_NAME: $dps/registrations/res/202/?$rid=1&retry-after=3 | PACKET_ID: 2 | PAYLOAD_LEN: 94
-> 09:43:31 PUBACK | PACKET_ID: 2
-> 09:43:33 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_MOST_ONCE | TOPIC_NAME: $dps/registrations/GET/iotdps-get-operationstatus/?$rid=2&operationId=4.2f792ade0a5c3e68.baf0e879-d88a-4153-afef-71aff51fd847 | PAYLOAD_LEN: 102
<- 09:43:34 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_LEAST_ONCE | TOPIC_NAME: $dps/registrations/res/202/?$rid=2&retry-after=3 | PACKET_ID: 2 | PAYLOAD_LEN: 173
-> 09:43:34 PUBACK | PACKET_ID: 2
-> 09:43:36 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_MOST_ONCE | TOPIC_NAME: $dps/registrations/GET/iotdps-get-operationstatus/?$rid=3&operationId=4.2f792ade0a5c3e68.baf0e879-d88a-4153-afef-71aff51fd847 | PAYLOAD_LEN: 102
<- 09:43:37 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_LEAST_ONCE | TOPIC_NAME: $dps/registrations/res/200/?$rid=3 | PACKET_ID: 2 | PAYLOAD_LEN: 478
-> 09:43:37 PUBACK | PACKET_ID: 2
Info: Provisioning callback indicates success.  iothubUri=iotc-60a....azure-devices.net, deviceId=sample-device-01
-> 09:43:37 DISCONNECT
Info: DPS successfully registered.  Continuing on to creation of IoTHub device client handle.
Info: Successfully created device client.  Hit Control-C to exit program

Info: Sending serialNumber property to IoTHub
Info: Sending device information property to IoTHub.  propertyName=swVersion, propertyValue="1.0.0.0"
Info: Sending device information property to IoTHub.  propertyName=manufacturer, propertyValue="Sample-Manufacturer"
Info: Sending device information property to IoTHub.  propertyName=model, propertyValue="sample-Model-123"
Info: Sending device information property to IoTHub.  propertyName=osName, propertyValue="sample-OperatingSystem-name"
Info: Sending device information property to IoTHub.  propertyName=processorArchitecture, propertyValue="Contoso-Arch-64bit"
Info: Sending device information property to IoTHub.  propertyName=processorManufacturer, propertyValue="Processor Manufacturer(TM)"
Info: Sending device information property to IoTHub.  propertyName=totalStorage, propertyValue=10000
Info: Sending device information property to IoTHub.  propertyName=totalMemory, propertyValue=200
Info: Sending maximumTemperatureSinceLastReboot property to IoTHub for component=thermostat1
Info: Sending maximumTemperatureSinceLastReboot property to IoTHub for component=thermostat2
-> 09:43:44 CONNECT | VER: 4 | KEEPALIVE: 240 | FLAGS: 192 | USERNAME: iotc-60a576a2-eec7-48e2-9306-9e7089a79995.azure-devices.net/sample-device-01/?api-version=2020-09-30&DeviceClientType=iothubclient%2f1.6.0%20(native%3b%20Linux%3b%20x86_64)&model-id=dtmi%3acom%3aexample%3aTemperatureController%3b1 | PWD: XXXX | CLEAN: 0
<- 09:43:44 CONNACK | SESSION_PRESENT: false | RETURN_CODE: 0x0
-> 09:43:44 SUBSCRIBE | PACKET_ID: 2 | TOPIC_NAME: $iothub/twin/res/# | QOS: 0 | TOPIC_NAME: $iothub/methods/POST/# | QOS: 0
-> 09:43:44 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_LEAST_ONCE | TOPIC_NAME: devices/sample-device-01/messages/events/ | PACKET_ID: 3 | PAYLOAD_LEN: 19
-> 09:43:44 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_LEAST_ONCE | TOPIC_NAME: devices/sample-device-01/messages/events/%24.sub=thermostat1 | PACKET_ID: 4 | PAYLOAD_LEN: 21
-> 09:43:44 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_LEAST_ONCE | TOPIC_NAME: devices/sample-device-01/messages/events/%24.sub=thermostat2 | PACKET_ID: 5 | PAYLOAD_LEN: 21

Als Operator in Ihrer Azure IoT Central-Anwendung haben Sie folgende Möglichkeiten:

  • Anzeigen der von den beiden Thermostatkomponenten gesendeten Telemetriedaten auf der Seite Übersicht:

    Screenshot that shows the device overview page.

  • Anzeigen der Geräteeigenschaften auf der Seite Info. Auf dieser Seite werden die Eigenschaften der Geräteinformationskomponente und der beiden Thermostatkomponenten angezeigt:

    Screenshot that shows the device properties view.

Anpassen der Gerätevorlage

Als Lösungsentwickler können Sie die Gerätevorlage anpassen, die von IoT Central automatisch erstellt wurde, als der Temperaturregler eine Verbindung hergestellt hat.

So fügen Sie eine Cloudeigenschaft hinzu, um den dem Gerät zugeordneten Kundennamen zu speichern:

  1. Navigieren Sie in Ihrer IoT Central-Anwendung auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Wählen Sie im Modell Temperature Controller die Option + Funktion hinzufügen aus.

  3. Geben Sie Kundenname als Anzeigename ein, wählen Sie Cloudeigenschaft als Funktionstyp aus, erweitern Sie den Eintrag, und wählen Sie Zeichenfolge als Schema aus. Klicken Sie dann auf Speichern.

So passen Sie die Darstellung des Befehls Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) in Ihrer IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter getMaxMinReport (thermostat1) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat1 status report (Statusbericht für „thermostat1“ abrufen).

  3. Ersetzen Sie unter getMaxMinReport (thermostat2) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat2 status report (Statusbericht für „thermostat2“ abrufen).

  4. Wählen Sie Speichern aus.

So passen Sie die Darstellung der schreibbaren Eigenschaften für die Zieltemperatur in der IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter targetTemperature (thermostat1) die Option Zieltemperatur durch Zieltemperatur (1) .

  3. Ersetzen Sie unter targetTemperature (thermostat2) die Option Zieltemperatur durch Zieltemperatur (2) .

  4. Wählen Sie Speichern aus.

Die Thermostatkomponenten im Modell Thermostat enthalten die beschreibbare Eigenschaft Target Temperature (Zieltemperatur), und die Gerätevorlage enthält die Cloudeigenschaft Customer Name (Kundenname). Erstellen Sie eine Ansicht, die von einem Operator zum Bearbeiten dieser Eigenschaften verwendet werden kann:

  1. Wählen Sie Ansichten und anschließend die Kachel Geräte- und Clouddaten bearbeiten aus.

  2. Geben Sie Properties (Eigenschaften) als Formularname ein.

  3. Wählen Sie die Eigenschaften Target Temperature (1) (Zieltemperatur (1)), Target Temperature (2) (Zieltemperatur (2)) und Customer Name (Kundenname) aus. Wählen Sie anschließend Abschnitt hinzufügen aus.

  4. Speichern Sie die Änderungen.

Screenshot that shows a view for updating property values.

Veröffentlichen der Gerätevorlage

Damit die von Ihnen vorgenommenen Anpassungen von einem Operator angezeigt und verwendet werden können, müssen Sie die Gerätevorlage veröffentlichen.

Wählen Sie in der Gerätevorlage Thermostat die Option Veröffentlichen aus. Wählen Sie im Bereich Diese Gerätevorlage für die Anwendung veröffentlichen die Option Veröffentlichen aus.

Ein Operator kann nun die Ansicht Eigenschaften verwenden, um die Eigenschaftswerte zu aktualisieren, und auf der Seite mit Gerätebefehlen Befehle namens Get thermostat1 status report (Statusbericht für "thermostat1" abrufen) und Get thermostat2 status report (Statusbericht für "thermostat2" abrufen) aufrufen:

  • Aktualisieren beschreibbarer Eigenschaftswerte auf der Seite Properties (Eigenschaften):

    Screenshot that shows updating the device properties.

  • Rufen Sie die Befehle auf der Seite Befehle auf. Wählen Sie bei Ausführung des Statusberichtsbefehls ein Datum und eine Uhrzeit für den Since-Parameter aus, bevor Sie ihn ausführen:

    Screenshot that shows calling a command.

    Screenshot that shows a command response.

Sie können sehen, wie das Gerät auf Befehle und Eigenschaftsaktualisierungen reagiert:

<- 09:49:03 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_MOST_ONCE | TOPIC_NAME: $iothub/methods/POST/thermostat1*getMaxMinReport/?$rid=1 | PAYLOAD_LEN: 26
Info: Received PnP command for component=thermostat1, command=getMaxMinReport
Info: Returning success from command request for component=thermostat1
-> 09:49:03 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_MOST_ONCE | TOPIC_NAME: $iothub/methods/res/200/?$rid=1 | PAYLOAD_LEN: 117

...

<- 09:50:04 PUBLISH | IS_DUP: false | RETAIN: 0 | QOS: DELIVER_AT_MOST_ONCE | TOPIC_NAME: $iothub/twin/PATCH/properties/desired/?$version=2 | PAYLOAD_LEN: 63
Info: Received targetTemperature=67.000000 for component=thermostat2
Info: Sending acknowledgement of property to IoTHub for component=thermostat2

Browse code

Voraussetzungen

Zum Ausführen der Schritte in diesem Artikel benötigen Sie folgende Ressourcen:

Überprüfen des Codes

Öffnen Sie in der zuvor heruntergeladenen Kopie des Microsoft Azure IoT SDK für C#-Repository die Lösungsdatei azure-iot-sdk-csharp-main\azureiot.sln in Visual Studio. Erweitern Sie im Projektmappen-Explorer den Ordner PnpDeviceSamples > TemperatureController, und öffnen Sie die Dateien Program.cs und TemperatureControllerSample.cs, um den Code für dieses Beispiel anzuzeigen.

Im Beispiel wird das Temperaturcontroller-Sprachmodell mit mehreren Komponenten der Definition von digitalen Zwillingen implementiert.

Wenn Sie das Beispiel ausführen, um eine Verbindung mit IoT Central herzustellen, wird Device Provisioning Service (DPS) zum Registrieren des Geräts und zum Generieren einer Verbindungszeichenfolge verwendet. Das Beispiel ruft die erforderlichen DPS-Verbindungsinformationen aus der Umgebung ab.

In Program.cs ruft die Main-Methode SetupDeviceClientAsync zu folgenden Zwecken auf:

  • Verwenden der Modell-ID dtmi:com:example:TemperatureController;2 beim Bereitstellen des Geräts mit DPS IoT Central verwendet die Modell-ID zum Identifizieren oder Generieren der Gerätevorlage für dieses Gerät. Weitere Informationen finden Sie unter Zuweisen eines Geräts zu einer Gerätevorlage.
  • Erstellen einer DeviceClient-Instanz zum Herstellen einer Verbindung mit IoT Central
private static async Task<DeviceClient> SetupDeviceClientAsync(Parameters parameters, CancellationToken cancellationToken)
{
  DeviceClient deviceClient;
  switch (parameters.DeviceSecurityType.ToLowerInvariant())
  {
    case "dps":
      DeviceRegistrationResult dpsRegistrationResult = await ProvisionDeviceAsync(parameters, cancellationToken);
      var authMethod = new DeviceAuthenticationWithRegistrySymmetricKey(dpsRegistrationResult.DeviceId, parameters.DeviceSymmetricKey);
      deviceClient = InitializeDeviceClient(dpsRegistrationResult.AssignedHub, authMethod);
      break;

    case "connectionstring":
      // ...

    default:
      // ...
  }
  return deviceClient;
}

Die main-Methode erstellt dann eine TemperatureControllerSample-Instanz und ruft die PerformOperationsAsync-Methode auf, um die Interaktionen mit IoT Central zu verarbeiten.

In TemperatureControllerSample.cs werden von der Methode PerformOperationsAsync folgende Aktionen ausgeführt:

  • Festlegen eines Handlers für den reboot-Befehl für die Standardkomponente
  • Festlegen von Handlern für die getMaxMinReport-Befehle für die beiden Thermostatkomponenten
  • Festlegen von Handlern, um Eigenschaftsaktualisierung für die Zieltemperatur der beiden Thermostatkomponenten zu erhalten
  • Senden von Eigenschaftsaktualisierungen für die anfänglichen Geräteinformationen
  • Senden von Temperaturtelemetriedaten von den beiden Thermostatkomponenten in regelmäßigen Abständen
  • Senden von Arbeitssatz-Telemetriedaten von der Standardkomponente in regelmäßigen Abständen
  • Senden der Höchsttemperatur seit dem letzten Neustart, wenn eine neue Höchsttemperatur auf den beiden Thermostatkomponenten erreicht wird
public async Task PerformOperationsAsync(CancellationToken cancellationToken)
{
  await _deviceClient.SetMethodHandlerAsync("reboot", HandleRebootCommandAsync, _deviceClient, cancellationToken);

  // For a component-level command, the command name is in the format "<component-name>*<command-name>".
  await _deviceClient.SetMethodHandlerAsync("thermostat1*getMaxMinReport", HandleMaxMinReportCommand, Thermostat1, cancellationToken);
  await _deviceClient.SetMethodHandlerAsync("thermostat2*getMaxMinReport", HandleMaxMinReportCommand, Thermostat2, cancellationToken);

  await _deviceClient.SetDesiredPropertyUpdateCallbackAsync(SetDesiredPropertyUpdateCallback, null, cancellationToken);
  _desiredPropertyUpdateCallbacks.Add(Thermostat1, TargetTemperatureUpdateCallbackAsync);
  _desiredPropertyUpdateCallbacks.Add(Thermostat2, TargetTemperatureUpdateCallbackAsync);

  await UpdateDeviceInformationAsync(cancellationToken);
  await SendDeviceSerialNumberAsync(cancellationToken);

  bool temperatureReset = true;
  _maxTemp[Thermostat1] = 0d;
  _maxTemp[Thermostat2] = 0d;

  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] = Math.Round(s_random.NextDouble() * 40.0 + 5.0, 1);
      _temperature[Thermostat2] = Math.Round(s_random.NextDouble() * 40.0 + 5.0, 1);
    }

    await SendTemperatureAsync(Thermostat1, cancellationToken);
    await SendTemperatureAsync(Thermostat2, cancellationToken);
    await SendDeviceMemoryAsync(cancellationToken);

    temperatureReset = _temperature[Thermostat1] == 0 && _temperature[Thermostat2] == 0;
    await Task.Delay(5 * 1000);
  }
}

Die SendTemperatureAsync-Methode zeigt, wie das Gerät die Temperaturtelemetriedaten von einer Komponente an IoT Central sendet. Die SendTemperatureTelemetryAsync-Methode verwendet die PnpConvention-Klasse zum Erstellen der Nachricht:

private async Task SendTemperatureAsync(string componentName, CancellationToken cancellationToken)
{
  await SendTemperatureTelemetryAsync(componentName, cancellationToken);

  double maxTemp = _temperatureReadingsDateTimeOffset[componentName].Values.Max<double>();
  if (maxTemp > _maxTemp[componentName])
  {
    _maxTemp[componentName] = maxTemp;
    await UpdateMaxTemperatureSinceLastRebootAsync(componentName, cancellationToken);
  }
}

private async Task SendTemperatureTelemetryAsync(string componentName, CancellationToken cancellationToken)
{
  const string telemetryName = "temperature";
  double currentTemperature = _temperature[componentName];
  using Message msg = PnpConvention.CreateMessage(telemetryName, currentTemperature, componentName);

  await _deviceClient.SendEventAsync(msg, cancellationToken);

  if (_temperatureReadingsDateTimeOffset.ContainsKey(componentName))
  {
    _temperatureReadingsDateTimeOffset[componentName].TryAdd(DateTimeOffset.UtcNow, currentTemperature);
  }
  else
  {
    _temperatureReadingsDateTimeOffset.TryAdd(
      componentName,
      new Dictionary<DateTimeOffset, double>
      {
        { DateTimeOffset.UtcNow, currentTemperature },
      });
  }
}

Die UpdateMaxTemperatureSinceLastRebootAsync-Methode sendet eine Aktualisierung der Eigenschaft maxTempSinceLastReboot an IoT Central. Diese Methode verwendet die PnpConvention-Klasse zum Erstellen des Patch:

private async Task UpdateMaxTemperatureSinceLastRebootAsync(string componentName, CancellationToken cancellationToken)
{
  const string propertyName = "maxTempSinceLastReboot";
  double maxTemp = _maxTemp[componentName];
  TwinCollection reportedProperties = PnpConvention.CreateComponentPropertyPatch(componentName, propertyName, maxTemp);

  await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties, cancellationToken);
}

Die TargetTemperatureUpdateCallbackAsync-Methode behandelt die schreibbare Eigenschaftsaktualisierung für die Zieltemperatur aus IoT Central. Diese Methode verwendet die PnpConvention-Klasse, um die Nachricht für die Eigenschaftsaktualisierung zu lesen und die Antwort zu erstellen:

private async Task TargetTemperatureUpdateCallbackAsync(TwinCollection desiredProperties, object userContext)
{
  const string propertyName = "targetTemperature";
  string componentName = (string)userContext;

  bool targetTempUpdateReceived = PnpConvention.TryGetPropertyFromTwin(
    desiredProperties,
    propertyName,
    out double targetTemperature,
    componentName);
  if (!targetTempUpdateReceived)
  {
      return;
  }

  TwinCollection pendingReportedProperty = PnpConvention.CreateComponentWritablePropertyResponse(
      componentName,
      propertyName,
      targetTemperature,
      (int)StatusCode.InProgress,
      desiredProperties.Version);

  await _deviceClient.UpdateReportedPropertiesAsync(pendingReportedProperty);

  // 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,
      propertyName,
      _temperature[componentName],
      (int)StatusCode.Completed,
      desiredProperties.Version,
      "Successfully updated target temperature");

  await _deviceClient.UpdateReportedPropertiesAsync(completedReportedProperty);
}

Die HandleMaxMinReportCommand-Methode behandelt die über IoT Central aufgerufenen Befehle für die Komponenten:

private Task<MethodResponse> HandleMaxMinReportCommand(MethodRequest request, object userContext)
{
    try
    {
        string componentName = (string)userContext;
        DateTime sinceInUtc = JsonConvert.DeserializeObject<DateTime>(request.DataAsJson);
        var sinceInDateTimeOffset = new DateTimeOffset(sinceInUtc);

        if (_temperatureReadingsDateTimeOffset.ContainsKey(componentName))
        {

            Dictionary<DateTimeOffset, double> allReadings = _temperatureReadingsDateTimeOffset[componentName];
            Dictionary<DateTimeOffset, double> filteredReadings = allReadings.Where(i => i.Key > sinceInDateTimeOffset)
                .ToDictionary(i => i.Key, i => i.Value);

            if (filteredReadings != null && filteredReadings.Any())
            {
                var report = new
                {
                    maxTemp = filteredReadings.Values.Max<double>(),
                    minTemp = filteredReadings.Values.Min<double>(),
                    avgTemp = filteredReadings.Values.Average(),
                    startTime = filteredReadings.Keys.Min(),
                    endTime = filteredReadings.Keys.Max(),
                };

                byte[] responsePayload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(report));
                return Task.FromResult(new MethodResponse(responsePayload, (int)StatusCode.Completed));
            }

            return Task.FromResult(new MethodResponse((int)StatusCode.NotFound));
        }

        return Task.FromResult(new MethodResponse((int)StatusCode.NotFound));
    }
    catch (JsonReaderException ex)
    {
        // ...
    }
}

Abrufen von Verbindungsinformationen

Wenn Sie die Beispielgeräteanwendung später in diesem Tutorial ausführen, benötigen Sie die folgenden Konfigurationswerte:

  • ID-Bereich: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen. Notieren Sie sich den Wert für ID-Bereich.
  • Gruppenprimärschlüssel: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen > SAS-IoT-Devices. Notieren Sie sich den Wert für den SAS-Primärschlüssel (Shared Access Signature).

Verwenden Sie Azure Cloud Shell, um einen Geräteschlüssel auf der Grundlage des von Ihnen abgerufenen Gruppenprimärschlüssels zu generieren:

az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>

Notieren Sie sich den generierten Geräteschlüssel. Sie verwenden ihn später in diesem Tutorial.

Hinweis

Um dieses Beispiel auszuführen, müssen Sie das Gerät nicht im Voraus in Ihrer IoT Central-Anwendung registrieren. Im Beispiel wird die IoT Central-Funktion verwendet, um Geräte automatisch zu registrieren, wenn sie zum ersten Mal eine Verbindung herstellen.

Ausführen des Codes

Hinweis

Richten Sie TemperatureController als Startprojekt ein, bevor Sie den Code ausführen.

So führen Sie die Beispielanwendung in Visual Studio aus:

  1. Wählen Sie im Projektmappen-Explorer die Projektdatei PnpDeviceSamples > TemperatureController aus.

  2. Navigieren Sie zu Projekt > TemperatureController-Eigenschaften > Debuggen. Fügen Sie dem Projekt dann die folgenden Umgebungsvariablen hinzu:

    Name Wert
    IOTHUB_DEVICE_SECURITY_TYPE DPS
    IOTHUB_DEVICE_DPS_ENDPOINT global.azure-devices-provisioning.net
    IOTHUB_DEVICE_DPS_ID_SCOPE Der zuvor notierte ID-Bereichswert
    IOTHUB_DEVICE_DPS_DEVICE_ID sample-device-01
    IOTHUB_DEVICE_DPS_DEVICE_KEY Der generierte Wert für den Geräteschlüssel, den Sie sich zuvor notiert haben

Sie können das Beispiel jetzt in Visual Studio ausführen und debuggen.

Die folgende Ausgabe zeigt, wie das Gerät registriert und eine Verbindung mit IoT Central hergestellt wird. Das Beispiel beginnt mit dem Senden von Telemetriedaten:

[03/31/2021 14:43:17]info: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Press Control+C to quit the sample.
[03/31/2021 14:43:17]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Set up the device client.
[03/31/2021 14:43:18]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Initializing via DPS
[03/31/2021 14:43:27]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Set handler for 'reboot' command.
[03/31/2021 14:43:27]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Connection status change registered - status=Connected, reason=Connection_Ok.
[03/31/2021 14:43:28]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Set handler for "getMaxMinReport" command.
[03/31/2021 14:43:28]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Set handler to receive 'targetTemperature' updates.
[03/31/2021 14:43:28]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Update - component = 'deviceInformation', properties update is complete.
[03/31/2021 14:43:28]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Update - { "serialNumber": "SR-123456" } is complete.
[03/31/2021 14:43:29]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Telemetry: Sent - component="thermostat1", { "temperature": 34.2 } in °C.
[03/31/2021 14:43:29]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Update - component="thermostat1", { "maxTempSinceLastReboot": 34.2 } in °C is complete.
[03/31/2021 14:43:29]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Telemetry: Sent - component="thermostat2", { "temperature": 25.1 } in °C.
[03/31/2021 14:43:29]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Update - component="thermostat2", { "maxTempSinceLastReboot": 25.1 } in °C is complete.
[03/31/2021 14:43:29]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Telemetry: Sent - {"workingSet":31412} in KB.

Als Operator in Ihrer Azure IoT Central-Anwendung haben Sie folgende Möglichkeiten:

  • Anzeigen der von den beiden Thermostatkomponenten gesendeten Telemetriedaten auf der Seite Übersicht:

    Screenshot that shows the device overview page.

  • Anzeigen der Geräteeigenschaften auf der Seite Info. Auf dieser Seite werden die Eigenschaften der Geräteinformationskomponente und der beiden Thermostatkomponenten angezeigt:

    Screenshot that shows the device properties view.

Anpassen der Gerätevorlage

Als Lösungsentwickler können Sie die Gerätevorlage anpassen, die von IoT Central automatisch erstellt wurde, als der Temperaturregler eine Verbindung hergestellt hat.

So fügen Sie eine Cloudeigenschaft hinzu, um den dem Gerät zugeordneten Kundennamen zu speichern:

  1. Navigieren Sie in Ihrer IoT Central-Anwendung auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Wählen Sie im Modell Temperature Controller die Option + Funktion hinzufügen aus.

  3. Geben Sie Kundenname als Anzeigename ein, wählen Sie Cloudeigenschaft als Funktionstyp aus, erweitern Sie den Eintrag, und wählen Sie Zeichenfolge als Schema aus. Klicken Sie dann auf Speichern.

So passen Sie die Darstellung des Befehls Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) in Ihrer IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter getMaxMinReport (thermostat1) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat1 status report (Statusbericht für „thermostat1“ abrufen).

  3. Ersetzen Sie unter getMaxMinReport (thermostat2) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat2 status report (Statusbericht für „thermostat2“ abrufen).

  4. Wählen Sie Speichern aus.

So passen Sie die Darstellung der schreibbaren Eigenschaften für die Zieltemperatur in der IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter targetTemperature (thermostat1) die Option Zieltemperatur durch Zieltemperatur (1) .

  3. Ersetzen Sie unter targetTemperature (thermostat2) die Option Zieltemperatur durch Zieltemperatur (2) .

  4. Wählen Sie Speichern aus.

Die Thermostatkomponenten im Modell Thermostat enthalten die beschreibbare Eigenschaft Target Temperature (Zieltemperatur), und die Gerätevorlage enthält die Cloudeigenschaft Customer Name (Kundenname). Erstellen Sie eine Ansicht, die von einem Operator zum Bearbeiten dieser Eigenschaften verwendet werden kann:

  1. Wählen Sie Ansichten und anschließend die Kachel Geräte- und Clouddaten bearbeiten aus.

  2. Geben Sie Properties (Eigenschaften) als Formularname ein.

  3. Wählen Sie die Eigenschaften Target Temperature (1) (Zieltemperatur (1)), Target Temperature (2) (Zieltemperatur (2)) und Customer Name (Kundenname) aus. Wählen Sie anschließend Abschnitt hinzufügen aus.

  4. Speichern Sie die Änderungen.

Screenshot that shows a view for updating property values.

Veröffentlichen der Gerätevorlage

Damit die von Ihnen vorgenommenen Anpassungen von einem Operator angezeigt und verwendet werden können, müssen Sie die Gerätevorlage veröffentlichen.

Wählen Sie in der Gerätevorlage Thermostat die Option Veröffentlichen aus. Wählen Sie im Bereich Diese Gerätevorlage für die Anwendung veröffentlichen die Option Veröffentlichen aus.

Ein Operator kann nun die Ansicht Eigenschaften verwenden, um die Eigenschaftswerte zu aktualisieren, und auf der Seite mit Gerätebefehlen Befehle namens Get thermostat1 status report (Statusbericht für "thermostat1" abrufen) und Get thermostat2 status report (Statusbericht für "thermostat2" abrufen) aufrufen:

  • Aktualisieren beschreibbarer Eigenschaftswerte auf der Seite Properties (Eigenschaften):

    Screenshot that shows updating the device properties.

  • Rufen Sie die Befehle auf der Seite Befehle auf. Wählen Sie bei Ausführung des Statusberichtsbefehls ein Datum und eine Uhrzeit für den Since-Parameter aus, bevor Sie ihn ausführen:

    Screenshot that shows calling a command.

    Screenshot that shows a command response.

Sie können sehen, wie das Gerät auf Befehle und Eigenschaftsaktualisierungen reagiert:

[03/31/2021 14:47:00]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Command: Received - component="thermostat2", generating max, min and avg temperature report since 31/03/2021 06:00:00.
[03/31/2021 14:47:00]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Command: component="thermostat2", MaxMinReport since 31/03/2021 06:00:00: maxTemp=36.4, minTemp=36.4, avgTemp=36.4, startTime=31/03/2021 14:46:33, endTime=31/03/2021 14:46:55

...

[03/31/2021 14:46:36]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Received - component="thermostat1", { "targetTemperature": 67°C }.
[03/31/2021 14:46:36]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Update - component="thermostat1", {"targetTemperature": 67 } in °C is InProgress.
[03/31/2021 14:46:49]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Property: Update - component="thermostat1", {"targetTemperature": 67 } in °C is Completed
[03/31/2021 14:46:49]dbug: Microsoft.Azure.Devices.Client.Samples.TemperatureControllerSample[0]
      Telemetry: Sent - component="thermostat1", { "temperature": 67 } in °C.

Browse code

Voraussetzungen

Zum Ausführen der Schritte in diesem Artikel benötigen Sie folgende Ressourcen:

  • Einen Entwicklungscomputer mit Java SE Development Kit 8 oder höher. Weitere Informationen finden Sie unter Installieren von JDK.

  • Apache Maven 3

  • Eine lokale Kopie des GitHub-Repositorys mit dem Microsoft Azure IoT SDK für Java, das den Beispielcode enthält. Laden Sie über den folgenden Link eine Kopie des Repositorys herunter: ZIP herunterladen. Entzippen Sie anschließend die Datei an einem geeigneten Speicherort auf Ihrem lokalen Computer.

Überprüfen des Codes

Öffnen Sie in der Kopie des zuvor heruntergeladenen Microsoft Azure IoT SDK für Java die Datei azure-iot-sdk-java/iothub/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample/src/main/java/samples/com/microsoft/azure/sdk/iot/device/TemperatureController.java in einem Text-Editor.

Im Beispiel wird das Temperaturcontroller-Sprachmodell mit mehreren Komponenten der Definition von digitalen Zwillingen implementiert.

Wenn Sie das Beispiel ausführen, um eine Verbindung mit IoT Central herzustellen, wird Device Provisioning Service (DPS) zum Registrieren des Geräts und zum Generieren einer Verbindungszeichenfolge verwendet. Das Beispiel ruft die erforderlichen DPS-Verbindungsinformationen aus der Befehlszeilenumgebung ab.

Die main-Methode:

  • Ruft initializeAndProvisionDevice auf, um die Modell-ID dtmi:com:example:TemperatureController;2 festzulegen, das Gerät mithilfe von DPS bereitzustellen und zu registrieren, eine initializeAndProvisionDevice-Instanz zu erstellen und eine Verbindung mit Ihrer IoT Central-Anwendung herzustellen. IoT Central verwendet die Modell-ID zum Identifizieren oder Generieren der Gerätevorlage für dieses Gerät. Weitere Informationen finden Sie unter Zuweisen eines Geräts zu einer Gerätevorlage.
  • Erstellen von Befehlshandlern für die Befehle getMaxMinReport und reboot
  • Erstellen von Befehlshandlern für die schreibbaren targetTemperature-Eigenschaften
  • Senden der Anfangswerte für die Eigenschaften in der Schnittstelle Geräteinformationen und die Eigenschaften Gerätespeicher und Seriennummer
  • Starten eines Threads, um alle fünf Sekunden Temperaturtelemetriedaten von den beiden Thermostate zu senden und die Eigenschaft maxTempSinceLastReboot zu aktualisieren
public static void main(String[] args) throws Exception {

  // ...
  
  switch (deviceSecurityType.toLowerCase())
  {
    case "dps":
    {
      if (validateArgsForDpsFlow())
      {
        initializeAndProvisionDevice();
        break;
      }
      throw new IllegalArgumentException("Required environment variables are not set for DPS flow, please recheck your environment.");
    }
    case "connectionstring":
    {
      // ...
    }
    default:
    {
      // ...
    }
  }
  
  deviceClient.subscribeToMethods(new MethodCallback(), null);
  
  deviceClient.subscribeToDesiredPropertiesAsync(
  {
  (twin, context) ->
      TwinCollection desiredProperties = twin.getDesiredProperties();
      for (String desiredPropertyKey : desiredProperties.keySet())
      {
          TargetTemperatureUpdateCallback.onPropertyChanged(new Property(desiredPropertyKey, desiredProperties.get(desiredPropertyKey)), null);
      }
  },
  null,
  (exception, context) ->
  {
      if (exception == null)
      {
          log.info("Successfully subscribed to desired properties. Getting initial state");
          deviceClient.getTwinAsync(
              (twin, getTwinException, getTwinContext) ->
              {
                  log.info("Initial twin state received");
                  log.info(twin.toString());
              },
              null);
      }
      else
      {
          log.info("Failed to subscribe to desired properties. Error code {}", exception.getStatusCode());
          System.exit(-1);
      }
  },
  null);

  updateDeviceInformation();
  sendDeviceMemory();
  sendDeviceSerialNumber();
  
  final AtomicBoolean temperatureReset = new AtomicBoolean(true);
  maxTemperature.put(THERMOSTAT_1, 0.0d);
  maxTemperature.put(THERMOSTAT_2, 0.0d);
  
  new Thread(new Runnable() {
    @SneakyThrows({InterruptedException.class, IOException.class})
    @Override
    public void run() {
      while (true) {
        if (temperatureReset.get()) {
          // Generate a random value between 5.0°C and 45.0°C for the current temperature reading for each "Thermostat" component.
          temperature.put(THERMOSTAT_1, BigDecimal.valueOf(random.nextDouble() * 40 + 5).setScale(1, RoundingMode.HALF_UP).doubleValue());
          temperature.put(THERMOSTAT_2, BigDecimal.valueOf(random.nextDouble() * 40 + 5).setScale(1, RoundingMode.HALF_UP).doubleValue());
        }

        sendTemperatureReading(THERMOSTAT_1);
        sendTemperatureReading(THERMOSTAT_2);

        temperatureReset.set(temperature.get(THERMOSTAT_1) == 0 && temperature.get(THERMOSTAT_2) == 0);
        Thread.sleep(5 * 1000);
      }
    }
  }).start();
}

Die initializeAndProvisionDevice-Methode zeigt, wie das Gerät mithilfe von DPS die Registrierung bei IoT Central durchführt und eine Verbindung mit IoT Central herstellt. Die Nutzdaten enthalten die Modell-ID, die IoT Central zum Zuweisen eines Geräts zu einer Gerätevorlage verwendet:

private static void initializeAndProvisionDevice() throws Exception {
  SecurityProviderSymmetricKey securityClientSymmetricKey = new SecurityProviderSymmetricKey(deviceSymmetricKey.getBytes(), registrationId);
  ProvisioningDeviceClient provisioningDeviceClient;
  ProvisioningStatus provisioningStatus = new ProvisioningStatus();

  provisioningDeviceClient = ProvisioningDeviceClient.create(globalEndpoint, scopeId, provisioningProtocol, securityClientSymmetricKey);

  AdditionalData additionalData = new AdditionalData();
  additionalData.setProvisioningPayload(com.microsoft.azure.sdk.iot.provisioning.device.plugandplay.PnpHelper.createDpsPayload(MODEL_ID));

  ProvisioningDeviceClientRegistrationResult registrationResult = provisioningDeviceClient.registerDeviceSync(additionalData);

    ClientOptions options = ClientOptions.builder().modelId(MODEL_ID).build();
    if (registrationResult.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ASSIGNED) {
        System.out.println("IotHUb Uri : " + registrationResult.getIothubUri());
        System.out.println("Device ID : " + registrationResult.getDeviceId());
        String iotHubUri = registrationResult.getIothubUri();
        String deviceId = registrationResult.getDeviceId();
        log.debug("Opening the device client.");
        deviceClient = new DeviceClient(iotHubUri, deviceId, securityClientSymmetricKey, IotHubClientProtocol.MQTT, options);
        deviceClient.open(true);
    }
}

Die sendTemperatureTelemetry-Methode zeigt, wie das Gerät die Temperaturtelemetriedaten von einer Komponente an IoT Central sendet. Diese Methode verwendet die PnpConvention-Klasse zum Erstellen der Nachricht:

  private static void sendTemperatureTelemetry(String componentName) {
    String telemetryName = "temperature";
    double currentTemperature = temperature.get(componentName);

    Message message = PnpConvention.createIotHubMessageUtf8(telemetryName, currentTemperature, componentName);
    deviceClient.sendEventAsync(message, new MessageIotHubEventCallback(), message);

    // Add the current temperature entry to the list of temperature readings.
    Map<Date, Double> currentReadings;
    if (temperatureReadings.containsKey(componentName)) {
      currentReadings = temperatureReadings.get(componentName);
    } else {
      currentReadings = new HashMap<>();
    }
    currentReadings.put(new Date(), currentTemperature);
    temperatureReadings.put(componentName, currentReadings);
  }

Die updateMaxTemperatureSinceLastReboot-Methode sendet eine Aktualisierung der Eigenschaft maxTempSinceLastReboot einer Komponente an IoT Central. Diese Methode verwendet die PnpConvention-Klasse zum Erstellen des Patch:

private static void updateMaxTemperatureSinceLastReboot(String componentName) throws IOException {
  String propertyName = "maxTempSinceLastReboot";
  double maxTemp = maxTemperature.get(componentName);

  TwinCollection reportedProperty = PnpConvention.createComponentPropertyPatch(propertyName, maxTemp, componentName);
  deviceClient.updateReportedPropertiesAsync(reportedProperty, sendReportedPropertiesResponseCallback, null);
  log.debug("Property: Update - {\"{}\": {}°C} is {}.", propertyName, maxTemp, StatusCode.COMPLETED);
}

Die TargetTemperatureUpdateCallback-Klasse enthält die onPropertyChanged-Methode, um schreibbare Eigenschaftsaktualisierungen für eine Komponente aus IoT Central zu behandeln. Diese Methode verwendet die PnpConvention-Klasse zum Erstellen der Antwort:

private static class TargetTemperatureUpdateCallback
{
    final static String propertyName = "targetTemperature";
    @SneakyThrows(InterruptedException.class)
    public static void onPropertyChanged(Property property, Object context) {
        String componentName = (String) context;
        if (property.getKey().equalsIgnoreCase(componentName)) {
            double targetTemperature = (double) ((TwinCollection) property.getValue()).get(propertyName);
            log.debug("Property: Received - component=\"{}\", {\"{}\": {}°C}.", componentName, propertyName, targetTemperature);
            TwinCollection pendingPropertyPatch = PnpConvention.createComponentWritablePropertyResponse(
                    propertyName,
                    targetTemperature,
                    componentName,
                    StatusCode.IN_PROGRESS.value,
                    property.getVersion().longValue(),
                    null);
            deviceClient.updateReportedPropertiesAsync(pendingPropertyPatch, sendReportedPropertiesResponseCallback, null);
            log.debug("Property: Update - component=\"{}\", {\"{}\": {}°C} is {}", componentName, propertyName, targetTemperature, StatusCode.IN_PROGRESS);
            // Update temperature in 2 steps
            double step = (targetTemperature - temperature.get(componentName)) / 2;
            for (int i = 1; i <=2; i++) {
                temperature.put(componentName, BigDecimal.valueOf(temperature.get(componentName) + step).setScale(1, RoundingMode.HALF_UP).doubleValue());
                Thread.sleep(5 * 1000);
            }
            TwinCollection completedPropertyPatch = PnpConvention.createComponentWritablePropertyResponse(
                    propertyName,
                    temperature.get(componentName),
                    componentName,
                    StatusCode.COMPLETED.value,
                    property.getVersion().longValue(),
                    "Successfully updated target temperature.");
            deviceClient.updateReportedPropertiesAsync(completedPropertyPatch, sendReportedPropertiesResponseCallback, null);
            log.debug("Property: Update - {\"{}\": {}°C} is {}", propertyName, temperature.get(componentName), StatusCode.COMPLETED);
        } else {
            log.debug("Property: Received an unrecognized property update from service.");
        }
    }
}

Die MethodCallback-Klasse enthält die onMethodInvoked-Methode, um aus IoT Central aufgerufene Komponentenbefehle zu behandeln:

private static class MethodCallback implements com.microsoft.azure.sdk.iot.device.twin.MethodCallback
{
    final String reboot = "reboot";
    final String getMaxMinReport1 = "thermostat1*getMaxMinReport";
    final String getMaxMinReport2 = "thermostat2*getMaxMinReport";
    @SneakyThrows(InterruptedException.class)
    @Override
    public DirectMethodResponse onMethodInvoked(String methodName, DirectMethodPayload methodData, Object context) {
        String jsonRequest = methodData.getPayload(String.class);
        switch (methodName) {
            case reboot:
                int delay = getCommandRequestValue(jsonRequest, Integer.class);
                log.debug("Command: Received - Rebooting thermostat (resetting temperature reading to 0°C after {} seconds).", delay);
                Thread.sleep(delay * 1000L);
                temperature.put(THERMOSTAT_1, 0.0d);
                temperature.put(THERMOSTAT_2, 0.0d);
                maxTemperature.put(THERMOSTAT_1, 0.0d);
                maxTemperature.put(THERMOSTAT_2, 0.0d);
                temperatureReadings.clear();
                return new DirectMethodResponse(StatusCode.COMPLETED.value, null);
            case getMaxMinReport1:
            case getMaxMinReport2:
                String[] words = methodName.split("\\*");
                String componentName = words[0];
                if (temperatureReadings.containsKey(componentName)) {
                    Date since = getCommandRequestValue(jsonRequest, Date.class);
                    log.debug("Command: Received - component=\"{}\", generating min, max, avg temperature report since {}", componentName, since);
                    Map<Date, Double> allReadings = temperatureReadings.get(componentName);
                    Map<Date, Double> filteredReadings = allReadings.entrySet().stream()
                            .filter(map -> map.getKey().after(since))
                            .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
                    if (!filteredReadings.isEmpty()) {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                        double maxTemp = Collections.max(filteredReadings.values());
                        double minTemp = Collections.min(filteredReadings.values());
                        double avgTemp = filteredReadings.values().stream().mapToDouble(Double::doubleValue).average().orElse(Double.NaN);
                        String startTime =  sdf.format(Collections.min(filteredReadings.keySet()));
                        String endTime =  sdf.format(Collections.max(filteredReadings.keySet()));
                        String responsePayload = String.format(
                                "{\"maxTemp\": %.1f, \"minTemp\": %.1f, \"avgTemp\": %.1f, \"startTime\": \"%s\", \"endTime\": \"%s\"}",
                                maxTemp,
                                minTemp,
                                avgTemp,
                                startTime,
                                endTime);
                        log.debug("Command: MaxMinReport since {}: \"maxTemp\": {}°C, \"minTemp\": {}°C, \"avgTemp\": {}°C, \"startTime\": {}, \"endTime\": {}",
                                since,
                                maxTemp,
                                minTemp,
                                avgTemp,
                                startTime,
                                endTime);
                        return new DirectMethodResponse(StatusCode.COMPLETED.value, responsePayload);
                    }
                    log.debug("Command: component=\"{}\", no relevant readings found since {}, cannot generate any report.", componentName, since);
                    return new DirectMethodResponse(StatusCode.NOT_FOUND.value, null);
                }
                log.debug("Command: component=\"{}\", no temperature readings sent yet, cannot generate any report.", componentName);
                return new DirectMethodResponse(StatusCode.NOT_FOUND.value, null);
            default:
                log.debug("Command: command=\"{}\" is not implemented, no action taken.", methodName);
                return new DirectMethodResponse(StatusCode.NOT_FOUND.value, null);
        }
    }
}

Abrufen von Verbindungsinformationen

Wenn Sie die Beispielgeräteanwendung später in diesem Tutorial ausführen, benötigen Sie die folgenden Konfigurationswerte:

  • ID-Bereich: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen. Notieren Sie sich den Wert für ID-Bereich.
  • Gruppenprimärschlüssel: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen > SAS-IoT-Devices. Notieren Sie sich den Wert für den SAS-Primärschlüssel (Shared Access Signature).

Verwenden Sie Azure Cloud Shell, um einen Geräteschlüssel auf der Grundlage des von Ihnen abgerufenen Gruppenprimärschlüssels zu generieren:

az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>

Notieren Sie sich den generierten Geräteschlüssel. Sie verwenden ihn später in diesem Tutorial.

Hinweis

Um dieses Beispiel auszuführen, müssen Sie das Gerät nicht im Voraus in Ihrer IoT Central-Anwendung registrieren. Im Beispiel wird die IoT Central-Funktion verwendet, um Geräte automatisch zu registrieren, wenn sie zum ersten Mal eine Verbindung herstellen.

Navigieren Sie unter Windows zum Stammordner des heruntergeladenen Repositorys mit dem Azure IoT SDK für Java.

Führen Sie den folgenden Befehl aus, um die Beispielanwendung zu erstellen:

mvn install -T 2C -DskipTests

Ausführen des Codes

Öffnen Sie zum Ausführen der Beispielanwendung eine Befehlszeilenumgebung, und navigieren Sie zum Ordner azure-iot-sdk-java/iothub/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample, der den Ordner src mit der Beispieldatei TemperatureController.java enthält.

Legen Sie die Umgebungsvariablen zum Konfigurieren des Beispiels fest. Der folgende Ausschnitt zeigt, wie Sie die Umgebungsvariablen in der Windows-Eingabeaufforderung festlegen. Ersetzen Sie bei Verwendung einer Bash-Shell die set-Befehle durch export-Befehle:

set IOTHUB_DEVICE_SECURITY_TYPE=DPS
set IOTHUB_DEVICE_DPS_ID_SCOPE=<The ID scope you made a note of previously>
set IOTHUB_DEVICE_DPS_DEVICE_ID=sample-device-01
set IOTHUB_DEVICE_DPS_DEVICE_KEY=<The generated device key you made a note of previously>
set IOTHUB_DEVICE_DPS_ENDPOINT=global.azure-devices-provisioning.net

Führen Sie das Beispiel aus:

mvn exec:java -Dexec.mainClass="samples.com.microsoft.azure.sdk.iot.device.TemperatureController"

Die folgende Ausgabe zeigt, wie das Gerät registriert und eine Verbindung mit IoT Central hergestellt wird. Das Beispiel beginnt mit dem Senden von Telemetriedaten:

2021-03-30 15:33:25.138 DEBUG TemperatureController:123 - Initialize the device client.
Waiting for Provisioning Service to register
Waiting for Provisioning Service to register
IotHUb Uri : iotc-60a.....azure-devices.net
Device ID : sample-device-01
2021-03-30 15:33:38.294 DEBUG TemperatureController:247 - Opening the device client.
2021-03-30 15:33:38.307 INFO  ExponentialBackoffWithJitter:98 - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
2021-03-30 15:33:38.321 INFO  ExponentialBackoffWithJitter:98 - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
2021-03-30 15:33:38.427 DEBUG MqttIotHubConnection:274 - Opening MQTT connection...
2021-03-30 15:33:38.427 DEBUG Mqtt:123 - Sending MQTT CONNECT packet...
2021-03-30 15:33:44.628 DEBUG Mqtt:126 - Sent MQTT CONNECT packet was acknowledged
2021-03-30 15:33:44.630 DEBUG Mqtt:256 - Sending MQTT SUBSCRIBE packet for topic devices/sample-device-01/messages/devicebound/#
2021-03-30 15:33:44.731 DEBUG Mqtt:261 - Sent MQTT SUBSCRIBE packet for topic devices/sample-device-01/messages/devicebound/# was acknowledged
2021-03-30 15:33:44.733 DEBUG MqttIotHubConnection:279 - MQTT connection opened successfully
2021-03-30 15:33:44.733 DEBUG IotHubTransport:302 - The connection to the IoT Hub has been established
2021-03-30 15:33:44.734 INFO  IotHubTransport:1429 - Updating transport status to new status CONNECTED with reason CONNECTION_OK
2021-03-30 15:33:44.735 DEBUG IotHubTransport:1439 - Invoking connection status callbacks with new status details
2021-03-30 15:33:44.739 DEBUG IotHubTransport:394 - Client connection opened successfully
2021-03-30 15:33:44.740 INFO  DeviceClient:438 - Device client opened successfully
2021-03-30 15:33:44.740 DEBUG TemperatureController:152 - Set handler for "reboot" command.
2021-03-30 15:33:44.742 DEBUG TemperatureController:153 - Set handler for "getMaxMinReport" command.
2021-03-30 15:33:44.774 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [029d30d4-acbd-462d-b155-82d53ce7786c] Message Id [1b2adf93-ba81-41e4-b8c7-7c90c8b0d6a1] Device Operation Type [DEVICE_OPERATION_METHOD_SUBSCRIBE_REQUEST] )
2021-03-30 15:33:44.774 DEBUG TemperatureController:156 - Set handler to receive "targetTemperature" updates.
2021-03-30 15:33:44.775 INFO  IotHubTransport:1344 - Sending message ( Message details: Correlation Id [029d30d4-acbd-462d-b155-82d53ce7786c] Message Id [1b2adf93-ba81-41e4-b8c7-7c90c8b0d6a1] Device Operation Type [DEVICE_OPERATION_METHOD_SUBSCRIBE_REQUEST] )
2021-03-30 15:33:44.779 DEBUG Mqtt:256 - Sending MQTT SUBSCRIBE packet for topic $iothub/methods/POST/#
2021-03-30 15:33:44.793 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [f2f9ed95-9778-44f2-b9ec-f60c84061251] Message Id [0d5abdb2-6460-414c-a10e-786ee24cacff] Device Operation Type [DEVICE_OPERATION_TWIN_SUBSCRIBE_DESIRED_PROPERTIES_REQUEST] )
2021-03-30 15:33:44.794 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [417d659a-7324-43fa-84eb-8a3f3d07963c] Message Id [55532cad-8a5a-489f-9aa8-8f0e5bc21541] Request Id [0] Device Operation Type [DEVICE_OPERATION_TWIN_GET_REQUEST] )
2021-03-30 15:33:44.819 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [d46a0d8a-8a18-4014-abeb-768bd9b17ad2] Message Id [780abc81-ce42-4e5f-aa80-e4785883604e] Device Operation Type [DEVICE_OPERATION_TWIN_SUBSCRIBE_DESIRED_PROPERTIES_REQUEST] )
2021-03-30 15:33:44.881 DEBUG Mqtt:261 - Sent MQTT SUBSCRIBE packet for topic $iothub/methods/POST/# was acknowledged
2021-03-30 15:33:44.882 INFO  IotHubTransport:1344 - Sending message ( Message details: Correlation Id [f2f9ed95-9778-44f2-b9ec-f60c84061251] Message Id [0d5abdb2-6460-414c-a10e-786ee24cacff] Device Operation Type [DEVICE_OPERATION_TWIN_SUBSCRIBE_DESIRED_PROPERTIES_REQUEST] )
2021-03-30 15:33:44.882 DEBUG Mqtt:256 - Sending MQTT SUBSCRIBE packet for topic $iothub/twin/res/#
2021-03-30 15:33:44.893 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [a77b1c02-f043-4477-b610-e31a774772c0] Message Id [2e2f6bee-c480-42cf-ac31-194118930846] Request Id [1] Device Operation Type [DEVICE_OPERATION_TWIN_UPDATE_REPORTED_PROPERTIES_REQUEST] )
2021-03-30 15:33:44.904 DEBUG TemperatureController:423 - Property: Update - component = "deviceInformation" is COMPLETED.
2021-03-30 15:33:44.915 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [bbb7e3cf-3550-4fdf-90f9-0787740f028a] Message Id [e06ac385-ae0d-46dd-857a-d9725707527a] )
2021-03-30 15:33:44.915 DEBUG TemperatureController:434 - Telemetry: Sent - {"workingSet": 1024.0KiB }
2021-03-30 15:33:44.915 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [6dbef765-cc9a-4e72-980a-2fe5b0cd77e1] Message Id [49bbad33-09bf-417a-9d6e-299ba7b7c562] Request Id [2] Device Operation Type [DEVICE_OPERATION_TWIN_UPDATE_REPORTED_PROPERTIES_REQUEST] )
2021-03-30 15:33:44.916 DEBUG TemperatureController:442 - Property: Update - {"serialNumber": SR-123456} is COMPLETED
2021-03-30 15:33:44.927 INFO  IotHubTransport:489 - Message was queued to be sent later ( Message details: Correlation Id [86787c32-87a5-4c49-9083-c7f2b17446a7] Message Id [0a45fa0c-a467-499d-b214-9bb5995772ba] )
2021-03-30 15:33:44.927 DEBUG TemperatureController:461 - Telemetry: Sent - {"temperature": 5.8°C} with message Id 0a45fa0c-a467-499d-b214-9bb5995772ba.

Als Operator in Ihrer Azure IoT Central-Anwendung haben Sie folgende Möglichkeiten:

  • Anzeigen der von den beiden Thermostatkomponenten gesendeten Telemetriedaten auf der Seite Übersicht:

    Screenshot that shows the device overview page.

  • Anzeigen der Geräteeigenschaften auf der Seite Info. Auf dieser Seite werden die Eigenschaften der Geräteinformationskomponente und der beiden Thermostatkomponenten angezeigt:

    Screenshot that shows the device properties view.

Anpassen der Gerätevorlage

Als Lösungsentwickler können Sie die Gerätevorlage anpassen, die von IoT Central automatisch erstellt wurde, als der Temperaturregler eine Verbindung hergestellt hat.

So fügen Sie eine Cloudeigenschaft hinzu, um den dem Gerät zugeordneten Kundennamen zu speichern:

  1. Navigieren Sie in Ihrer IoT Central-Anwendung auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Wählen Sie im Modell Temperature Controller die Option + Funktion hinzufügen aus.

  3. Geben Sie Kundenname als Anzeigename ein, wählen Sie Cloudeigenschaft als Funktionstyp aus, erweitern Sie den Eintrag, und wählen Sie Zeichenfolge als Schema aus. Klicken Sie dann auf Speichern.

So passen Sie die Darstellung des Befehls Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) in Ihrer IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter getMaxMinReport (thermostat1) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat1 status report (Statusbericht für „thermostat1“ abrufen).

  3. Ersetzen Sie unter getMaxMinReport (thermostat2) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat2 status report (Statusbericht für „thermostat2“ abrufen).

  4. Wählen Sie Speichern aus.

So passen Sie die Darstellung der schreibbaren Eigenschaften für die Zieltemperatur in der IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter targetTemperature (thermostat1) die Option Zieltemperatur durch Zieltemperatur (1) .

  3. Ersetzen Sie unter targetTemperature (thermostat2) die Option Zieltemperatur durch Zieltemperatur (2) .

  4. Wählen Sie Speichern aus.

Die Thermostatkomponenten im Modell Thermostat enthalten die beschreibbare Eigenschaft Target Temperature (Zieltemperatur), und die Gerätevorlage enthält die Cloudeigenschaft Customer Name (Kundenname). Erstellen Sie eine Ansicht, die von einem Operator zum Bearbeiten dieser Eigenschaften verwendet werden kann:

  1. Wählen Sie Ansichten und anschließend die Kachel Geräte- und Clouddaten bearbeiten aus.

  2. Geben Sie Properties (Eigenschaften) als Formularname ein.

  3. Wählen Sie die Eigenschaften Target Temperature (1) (Zieltemperatur (1)), Target Temperature (2) (Zieltemperatur (2)) und Customer Name (Kundenname) aus. Wählen Sie anschließend Abschnitt hinzufügen aus.

  4. Speichern Sie die Änderungen.

Screenshot that shows a view for updating property values.

Veröffentlichen der Gerätevorlage

Damit die von Ihnen vorgenommenen Anpassungen von einem Operator angezeigt und verwendet werden können, müssen Sie die Gerätevorlage veröffentlichen.

Wählen Sie in der Gerätevorlage Thermostat die Option Veröffentlichen aus. Wählen Sie im Bereich Diese Gerätevorlage für die Anwendung veröffentlichen die Option Veröffentlichen aus.

Ein Operator kann nun die Ansicht Eigenschaften verwenden, um die Eigenschaftswerte zu aktualisieren, und auf der Seite mit Gerätebefehlen Befehle namens Get thermostat1 status report (Statusbericht für "thermostat1" abrufen) und Get thermostat2 status report (Statusbericht für "thermostat2" abrufen) aufrufen:

  • Aktualisieren beschreibbarer Eigenschaftswerte auf der Seite Properties (Eigenschaften):

    Screenshot that shows updating the device properties.

  • Rufen Sie die Befehle auf der Seite Befehle auf. Wählen Sie bei Ausführung des Statusberichtsbefehls ein Datum und eine Uhrzeit für den Since-Parameter aus, bevor Sie ihn ausführen:

    Screenshot that shows calling a command.

    Screenshot that shows a command response.

Sie können sehen, wie das Gerät auf Befehle und Eigenschaftsaktualisierungen reagiert:

2021-03-30 15:43:57.133 DEBUG TemperatureController:309 - Command: Received - component="thermostat1", generating min, max, avg temperature report since Tue Mar 30 06:00:00 BST 2021
2021-03-30 15:43:57.153 DEBUG TemperatureController:332 - Command: MaxMinReport since Tue Mar 30 06:00:00 BST 2021: "maxTemp": 35.6°C, "minTemp": 35.6°C, "avgTemp": 35.6°C, "startTime": 2021-03-30T15:43:41Z, "endTime": 2021-03-30T15:43:56Z
2021-03-30 15:43:57.394 DEBUG TemperatureController:502 - Command - Response from IoT Hub: command name=null, status=OK_EMPTY


...

2021-03-30 15:48:47.808 DEBUG TemperatureController:372 - Property: Received - component="thermostat2", {"targetTemperature": 67.0°C}.
2021-03-30 15:48:47.837 DEBUG TemperatureController:382 - Property: Update - component="thermostat2", {"targetTemperature": 67.0°C} is IN_PROGRESS

Browse code

Voraussetzungen

Zum Ausführen der Schritte in diesem Artikel benötigen Sie folgende Ressourcen:

  • Einen Entwicklungscomputer, auf dem mindestens Version 6 von Node.js installiert ist. Sie können node --version in der Befehlszeile ausführen, um Ihre Version zu überprüfen. Bei den Anweisungen in diesem Tutorial wird davon ausgegangen, dass Sie den Befehl node an der Windows-Eingabeaufforderung ausführen. Node.js kann jedoch unter einer Reihe anderer Betriebssysteme verwendet werden.

  • Eine lokale Kopie des GitHub-Repositorys mit dem Microsoft Azure IoT SDK für Node.js, das den Beispielcode enthält. Laden Sie über den folgenden Link eine Kopie des Repositorys herunter: ZIP herunterladen. Entzippen Sie anschließend die Datei an einem geeigneten Speicherort auf Ihrem lokalen Computer.

Überprüfen des Codes

Öffnen Sie in der Kopie des zuvor heruntergeladenen Microsoft Azure IoT SDK für Node.js die Datei azure-iot-sdk-node/device/samples/javascript/pnp_temperature_controller.js in einem Text-Editor.

Im Beispiel wird das Temperaturcontroller-Sprachmodell mit mehreren Komponenten der Definition von digitalen Zwillingen implementiert.

Wenn Sie das Beispiel ausführen, um eine Verbindung mit IoT Central herzustellen, wird Device Provisioning Service (DPS) zum Registrieren des Geräts und zum Generieren einer Verbindungszeichenfolge verwendet. Das Beispiel ruft die erforderlichen DPS-Verbindungsinformationen aus der Befehlszeilenumgebung ab.

Die main-Methode:

  • Erstellen eines Objekts vom Typ client und Festlegen der Modell-ID dtmi:com:example:TemperatureController;2 vor dem Öffnen der Verbindung IoT Central verwendet die Modell-ID zum Identifizieren oder Generieren der Gerätevorlage für dieses Gerät. Weitere Informationen finden Sie unter Zuweisen eines Geräts zu einer Gerätevorlage.
  • Erstellen von Befehlshandlern für drei Befehle
  • Starten einer Schleife für jede Thermostatkomponente, um alle fünf Sekunden Temperaturtelemetriedaten zu senden
  • Starten einer Schleife für die Standardkomponente, um alle sechs Sekunden Telemetriedaten zur Arbeitssatzgröße zu senden
  • Senden der Eigenschaft maxTempSinceLastReboot für jede Thermostatkomponente
  • Senden der Geräteinformationseigenschaften
  • Erstellen schreibbarer Eigenschaftenhandler für die drei Komponenten
async function main() {
  // ...

  // fromConnectionString must specify a transport, coming from any transport package.
  const client = Client.fromConnectionString(deviceConnectionString, Protocol);
  console.log('Connecting using connection string: ' + deviceConnectionString);
  let resultTwin;

  try {
    // Add the modelId here
    await client.setOptions(modelIdObject);
    await client.open();
    console.log('Enabling the commands on the client');
    client.onDeviceMethod(commandNameGetMaxMinReport1, commandHandler);
    client.onDeviceMethod(commandNameGetMaxMinReport2, commandHandler);
    client.onDeviceMethod(commandNameReboot, commandHandler);

    // Send Telemetry after some interval
    let index1 = 0;
    let index2 = 0;
    let index3 = 0;
    intervalToken1 = setInterval(() => {
      const data = JSON.stringify(thermostat1.updateSensor().getCurrentTemperatureObject());
      sendTelemetry(client, data, index1, thermostat1ComponentName).catch((err) => console.log('error ', err.toString()));
      index1 += 1;
    }, 5000);

    intervalToken2 = setInterval(() => {
      const data = JSON.stringify(thermostat2.updateSensor().getCurrentTemperatureObject());
      sendTelemetry(client, data, index2, thermostat2ComponentName).catch((err) => console.log('error ', err.toString()));
      index2 += 1;
    }, 5500);


    intervalToken3 = setInterval(() => {
      const data = JSON.stringify({ workingset: 1 + (Math.random() * 90) });
      sendTelemetry(client, data, index3, null).catch((err) => console.log('error ', err.toString()));
      index3 += 1;
    }, 6000);

    // attach a standard input exit listener
    exitListener(client);

    try {
      resultTwin = await client.getTwin();
      // Only report readable properties
      const patchRoot = helperCreateReportedPropertiesPatch({ serialNumber: serialNumber }, null);
      const patchThermostat1Info = helperCreateReportedPropertiesPatch({
        maxTempSinceLastReboot: thermostat1.getMaxTemperatureValue(),
      }, thermostat1ComponentName);

      const patchThermostat2Info = helperCreateReportedPropertiesPatch({
        maxTempSinceLastReboot: thermostat2.getMaxTemperatureValue(),
      }, thermostat2ComponentName);

      const patchDeviceInfo = helperCreateReportedPropertiesPatch({
        manufacturer: 'Contoso Device Corporation',
        model: 'Contoso 47-turbo',
        swVersion: '10.89',
        osName: 'Contoso_OS',
        processorArchitecture: 'Contoso_x86',
        processorManufacturer: 'Contoso Industries',
        totalStorage: 65000,
        totalMemory: 640,
      }, deviceInfoComponentName);

      // the below things can only happen once the twin is there
      updateComponentReportedProperties(resultTwin, patchRoot, null);
      updateComponentReportedProperties(resultTwin, patchThermostat1Info, thermostat1ComponentName);
      updateComponentReportedProperties(resultTwin, patchThermostat2Info, thermostat2ComponentName);
      updateComponentReportedProperties(resultTwin, patchDeviceInfo, deviceInfoComponentName);
      desiredPropertyPatchListener(resultTwin, [thermostat1ComponentName, thermostat2ComponentName, deviceInfoComponentName]);
    } catch (err) {
      console.error('could not retrieve twin or report twin properties\n' + err.toString());
    }
  } catch (err) {
    console.error('could not connect Plug and Play client or could not attach interval function for telemetry\n' + err.toString());
  }
}

Die Funktion provisionDevice zeigt, wie das Gerät mithilfe von DPS die Registrierung bei IoT Central durchführt und eine Verbindung mit IoT Central herstellt. Die Nutzdaten enthalten die Modell-ID, die IoT Central zum Zuweisen eines Geräts zu einer Gerätevorlage verwendet:

async function provisionDevice(payload) {
  var provSecurityClient = new SymmetricKeySecurityClient(registrationId, symmetricKey);
  var provisioningClient = ProvisioningDeviceClient.create(provisioningHost, idScope, new ProvProtocol(), provSecurityClient);

  if (payload) {
    provisioningClient.setProvisioningPayload(payload);
  }

  try {
    let result = await provisioningClient.register();
    deviceConnectionString = 'HostName=' + result.assignedHub + ';DeviceId=' + result.deviceId + ';SharedAccessKey=' + symmetricKey;
    console.log('registration succeeded');
    console.log('assigned hub=' + result.assignedHub);
    console.log('deviceId=' + result.deviceId);
    console.log('payload=' + JSON.stringify(result.payload));
  } catch (err) {
    console.error("error registering device: " + err.toString());
  }
}

Die Funktion sendTelemetry zeigt, wie das Gerät die Temperaturtelemetriedaten an IoT Central sendet: Für Telemetriedaten von Komponenten wird eine Eigenschaft namens $.sub mit dem Komponentennamen hinzugefügt:

async function sendTelemetry(deviceClient, data, index, componentName) {
  if componentName) {
    console.log('Sending telemetry message %d from component: %s ', index, componentName);
  } else {
    console.log('Sending telemetry message %d from root interface', index);
  }
  const msg = new Message(data);
  if (componentName) {
    msg.properties.add(messageSubjectProperty, componentName);
  }
  msg.contentType = 'application/json';
  msg.contentEncoding = 'utf-8';
  await deviceClient.sendEvent(msg);
}

Die main-Methode verwendet eine Hilfsmethode namens helperCreateReportedPropertiesPatch, um Nachrichten zu Eigenschaftsaktualisierungen zu erstellen. Diese Methode verwendet einen optionalen Parameter, um die Komponente anzugeben, die die Eigenschaft sendet:

const helperCreateReportedPropertiesPatch = (propertiesToReport, componentName) => {
  let patch;
  if (!!(componentName)) {
    patch = { };
    propertiesToReport.__t = 'c';
    patch[componentName] = propertiesToReport;
  } else {
    patch = { };
    patch = propertiesToReport;
  }
  if (!!(componentName)) {
    console.log('The following properties will be updated for component: ' + componentName);
  } else {
    console.log('The following properties will be updated for root interface.');
  }
  console.log(patch);
  return patch;
};

Die main-Methode nutzt die folgende Methode, um Aktualisierungen der schreibbaren Eigenschaften aus IoT Central zu behandeln. Beachten Sie, wie die Methode die Antwort mit der Version und dem Statuscode erstellt:

const desiredPropertyPatchListener = (deviceTwin, componentNames) => {
  deviceTwin.on('properties.desired', (delta) => {
    console.log('Received an update for device with value: ' + JSON.stringify(delta));
    Object.entries(delta).forEach(([key, values]) => {
      const version = delta.$version;
      if (!!(componentNames) && componentNames.includes(key)) { // then it is a component we are expecting
        const componentName = key;
        const patchForComponents = { [componentName]: {} };
        Object.entries(values).forEach(([propertyName, propertyValue]) => {
          if (propertyName !== '__t' && propertyName !== '$version') {
            console.log('Will update property: ' + propertyName + ' to value: ' + propertyValue + ' of component: ' + componentName);
            const propertyContent = { value: propertyValue };
            propertyContent.ac = 200;
            propertyContent.ad = 'Successfully executed patch';
            propertyContent.av = version;
            patchForComponents[componentName][propertyName] = propertyContent;
          }
        });
        updateComponentReportedProperties(deviceTwin, patchForComponents, componentName);
      }
      else if  (key !== '$version') { // individual property for root
        const patchForRoot = { };
        console.log('Will update property: ' + key + ' to value: ' + values + ' for root');
        const propertyContent = { value: values };
        propertyContent.ac = 200;
        propertyContent.ad = 'Successfully executed patch';
        propertyContent.av = version;
        patchForRoot[key] = propertyContent;
        updateComponentReportedProperties(deviceTwin, patchForRoot, null);
      }
    });
  });
};

Die main-Methode nutzt die folgenden Methoden, um Befehle aus IoT Central zu behandeln:

const commandHandler = async (request, response) => {
  helperLogCommandRequest(request);
  switch (request.methodName) {
  case commandNameGetMaxMinReport1: {
    await sendCommandResponse(request, response, 200, thermostat1.getMaxMinReportObject());
    break;
  }
  case commandNameGetMaxMinReport2: {
    await sendCommandResponse(request, response, 200, thermostat2.getMaxMinReportObject());
    break;
  }
  case commandNameReboot: {
    await sendCommandResponse(request, response, 200, 'reboot response');
    break;
  }
  default:
    await sendCommandResponse(request, response, 404, 'unknown method');
    break;
  }
};

const sendCommandResponse = async (request, response, status, payload) => {
  try {
    await response.send(status, payload);
    console.log('Response to method: ' + request.methodName + ' sent successfully.' );
  } catch (err) {
    console.error('An error occurred when sending a method response:\n' + err.toString());
  }
};

Abrufen von Verbindungsinformationen

Wenn Sie die Beispielgeräteanwendung später in diesem Tutorial ausführen, benötigen Sie die folgenden Konfigurationswerte:

  • ID-Bereich: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen. Notieren Sie sich den Wert für ID-Bereich.
  • Gruppenprimärschlüssel: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen > SAS-IoT-Devices. Notieren Sie sich den Wert für den SAS-Primärschlüssel (Shared Access Signature).

Verwenden Sie Azure Cloud Shell, um einen Geräteschlüssel auf der Grundlage des von Ihnen abgerufenen Gruppenprimärschlüssels zu generieren:

az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>

Notieren Sie sich den generierten Geräteschlüssel. Sie verwenden ihn später in diesem Tutorial.

Hinweis

Um dieses Beispiel auszuführen, müssen Sie das Gerät nicht im Voraus in Ihrer IoT Central-Anwendung registrieren. Im Beispiel wird die IoT Central-Funktion verwendet, um Geräte automatisch zu registrieren, wenn sie zum ersten Mal eine Verbindung herstellen.

Ausführen des Codes

Öffnen Sie zum Ausführen der Beispielanwendung eine Befehlszeilenumgebung, und navigieren Sie zum Ordner azure-iot-sdk-node/device/samples/javascript, der die Beispieldatei pnp_temperature_controller.js enthält.

Legen Sie die Umgebungsvariablen zum Konfigurieren des Beispiels fest. Der folgende Ausschnitt zeigt, wie Sie die Umgebungsvariablen in der Windows-Eingabeaufforderung festlegen. Ersetzen Sie bei Verwendung einer Bash-Shell die set-Befehle durch export-Befehle:

set IOTHUB_DEVICE_SECURITY_TYPE=DPS
set IOTHUB_DEVICE_DPS_ID_SCOPE=<The ID scope you made a note of previously>
set IOTHUB_DEVICE_DPS_DEVICE_ID=sample-device-01
set IOTHUB_DEVICE_DPS_DEVICE_KEY=<The generated device key you made a note of previously>
set IOTHUB_DEVICE_DPS_ENDPOINT=global.azure-devices-provisioning.net

Installieren Sie die erforderlichen Pakete:

npm install

Führen Sie das Beispiel aus:

node pnp_temperature_controller.js

Die folgende Ausgabe zeigt, wie das Gerät registriert und eine Verbindung mit IoT Central hergestellt wird. In dem Beispiel wird dann die Eigenschaft maxTempSinceLastReboot aus den beiden Thermostatkomponenten gesendet, bevor mit dem Senden von Telemetriedaten begonnen wird:

registration succeeded
assigned hub=iotc-....azure-devices.net
deviceId=sample-device-01
payload=undefined
Connecting using connection string: HostName=iotc-....azure-devices.net;DeviceId=sample-device-01;SharedAccessKey=qdv...IpAo=
Enabling the commands on the client
Please enter q or Q to exit sample.
The following properties will be updated for root interface.
{ serialNumber: 'alwinexlepaho8329' }
The following properties will be updated for component: thermostat1
{ thermostat1: { maxTempSinceLastReboot: 1.5902294191855972, __t: 'c' } }
The following properties will be updated for component: thermostat2
{ thermostat2: { maxTempSinceLastReboot: 16.181771928614545, __t: 'c' } }
The following properties will be updated for component: deviceInformation
{ deviceInformation:
   { manufacturer: 'Contoso Device Corporation',
     model: 'Contoso 47-turbo',
     swVersion: '10.89',
     osName: 'Contoso_OS',
     processorArchitecture: 'Contoso_x86',
     processorManufacturer: 'Contoso Industries',
     totalStorage: 65000,
     totalMemory: 640,
     __t: 'c' } }
executed sample
Received an update for device with value: {"$version":1}
Properties have been reported for component: thermostat1
Properties have been reported for component: thermostat2
Properties have been reported for component: deviceInformation
Properties have been reported for root interface.
Sending telemetry message 0 from component: thermostat1 
Sending telemetry message 0 from component: thermostat2 
Sending telemetry message 0 from root interface

Als Operator in Ihrer Azure IoT Central-Anwendung haben Sie folgende Möglichkeiten:

  • Anzeigen der von den beiden Thermostatkomponenten gesendeten Telemetriedaten auf der Seite Übersicht:

    Screenshot that shows the device overview page.

  • Anzeigen der Geräteeigenschaften auf der Seite Info. Auf dieser Seite werden die Eigenschaften der Geräteinformationskomponente und der beiden Thermostatkomponenten angezeigt:

    Screenshot that shows the device properties view.

Anpassen der Gerätevorlage

Als Lösungsentwickler können Sie die Gerätevorlage anpassen, die von IoT Central automatisch erstellt wurde, als der Temperaturregler eine Verbindung hergestellt hat.

So fügen Sie eine Cloudeigenschaft hinzu, um den dem Gerät zugeordneten Kundennamen zu speichern:

  1. Navigieren Sie in Ihrer IoT Central-Anwendung auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Wählen Sie im Modell Temperature Controller die Option + Funktion hinzufügen aus.

  3. Geben Sie Kundenname als Anzeigename ein, wählen Sie Cloudeigenschaft als Funktionstyp aus, erweitern Sie den Eintrag, und wählen Sie Zeichenfolge als Schema aus. Klicken Sie dann auf Speichern.

So passen Sie die Darstellung des Befehls Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) in Ihrer IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter getMaxMinReport (thermostat1) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat1 status report (Statusbericht für „thermostat1“ abrufen).

  3. Ersetzen Sie unter getMaxMinReport (thermostat2) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat2 status report (Statusbericht für „thermostat2“ abrufen).

  4. Wählen Sie Speichern aus.

So passen Sie die Darstellung der schreibbaren Eigenschaften für die Zieltemperatur in der IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter targetTemperature (thermostat1) die Option Zieltemperatur durch Zieltemperatur (1) .

  3. Ersetzen Sie unter targetTemperature (thermostat2) die Option Zieltemperatur durch Zieltemperatur (2) .

  4. Wählen Sie Speichern aus.

Die Thermostatkomponenten im Modell Thermostat enthalten die beschreibbare Eigenschaft Target Temperature (Zieltemperatur), und die Gerätevorlage enthält die Cloudeigenschaft Customer Name (Kundenname). Erstellen Sie eine Ansicht, die von einem Operator zum Bearbeiten dieser Eigenschaften verwendet werden kann:

  1. Wählen Sie Ansichten und anschließend die Kachel Geräte- und Clouddaten bearbeiten aus.

  2. Geben Sie Properties (Eigenschaften) als Formularname ein.

  3. Wählen Sie die Eigenschaften Target Temperature (1) (Zieltemperatur (1)), Target Temperature (2) (Zieltemperatur (2)) und Customer Name (Kundenname) aus. Wählen Sie anschließend Abschnitt hinzufügen aus.

  4. Speichern Sie die Änderungen.

Screenshot that shows a view for updating property values.

Veröffentlichen der Gerätevorlage

Damit die von Ihnen vorgenommenen Anpassungen von einem Operator angezeigt und verwendet werden können, müssen Sie die Gerätevorlage veröffentlichen.

Wählen Sie in der Gerätevorlage Thermostat die Option Veröffentlichen aus. Wählen Sie im Bereich Diese Gerätevorlage für die Anwendung veröffentlichen die Option Veröffentlichen aus.

Ein Operator kann nun die Ansicht Eigenschaften verwenden, um die Eigenschaftswerte zu aktualisieren, und auf der Seite mit Gerätebefehlen Befehle namens Get thermostat1 status report (Statusbericht für "thermostat1" abrufen) und Get thermostat2 status report (Statusbericht für "thermostat2" abrufen) aufrufen:

  • Aktualisieren beschreibbarer Eigenschaftswerte auf der Seite Properties (Eigenschaften):

    Screenshot that shows updating the device properties.

  • Rufen Sie die Befehle auf der Seite Befehle auf. Wählen Sie bei Ausführung des Statusberichtsbefehls ein Datum und eine Uhrzeit für den Since-Parameter aus, bevor Sie ihn ausführen:

    Screenshot that shows calling a command.

    Screenshot that shows a command response.

Sie können sehen, wie das Gerät auf Befehle und Eigenschaftsaktualisierungen reagiert. Der Befehl getMaxMinReport befindet sich in der Komponente thermostat2, der Befehl reboot ist in der Standardkomponente enthalten. Die schreibbare Eigenschaft targetTemperature wurde für die Komponente thermostat2 festgelegt:

Received command request for command name: thermostat2*getMaxMinReport
The command request payload is:
2021-03-26T06:00:00.000Z
Response to method: thermostat2*getMaxMinReport sent successfully.

...

Received command request for command name: reboot
The command request payload is:
10
Response to method: reboot sent successfully.

...

Received an update for device with value: {"thermostat2":{"targetTemperature":76,"__t":"c"},"$version":2}
Will update property: targetTemperature to value: 76 of component: thermostat2
Properties have been reported for component: thermostat2

Browse code

Voraussetzungen

Zum Ausführen der Schritte in diesem Artikel benötigen Sie folgende Ressourcen:

  • Ein Entwicklungscomputer, auf dem Python installiert ist. Prüfen Sie das Azure IoT Python SDK auf die aktuellen Python-Versionsanforderungen. Sie können python --version an der Befehlszeile ausführen, um Ihre Version zu überprüfen. Python ist für eine Vielzahl von Betriebssystemen verfügbar. Bei den Anweisungen in diesem Tutorial wird davon ausgegangen, dass Sie den Befehl python an der Windows-Eingabeaufforderung ausführen.

  • Eine lokale Kopie des GitHub-Repositorys mit dem Microsoft Azure IoT SDK für Python, das den Beispielcode enthält. Laden Sie über den folgenden Link eine Kopie des Repositorys herunter: ZIP herunterladen. Entzippen Sie anschließend die Datei an einem geeigneten Speicherort auf Ihrem lokalen Computer.

Überprüfen des Codes

Öffnen Sie in der Kopie des Microsoft Azure IoT SDK für Python, die Sie heruntergeladen haben, die Datei azure-iot-sdk-python/samples/pnp/temp_controller_with_thermostats.py in einem Text-Editor.

Im Beispiel wird das Temperaturcontroller-Sprachmodell mit mehreren Komponenten der Definition von digitalen Zwillingen implementiert.

Wenn Sie das Beispiel ausführen, um eine Verbindung mit IoT Central herzustellen, wird Device Provisioning Service (DPS) zum Registrieren des Geräts und zum Generieren einer Verbindungszeichenfolge verwendet. Das Beispiel ruft die erforderlichen DPS-Verbindungsinformationen aus der Befehlszeilenumgebung ab.

Mit der Funktion main werden folgende Aktionen ausgeführt:

  • Bereitstellen des Geräts mithilfe von DPS. Die Bereitstellungsinformationen enthalten die Modell-ID. IoT Central verwendet die Modell-ID zum Identifizieren oder Generieren der Gerätevorlage für dieses Gerät. Weitere Informationen finden Sie unter Zuweisen eines Geräts zu einer Gerätevorlage.
  • Erstellen eines Objekts vom Typ Device_client und Festlegen der Modell-ID dtmi:com:example:TemperatureController;2 vor dem Öffnen der Verbindung
  • Senden der Eigenschaftsanfangswerte an IoT Central. Zum Erstellen der Patches wird pnp_helper verwendet.
  • Erstellen von Listenern für die Befehle getMaxMinReport und reboot. Jede Thermostatkomponente verfügt über einen eigenen getMaxMinReport-Befehl.
  • Erstellen eines Eigenschaftenlisteners zum Lauschen auf schreibbare Eigenschaftsaktualisierungen
  • Starten einer Schleife, um alle acht Sekunden Temperaturtelemetriedaten von beiden Thermostatkomponenten und Arbeitssatz-Telemetriedaten von der Standardkomponente zu senden
async def main():
    switch = os.getenv("IOTHUB_DEVICE_SECURITY_TYPE")
    if switch == "DPS":
        provisioning_host = (
            os.getenv("IOTHUB_DEVICE_DPS_ENDPOINT")
            if os.getenv("IOTHUB_DEVICE_DPS_ENDPOINT")
            else "global.azure-devices-provisioning.net"
        )
        id_scope = os.getenv("IOTHUB_DEVICE_DPS_ID_SCOPE")
        registration_id = os.getenv("IOTHUB_DEVICE_DPS_DEVICE_ID")
        symmetric_key = os.getenv("IOTHUB_DEVICE_DPS_DEVICE_KEY")

        registration_result = await provision_device(
            provisioning_host, id_scope, registration_id, symmetric_key, model_id
        )

        if registration_result.status == "assigned":
            print("Device was assigned")
            print(registration_result.registration_state.assigned_hub)
            print(registration_result.registration_state.device_id)
            device_client = IoTHubDeviceClient.create_from_symmetric_key(
                symmetric_key=symmetric_key,
                hostname=registration_result.registration_state.assigned_hub,
                device_id=registration_result.registration_state.device_id,
                product_info=model_id,
            )
        else:
            raise RuntimeError(
                "Could not provision device. Aborting Plug and Play device connection."
            )

    elif switch == "connectionString":
        # ...

    # Connect the client.
    await device_client.connect()

    ################################################
    # Update readable properties from various components

    properties_root = pnp_helper.create_reported_properties(serialNumber=serial_number)
    properties_thermostat1 = pnp_helper.create_reported_properties(
        thermostat_1_component_name, maxTempSinceLastReboot=98.34
    )
    properties_thermostat2 = pnp_helper.create_reported_properties(
        thermostat_2_component_name, maxTempSinceLastReboot=48.92
    )
    properties_device_info = pnp_helper.create_reported_properties(
        device_information_component_name,
        swVersion="5.5",
        manufacturer="Contoso Device Corporation",
        model="Contoso 4762B-turbo",
        osName="Mac Os",
        processorArchitecture="x86-64",
        processorManufacturer="Intel",
        totalStorage=1024,
        totalMemory=32,
    )

    property_updates = asyncio.gather(
        device_client.patch_twin_reported_properties(properties_root),
        device_client.patch_twin_reported_properties(properties_thermostat1),
        device_client.patch_twin_reported_properties(properties_thermostat2),
        device_client.patch_twin_reported_properties(properties_device_info),
    )

    ################################################
    # Get all the listeners running
    print("Listening for command requests and property updates")

    global THERMOSTAT_1
    global THERMOSTAT_2
    THERMOSTAT_1 = Thermostat(thermostat_1_component_name, 10)
    THERMOSTAT_2 = Thermostat(thermostat_2_component_name, 10)

    listeners = asyncio.gather(
        execute_command_listener(
            device_client, method_name="reboot", user_command_handler=reboot_handler
        ),
        execute_command_listener(
            device_client,
            thermostat_1_component_name,
            method_name="getMaxMinReport",
            user_command_handler=max_min_handler,
            create_user_response_handler=create_max_min_report_response,
        ),
        execute_command_listener(
            device_client,
            thermostat_2_component_name,
            method_name="getMaxMinReport",
            user_command_handler=max_min_handler,
            create_user_response_handler=create_max_min_report_response,
        ),
        execute_property_listener(device_client),
    )

    ################################################
    # Function to send telemetry every 8 seconds

    async def send_telemetry():
        print("Sending telemetry from various components")

        while True:
            curr_temp_ext = random.randrange(10, 50)
            THERMOSTAT_1.record(curr_temp_ext)

            temperature_msg1 = {"temperature": curr_temp_ext}
            await send_telemetry_from_temp_controller(
                device_client, temperature_msg1, thermostat_1_component_name
            )

            curr_temp_int = random.randrange(10, 50)  # Current temperature in Celsius
            THERMOSTAT_2.record(curr_temp_int)

            temperature_msg2 = {"temperature": curr_temp_int}

            await send_telemetry_from_temp_controller(
                device_client, temperature_msg2, thermostat_2_component_name
            )

            workingset_msg3 = {"workingSet": random.randrange(1, 100)}
            await send_telemetry_from_temp_controller(device_client, workingset_msg3)

    send_telemetry_task = asyncio.ensure_future(send_telemetry())

    # ...

Die Funktion provision_device verwendet DPS, um das Gerät bereitzustellen und bei IoT Central zu registrieren. Die Funktion enthält die Gerätemodell-ID, die IoT Central zum Zuweisen eines Geräts zu einer Gerätevorlage in den Bereitstellungsnutzdaten verwendet:

async def provision_device(provisioning_host, id_scope, registration_id, symmetric_key, model_id):
    provisioning_device_client = ProvisioningDeviceClient.create_from_symmetric_key(
        provisioning_host=provisioning_host,
        registration_id=registration_id,
        id_scope=id_scope,
        symmetric_key=symmetric_key,
    )

    provisioning_device_client.provisioning_payload = {"modelId": model_id}
    return await provisioning_device_client.register()

Die Funktion execute_command_listener verarbeitet Befehlsanforderungen. Sie führt die Funktion max_min_handler aus, wenn das Gerät den Befehl getMaxMinReport für die Thermostatkomponenten empfängt, und die Funktion reboot_handler, wenn das Gerät den Befehl reboot empfängt. Zum Erstellen der Antwort wird das Modul pnp_helper verwendet:

async def execute_command_listener(
    device_client,
    component_name=None,
    method_name=None,
    user_command_handler=None,
    create_user_response_handler=None,
):
    while True:
        if component_name and method_name:
            command_name = component_name + "*" + method_name
        elif method_name:
            command_name = method_name
        else:
            command_name = None

        command_request = await device_client.receive_method_request(command_name)
        print("Command request received with payload")
        values = command_request.payload
        print(values)

        if user_command_handler:
            await user_command_handler(values)
        else:
            print("No handler provided to execute")

        (response_status, response_payload) = pnp_helper.create_response_payload_with_status(
            command_request, method_name, create_user_response=create_user_response_handler
        )

        command_response = MethodResponse.create_from_method_request(
            command_request, response_status, response_payload
        )

        try:
            await device_client.send_method_response(command_response)
        except Exception:
            print("responding to the {command} command failed".format(command=method_name))

async def execute_property_listener verarbeitet schreibbare Eigenschaftsaktualisierungen wie targetTemperature für die Thermostatkomponenten und generiert die JSON-Antwort. Zum Erstellen der Antwort wird das Modul pnp_helper verwendet:

async def execute_property_listener(device_client):
    while True:
        patch = await device_client.receive_twin_desired_properties_patch()  # blocking call
        print(patch)
        properties_dict = pnp_helper.create_reported_properties_from_desired(patch)

        await device_client.patch_twin_reported_properties(properties_dict)

Die Funktion send_telemetry_from_temp_controller sendet die Telemetrienachrichten von den Thermostatkomponenten an IoT Central. Zum Erstellen der Nachrichten wird das Modul pnp_helper verwendet:

async def send_telemetry_from_temp_controller(device_client, telemetry_msg, component_name=None):
    msg = pnp_helper.create_telemetry(telemetry_msg, component_name)
    await device_client.send_message(msg)
    print("Sent message")
    print(msg)
    await asyncio.sleep(5)

Abrufen von Verbindungsinformationen

Wenn Sie die Beispielgeräteanwendung später in diesem Tutorial ausführen, benötigen Sie die folgenden Konfigurationswerte:

  • ID-Bereich: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen. Notieren Sie sich den Wert für ID-Bereich.
  • Gruppenprimärschlüssel: Navigieren Sie in Ihrer IoT Central-Anwendung zu Berechtigungen > Geräteverbindungsgruppen > SAS-IoT-Devices. Notieren Sie sich den Wert für den SAS-Primärschlüssel (Shared Access Signature).

Verwenden Sie Azure Cloud Shell, um einen Geräteschlüssel auf der Grundlage des von Ihnen abgerufenen Gruppenprimärschlüssels zu generieren:

az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>

Notieren Sie sich den generierten Geräteschlüssel. Sie verwenden ihn später in diesem Tutorial.

Hinweis

Um dieses Beispiel auszuführen, müssen Sie das Gerät nicht im Voraus in Ihrer IoT Central-Anwendung registrieren. Im Beispiel wird die IoT Central-Funktion verwendet, um Geräte automatisch zu registrieren, wenn sie zum ersten Mal eine Verbindung herstellen.

Ausführen des Codes

Um die Beispielanwendung auszuführen, öffnen Sie eine Befehlszeilenumgebung und navigieren Sie zu dem Ordner azure-iot-sdk-python-2/samples/pnp, der die Beispieldatei temp_controller_with_thermostats.py enthält.

Legen Sie die Umgebungsvariablen zum Konfigurieren des Beispiels fest. Der folgende Ausschnitt zeigt, wie Sie die Umgebungsvariablen in der Windows-Eingabeaufforderung festlegen. Ersetzen Sie bei Verwendung einer Bash-Shell die set-Befehle durch export-Befehle:

set IOTHUB_DEVICE_SECURITY_TYPE=DPS
set IOTHUB_DEVICE_DPS_ID_SCOPE=<The ID scope you made a note of previously>
set IOTHUB_DEVICE_DPS_DEVICE_ID=sample-device-01
set IOTHUB_DEVICE_DPS_DEVICE_KEY=<The generated device key you made a note of previously>
set IOTHUB_DEVICE_DPS_ENDPOINT=global.azure-devices-provisioning.net

Installieren Sie die erforderlichen Pakete:

pip install azure-iot-device

Führen Sie das Beispiel aus:

python temp_controller_with_thermostats.py

Die folgende Ausgabe zeigt, wie das Gerät registriert und eine Verbindung mit IoT Central hergestellt wird. In dem Beispiel werden die maxTempSinceLastReboot-Eigenschaften von den beiden Thermostatkomponenten gesendet, bevor mit dem Senden von Telemetriedaten begonnen wird:

Device was assigned
iotc-60a.....azure-devices.net
sample-device-01
Updating pnp properties for root interface
{'serialNumber': 'alohomora'}
Updating pnp properties for thermostat1
{'thermostat1': {'maxTempSinceLastReboot': 98.34, '__t': 'c'}}
Updating pnp properties for thermostat2
{'thermostat2': {'maxTempSinceLastReboot': 48.92, '__t': 'c'}}
Updating pnp properties for deviceInformation
{'deviceInformation': {'swVersion': '5.5', 'manufacturer': 'Contoso Device Corporation', 'model': 'Contoso 4762B-turbo', 'osName': 'Mac Os', 'processorArchitecture': 'x86-64', 'processorManufacturer': 'Intel', 'totalStorage': 1024, 'totalMemory': 32, '__t': 'c'}}
Listening for command requests and property updates
Press Q to quit
Sending telemetry from various components
Sent message
{"temperature": 27}
Sent message
{"temperature": 17}
Sent message
{"workingSet": 13}

Als Operator in Ihrer Azure IoT Central-Anwendung haben Sie folgende Möglichkeiten:

  • Anzeigen der von den beiden Thermostatkomponenten gesendeten Telemetriedaten auf der Seite Übersicht:

    Screenshot that shows the device overview page.

  • Anzeigen der Geräteeigenschaften auf der Seite Info. Auf dieser Seite werden die Eigenschaften der Geräteinformationskomponente und der beiden Thermostatkomponenten angezeigt:

    Screenshot that shows the device properties view.

Anpassen der Gerätevorlage

Als Lösungsentwickler können Sie die Gerätevorlage anpassen, die von IoT Central automatisch erstellt wurde, als der Temperaturregler eine Verbindung hergestellt hat.

So fügen Sie eine Cloudeigenschaft hinzu, um den dem Gerät zugeordneten Kundennamen zu speichern:

  1. Navigieren Sie in Ihrer IoT Central-Anwendung auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Wählen Sie im Modell Temperature Controller die Option + Funktion hinzufügen aus.

  3. Geben Sie Kundenname als Anzeigename ein, wählen Sie Cloudeigenschaft als Funktionstyp aus, erweitern Sie den Eintrag, und wählen Sie Zeichenfolge als Schema aus. Klicken Sie dann auf Speichern.

So passen Sie die Darstellung des Befehls Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) in Ihrer IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter getMaxMinReport (thermostat1) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat1 status report (Statusbericht für „thermostat1“ abrufen).

  3. Ersetzen Sie unter getMaxMinReport (thermostat2) die Option Get Max-Min report (Bericht zu Maximal-/Mindesttemperatur abrufen) durch Get thermostat2 status report (Statusbericht für „thermostat2“ abrufen).

  4. Wählen Sie Speichern aus.

So passen Sie die Darstellung der schreibbaren Eigenschaften für die Zieltemperatur in der IoT Central-Anwendung an:

  1. Navigieren Sie auf der Seite Gerätevorlagen zur Gerätevorlage Temperaturregler.

  2. Ersetzen Sie unter targetTemperature (thermostat1) die Option Zieltemperatur durch Zieltemperatur (1) .

  3. Ersetzen Sie unter targetTemperature (thermostat2) die Option Zieltemperatur durch Zieltemperatur (2) .

  4. Wählen Sie Speichern aus.

Die Thermostatkomponenten im Modell Thermostat enthalten die beschreibbare Eigenschaft Target Temperature (Zieltemperatur), und die Gerätevorlage enthält die Cloudeigenschaft Customer Name (Kundenname). Erstellen Sie eine Ansicht, die von einem Operator zum Bearbeiten dieser Eigenschaften verwendet werden kann:

  1. Wählen Sie Ansichten und anschließend die Kachel Geräte- und Clouddaten bearbeiten aus.

  2. Geben Sie Properties (Eigenschaften) als Formularname ein.

  3. Wählen Sie die Eigenschaften Target Temperature (1) (Zieltemperatur (1)), Target Temperature (2) (Zieltemperatur (2)) und Customer Name (Kundenname) aus. Wählen Sie anschließend Abschnitt hinzufügen aus.

  4. Speichern Sie die Änderungen.

Screenshot that shows a view for updating property values.

Veröffentlichen der Gerätevorlage

Damit die von Ihnen vorgenommenen Anpassungen von einem Operator angezeigt und verwendet werden können, müssen Sie die Gerätevorlage veröffentlichen.

Wählen Sie in der Gerätevorlage Thermostat die Option Veröffentlichen aus. Wählen Sie im Bereich Diese Gerätevorlage für die Anwendung veröffentlichen die Option Veröffentlichen aus.

Ein Operator kann nun die Ansicht Eigenschaften verwenden, um die Eigenschaftswerte zu aktualisieren, und auf der Seite mit Gerätebefehlen Befehle namens Get thermostat1 status report (Statusbericht für "thermostat1" abrufen) und Get thermostat2 status report (Statusbericht für "thermostat2" abrufen) aufrufen:

  • Aktualisieren beschreibbarer Eigenschaftswerte auf der Seite Properties (Eigenschaften):

    Screenshot that shows updating the device properties.

  • Rufen Sie die Befehle auf der Seite Befehle auf. Wählen Sie bei Ausführung des Statusberichtsbefehls ein Datum und eine Uhrzeit für den Since-Parameter aus, bevor Sie ihn ausführen:

    Screenshot that shows calling a command.

    Screenshot that shows a command response.

Sie können sehen, wie das Gerät auf Befehle und Eigenschaftsaktualisierungen reagiert:

{'thermostat1': {'targetTemperature': 67, '__t': 'c'}, '$version': 2}
the data in the desired properties patch was: {'thermostat1': {'targetTemperature': 67, '__t': 'c'}, '$version': 2}
Values received are :-
{'targetTemperature': 67, '__t': 'c'}
Sent message

...

Command request received with payload
2021-03-31T05:00:00.000Z
Will return the max, min and average temperature from the specified time 2021-03-31T05:00:00.000Z to the current time
Done generating
{"avgTemp": 4.0, "endTime": "2021-03-31T12:29:48.322427", "maxTemp": 18, "minTemp": null, "startTime": "2021-03-31T12:28:28.322381"}

Anzeigen von Rohdaten

Sie können die Ansicht Rohdaten verwenden, um die Rohdaten zu untersuchen, die von Ihrem Gerät an IoT Central gesendet werden:

Screenshot that shows the raw data view.

In dieser Ansicht können Sie die anzuzeigenden Spalten auswählen und einen Zeitbereich zum Anzeigen festlegen. In der Spalte für Nicht modellierte Daten werden die Daten des Geräts angezeigt, die keiner der Definitionen für Eigenschaften oder Telemetriedaten in der Gerätevorlage entsprechen.

Bereinigen von Ressourcen

Falls Sie keine weiteren IoT Central-Schnellstarts oder -Tutorials absolvieren möchten, können Sie die IoT Central-Anwendung löschen:

  1. Navigieren Sie in Ihrer IoT Central-Anwendung zu Anwendung > Verwaltung.
  2. Wählen Sie Löschen aus, und bestätigen Sie anschließend Ihre Aktion.

Nächste Schritte

Wenn Sie mit den Tutorials zu IoT Central fortfahren und mehr über das Erstellen einer IoT Central-Lösung erfahren möchten, lesen Sie den folgenden Artikel: