Delen via


Een bestaand apparaat converteren naar een IoT-Plug en Play-apparaat

In dit artikel worden de stappen beschreven die u moet volgen om een bestaand apparaat te converteren naar een IoT-Plug en Play-apparaat. Hierin wordt beschreven hoe u het model maakt dat voor elk IoT Plug en Play-apparaat is vereist en de benodigde codewijzigingen om het apparaat in staat te stellen te functioneren als een IoT-Plug en Play-apparaat.

Voor de codevoorbeelden toont dit artikel C-code die gebruikmaakt van een MQTT-bibliotheek om verbinding te maken met een IoT-hub. U kunt de wijzigingen die in dit artikel worden beschreven, toepassen op apparaten die zijn geïmplementeerd met andere talen en SDK's.

Uw bestaande apparaat converteren naar een IoT-Plug en Play-apparaat:

  1. Controleer uw apparaatcode om inzicht te hebben in de telemetrie, eigenschappen en opdrachten die worden geïmplementeerd.
  2. Maak een model dat de telemetrie, eigenschappen en opdrachten beschrijft die uw apparaat implementeert.
  3. Wijzig de apparaatcode om de model-id aan te kondigen wanneer deze verbinding maakt met uw service.

Uw apparaatcode controleren

Voordat u een model voor uw apparaat maakt, moet u de bestaande mogelijkheden van uw apparaat begrijpen:

  • De telemetrie die het apparaat regelmatig verzendt.
  • De alleen-lezen en beschrijfbare eigenschappen die het apparaat synchroniseert met uw service.
  • De opdrachten die worden aangeroepen vanuit de service waarop het apparaat reageert.

Bekijk bijvoorbeeld de volgende codefragmenten voor apparaten die verschillende apparaatmogelijkheden implementeren.

Het volgende codefragment toont het apparaat dat temperatuurtelemetrie verzendt:

#define TOPIC "devices/" DEVICEID "/messages/events/"

// ...

void Thermostat_SendCurrentTemperature()
{
  char msg[] = "{\"temperature\":25.6}";
  int msgId = rand();
  int rc = mosquitto_publish(mosq, &msgId, TOPIC, sizeof(msg) - 1, msg, 1, true);
  if (rc != MOSQ_ERR_SUCCESS)
  {
    printf("Error: %s\r\n", mosquitto_strerror(rc));
  }
}

De naam van het telemetrieveld is temperature en het type is zwevend of dubbel. De modeldefinitie voor dit telemetrietype ziet eruit als de volgende JSON. Zie Hieronder een model ontwerpen voor meer informatie over de modus:

{
  "@type": [
    "Telemetry"
  ],
  "name": "temperature",
  "displayName": "Temperature",
  "description": "Temperature in degrees Celsius.",
  "schema": "double"
}

Het volgende codefragment toont het apparaat dat een eigenschapswaarde rapporteert:

#define DEVICETWIN_MESSAGE_PATCH "$iothub/twin/PATCH/properties/reported/?$rid=patch_temp"

static void SendMaxTemperatureSinceReboot()
{
  char msg[] = "{\"maxTempSinceLastReboot\": 42.500}";
  int msgId = rand();
  int rc = mosquitto_publish(mosq, &msgId, DEVICETWIN_MESSAGE_PATCH, sizeof(msg) - 1, msg, 1, true);
  if (rc != MOSQ_ERR_SUCCESS)
  {
    printf("Error: %s\r\n", mosquitto_strerror(rc));
  }
}

De naam van de eigenschap is maxTempSinceLastReboot en het type is zwevend of dubbel. Deze eigenschap wordt gerapporteerd door het apparaat. Het apparaat ontvangt nooit een update voor deze waarde van de service. De modeldefinitie voor deze eigenschap ziet eruit als de volgende JSON. Zie Hieronder een model ontwerpen voor meer informatie over de modus:

{
  "@type": [
    "Property"
  ],
  "name": "maxTempSinceLastReboot",
  "schema": "double",
  "displayName": "Max temperature since last reboot.",
  "description": "Returns the max temperature since last device reboot."
}

Het volgende codefragment toont het apparaat dat reageert op berichten van de service:

void message_callback(struct mosquitto* mosq, void* obj, const struct mosquitto_message* message)
{
  printf("Message received: %s payload: %s \r\n", message->topic, (char*)message->payload);
  
  if (strncmp(message->topic, "$iothub/methods/POST/getMaxMinReport/?$rid=1",37) == 0)
  {
    char* pch;
    char* context;
    int msgId = 0;
    pch = strtok_s((char*)message->topic, "=",&context);
    while (pch != NULL)
    {
      pch = strtok_s(NULL, "=", &context);
      if (pch != NULL) {
        char * pEnd;
        msgId = strtol(pch,&pEnd,16 );
      }
    }
    char topic[64];
    sprintf_s(topic, "$iothub/methods/res/200/?$rid=%d", msgId);
    char msg[] = "{\"maxTemp\":83.51,\"minTemp\":77.68}";
    int rc = mosquitto_publish(mosq, &msgId, topic, sizeof(msg) - 1, msg, 1, true);
    if (rc != MOSQ_ERR_SUCCESS)
    {
      printf("Error: %s\r\n", mosquitto_strerror(rc));
    }
    delete pch;
  }

  if (strncmp(message->topic, "$iothub/twin/PATCH/properties/desired/?$version=1", 38) == 0)
  {
    char* pch;
    char* context;
    int version = 0; 
    pch = strtok_s((char*)message->topic, "=", &context);
    while (pch != NULL)
    {
      pch = strtok_s(NULL, "=", &context);
      if (pch != NULL) {
        char* pEnd;
        version = strtol(pch, &pEnd, 10);
      }
    }
    // To do: Parse payload and extract target value
    char msg[128];
    int value = 46;
    sprintf_s(msg, "{\"targetTemperature\":{\"value\":%d,\"ac\":200,\"av\":%d,\"ad\":\"success\"}}", value, version);
    int rc = mosquitto_publish(mosq, &version, DEVICETWIN_MESSAGE_PATCH, strlen(msg), msg, 1, true);
    if (rc != MOSQ_ERR_SUCCESS)
    {
      printf("Error: %s\r\n", mosquitto_strerror(rc));
    }
    delete pch;
  }
}

Het $iothub/methods/POST/getMaxMinReport/ onderwerp ontvangt een aanvraag voor een opdracht die wordt aangeroepen getMaxMinReport vanuit de service. Deze aanvraag kan een nettolading met opdrachtparameters bevatten. Het apparaat verzendt een antwoord met een nettolading die waarden bevat en minTemp bevatmaxTemp.

Het $iothub/twin/PATCH/properties/desired/ onderwerp ontvangt eigenschapsupdates van de service. In dit voorbeeld wordt ervan uitgegaan dat de eigenschapsupdate voor de targetTemperature eigenschap is. Het reageert met een bevestiging die er als volgt {\"targetTemperature\":{\"value\":46,\"ac\":200,\"av\":12,\"ad\":\"success\"}}uitziet.

Kortom, het voorbeeld implementeert de volgende mogelijkheden:

Naam Type mogelijkheid DETAILS
temperatuur Telemetrie Stel dat het gegevenstype dubbel is
maxTempSinceLastReboot Eigenschappen Stel dat het gegevenstype dubbel is
targetTemperature Beschrijfbare eigenschap Gegevenstype is geheel getal
getMaxMinReport Opdracht Retourneert JSON met maxTemp en minTemp velden van het type double

Een model ontwerpen

Elk IoT-Plug en Play-apparaat heeft een model dat de functies en mogelijkheden van het apparaat beschrijft. Het model maakt gebruik van de Digital Twin Definition Language (DTDL) om de mogelijkheden van het apparaat te beschrijven.

Voor een eenvoudig model waarmee de bestaande mogelijkheden van uw apparaat worden toegewezen, gebruikt u de DTDL-elementen Telemetrie, Eigenschap en Opdracht .

Een DTDL-model voor het voorbeeld dat in de vorige sectie wordt beschreven, ziet eruit als in het volgende voorbeeld:

{
  "@context": "dtmi:dtdl:context;2",
  "@id": "dtmi:com:example:ConvertSample;1",
  "@type": "Interface",
  "displayName": "Simple device",
  "description": "Example that shows model for simple device converted to act as an IoT Plug and Play device.",
  "contents": [
    {
      "@type": [
        "Telemetry",
        "Temperature"
      ],
      "name": "temperature",
      "displayName": "Temperature",
      "description": "Temperature in degrees Celsius.",
      "schema": "double",
      "unit": "degreeCelsius"
    },
    {
      "@type": [
        "Property",
        "Temperature"
      ],
      "name": "targetTemperature",
      "schema": "double",
      "displayName": "Target Temperature",
      "description": "Allows to remotely specify the desired target temperature.",
      "unit": "degreeCelsius",
      "writable": true
    },
    {
      "@type": [
        "Property",
        "Temperature"
      ],
      "name": "maxTempSinceLastReboot",
      "schema": "double",
      "unit": "degreeCelsius",
      "displayName": "Max temperature since last reboot.",
      "description": "Returns the max temperature since last device reboot."
    },
    {
      "@type": "Command",
      "name": "getMaxMinReport",
      "displayName": "Get Max-Min report.",
      "description": "This command returns the max and min temperature.",
      "request": {
      },
      "response": {
        "name": "tempReport",
        "displayName": "Temperature Report",
        "schema": {
          "@type": "Object",
          "fields": [
            {
              "name": "maxTemp",
              "displayName": "Max temperature",
              "schema": "double"
            },
            {
              "name": "minTemp",
              "displayName": "Min temperature",
              "schema": "double"
            }
          ]
        }
      }
    }
  ]
}

In dit model:

  • De name en schema waarden worden toegewezen aan de gegevens die het apparaat verzendt en ontvangt.
  • Alle mogelijkheden zijn gegroepeerd in één interface.
  • De @type velden identificeren de DTDL-typen, zoals Eigenschap en Opdracht.
  • Velden zoals unit, displayNameen description geef extra informatie op voor de service die moet worden gebruikt. IoT Central gebruikt deze waarden bijvoorbeeld wanneer er gegevens worden weergegeven op apparaatdashboards.

Zie de handleiding voor IoT-Plug en Play-conventies en IoT-Plug en Play modellering voor meer informatie.

De code bijwerken

Als uw apparaat al werkt met IoT Hub of IoT Central, hoeft u geen wijzigingen aan te brengen in de implementatie van de telemetrie-, eigenschaps- en opdrachtmogelijkheden. Als u wilt dat het apparaat de IoT-Plug en Play-conventies volgt, wijzigt u de manier waarop het apparaat verbinding maakt met uw service, zodat de id wordt aangekondigd van het model dat u hebt gemaakt. De service kan vervolgens het model gebruiken om inzicht te hebben in de mogelijkheden van het apparaat. IoT Central kan bijvoorbeeld de model-id gebruiken om het model automatisch op te halen uit een opslagplaats en een apparaatsjabloon voor uw apparaat te genereren.

IoT-apparaten maken verbinding met uw IoT-service via Device Provisioning Service (DPS) of rechtstreeks met een verbindingsreeks.

Als uw apparaat DPS gebruikt om verbinding te maken, neemt u de model-id op in de nettolading die u verzendt wanneer u het apparaat registreert. Voor het voorbeeldmodel dat eerder wordt weergegeven, ziet de nettolading er als volgt uit:

{
  "modelId" : "dtmi:com:example:ConvertSample;1"
}

Zie Runtime-registratie - Apparaat registreren voor meer informatie.

Als uw apparaat DPS gebruikt om verbinding te maken of rechtstreeks verbinding te maken met een verbindingsreeks, neemt u de model-id op wanneer uw code verbinding maakt met IoT Hub. Voorbeeld:

#define USERNAME IOTHUBNAME ".azure-devices.net/" DEVICEID "/?api-version=2020-09-30&model-id=dtmi:com:example:ConvertSample;1"

// ...

mosquitto_username_pw_set(mosq, USERNAME, PWD);

// ...

rc = mosquitto_connect(mosq, HOST, PORT, 10);

Volgende stappen

Nu u weet hoe u een bestaand apparaat converteert naar een IoT Plug en Play-apparaat, is een voorgestelde volgende stap het lezen van de IoT Plug en Play modelleringshandleiding.