Připojení zařízení k akcelerátoru řešení vzdáleného monitorování (Linux)

V tomto kurzu implementujete zařízení Chiller , které odesílá následující telemetrii do akcelerátoru řešení vzdáleného monitorování:

  • Teplota
  • Tlak
  • Vlhkost

Pro zjednodušení kód vygeneruje ukázkové telemetrické hodnoty pro chladič. Ukázku můžete rozšířit připojením skutečných senzorů k zařízení a odesláním skutečné telemetrie.

Ukázkové zařízení také:

  • Odešle do řešení metadata, která popisují jeho možnosti.
  • Reaguje na akce aktivované ze stránky Zařízení v řešení.
  • Reaguje na změny konfigurace odeslané ze stránky Zařízení v řešení.

K dokončení tohoto kurzu potřebujete mít aktivní účet Azure. Pokud účet nemáte, můžete si během několika minut vytvořit bezplatný zkušební účet. Podrobnosti najdete v článku Bezplatná zkušební verze Azure.

Než začnete

Než napíšete jakýkoli kód pro vaše zařízení, nasaďte akcelerátor řešení vzdáleného monitorování a přidejte do řešení nové skutečné zařízení.

Nasazení akcelerátoru řešení vzdáleného monitorování

Zařízení Chiller, které vytvoříte v tomto kurzu, odesílá data do instance akcelerátoru řešení vzdáleného monitorování. Pokud jste v účtu Azure ještě nezřídili akcelerátor řešení vzdáleného monitorování, přečtěte si téma Nasazení akcelerátoru řešení vzdáleného monitorování.

Po dokončení procesu nasazení řešení vzdáleného monitorování kliknutím na Spustit otevřete řídicí panel řešení v prohlížeči.

Řídicí panel řešení

Přidání zařízení do řešení pro vzdálené monitorování

Poznámka

Pokud jste už v řešení přidali zařízení, můžete tento krok přeskočit. Další krok ale vyžaduje připojovací řetězec vašeho zařízení. Připojovací řetězec zařízení můžete načíst z Azure Portal nebo pomocí nástroje az iot CLI.

Aby se zařízení mohlo připojit k akcelerátoru řešení, musí se identifikovat, aby se IoT Hub pomocí platných přihlašovacích údajů. Máte možnost uložit připojovací řetězec zařízení, který obsahuje tyto přihlašovací údaje, když zařízení přidáte do řešení. Do klientské aplikace zahrnete připojovací řetězec zařízení později v tomto kurzu.

Pokud chcete přidat zařízení do řešení vzdáleného monitorování, proveďte následující kroky na stránce Průzkumníka zařízení v řešení:

  1. Zvolte + Nové zařízení a pak jako typ zařízení zvolte Skutečné:

    Přidání skutečného zařízení

  2. Jako ID zařízení zadejte fyzický chladič . Zvolte možnosti symetrického klíče a automatického generování klíčů :

    Volba možností zařízení

  3. Zvolte Použít. Pak si poznamenejte hodnoty primárního klíče zařízení, primárního klíče a připojovacího řetězce :

    Načtení přihlašovacích údajů

Teď jste přidali skutečné zařízení do akcelerátoru řešení vzdáleného monitorování a poznamenali jste si připojovací řetězec zařízení. V následujících částech implementujete klientskou aplikaci, která používá připojovací řetězec zařízení pro připojení k vašemu řešení.

Klientská aplikace implementuje integrovaný model zařízení Chiller . Model zařízení akcelerátoru řešení určuje následující informace o zařízení:

  • Vlastnosti zařízení hlásí řešení. Například zařízení Chiller hlásí informace o jeho firmwaru a umístění.
  • Typy telemetrie, které zařízení odesílá do řešení. Například chladicí zařízení odesílá hodnoty teploty, vlhkosti a tlaku.
  • Metody, které můžete naplánovat z řešení, aby běžely na zařízení. Například zařízení Chiller musí implementovat metody Reboot, FirmwareUpdate, EmergencyValveRelease a IncreasePressure .

V tomto kurzu se dozvíte, jak připojit skutečné zařízení k akcelerátoru řešení vzdáleného monitorování.

Stejně jako u většiny vložených aplikací, které běží na omezených zařízeních, je klientský kód aplikace zařízení napsaný v jazyce C. V tomto kurzu vytvoříte aplikaci na počítači s Ubuntu (Linuxem).

Pokud dáváte přednost simulaci zařízení, přečtěte si téma Vytvoření a testování nového simulovaného zařízení.

Požadavky

K dokončení kroků v tomto průvodci postupy potřebujete zařízení s Ubuntu verze 15.04 nebo novější. Než budete pokračovat, nastavte vývojové prostředí pro Linux.

Zobrazení kódu

Ukázkový kód použitý v této příručce je k dispozici v úložišti GitHub sdk pro Azure IoT C.

Stažení zdrojového kódu a příprava projektu

Pokud chcete projekt připravit, naklonujte nebo stáhněte úložiště sad SDK pro Azure IoT C z GitHubu.

Ukázka se nachází ve složce samples, solutions/remote_monitoring_client .

Otevřete soubor remote_monitoring.c ve složce samples/solutions/remote_monitoring_client v textovém editoru.

Průvodce kódem

Tato část popisuje některé klíčové části ukázkového kódu a vysvětluje, jak souvisí s akcelerátorem řešení vzdáleného monitorování.

Následující fragment kódu ukazuje, jak jsou definované hlášené vlastnosti, které popisují možnosti zařízení. Mezi tyto vlastnosti patří:

  • Umístění zařízení, které umožní akcelerátoru řešení přidat zařízení do mapy.
  • Aktuální verze firmwaru.
  • Seznam metod, které zařízení podporuje.
  • Schéma telemetrických zpráv odesílaných zařízením
typedef struct MESSAGESCHEMA_TAG
{
    char* name;
    char* format;
    char* fields;
} MessageSchema;

typedef struct TELEMETRYSCHEMA_TAG
{
    MessageSchema messageSchema;
} TelemetrySchema;

typedef struct TELEMETRYPROPERTIES_TAG
{
    TelemetrySchema temperatureSchema;
    TelemetrySchema humiditySchema;
    TelemetrySchema pressureSchema;
} TelemetryProperties;

typedef struct CHILLER_TAG
{
    // Reported properties
    char* protocol;
    char* supportedMethods;
    char* type;
    char* firmware;
    FIRMWARE_UPDATE_STATUS firmwareUpdateStatus;
    char* location;
    double latitude;
    double longitude;
    TelemetryProperties telemetry;

    // Manage firmware update process
    char* new_firmware_version;
    char* new_firmware_URI;
} Chiller;

Ukázka obsahuje serializaciToJson funkce, která serializuje tuto datovou strukturu pomocí knihovny Parson.

Ukázka obsahuje několik funkcí zpětného volání, které tisknou informace do konzoly, protože klient komunikuje s akcelerátorem řešení:

  • connection_status_callback
  • send_confirm_callback
  • reported_state_callback
  • device_method_callback

Následující fragment kódu ukazuje funkci device_method_callback . Tato funkce určuje akci, která se má provést při přijetí volání metody z akcelerátoru řešení. Funkce obdrží odkaz na datovou strukturu Chilleru v parametru userContextCallback . Hodnota userContextCallback je nastavena při konfiguraci funkce zpětného volání v hlavní funkci:

static int device_method_callback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* response_size, void* userContextCallback)
{
    Chiller *chiller = (Chiller *)userContextCallback;

    int result;

    (void)printf("Direct method name:    %s\r\n", method_name);

    (void)printf("Direct method payload: %.*s\r\n", (int)size, (const char*)payload);

    if (strcmp("Reboot", method_name) == 0)
    {
        MESSAGERESPONSE(201, "{ \"Response\": \"Rebooting\" }")
    }
    else if (strcmp("EmergencyValveRelease", method_name) == 0)
    {
        MESSAGERESPONSE(201, "{ \"Response\": \"Releasing emergency valve\" }")
    }
    else if (strcmp("IncreasePressure", method_name) == 0)
    {
        MESSAGERESPONSE(201, "{ \"Response\": \"Increasing pressure\" }")
    }
    else if (strcmp("FirmwareUpdate", method_name) == 0)
    {
        if (chiller->firmwareUpdateStatus != IDLE)
        {
            (void)printf("Attempt to invoke firmware update out of order\r\n");
            MESSAGERESPONSE(400, "{ \"Response\": \"Attempting to initiate a firmware update out of order\" }")
        }
        else
        {
            getFirmwareUpdateValues(chiller, payload);

            if (chiller->new_firmware_version != NULL && chiller->new_firmware_URI != NULL)
            {
                // Create a thread for the long-running firmware update process.
                THREAD_HANDLE thread_apply;
                THREADAPI_RESULT t_result = ThreadAPI_Create(&thread_apply, do_firmware_update, chiller);
                if (t_result == THREADAPI_OK)
                {
                    (void)printf("Starting firmware update thread\r\n");
                    MESSAGERESPONSE(201, "{ \"Response\": \"Starting firmware update thread\" }")
                }
                else
                {
                    (void)printf("Failed to start firmware update thread\r\n");
                    MESSAGERESPONSE(500, "{ \"Response\": \"Failed to start firmware update thread\" }")
                }
            }
            else
            {
                (void)printf("Invalid method payload\r\n");
                MESSAGERESPONSE(400, "{ \"Response\": \"Invalid payload\" }")
            }
        }
    }
    else
    {
        // All other entries are ignored.
        (void)printf("Method not recognized\r\n");
        MESSAGERESPONSE(400, "{ \"Response\": \"Method not recognized\" }")
    }

    return result;
}

Když akcelerátor řešení volá metodu aktualizace firmwaru, ukázka deserializuje datovou část JSON a spustí vlákno na pozadí pro dokončení procesu aktualizace. Následující fragment kódu ukazuje do_firmware_update , která běží na vlákně:

/*
 This is a thread allocated to process a long-running device method call.
 It uses device twin reported properties to communicate status values
 to the Remote Monitoring solution accelerator.
*/
static int do_firmware_update(void *param)
{
    Chiller *chiller = (Chiller *)param;
    printf("Running simulated firmware update: URI: %s, Version: %s\r\n", chiller->new_firmware_URI, chiller->new_firmware_version);

    printf("Simulating download phase...\r\n");
    chiller->firmwareUpdateStatus = DOWNLOADING;
    sendChillerReportedProperties(chiller);

    ThreadAPI_Sleep(5000);

    printf("Simulating apply phase...\r\n");
    chiller->firmwareUpdateStatus = APPLYING;
    sendChillerReportedProperties(chiller);

    ThreadAPI_Sleep(5000);

    printf("Simulating reboot phase...\r\n");
    chiller->firmwareUpdateStatus = REBOOTING;
    sendChillerReportedProperties(chiller);

    ThreadAPI_Sleep(5000);

    size_t size = strlen(chiller->new_firmware_version) + 1;
    (void)memcpy(chiller->firmware, chiller->new_firmware_version, size);

    chiller->firmwareUpdateStatus = IDLE;
    sendChillerReportedProperties(chiller);

    return 0;
}

Následující fragment kódu ukazuje, jak klient odešle zprávu telemetrie do akcelerátoru řešení. Vlastnosti zprávy zahrnují schéma zprávy, které pomáhá akcelerátoru řešení zobrazit telemetrii na řídicím panelu:

static void send_message(IOTHUB_DEVICE_CLIENT_HANDLE handle, char* message, char* schema)
{
    IOTHUB_MESSAGE_HANDLE message_handle = IoTHubMessage_CreateFromString(message);
    if (message_handle != NULL)
    {
        // Set system properties
        (void)IoTHubMessage_SetMessageId(message_handle, "MSG_ID");
        (void)IoTHubMessage_SetCorrelationId(message_handle, "CORE_ID");
        (void)IoTHubMessage_SetContentTypeSystemProperty(message_handle, "application%2fjson");
        (void)IoTHubMessage_SetContentEncodingSystemProperty(message_handle, "utf-8");

        // Set application properties
        MAP_HANDLE propMap = IoTHubMessage_Properties(message_handle);
        (void)Map_AddOrUpdate(propMap, "$$MessageSchema", schema);
        (void)Map_AddOrUpdate(propMap, "$$ContentType", "JSON");

        time_t now = time(0);
        struct tm* timeinfo;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996) /* Suppress warning about possible unsafe function in Visual Studio */
#endif
        timeinfo = gmtime(&now);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
        char timebuff[50];
        strftime(timebuff, 50, "%Y-%m-%dT%H:%M:%SZ", timeinfo);
        (void)Map_AddOrUpdate(propMap, "$$CreationTimeUtc", timebuff);

        IoTHubDeviceClient_SendEventAsync(handle, message_handle, send_confirm_callback, NULL);

        IoTHubMessage_Destroy(message_handle);
    }
}

Hlavní funkce v ukázce:

  • Inicializuje a vypne subsystém sady SDK.
  • Inicializuje datovou strukturu chladiče .
  • Odešle hlášené vlastnosti do akcelerátoru řešení.
  • Nakonfiguruje funkci zpětného volání metody zařízení.
  • Odesílá simulované hodnoty telemetrie do akcelerátoru řešení.
int main(void)
{
    srand((unsigned int)time(NULL));
    double minTemperature = 50.0;
    double minPressure = 55.0;
    double minHumidity = 30.0;
    double temperature = 0;
    double pressure = 0;
    double humidity = 0;

    (void)printf("This sample simulates a Chiller device connected to the Remote Monitoring solution accelerator\r\n\r\n");

    // Used to initialize sdk subsystem
    (void)IoTHub_Init();

    (void)printf("Creating IoTHub handle\r\n");
    // Create the iothub handle here
    device_handle = IoTHubDeviceClient_CreateFromConnectionString(connectionString, MQTT_Protocol);
    if (device_handle == NULL)
    {
        (void)printf("Failure creating IotHub device. Hint: Check your connection string.\r\n");
    }
    else
    {
        // Setting connection status callback to get indication of connection to iothub
        (void)IoTHubDeviceClient_SetConnectionStatusCallback(device_handle, connection_status_callback, NULL);

        Chiller chiller;
        memset(&chiller, 0, sizeof(Chiller));
        chiller.protocol = "MQTT";
        chiller.supportedMethods = "Reboot,FirmwareUpdate,EmergencyValveRelease,IncreasePressure";
        chiller.type = "Chiller";
        size_t size = strlen(initialFirmwareVersion) + 1;
        chiller.firmware = malloc(size);
        if (chiller.firmware == NULL)
        {
            (void)printf("Chiller Firmware failed to allocate memory.\r\n");
        }
        else
        {
            memcpy(chiller.firmware, initialFirmwareVersion, size);
            chiller.firmwareUpdateStatus = IDLE;
            chiller.location = "Building 44";
            chiller.latitude = 47.638928;
            chiller.longitude = -122.13476;
            chiller.telemetry.temperatureSchema.messageSchema.name = "chiller-temperature;v1";
            chiller.telemetry.temperatureSchema.messageSchema.format = "JSON";
            chiller.telemetry.temperatureSchema.messageSchema.fields = "{\"temperature\":\"Double\",\"temperature_unit\":\"Text\"}";
            chiller.telemetry.humiditySchema.messageSchema.name = "chiller-humidity;v1";
            chiller.telemetry.humiditySchema.messageSchema.format = "JSON";
            chiller.telemetry.humiditySchema.messageSchema.fields = "{\"humidity\":\"Double\",\"humidity_unit\":\"Text\"}";
            chiller.telemetry.pressureSchema.messageSchema.name = "chiller-pressure;v1";
            chiller.telemetry.pressureSchema.messageSchema.format = "JSON";
            chiller.telemetry.pressureSchema.messageSchema.fields = "{\"pressure\":\"Double\",\"pressure_unit\":\"Text\"}";

            sendChillerReportedProperties(&chiller);

            (void)IoTHubDeviceClient_SetDeviceMethodCallback(device_handle, device_method_callback, &chiller);

            while (1)
            {
                temperature = minTemperature + ((double)(rand() % 10) + 5);
                pressure = minPressure + ((double)(rand() % 10) + 5);
                humidity = minHumidity + ((double)(rand() % 20) + 5);

                if (chiller.firmwareUpdateStatus == IDLE)
                {
                    (void)printf("Sending sensor value Temperature = %f %s,\r\n", temperature, "F");
                    (void)sprintf_s(msgText, sizeof(msgText), "{\"temperature\":%.2f,\"temperature_unit\":\"F\"}", temperature);
                    send_message(device_handle, msgText, chiller.telemetry.temperatureSchema.messageSchema.name);


                    (void)printf("Sending sensor value Pressure = %f %s,\r\n", pressure, "psig");
                    (void)sprintf_s(msgText, sizeof(msgText), "{\"pressure\":%.2f,\"pressure_unit\":\"psig\"}", pressure);
                    send_message(device_handle, msgText, chiller.telemetry.pressureSchema.messageSchema.name);


                    (void)printf("Sending sensor value Humidity = %f %s,\r\n", humidity, "%");
                    (void)sprintf_s(msgText, sizeof(msgText), "{\"humidity\":%.2f,\"humidity_unit\":\"%%\"}", humidity);
                    send_message(device_handle, msgText, chiller.telemetry.humiditySchema.messageSchema.name);
                }

                ThreadAPI_Sleep(5000);
            }

            (void)printf("\r\nShutting down\r\n");

            // Clean up the iothub sdk handle and free resources
            IoTHubDeviceClient_Destroy(device_handle);
            free(chiller.firmware);
            free(chiller.new_firmware_URI);
            free(chiller.new_firmware_version);
        }
    }
    // Shutdown the sdk subsystem
    IoTHub_Deinit();

    return 0;
}

Sestavení a spuštění aplikace

Následující kroky popisují, jak pomocí CMake sestavit klientskou aplikaci. Klientská aplikace pro vzdálené monitorování je vytvořena jako součást procesu sestavení sady SDK.

  1. Upravte soubor remote_monitoring.c tak, aby se nahradil <connectionstring> připojovacím řetězcem zařízení, který jste si poznamenali na začátku tohoto průvodce postupy při přidání zařízení do akcelerátoru řešení.

  2. Přejděte do kořenového adresáře klonované kopie úložiště sad SDK pro Azure IoT C a spusťte následující příkazy pro sestavení klientské aplikace:

    mkdir cmake
    cd cmake
    cmake ../
    make
    
  3. Spusťte klientskou aplikaci a odešlete telemetrii do IoT Hub:

    ./samples/solutions/remote_monitoring_client/remote_monitoring_client
    

    Konzola zobrazí zprávy takto:

    • Aplikace odesílá ukázkovou telemetrii do akcelerátoru řešení.
    • Reaguje na metody vyvolané z řídicího panelu řešení.

Zobrazení telemetrie zařízení

Telemetrická data odeslaná ze zařízení můžete zobrazit na stránce Průzkumníka zařízení v řešení.

  1. Vyberte zařízení, které jste zřídili v seznamu zařízení na stránce Průzkumník zařízení . Na panelu se zobrazí informace o vašem zařízení včetně grafu telemetrie zařízení:

    Zobrazit podrobnosti o zařízení

  2. Zvolte Tlak a změňte zobrazení telemetrie:

    Zobrazení telemetrie tlaku

  3. Pokud chcete zobrazit diagnostické informace o zařízení, posuňte se dolů k diagnostice:

    Zobrazení diagnostiky zařízení

Akce na vašem zařízení

K vyvolání metod na vašich zařízeních použijte stránku Průzkumníka zařízení v řešení vzdáleného monitorování. Například v zařízeních Chladič řešení vzdáleného monitorování implementují metodu restartování .

  1. Zvolte Zařízení a přejděte na stránku Průzkumníka zařízení v řešení.

  2. Vyberte zařízení, které jste zřídili v seznamu zařízení na stránce Průzkumník zařízení :

    Výběr skutečného zařízení

  3. Pokud chcete zobrazit seznam metod, které můžete volat na zařízení, zvolte Úlohy a pak Metody. Pokud chcete naplánovat spuštění úlohy na více zařízeních, můžete v seznamu vybrat několik zařízení. Na panelu Úlohy se zobrazují typy běžných metod pro všechna vybraná zařízení.

  4. Zvolte Restartovat, nastavte název úlohy na RebootPhysicalChiller a pak zvolte Použít:

    Naplánování aktualizace firmwaru

  5. Posloupnost zpráv se zobrazí v konzole s kódem zařízení, zatímco simulované zařízení zpracovává metodu.

Poznámka

Pokud chcete sledovat stav úlohy v řešení, zvolte Zobrazit stav úlohy.

Další kroky

Článek Přizpůsobení akcelerátoru řešení vzdáleného monitorování popisuje některé způsoby přizpůsobení akcelerátoru řešení.