Samouczek: tworzenie i łączenie aplikacji klienckiej z aplikacją usługi Azure IoT Central
Ważne
Ten artykuł zawiera kroki łączenia urządzenia przy użyciu sygnatury dostępu współdzielonego, nazywanej również uwierzytelnianiem klucza symetrycznego. Ta metoda uwierzytelniania jest wygodna do testowania i oceny, ale uwierzytelnianie urządzenia przy użyciu certyfikatów X.509 jest bardziej bezpieczne. Aby dowiedzieć się więcej, zobacz Zabezpieczenia najlepszych rozwiązań > zabezpieczeń Zabezpieczenia zabezpieczeń Zabezpieczenia zabezpieczeń.
W tym samouczku pokazano, jak połączyć aplikację kliencką z aplikacją usługi Azure IoT Central. Aplikacja symuluje zachowanie urządzenia kontrolera temperatury. Gdy aplikacja łączy się z usługą IoT Central, wysyła identyfikator modelu urządzenia kontrolera temperatury. Usługa IoT Central używa identyfikatora modelu do pobrania modelu urządzenia i utworzenia szablonu urządzenia. Widoki są dodawane do szablonu urządzenia, aby umożliwić operatorowi interakcję z urządzeniem.
Z tego samouczka dowiesz się, jak wykonywać następujące czynności:
- Utwórz i uruchom kod urządzenia i zobacz, jak nawiązuje połączenie z aplikacją usługi IoT Central.
- Wyświetl symulowane dane telemetryczne wysyłane z urządzenia.
- Dodawanie widoków niestandardowych do szablonu urządzenia.
- Publikowanie szablonu urządzenia.
- Użyj widoku do zarządzania właściwościami urządzenia.
- Wywołaj polecenie , aby kontrolować urządzenie.
Wymagania wstępne
Aby wykonać kroki opisane w tym samouczku, potrzebne są następujące elementy:
Aktywna subskrypcja platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.
Aplikacja usługi IoT Central utworzona na podstawie szablonu aplikacji niestandardowej. Aby dowiedzieć się więcej, zobacz Tworzenie aplikacji usługi IoT Central i Informacje o aplikacji.
Ten samouczek można uruchomić w systemie Linux lub Windows. Polecenia powłoki w tym samouczku są zgodne z konwencją systemu Linux dla separatorów ścieżek "/
", jeśli obserwujesz w systemie Windows, pamiętaj, aby zamienić te separatory na "\
".
Wymagania wstępne różnią się w zależności od systemu operacyjnego:
Linux
W tym samouczku założono, że używasz systemu Ubuntu Linux. Kroki opisane w tym samouczku zostały przetestowane przy użyciu systemu Ubuntu 18.04.
Aby ukończyć ten samouczek w systemie Linux, zainstaluj następujące oprogramowanie w lokalnym środowisku systemu Linux:
Zainstaluj bibliotekę GCC, git, narzędzie cmake i wszystkie wymagane zależności przy użyciu apt-get
polecenia :
sudo apt-get update
sudo apt-get install -y git cmake build-essential curl libcurl4-openssl-dev libssl-dev uuid-dev
Sprawdź, czy wersja biblioteki cmake
jest większa niż 2.8.12 , a wersja GCC jest większa niż 4.4.7.
cmake --version
gcc --version
Windows
Aby ukończyć ten samouczek w systemie Windows, zainstaluj następujące oprogramowanie w lokalnym środowisku systemu Windows:
- Visual Studio (Community, Professional lub Enterprise) — upewnij się, że podczas instalowania programu Visual Studio dołączysz pakiet roboczy Programowanie aplikacji klasycznych z językiem C++.
- Git.
- CMake.
Pobieranie kodu
W tym samouczku przygotujesz środowisko programistyczne, którego można użyć do sklonowania i skompilowania zestawu SDK języka C urządzenia usługi Azure IoT Hub.
Otwórz wiersz polecenia w wybranym katalogu. Wykonaj następujące polecenie, aby sklonować repozytorium GitHub zestawów SDK i bibliotek języka C usługi Azure IoT do tej lokalizacji:
git clone https://github.com/Azure/azure-iot-sdk-c.git
cd azure-iot-sdk-c
git submodule update --init
Spodziewaj się, że wykonanie tej operacji potrwa kilka minut.
Przeglądanie kodu
W kopii pobranego wcześniej zestawu MICROSOFT Azure IoT SDK dla języka C otwórz plik azure-iot-sdk-c/iothub_client/samples/pnp/pnp_temperature_controller/pnp_temperature_controller.c i azure-iot-sdk-c/iothub_client/samples/pnp/pnp_temperature_controller/pnp_thermostat_component.c w edytorze tekstów.
Przykład implementuje model języka cyfrowej reprezentacji bliźniaczej kontrolera temperatury z wieloma składnikami.
Po uruchomieniu przykładu w celu nawiązania połączenia z usługą IoT Central usługa Device Provisioning Service (DPS) służy do rejestrowania urządzenia i generowania parametry połączenia. Przykład pobiera informacje o połączeniu z usługą DPS, których potrzebuje ze środowiska wiersza polecenia.
W pliku pnp_temperature_controller.cmain
funkcja najpierw wywołuje następujące wywołaniaCreateDeviceClientAndAllocateComponents
:
dtmi:com:example:Thermostat;1
Ustaw identyfikator modelu. Usługa IoT Central używa identyfikatora modelu do identyfikowania lub generowania szablonu urządzenia dla tego urządzenia. Aby dowiedzieć się więcej, zobacz Przypisywanie urządzenia do szablonu urządzenia.- Użyj usługi DPS, aby aprowizować i rejestrować urządzenie.
- Utwórz dojście klienta urządzenia i połącz się z aplikacją usługi IoT Central.
- Tworzy procedurę obsługi dla poleceń w składniku kontrolera temperatury.
- Tworzy procedurę obsługi aktualizacji właściwości w składniku kontrolera temperatury.
- Tworzy dwa składniki termostatu.
Następnie main
funkcja:
- Zgłasza niektóre początkowe wartości właściwości dla wszystkich składników.
- Uruchamia pętlę do wysyłania danych telemetrycznych ze wszystkich składników.
Następnie main
funkcja uruchamia wątek do okresowego wysyłania danych telemetrycznych.
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;
}
W pnp_thermostat_component.c
systemie PnP_ThermostatComponent_SendCurrentTemperature
funkcja pokazuje, jak urządzenie wysyła dane telemetryczne temperatury ze składnika do usługi IoT Central:
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);
}
W pnp_thermostat_component.c
systemie PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property
funkcja wysyła aktualizację maxTempSinceLastReboot
właściwości ze składnika do usługi 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);
}
}
W pnp_thermostat_component.c
systemie PnP_ThermostatComponent_ProcessPropertyUpdate
funkcja obsługuje zapisywalne aktualizacje właściwości z usługi 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);
}
}
}
}
W pnp_thermostat_component.c
systemie PnP_ThermostatComponent_ProcessCommand
funkcja obsługuje polecenia wywoływane z usługi IoT Central:
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;
}
}
Kompilowanie kod
Zestaw SDK urządzenia służy do kompilowania dołączonego przykładowego kodu:
Utwórz podkatalog cmake w folderze głównym zestawu SDK urządzenia i przejdź do tego folderu:
cd azure-iot-sdk-c mkdir cmake cd cmake
Uruchom następujące polecenia, aby skompilować zestaw SDK i przykłady:
cmake -Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF .. cmake --build .
Pobieranie informacji o połączeniu
Po uruchomieniu przykładowej aplikacji urządzenia w dalszej części tego samouczka potrzebne są następujące wartości konfiguracji:
- Zakres identyfikatorów: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy połączeń urządzeń. Zanotuj wartość zakresu identyfikatora.
- Klucz podstawowy grupy: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy > połączeń urządzeń SAS-IoT-Devices. Zanotuj wartość klucza podstawowego sygnatury dostępu współdzielonego.
Użyj usługi Azure Cloud Shell, aby wygenerować klucz urządzenia z pobranego klucza podstawowego grupy:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Zanotuj wygenerowany klucz urządzenia. Użyj go w dalszej części tego samouczka.
Uwaga
Aby uruchomić ten przykład, nie musisz wcześniej rejestrować urządzenia w aplikacji usługi IoT Central. W przykładzie użyto funkcji usługi IoT Central do automatycznego rejestrowania urządzeń podczas pierwszego nawiązywania połączenia.
Uruchamianie kodu
Aby uruchomić przykładową aplikację, otwórz środowisko wiersza polecenia i przejdź do folderu azure-iot-sdk-c\cmake.
Ustaw zmienne środowiskowe, aby skonfigurować przykład. Poniższy fragment kodu pokazuje, jak ustawić zmienne środowiskowe w wierszu polecenia systemu Windows. Jeśli używasz powłoki bash, zastąp set
polecenia polecenia export
poleceniami:
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
Aby uruchomić przykład:
# 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
W poniższych danych wyjściowych przedstawiono rejestrowanie urządzenia i nawiązywanie połączenia z usługą IoT Central. Przykład rozpoczyna wysyłanie danych telemetrycznych:
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
Jako operator w aplikacji usługi Azure IoT Central możesz wykonywać następujące czynności:
Wyświetl dane telemetryczne wysyłane przez dwa składniki termostatu na stronie Przegląd :
Wyświetl właściwości urządzenia na stronie Informacje . Na tej stronie przedstawiono właściwości składnika informacji o urządzeniu i dwa składniki termostatu:
Dostosowywanie szablonu urządzenia
Jako deweloper rozwiązań możesz dostosować szablon urządzenia utworzony automatycznie przez usługę IoT Central po nawiązaniu połączenia z urządzeniem kontrolera temperatury.
Aby dodać właściwość w chmurze do przechowywania nazwy klienta skojarzonej z urządzeniem:
W aplikacji usługi IoT Central przejdź do szablonu urządzenia Temperature Controller na stronie Szablony urządzeń.
W modelu Kontrolera temperatury wybierz pozycję +Dodaj możliwość.
Wprowadź nazwę klienta jako nazwę wyświetlaną, wybierz pozycję Właściwość Chmura jako typ możliwości, rozwiń wpis i wybierz pozycję Ciąg jako schemat. Następnie wybierz opcję Zapisz.
Aby dostosować sposób wyświetlania poleceń raportu Get Max-Min w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku polecenia getMaxMinReport (termostat1)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat1).
W przypadku polecenia getMaxMinReport (termostat2)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat2).
Wybierz pozycję Zapisz.
Aby dostosować sposób wyświetlania właściwości zapisywalnych temperatury docelowej w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku parametru targetTemperature (termostat1)zastąp wartość Target Temperature (1).
W przypadku parametru targetTemperature (termostat2)zastąp wartość Target Temperature (2).
Wybierz pozycję Zapisz.
Składniki termostatu w modelu Kontrolera temperatury obejmują właściwość Docelowa temperatura zapisywalna, szablon urządzenia zawiera właściwość chmury Nazwa klienta. Utwórz widok, za pomocą których operator może edytować następujące właściwości:
Wybierz pozycję Widoki , a następnie wybierz kafelek Edytowanie danych urządzenia i chmury.
Wprowadź właściwości jako nazwę formularza.
Wybierz właściwości Temperatura docelowa (1), Temperatura docelowa (2) i Nazwa klienta. Następnie wybierz pozycję Dodaj sekcję.
Zapisz zmiany.
Publikowanie szablonu urządzenia
Zanim operator będzie mógł zobaczyć wprowadzone dostosowania i korzystać z nich, musisz opublikować szablon urządzenia.
W szablonie urządzenia Termostat wybierz pozycję Publikuj. Na panelu Publikowanie tego urządzenia w panelu aplikacji wybierz pozycję Publikuj.
Operator może teraz użyć widoku Właściwości, aby zaktualizować wartości właściwości, i wywołać polecenia o nazwie Pobierz raport o stanie termostat1 i Pobierz raport stanu termostat2 na stronie poleceń urządzenia:
Zaktualizuj wartości właściwości zapisywalnych na stronie Właściwości :
Wywołaj polecenia ze strony Polecenia . Jeśli uruchomisz polecenie raportu o stanie, wybierz datę i godzinę dla parametru Since przed jego uruchomieniem:
Zobaczysz, jak urządzenie reaguje na polecenia i aktualizacje właściwości:
<- 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
Wymagania wstępne
Aby wykonać kroki opisane w tym artykule, potrzebne są następujące zasoby:
Aktywna subskrypcja platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.
Aplikacja usługi IoT Central utworzona na podstawie szablonu aplikacji niestandardowej. Aby dowiedzieć się więcej, zobacz Tworzenie aplikacji usługi IoT Central i Informacje o aplikacji.
Maszyna programistycza z programem Visual Studio (Community, Professional lub Enterprise).
Lokalna kopia repozytorium GitHub zestawu MICROSOFT Azure IoT SDK dla języka C# (.NET), które zawiera przykładowy kod. Użyj tego linku, aby pobrać kopię repozytorium: Pobierz plik ZIP. Następnie rozpakuj plik do odpowiedniej lokalizacji na komputerze lokalnym.
Przeglądanie kodu
W kopii pobranego wcześniej repozytorium zestawu MICROSOFT Azure IoT SDK dla języka C# otwórz plik rozwiązania azure-iot-sdk-csharp-main\azureiot.sln w programie Visual Studio. W Eksplorator rozwiązań rozwiń folder PnpDeviceSamples > TemperatureController i otwórz pliki Program.cs i TemperatureControllerSample.cs, aby wyświetlić kod dla tego przykładu.
Przykład implementuje model języka cyfrowej reprezentacji bliźniaczej kontrolera temperatury z wieloma składnikami.
Po uruchomieniu przykładu w celu nawiązania połączenia z usługą IoT Central usługa Device Provisioning Service (DPS) służy do rejestrowania urządzenia i generowania parametry połączenia. Przykład pobiera informacje o połączeniu z usługą DPS, których potrzebuje ze środowiska.
W Program.csMain
metoda wywołuje następujące wywołaniaSetupDeviceClientAsync
:
- Użyj identyfikatora
dtmi:com:example:TemperatureController;2
modelu, gdy aprowizuje urządzenie z usługą DPS. Usługa IoT Central używa identyfikatora modelu do identyfikowania lub generowania szablonu urządzenia dla tego urządzenia. Aby dowiedzieć się więcej, zobacz Przypisywanie urządzenia do szablonu urządzenia. - Utwórz wystąpienie DeviceClient, aby nawiązać połączenie z usługą 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;
}
Następnie metoda główna tworzy wystąpienie TemperatureControllerSample i wywołuje PerformOperationsAsync
metodę w celu obsługi interakcji z usługą IoT Central.
W TemperatureControllerSample.csPerformOperationsAsync
metoda:
- Ustawia procedurę obsługi dla polecenia ponownego uruchamiania w składniku domyślnym.
- Ustawia programy obsługi dla poleceń getMaxMinReport na dwóch składnikach termostatu.
- Ustawia programy obsługi do odbierania aktualizacji właściwości temperatury docelowej na dwóch składnikach termostatu.
- Wysyła początkowe aktualizacje właściwości informacji o urządzeniu.
- Okresowo wysyła dane telemetryczne temperatury z dwóch składników termostatu.
- Okresowo wysyła dane telemetryczne zestawu roboczego z domyślnego składnika.
- Wysyła maksymalną temperaturę od ostatniego ponownego rozruchu, gdy osiągnięto nową maksymalną temperaturę w dwóch składnikach termostatu.
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);
}
}
Metoda SendTemperatureAsync
pokazuje, jak urządzenie wysyła dane telemetryczne temperatury ze składnika do usługi IoT Central. Metoda SendTemperatureTelemetryAsync
używa PnpConvention
klasy do skompilowania komunikatu:
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 },
});
}
}
Metoda UpdateMaxTemperatureSinceLastRebootAsync
wysyła aktualizację maxTempSinceLastReboot
właściwości do usługi IoT Central. Ta metoda używa PnpConvention
klasy do utworzenia poprawki:
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);
}
Metoda TargetTemperatureUpdateCallbackAsync
obsługuje zapisywalną docelową aktualizację właściwości temperatury z usługi IoT Central. Ta metoda używa PnpConvention
klasy do odczytywania komunikatu aktualizacji właściwości i konstruowania odpowiedzi:
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);
}
Metoda HandleMaxMinReportCommand
obsługuje polecenia dla składników wywoływanych z usługi IoT Central:
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)
{
// ...
}
}
Pobieranie informacji o połączeniu
Po uruchomieniu przykładowej aplikacji urządzenia w dalszej części tego samouczka potrzebne są następujące wartości konfiguracji:
- Zakres identyfikatorów: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy połączeń urządzeń. Zanotuj wartość zakresu identyfikatora.
- Klucz podstawowy grupy: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy > połączeń urządzeń SAS-IoT-Devices. Zanotuj wartość klucza podstawowego sygnatury dostępu współdzielonego.
Użyj usługi Azure Cloud Shell, aby wygenerować klucz urządzenia z pobranego klucza podstawowego grupy:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Zanotuj wygenerowany klucz urządzenia. Użyj go w dalszej części tego samouczka.
Uwaga
Aby uruchomić ten przykład, nie musisz wcześniej rejestrować urządzenia w aplikacji usługi IoT Central. W przykładzie użyto funkcji usługi IoT Central do automatycznego rejestrowania urządzeń podczas pierwszego nawiązywania połączenia.
Uruchamianie kodu
Uwaga
Skonfiguruj aplikację TemperatureController jako projekt startowy przed uruchomieniem kodu.
Aby uruchomić przykładową aplikację w programie Visual Studio:
W Eksplorator rozwiązań wybierz plik projektu PnpDeviceSamples > TemperatureController.
Przejdź do pozycji Project TemperatureController Properties Debug (Debugowanie właściwości > projektu > TemperatureController). Następnie dodaj następujące zmienne środowiskowe do projektu:
Nazwa/nazwisko Wartość IOTHUB_DEVICE_SECURITY_TYPE DPS IOTHUB_DEVICE_DPS_ENDPOINT global.azure-devices-provisioning.net IOTHUB_DEVICE_DPS_ID_SCOPE Wartość zakresu identyfikatora zanotowana wcześniej. IOTHUB_DEVICE_DPS_DEVICE_ID sample-device-01 IOTHUB_DEVICE_DPS_DEVICE_KEY Wygenerowana wartość klucza urządzenia zanotowana wcześniej.
Teraz możesz uruchomić i debugować przykład w programie Visual Studio.
W poniższych danych wyjściowych przedstawiono rejestrowanie urządzenia i nawiązywanie połączenia z usługą IoT Central. Przykład rozpoczyna wysyłanie danych telemetrycznych:
[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.
Jako operator w aplikacji usługi Azure IoT Central możesz wykonywać następujące czynności:
Wyświetl dane telemetryczne wysyłane przez dwa składniki termostatu na stronie Przegląd :
Wyświetl właściwości urządzenia na stronie Informacje . Na tej stronie przedstawiono właściwości składnika informacji o urządzeniu i dwa składniki termostatu:
Dostosowywanie szablonu urządzenia
Jako deweloper rozwiązań możesz dostosować szablon urządzenia utworzony automatycznie przez usługę IoT Central po nawiązaniu połączenia z urządzeniem kontrolera temperatury.
Aby dodać właściwość w chmurze do przechowywania nazwy klienta skojarzonej z urządzeniem:
W aplikacji usługi IoT Central przejdź do szablonu urządzenia Temperature Controller na stronie Szablony urządzeń.
W modelu Kontrolera temperatury wybierz pozycję +Dodaj możliwość.
Wprowadź nazwę klienta jako nazwę wyświetlaną, wybierz pozycję Właściwość Chmura jako typ możliwości, rozwiń wpis i wybierz pozycję Ciąg jako schemat. Następnie wybierz opcję Zapisz.
Aby dostosować sposób wyświetlania poleceń raportu Get Max-Min w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku polecenia getMaxMinReport (termostat1)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat1).
W przypadku polecenia getMaxMinReport (termostat2)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat2).
Wybierz pozycję Zapisz.
Aby dostosować sposób wyświetlania właściwości zapisywalnych temperatury docelowej w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku parametru targetTemperature (termostat1)zastąp wartość Target Temperature (1).
W przypadku parametru targetTemperature (termostat2)zastąp wartość Target Temperature (2).
Wybierz pozycję Zapisz.
Składniki termostatu w modelu Kontrolera temperatury obejmują właściwość Docelowa temperatura zapisywalna, szablon urządzenia zawiera właściwość chmury Nazwa klienta. Utwórz widok, za pomocą których operator może edytować następujące właściwości:
Wybierz pozycję Widoki , a następnie wybierz kafelek Edytowanie danych urządzenia i chmury.
Wprowadź właściwości jako nazwę formularza.
Wybierz właściwości Temperatura docelowa (1), Temperatura docelowa (2) i Nazwa klienta. Następnie wybierz pozycję Dodaj sekcję.
Zapisz zmiany.
Publikowanie szablonu urządzenia
Zanim operator będzie mógł zobaczyć wprowadzone dostosowania i korzystać z nich, musisz opublikować szablon urządzenia.
W szablonie urządzenia Termostat wybierz pozycję Publikuj. Na panelu Publikowanie tego urządzenia w panelu aplikacji wybierz pozycję Publikuj.
Operator może teraz użyć widoku Właściwości, aby zaktualizować wartości właściwości, i wywołać polecenia o nazwie Pobierz raport o stanie termostat1 i Pobierz raport stanu termostat2 na stronie poleceń urządzenia:
Zaktualizuj wartości właściwości zapisywalnych na stronie Właściwości :
Wywołaj polecenia ze strony Polecenia . Jeśli uruchomisz polecenie raportu o stanie, wybierz datę i godzinę dla parametru Since przed jego uruchomieniem:
Zobaczysz, jak urządzenie reaguje na polecenia i aktualizacje właściwości:
[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.
Wymagania wstępne
Aby wykonać kroki opisane w tym artykule, potrzebne są następujące zasoby:
Aktywna subskrypcja platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.
Aplikacja usługi IoT Central utworzona na podstawie szablonu aplikacji niestandardowej. Aby dowiedzieć się więcej, zobacz Tworzenie aplikacji usługi IoT Central i Informacje o aplikacji.
Maszyna programistyczna z zestawem Java SE Development Kit 8 lub nowszym. Aby uzyskać więcej informacji, zobacz Instalowanie zestawu JDK.
Lokalna kopia repozytorium GitHub zestawu Microsoft Azure IoT SDK for Java , które zawiera przykładowy kod. Użyj tego linku, aby pobrać kopię repozytorium: Pobierz plik ZIP. Następnie rozpakuj plik do odpowiedniej lokalizacji na komputerze lokalnym.
Przeglądanie kodu
W kopii pobranego wcześniej zestawu SDK usługi Microsoft Azure IoT dla języka Java otwórz plik 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 w edytorze tekstów.
Przykład implementuje model języka cyfrowej reprezentacji bliźniaczej kontrolera temperatury z wieloma składnikami.
Po uruchomieniu przykładu w celu nawiązania połączenia z usługą IoT Central usługa Device Provisioning Service (DPS) służy do rejestrowania urządzenia i generowania parametry połączenia. Przykład pobiera informacje o połączeniu z usługą DPS, których potrzebuje ze środowiska wiersza polecenia.
Metoda main
:
- Wywołania
initializeAndProvisionDevice
ustawiania identyfikatoradtmi:com:example:TemperatureController;2
modelu, aprowizowania i rejestrowania urządzenia przy użyciu usługi DPS, tworzenia wystąpienia DeviceClient i nawiązywania połączenia z aplikacją usługi IoT Central. Usługa IoT Central używa identyfikatora modelu do identyfikowania lub generowania szablonu urządzenia dla tego urządzenia. Aby dowiedzieć się więcej, zobacz Przypisywanie urządzenia do szablonu urządzenia. - Tworzy programy obsługi poleceń dla
getMaxMinReport
poleceń ireboot
. - Tworzy programy obsługi aktualizacji właściwości dla właściwości zapisywalnych
targetTemperature
. - Wysyła początkowe wartości właściwości w interfejsie informacje o urządzeniu oraz właściwości Pamięć urządzenia i Numer seryjny.
- Uruchamia wątek, aby wysyłać dane telemetryczne temperatury z dwóch termostatów i aktualizować
maxTempSinceLastReboot
właściwość co pięć sekund.
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();
}
Metoda initializeAndProvisionDevice
pokazuje, jak urządzenie używa usługi DPS do rejestrowania i nawiązywania połączenia z usługą IoT Central. Ładunek zawiera identyfikator modelu używany przez usługę IoT Central do przypisywania urządzenia do szablonu urządzenia:
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);
}
}
Metoda sendTemperatureTelemetry
pokazuje, jak urządzenie wysyła dane telemetryczne temperatury ze składnika do usługi IoT Central. Ta metoda używa PnpConvention
klasy do utworzenia komunikatu:
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);
}
Metoda updateMaxTemperatureSinceLastReboot
wysyła aktualizację maxTempSinceLastReboot
właściwości ze składnika do usługi IoT Central. Ta metoda używa PnpConvention
klasy do utworzenia poprawki:
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);
}
Klasa TargetTemperatureUpdateCallback
zawiera metodę onPropertyChanged
do obsługi aktualizacji właściwości zapisywalnych do składnika z usługi IoT Central. Ta metoda używa PnpConvention
klasy do utworzenia odpowiedzi:
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.");
}
}
}
Klasa MethodCallback
zawiera metodę onMethodInvoked
obsługi poleceń składników wywoływanych z usługi IoT Central:
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);
}
}
}
Pobieranie informacji o połączeniu
Po uruchomieniu przykładowej aplikacji urządzenia w dalszej części tego samouczka potrzebne są następujące wartości konfiguracji:
- Zakres identyfikatorów: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy połączeń urządzeń. Zanotuj wartość zakresu identyfikatora.
- Klucz podstawowy grupy: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy > połączeń urządzeń SAS-IoT-Devices. Zanotuj wartość klucza podstawowego sygnatury dostępu współdzielonego.
Użyj usługi Azure Cloud Shell, aby wygenerować klucz urządzenia z pobranego klucza podstawowego grupy:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Zanotuj wygenerowany klucz urządzenia. Użyj go w dalszej części tego samouczka.
Uwaga
Aby uruchomić ten przykład, nie musisz wcześniej rejestrować urządzenia w aplikacji usługi IoT Central. W przykładzie użyto funkcji usługi IoT Central do automatycznego rejestrowania urządzeń podczas pierwszego nawiązywania połączenia.
W systemie Windows przejdź do folderu głównego pobranego repozytorium Zestawu SDK usługi Azure IoT dla języka Java.
Uruchom następujące polecenie, aby skompilować przykładową aplikację:
mvn install -T 2C -DskipTests
Uruchamianie kodu
Aby uruchomić przykładową aplikację, otwórz środowisko wiersza polecenia i przejdź do folderu azure-iot-sdk-java/iothub/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample , który zawiera folder src z przykładowym plikiem TemperatureController.java .
Ustaw zmienne środowiskowe, aby skonfigurować przykład. Poniższy fragment kodu pokazuje, jak ustawić zmienne środowiskowe w wierszu polecenia systemu Windows. Jeśli używasz powłoki bash, zastąp set
polecenia polecenia export
poleceniami:
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
Uruchom przykład:
mvn exec:java -Dexec.mainClass="samples.com.microsoft.azure.sdk.iot.device.TemperatureController"
W poniższych danych wyjściowych przedstawiono rejestrowanie urządzenia i nawiązywanie połączenia z usługą IoT Central. Przykład rozpoczyna wysyłanie danych telemetrycznych:
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 [aaaa0000-bb11-2222-33cc-444444dddddd] Message Id [bbbb1111-cc22-3333-44dd-555555eeeeee] 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 [aaaa0000-bb11-2222-33cc-444444dddddd] Message Id [bbbb1111-cc22-3333-44dd-555555eeeeee] 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 [cccc2222-dd33-4444-55ee-666666ffffff] Message Id [dddd3333-ee44-5555-66ff-777777aaaaaa] 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 [eeee4444-ff55-6666-77aa-888888bbbbbb] Message Id [ffff5555-aa66-7777-88bb-999999cccccc] 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 [aaaa6666-bb77-8888-99cc-000000dddddd] Message Id [aaaa0000-bb11-2222-33cc-444444dddddd] 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 [cccc2222-dd33-4444-55ee-666666ffffff] Message Id [dddd3333-ee44-5555-66ff-777777aaaaaa] 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 [bbbb1111-cc22-3333-44dd-555555eeeeee] Message Id [cccc2222-dd33-4444-55ee-666666ffffff] 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 [dddd3333-ee44-5555-66ff-777777aaaaaa] Message Id [eeee4444-ff55-6666-77aa-888888bbbbbb] )
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 [ffff5555-aa66-7777-88bb-999999cccccc] Message Id [aaaa6666-bb77-8888-99cc-000000dddddd] 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 [aaaa0000-bb11-2222-33cc-444444dddddd] Message Id [bbbb1111-cc22-3333-44dd-555555eeeeee] )
2021-03-30 15:33:44.927 DEBUG TemperatureController:461 - Telemetry: Sent - {"temperature": 5.8°C} with message Id bbbb1111-cc22-3333-44dd-555555eeeeee.
Jako operator w aplikacji usługi Azure IoT Central możesz wykonywać następujące czynności:
Wyświetl dane telemetryczne wysyłane przez dwa składniki termostatu na stronie Przegląd :
Wyświetl właściwości urządzenia na stronie Informacje . Na tej stronie przedstawiono właściwości składnika informacji o urządzeniu i dwa składniki termostatu:
Dostosowywanie szablonu urządzenia
Jako deweloper rozwiązań możesz dostosować szablon urządzenia utworzony automatycznie przez usługę IoT Central po nawiązaniu połączenia z urządzeniem kontrolera temperatury.
Aby dodać właściwość w chmurze do przechowywania nazwy klienta skojarzonej z urządzeniem:
W aplikacji usługi IoT Central przejdź do szablonu urządzenia Temperature Controller na stronie Szablony urządzeń.
W modelu Kontrolera temperatury wybierz pozycję +Dodaj możliwość.
Wprowadź nazwę klienta jako nazwę wyświetlaną, wybierz pozycję Właściwość Chmura jako typ możliwości, rozwiń wpis i wybierz pozycję Ciąg jako schemat. Następnie wybierz opcję Zapisz.
Aby dostosować sposób wyświetlania poleceń raportu Get Max-Min w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku polecenia getMaxMinReport (termostat1)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat1).
W przypadku polecenia getMaxMinReport (termostat2)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat2).
Wybierz pozycję Zapisz.
Aby dostosować sposób wyświetlania właściwości zapisywalnych temperatury docelowej w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku parametru targetTemperature (termostat1)zastąp wartość Target Temperature (1).
W przypadku parametru targetTemperature (termostat2)zastąp wartość Target Temperature (2).
Wybierz pozycję Zapisz.
Składniki termostatu w modelu Kontrolera temperatury obejmują właściwość Docelowa temperatura zapisywalna, szablon urządzenia zawiera właściwość chmury Nazwa klienta. Utwórz widok, za pomocą których operator może edytować następujące właściwości:
Wybierz pozycję Widoki , a następnie wybierz kafelek Edytowanie danych urządzenia i chmury.
Wprowadź właściwości jako nazwę formularza.
Wybierz właściwości Temperatura docelowa (1), Temperatura docelowa (2) i Nazwa klienta. Następnie wybierz pozycję Dodaj sekcję.
Zapisz zmiany.
Publikowanie szablonu urządzenia
Zanim operator będzie mógł zobaczyć wprowadzone dostosowania i korzystać z nich, musisz opublikować szablon urządzenia.
W szablonie urządzenia Termostat wybierz pozycję Publikuj. Na panelu Publikowanie tego urządzenia w panelu aplikacji wybierz pozycję Publikuj.
Operator może teraz użyć widoku Właściwości, aby zaktualizować wartości właściwości, i wywołać polecenia o nazwie Pobierz raport o stanie termostat1 i Pobierz raport stanu termostat2 na stronie poleceń urządzenia:
Zaktualizuj wartości właściwości zapisywalnych na stronie Właściwości :
Wywołaj polecenia ze strony Polecenia . Jeśli uruchomisz polecenie raportu o stanie, wybierz datę i godzinę dla parametru Since przed jego uruchomieniem:
Zobaczysz, jak urządzenie reaguje na polecenia i aktualizacje właściwości:
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
Wymagania wstępne
Aby wykonać kroki opisane w tym artykule, potrzebne są następujące zasoby:
Aktywna subskrypcja platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.
Aplikacja usługi IoT Central utworzona na podstawie szablonu aplikacji niestandardowej. Aby dowiedzieć się więcej, zobacz Tworzenie aplikacji usługi IoT Central i Informacje o aplikacji.
Maszyna programistyczna z zainstalowaną Node.js w wersji 6 lub nowszej. Możesz uruchomić
node --version
polecenie w wierszu polecenia, aby sprawdzić swoją wersję. W instrukcjach w tym samouczku założono, że uruchamiasz polecenie node w wierszu polecenia systemu Windows. Można jednak użyć Node.js w wielu innych systemach operacyjnych.Lokalna kopia zestawu MICROSOFT Azure IoT SDK dla Node.js repozytorium GitHub, które zawiera przykładowy kod. Użyj tego linku, aby pobrać kopię repozytorium: Pobierz plik ZIP. Następnie rozpakuj plik do odpowiedniej lokalizacji na komputerze lokalnym.
Przeglądanie kodu
W kopii zestawu Microsoft Azure IoT SDK dla Node.js pobranego wcześniej otwórz plik azure-iot-sdk-node/device/samples/javascript/pnp_temperature_controller.js w edytorze tekstów.
Przykład implementuje model języka cyfrowej reprezentacji bliźniaczej kontrolera temperatury z wieloma składnikami.
Po uruchomieniu przykładu w celu nawiązania połączenia z usługą IoT Central usługa Device Provisioning Service (DPS) służy do rejestrowania urządzenia i generowania parametry połączenia. Przykład pobiera informacje o połączeniu z usługą DPS, których potrzebuje ze środowiska wiersza polecenia.
Metoda main
:
client
Tworzy obiekt i ustawiadtmi:com:example:TemperatureController;2
identyfikator modelu przed otwarciem połączenia. Usługa IoT Central używa identyfikatora modelu do identyfikowania lub generowania szablonu urządzenia dla tego urządzenia. Aby dowiedzieć się więcej, zobacz Przypisywanie urządzenia do szablonu urządzenia.- Tworzy programy obsługi poleceń dla trzech poleceń.
- Uruchamia pętlę dla każdego składnika termostatu w celu wysyłania danych telemetrycznych temperatury co 5 sekund.
- Uruchamia pętlę dla domyślnego składnika do wysyłania telemetrii rozmiaru zestawu roboczego co 6 sekund.
maxTempSinceLastReboot
Wysyła właściwość dla każdego składnika termostatu.- Wysyła właściwości informacji o urządzeniu.
- Tworzy programy obsługi właściwości zapisywalnych dla trzech składników.
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());
}
}
Funkcja provisionDevice
pokazuje, jak urządzenie używa usługi DPS do rejestrowania i nawiązywania połączenia z usługą IoT Central. Ładunek zawiera identyfikator modelu używany przez usługę IoT Central do przypisywania urządzenia do szablonu urządzenia:
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());
}
}
Funkcja sendTelemetry
pokazuje, jak urządzenie wysyła dane telemetryczne temperatury do usługi IoT Central. W przypadku telemetrii ze składników dodaje właściwość o nazwie $.sub
o nazwie składnika:
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);
}
Metoda main
używa metody pomocniczej o nazwie helperCreateReportedPropertiesPatch
, aby utworzyć komunikaty aktualizacji właściwości. Ta metoda przyjmuje opcjonalny parametr, aby określić składnik wysyłający właściwość:
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;
};
Metoda main
używa następującej metody do obsługi aktualizacji do zapisywalnych właściwości z usługi IoT Central. Zwróć uwagę, że metoda kompiluje odpowiedź przy użyciu kodu wersji i stanu:
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);
}
});
});
};
Metoda main
używa następujących metod do obsługi poleceń z usługi IoT Central:
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());
}
};
Pobieranie informacji o połączeniu
Po uruchomieniu przykładowej aplikacji urządzenia w dalszej części tego samouczka potrzebne są następujące wartości konfiguracji:
- Zakres identyfikatorów: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy połączeń urządzeń. Zanotuj wartość zakresu identyfikatora.
- Klucz podstawowy grupy: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy > połączeń urządzeń SAS-IoT-Devices. Zanotuj wartość klucza podstawowego sygnatury dostępu współdzielonego.
Użyj usługi Azure Cloud Shell, aby wygenerować klucz urządzenia z pobranego klucza podstawowego grupy:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Zanotuj wygenerowany klucz urządzenia. Użyj go w dalszej części tego samouczka.
Uwaga
Aby uruchomić ten przykład, nie musisz wcześniej rejestrować urządzenia w aplikacji usługi IoT Central. W przykładzie użyto funkcji usługi IoT Central do automatycznego rejestrowania urządzeń podczas pierwszego nawiązywania połączenia.
Uruchamianie kodu
Aby uruchomić przykładową aplikację, otwórz środowisko wiersza polecenia i przejdź do folderu azure-iot-sdk-node/device/samples/javascript zawierającego przykładowy plik pnp_temperature_controller.js .
Ustaw zmienne środowiskowe, aby skonfigurować przykład. Poniższy fragment kodu pokazuje, jak ustawić zmienne środowiskowe w wierszu polecenia systemu Windows. Jeśli używasz powłoki bash, zastąp set
polecenia polecenia export
poleceniami:
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
Zainstaluj wymagane pakiety:
npm install
Uruchom przykład:
node pnp_temperature_controller.js
W poniższych danych wyjściowych przedstawiono rejestrowanie urządzenia i nawiązywanie połączenia z usługą IoT Central. Następnie próbka maxTempSinceLastReboot
wysyła właściwość z dwóch składników termostatu przed rozpoczęciem wysyłania danych telemetrycznych:
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
Jako operator w aplikacji usługi Azure IoT Central możesz wykonywać następujące czynności:
Wyświetl dane telemetryczne wysyłane przez dwa składniki termostatu na stronie Przegląd :
Wyświetl właściwości urządzenia na stronie Informacje . Na tej stronie przedstawiono właściwości składnika informacji o urządzeniu i dwa składniki termostatu:
Dostosowywanie szablonu urządzenia
Jako deweloper rozwiązań możesz dostosować szablon urządzenia utworzony automatycznie przez usługę IoT Central po nawiązaniu połączenia z urządzeniem kontrolera temperatury.
Aby dodać właściwość w chmurze do przechowywania nazwy klienta skojarzonej z urządzeniem:
W aplikacji usługi IoT Central przejdź do szablonu urządzenia Temperature Controller na stronie Szablony urządzeń.
W modelu Kontrolera temperatury wybierz pozycję +Dodaj możliwość.
Wprowadź nazwę klienta jako nazwę wyświetlaną, wybierz pozycję Właściwość Chmura jako typ możliwości, rozwiń wpis i wybierz pozycję Ciąg jako schemat. Następnie wybierz opcję Zapisz.
Aby dostosować sposób wyświetlania poleceń raportu Get Max-Min w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku polecenia getMaxMinReport (termostat1)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat1).
W przypadku polecenia getMaxMinReport (termostat2)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat2).
Wybierz pozycję Zapisz.
Aby dostosować sposób wyświetlania właściwości zapisywalnych temperatury docelowej w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku parametru targetTemperature (termostat1)zastąp wartość Target Temperature (1).
W przypadku parametru targetTemperature (termostat2)zastąp wartość Target Temperature (2).
Wybierz pozycję Zapisz.
Składniki termostatu w modelu Kontrolera temperatury obejmują właściwość Docelowa temperatura zapisywalna, szablon urządzenia zawiera właściwość chmury Nazwa klienta. Utwórz widok, za pomocą których operator może edytować następujące właściwości:
Wybierz pozycję Widoki , a następnie wybierz kafelek Edytowanie danych urządzenia i chmury.
Wprowadź właściwości jako nazwę formularza.
Wybierz właściwości Temperatura docelowa (1), Temperatura docelowa (2) i Nazwa klienta. Następnie wybierz pozycję Dodaj sekcję.
Zapisz zmiany.
Publikowanie szablonu urządzenia
Zanim operator będzie mógł zobaczyć wprowadzone dostosowania i korzystać z nich, musisz opublikować szablon urządzenia.
W szablonie urządzenia Termostat wybierz pozycję Publikuj. Na panelu Publikowanie tego urządzenia w panelu aplikacji wybierz pozycję Publikuj.
Operator może teraz użyć widoku Właściwości, aby zaktualizować wartości właściwości, i wywołać polecenia o nazwie Pobierz raport o stanie termostat1 i Pobierz raport stanu termostat2 na stronie poleceń urządzenia:
Zaktualizuj wartości właściwości zapisywalnych na stronie Właściwości :
Wywołaj polecenia ze strony Polecenia . Jeśli uruchomisz polecenie raportu o stanie, wybierz datę i godzinę dla parametru Since przed jego uruchomieniem:
Zobaczysz, jak urządzenie reaguje na polecenia i aktualizacje właściwości. Polecenie znajduje się w składniku. reboot
Polecenie getMaxMinReport
znajduje się w składniku thermostat2
domyślnym. Właściwość targetTemperature
zapisywalna została ustawiona thermostat2
dla składnika:
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
Wymagania wstępne
Aby wykonać kroki opisane w tym artykule, potrzebne są następujące zasoby:
Aktywna subskrypcja platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.
Aplikacja usługi IoT Central utworzona na podstawie szablonu aplikacji niestandardowej. Aby dowiedzieć się więcej, zobacz Tworzenie aplikacji usługi IoT Central i Informacje o aplikacji.
Maszyna dewelopera z zainstalowanym językiem Python . Zapoznaj się z zestawem SDK języka Python usługi Azure IoT, aby zapoznać się z bieżącymi wymaganiami dotyczącymi wersji języka Python. Możesz uruchomić polecenie
python --version
w wierszu polecenia, aby sprawdzić swoją wersję. Język Python jest dostępny dla wielu różnych systemów operacyjnych. W instrukcjach w tym samouczku założono, że uruchamiasz polecenie języka Python w wierszu polecenia systemu Windows.Lokalna kopia repozytorium GitHub zestawu MICROSOFT Azure IoT SDK dla języka Python , które zawiera przykładowy kod. Użyj tego linku, aby pobrać kopię repozytorium: Pobierz plik ZIP. Następnie rozpakuj plik do odpowiedniej lokalizacji na komputerze lokalnym.
Przeglądanie kodu
W kopii pobranego wcześniej zestawu MICROSOFT Azure IoT SDK dla języka Python otwórz plik azure-iot-sdk-python/samples/pnp/temp_controller_with_thermostats.py w edytorze tekstów.
Przykład implementuje model języka cyfrowej reprezentacji bliźniaczej kontrolera temperatury z wieloma składnikami.
Po uruchomieniu przykładu w celu nawiązania połączenia z usługą IoT Central usługa Device Provisioning Service (DPS) służy do rejestrowania urządzenia i generowania parametry połączenia. Przykład pobiera informacje o połączeniu z usługą DPS, których potrzebuje ze środowiska wiersza polecenia.
Funkcja main
:
- Używa usługi DPS do aprowizowania urządzenia. Informacje o aprowizacji zawierają identyfikator modelu. Usługa IoT Central używa identyfikatora modelu do identyfikowania lub generowania szablonu urządzenia dla tego urządzenia. Aby dowiedzieć się więcej, zobacz Przypisywanie urządzenia do szablonu urządzenia.
Device_client
Tworzy obiekt i ustawiadtmi:com:example:TemperatureController;2
identyfikator modelu przed otwarciem połączenia.- Wysyła początkowe wartości właściwości do usługi IoT Central. Używa elementu ,
pnp_helper
aby utworzyć poprawki. - Tworzy odbiorniki dla
getMaxMinReport
poleceń ireboot
. Każdy składnik termostatu ma własnegetMaxMinReport
polecenie. - Tworzy odbiornik właściwości, aby nasłuchiwać aktualizacji właściwości zapisywalnych.
- Uruchamia pętlę w celu wysyłania danych telemetrycznych temperatury z dwóch składników termostatu i telemetrii zestawu roboczego z domyślnego składnika co 8 sekund.
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())
# ...
Funkcja provision_device
używa usługi DPS do aprowizowania urządzenia i rejestrowania go w usłudze IoT Central. Funkcja zawiera identyfikator modelu urządzenia, którego usługa IoT Central używa do przypisania urządzenia do szablonu urządzenia w ładunku aprowizacji:
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()
Funkcja execute_command_listener
obsługuje żądania poleceń, uruchamia max_min_handler
funkcję, gdy urządzenie odbiera getMaxMinReport
polecenie dla składników termostatu i reboot_handler
funkcję, gdy urządzenie otrzymuje reboot
polecenie. Używa modułu pnp_helper
do skompilowania odpowiedzi:
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))
Obsługuje async def execute_property_listener
zapisywalne aktualizacje właściwości, takie jak targetTemperature
dla składników termostatu i generuje odpowiedź JSON. Używa modułu pnp_helper
do skompilowania odpowiedzi:
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)
Funkcja send_telemetry_from_temp_controller
wysyła komunikaty telemetryczne ze składników termostatu do usługi IoT Central. Używa modułu pnp_helper
do kompilowania komunikatów:
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)
Pobieranie informacji o połączeniu
Po uruchomieniu przykładowej aplikacji urządzenia w dalszej części tego samouczka potrzebne są następujące wartości konfiguracji:
- Zakres identyfikatorów: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy połączeń urządzeń. Zanotuj wartość zakresu identyfikatora.
- Klucz podstawowy grupy: w aplikacji usługi IoT Central przejdź do pozycji Uprawnienia > Grupy > połączeń urządzeń SAS-IoT-Devices. Zanotuj wartość klucza podstawowego sygnatury dostępu współdzielonego.
Użyj usługi Azure Cloud Shell, aby wygenerować klucz urządzenia z pobranego klucza podstawowego grupy:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Zanotuj wygenerowany klucz urządzenia. Użyj go w dalszej części tego samouczka.
Uwaga
Aby uruchomić ten przykład, nie musisz wcześniej rejestrować urządzenia w aplikacji usługi IoT Central. W przykładzie użyto funkcji usługi IoT Central do automatycznego rejestrowania urządzeń podczas pierwszego nawiązywania połączenia.
Uruchamianie kodu
Aby uruchomić przykładową aplikację, otwórz środowisko wiersza polecenia i przejdź do folderu azure-iot-sdk-python-2/samples/pnp zawierającego przykładowy plik temp_controller_with_thermostats.py.
Ustaw zmienne środowiskowe, aby skonfigurować przykład. Poniższy fragment kodu pokazuje, jak ustawić zmienne środowiskowe w wierszu polecenia systemu Windows. Jeśli używasz powłoki bash, zastąp set
polecenia polecenia export
poleceniami:
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
Zainstaluj wymagane pakiety:
pip install azure-iot-device
Uruchom przykład:
python temp_controller_with_thermostats.py
W poniższych danych wyjściowych przedstawiono rejestrowanie urządzenia i nawiązywanie połączenia z usługą IoT Central. Przykład wysyła maxTempSinceLastReboot
właściwości z dwóch składników termostatu przed rozpoczęciem wysyłania danych telemetrycznych:
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}
Jako operator w aplikacji usługi Azure IoT Central możesz wykonywać następujące czynności:
Wyświetl dane telemetryczne wysyłane przez dwa składniki termostatu na stronie Przegląd :
Wyświetl właściwości urządzenia na stronie Informacje . Na tej stronie przedstawiono właściwości składnika informacji o urządzeniu i dwa składniki termostatu:
Dostosowywanie szablonu urządzenia
Jako deweloper rozwiązań możesz dostosować szablon urządzenia utworzony automatycznie przez usługę IoT Central po nawiązaniu połączenia z urządzeniem kontrolera temperatury.
Aby dodać właściwość w chmurze do przechowywania nazwy klienta skojarzonej z urządzeniem:
W aplikacji usługi IoT Central przejdź do szablonu urządzenia Temperature Controller na stronie Szablony urządzeń.
W modelu Kontrolera temperatury wybierz pozycję +Dodaj możliwość.
Wprowadź nazwę klienta jako nazwę wyświetlaną, wybierz pozycję Właściwość Chmura jako typ możliwości, rozwiń wpis i wybierz pozycję Ciąg jako schemat. Następnie wybierz opcję Zapisz.
Aby dostosować sposób wyświetlania poleceń raportu Get Max-Min w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku polecenia getMaxMinReport (termostat1)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat1).
W przypadku polecenia getMaxMinReport (termostat2)zastąp ciąg Get Max-Min report (Pobierz raport o stanie termostat2).
Wybierz pozycję Zapisz.
Aby dostosować sposób wyświetlania właściwości zapisywalnych temperatury docelowej w aplikacji usługi IoT Central:
Przejdź do szablonu urządzenia Kontroler temperatury na stronie Szablony urządzeń.
W przypadku parametru targetTemperature (termostat1)zastąp wartość Target Temperature (1).
W przypadku parametru targetTemperature (termostat2)zastąp wartość Target Temperature (2).
Wybierz pozycję Zapisz.
Składniki termostatu w modelu Kontrolera temperatury obejmują właściwość Docelowa temperatura zapisywalna, szablon urządzenia zawiera właściwość chmury Nazwa klienta. Utwórz widok, za pomocą których operator może edytować następujące właściwości:
Wybierz pozycję Widoki , a następnie wybierz kafelek Edytowanie danych urządzenia i chmury.
Wprowadź właściwości jako nazwę formularza.
Wybierz właściwości Temperatura docelowa (1), Temperatura docelowa (2) i Nazwa klienta. Następnie wybierz pozycję Dodaj sekcję.
Zapisz zmiany.
Publikowanie szablonu urządzenia
Zanim operator będzie mógł zobaczyć wprowadzone dostosowania i korzystać z nich, musisz opublikować szablon urządzenia.
W szablonie urządzenia Termostat wybierz pozycję Publikuj. Na panelu Publikowanie tego urządzenia w panelu aplikacji wybierz pozycję Publikuj.
Operator może teraz użyć widoku Właściwości, aby zaktualizować wartości właściwości, i wywołać polecenia o nazwie Pobierz raport o stanie termostat1 i Pobierz raport stanu termostat2 na stronie poleceń urządzenia:
Zaktualizuj wartości właściwości zapisywalnych na stronie Właściwości :
Wywołaj polecenia ze strony Polecenia . Jeśli uruchomisz polecenie raportu o stanie, wybierz datę i godzinę dla parametru Since przed jego uruchomieniem:
Zobaczysz, jak urządzenie reaguje na polecenia i aktualizacje właściwości:
{'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"}
Wyświetlanie danych pierwotnych
Widok Nieprzetworzonych danych umożliwia sprawdzenie danych pierwotnych wysyłanych przez urządzenie do usługi IoT Central:
W tym widoku możesz wybrać kolumny do wyświetlenia i ustawić zakres czasu do wyświetlenia. W kolumnie Dane niemodelowane są wyświetlane dane urządzenia, które nie są zgodne z żadną definicją właściwości ani telemetrii w szablonie urządzenia.
Czyszczenie zasobów
Jeśli nie planujesz ukończenia dalszych przewodników Szybki start lub samouczków usługi IoT Central, możesz usunąć aplikację usługi IoT Central:
- W aplikacji usługi IoT Central przejdź do obszaru Zarządzanie aplikacjami>.
- Wybierz pozycję Usuń , a następnie potwierdź akcję.
Następne kroki
Jeśli wolisz kontynuować korzystanie z zestawu samouczków usługi IoT Central i dowiedzieć się więcej o tworzeniu rozwiązania usługi IoT Central, zobacz: