Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Importante
Este artigo inclui etapas para conectar um dispositivo usando uma assinatura de acesso compartilhado, também chamada de autenticação de chave simétrica. Esse método de autenticação é conveniente para testes e avaliações, mas autenticar um dispositivo usando certificados X.509 é uma abordagem mais segura. Para saber mais, consulte Práticas recomendadas de segurança para soluções > IoT Segurança de conexão.
Este tutorial mostra como conectar um aplicativo cliente ao seu aplicativo do Azure IoT Central. O aplicativo simula o comportamento de um dispositivo controlador de temperatura. Quando o aplicativo se conecta ao IoT Central, ele envia o ID do modelo do dispositivo controlador de temperatura. O IoT Central usa o ID do modelo para recuperar o modelo de dispositivo e criar um modelo de dispositivo para você. Você adiciona modos de exibição ao modelo de dispositivo para permitir que um operador interaja com um dispositivo.
Neste tutorial, irá aprender a:
- Crie e execute o código do dispositivo e veja-o conectar-se ao seu aplicativo IoT Central.
- Veja a telemetria simulada enviada a partir do dispositivo.
- Adicione vistas personalizadas a um modelo de dispositivo.
- Publique o modelo de dispositivo.
- Use uma vista para gerir as propriedades do dispositivo.
- Chame um comando para controlar o dispositivo.
Importante
Este artigo inclui etapas para conectar um dispositivo usando uma assinatura de acesso compartilhado, também chamada de autenticação de chave simétrica. Esse método de autenticação é conveniente para testes e avaliações, mas autenticar um dispositivo usando certificados X.509 é uma abordagem mais segura. Para saber mais, consulte Práticas recomendadas de segurança para soluções > IoT Segurança de conexão.
Pré-requisitos
Para concluir as etapas neste tutorial, você precisa:
Uma subscrição ativa do Azure. Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar.
Um aplicativo IoT Central criado a partir do modelo de aplicativo personalizado. Para saber mais, consulte Criar uma aplicação IoT Central e Como posso obter informações sobre a minha aplicação?
Você pode executar este tutorial no Linux ou Windows. Os comandos shell neste tutorial seguem a convenção do Linux para separadores de caminho '/', se você estiver acompanhando no Windows, certifique-se de trocar esses separadores por '\'.
Os pré-requisitos diferem de acordo com o sistema operacional:
Linux
Este tutorial assume que você está usando o Ubuntu Linux. As etapas neste tutorial foram testadas usando o Ubuntu 18.04.
Para concluir este tutorial no Linux, instale o seguinte software em seu ambiente Linux local:
Instale GCC, Git, cmake e todas as dependências necessárias usando o apt-get comando:
sudo apt-get update
sudo apt-get install -y git cmake build-essential curl libcurl4-openssl-dev libssl-dev uuid-dev
Verifique se a versão do cmake é maior que 2.8.12 e a versão do GCC é maior que 4.4.7.
cmake --version
gcc --version
Windows
Para concluir este tutorial no Windows, instale o seguinte software em seu ambiente Windows local:
- Visual Studio (Community, Professional ou Enterprise) - certifique-se de incluir a carga de trabalho Desenvolvimento de Desktop com C++ ao instalar o Visual Studio.
- Git.
- CMake.
Transferir o código
Neste tutorial, você prepara um ambiente de desenvolvimento que pode usar para clonar e criar o SDK C do Dispositivo do Hub IoT do Azure.
Abra um prompt de comando no diretório de sua escolha. Execute o seguinte comando para clonar o repositório GitHub dos SDKs e Bibliotecas do Azure IoT C neste local:
git clone https://github.com/Azure/azure-iot-sdk-c.git
cd azure-iot-sdk-c
git submodule update --init
Espere que esta operação demore vários minutos a concluir.
Rever o código
Na cópia do SDK do Microsoft Azure IoT para C que você baixou anteriormente, abra os arquivos azure-iot-sdk-c/iothub_client/samples/pnp/pnp_temperature_controller/pnp_temperature_controller.c e azure-iot-sdk-c/iothub_client/samples/pnp/pnp_temperature_controller/pnp_thermostat_component.c em um editor de texto.
O exemplo implementa o modelo de Linguagem de Definição de Gémeo Digital do Controlador de Temperatura de Múltiplos Componentes.
Quando você executa o exemplo para se conectar ao IoT Central, ele usa o Serviço de Provisionamento de Dispositivo (DPS) para registrar o dispositivo e gerar uma cadeia de conexão. O exemplo recupera as informações de conexão DPS necessárias do ambiente de linha de comando.
No pnp_temperature_controller.c, a main função primeiro chama CreateDeviceClientAndAllocateComponents para:
- Defina o ID do
dtmi:com:example:Thermostat;1modelo. O IoT Central usa o ID do modelo para identificar ou gerar o modelo de dispositivo para esse dispositivo. Para saber mais, consulte Atribuir um dispositivo a um modelo de dispositivo. - Use o DPS para provisionar e registrar o dispositivo.
- Crie um identificador de cliente de dispositivo e conecte-se ao seu aplicativo IoT Central.
- Cria um manipulador para comandos no componente controlador de temperatura.
- Cria um manipulador para atualizações de propriedade no componente controlador de temperatura.
- Cria os dois componentes do termostato.
A main função próxima:
- Relata alguns valores de propriedade inicial para todos os componentes.
- Inicia um ciclo para enviar telemetria de todos os componentes.
Em seguida, a função main inicia uma linha de execução para enviar telemetria periodicamente.
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;
}
No pnp_thermostat_component.c, a PnP_ThermostatComponent_SendCurrentTemperature função mostra como o dispositivo envia a telemetria de temperatura de um componente para o 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);
}
No pnp_thermostat_component.c, a PnP_TempControlComponent_Report_MaxTempSinceLastReboot_Property função envia uma atualização de propriedade maxTempSinceLastReboot do componente para 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);
}
}
No pnp_thermostat_component.c, a PnP_ThermostatComponent_ProcessPropertyUpdate função lida com atualizações de propriedade graváveis do 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);
}
}
}
}
No pnp_thermostat_component.c, a função PnP_ThermostatComponent_ProcessCommand lida com comandos provenientes do 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;
}
}
Compilar o código
Use o SDK do dispositivo para criar o código de exemplo incluído:
Crie um subdiretório cmake na pasta raiz do SDK do dispositivo e navegue até essa pasta:
cd azure-iot-sdk-c mkdir cmake cd cmakeExecute os seguintes comandos para criar o SDK e exemplos:
cmake -Duse_prov_client=ON -Dhsm_type_symm_key=ON -Drun_e2e_tests=OFF .. cmake --build .
Obter informações da ligação
Ao executar o aplicativo de dispositivo de exemplo posteriormente neste tutorial, você precisa dos seguintes valores de configuração:
- Escopo de ID: no seu aplicativo IoT Central, navegue até Permissões > Grupos de conexão de dispositivo. Anote o valor do escopo de ID.
- Chave primária do grupo: em seu aplicativo IoT Central, navegue até Permissões > Grupos > de conexão de dispositivos SAS-IoT-Devices. Anote o valor da chave primária da assinatura de acesso compartilhado.
Use o Azure Cloud Shell para gerar uma chave de dispositivo a partir da chave primária do grupo que você recuperou:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Anote a chave do dispositivo gerada, você a usará mais tarde neste tutorial.
Nota
Para executar este exemplo, você não precisa registrar o dispositivo com antecedência em seu aplicativo IoT Central. O exemplo usa o recurso IoT Central para registrar automaticamente dispositivos quando eles se conectam pela primeira vez.
Executar o código
Para executar o aplicativo de exemplo, abra um ambiente de linha de comando e navegue até a pasta azure-iot-sdk-c\cmake.
Defina as variáveis de ambiente para configurar o exemplo. O trecho a seguir mostra como definir as variáveis de ambiente no prompt de comando do Windows. Se você estiver usando um shell bash , substitua os set comandos por export comandos:
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
Para executar o exemplo:
# 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
A saída a seguir mostra o dispositivo registrando e se conectando ao IoT Central. A amostra começa a enviar telemetria:
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
Como operador em seu aplicativo do Azure IoT Central, você pode:
Veja a telemetria enviada pelos dois componentes do termostato na página Visão geral :
Exiba as propriedades do dispositivo na página Sobre . Esta página mostra as propriedades do componente de informações do dispositivo e os dois componentes do termostato:
Personalizar o modelo de dispositivo
Como desenvolvedor de soluções, você pode personalizar o modelo de dispositivo que o IoT Central criou automaticamente quando o dispositivo controlador de temperatura se conectou.
Para adicionar uma propriedade de nuvem para armazenar o nome do cliente associado ao dispositivo:
Na sua aplicação IoT Central, navegue até o modelo de dispositivo Controlador de Temperatura na página Modelos de Dispositivos.
No modelo Controlador de temperatura, selecione +Adicionar capacidade.
Digite Nome do cliente como Nome de exibição, selecione Propriedade de Cloud como o Tipo de capacidade, expanda aquela entrada e escolha String como o Esquema. Em seguida, selecione Guardar.
Para personalizar como os comandos Get Max-Min report são exibidos em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para getMaxMinReport (termostato1), substitua Get Max-Min report por Get thermostat1 status report.
Para getMaxMinReport (termostato2), substitua Get Max-Min report por relatório de estado do termostato2.
Selecione Guardar.
Para personalizar como as propriedades graváveis da Temperatura de Destino são exibidas em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para targetTemperature (termostato1), substitua Target Temperature por Target Temperature (1).
Para targetTemperature (termostato2), substitua Target Temperature por Target Temperature (2).
Selecione Guardar.
Os componentes do termostato no modelo Temperature Controller incluem a propriedade gravável Temperatura Alvo, o modelo de dispositivo inclui a propriedade na nuvem Nome do Cliente. Crie um modo de exibição que um operador pode usar para editar estas propriedades:
Selecione Vistas e, em seguida, selecione o mosaico Editar dispositivo e dados na nuvem.
Insira Propriedades como o nome do formulário.
Selecione as propriedades Temperatura alvo (1), Temperatura alvo (2) e Nome do cliente. Em seguida, selecione Adicionar seção.
Guardar as suas alterações.
Publicar o modelo de dispositivo
Antes que um operador possa ver e usar as personalizações feitas, você deve publicar o modelo de dispositivo.
Selecione Publicar no modelo de dispositivo Termostato. No painel Publicar este modelo de dispositivo na aplicação, selecione Publicar.
Um operador agora pode usar a visualização Propriedades para atualizar os valores de propriedade e chamar comandos chamados Obter relatório de status do termostato1 e Obter relatório de status do termostato2 na página de comandos do dispositivo:
Atualize os valores das propriedades graváveis na página Propriedades:
Execute os comandos na página Comandos. Se você executar o comando de relatório de status, selecione uma data e hora para o parâmetro Since antes de executá-lo:
Você pode ver como o dispositivo responde a comandos e atualizações de propriedade:
<- 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
Importante
Este artigo inclui etapas para conectar um dispositivo usando uma assinatura de acesso compartilhado, também chamada de autenticação de chave simétrica. Esse método de autenticação é conveniente para testes e avaliações, mas autenticar um dispositivo usando certificados X.509 é uma abordagem mais segura. Para saber mais, consulte Práticas recomendadas de segurança para soluções > IoT Segurança de conexão.
Pré-requisitos
Para concluir as etapas neste artigo, você precisa dos seguintes recursos:
Uma subscrição ativa do Azure. Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar.
Um aplicativo IoT Central criado a partir do modelo de aplicativo personalizado. Para saber mais, consulte Criar uma aplicação IoT Central e Como posso obter informações sobre a minha aplicação?
Uma máquina de desenvolvimento com Visual Studio (Community, Professional ou Enterprise).
Uma cópia local do repositório GitHub do SDK do Microsoft Azure IoT para C# (.NET) que contém o código de exemplo. Use este link para baixar uma cópia do repositório: Download ZIP. Em seguida, descompacte o arquivo para um local adequado em sua máquina local.
Rever o código
Na cópia do repositório do Microsoft Azure IoT SDK para C# que você baixou anteriormente, abra o arquivo de solução azure-iot-sdk-csharp-main\azureiot.sln no Visual Studio. No Gerenciador de Soluções, expanda a pasta PnpDeviceSamples > TemperatureController e abra os arquivos Program.cs e TemperatureControllerSample.cs para exibir o código deste exemplo.
O exemplo implementa o modelo de Linguagem de Definição de Gémeo Digital do Controlador de Temperatura de Múltiplos Componentes.
Quando você executa o exemplo para se conectar ao IoT Central, ele usa o Serviço de Provisionamento de Dispositivo (DPS) para registrar o dispositivo e gerar uma cadeia de conexão. O exemplo recupera as informações de conexão DPS necessárias do ambiente.
Em Program.cs, o Main método chama SetupDeviceClientAsync para:
- Utilize o ID do modelo
dtmi:com:example:TemperatureController;2ao provisionar o dispositivo com o DPS. O IoT Central usa o ID do modelo para identificar ou gerar o modelo de dispositivo para esse dispositivo. Para saber mais, consulte Atribuir um dispositivo a um modelo de dispositivo. - Crie uma instância DeviceClient para se conectar ao 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;
}
Em seguida, o método principal cria uma instância TemperatureControllerSample e chama o PerformOperationsAsync método para manipular as interações com o IoT Central.
Em TemperatureControllerSample.cs, o PerformOperationsAsync método:
- Define um manipulador para o comando de reinicialização no componente padrão.
- Define manipuladores para os comandos getMaxMinReport nos dois componentes do termostato.
- Define os manipuladores para receber atualizações de propriedade de temperatura de destino nos dois componentes do termostato.
- Envia atualizações iniciais das propriedades informativas do dispositivo.
- Envia periodicamente telemetria de temperatura dos dois componentes do termostato.
- Envia periodicamente a telemetria do conjunto de trabalho do componente padrão.
- Envia a temperatura máxima desde a última reinicialização sempre que uma nova temperatura máxima é atingida nos dois componentes do termostato.
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);
}
}
O SendTemperatureAsync método mostra como o dispositivo envia a telemetria de temperatura de um componente para o IoT Central. O SendTemperatureTelemetryAsync método usa a PnpConvention classe para criar a mensagem:
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 },
});
}
}
O método UpdateMaxTemperatureSinceLastRebootAsync envia uma atualização de propriedade maxTempSinceLastReboot para IoT Central. Este método usa a PnpConvention classe para criar o patch:
private async Task UpdateMaxTemperatureSinceLastRebootAsync(string componentName, CancellationToken cancellationToken)
{
const string propertyName = "maxTempSinceLastReboot";
double maxTemp = _maxTemp[componentName];
TwinCollection reportedProperties = PnpConvention.CreateComponentPropertyPatch(componentName, propertyName, maxTemp);
await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties, cancellationToken);
}
O método TargetTemperatureUpdateCallbackAsync gere a atualização da propriedade de temperatura alvo gravável do IoT Central. Esse método usa a PnpConvention classe para ler a mensagem de atualização de propriedade e construir a resposta:
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);
}
O HandleMaxMinReportCommand método manipula os comandos para os componentes chamados do 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)
{
// ...
}
}
Obter informações da ligação
Ao executar o aplicativo de dispositivo de exemplo posteriormente neste tutorial, você precisa dos seguintes valores de configuração:
- Escopo de ID: no seu aplicativo IoT Central, navegue até Permissões > Grupos de conexão de dispositivo. Anote o valor do escopo de ID.
- Chave primária do grupo: em seu aplicativo IoT Central, navegue até Permissões > Grupos > de conexão de dispositivos SAS-IoT-Devices. Anote o valor da chave primária da assinatura de acesso compartilhado.
Use o Azure Cloud Shell para gerar uma chave de dispositivo a partir da chave primária do grupo que você recuperou:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Anote a chave do dispositivo gerada, você a usará mais tarde neste tutorial.
Nota
Para executar este exemplo, você não precisa registrar o dispositivo com antecedência em seu aplicativo IoT Central. O exemplo usa o recurso IoT Central para registrar automaticamente dispositivos quando eles se conectam pela primeira vez.
Executar o código
Nota
Configure o TemperatureController como projeto de inicialização antes de executar o código.
Para executar o aplicativo de exemplo no Visual Studio:
No Gerenciador de Soluções, selecione o arquivo de projeto PnpDeviceSamples > TemperatureController .
Navegue até Project > TemperatureController Properties > Depuração. Em seguida, adicione as seguintes variáveis de ambiente ao projeto:
Nome Valor IOTHUB_DEVICE_SECURITY_TYPE DPS IOTHUB_DEVICE_DPS_ENDPOINT global.azure-devices-provisioning.net IOTHUB_DEVICE_DPS_ID_SCOPE O valor do escopo do ID que você anotou anteriormente. IOTHUB_DEVICE_DPS_DEVICE_ID amostra-dispositivo-01 IOTHUB_DEVICE_DPS_DEVICE_KEY O valor da chave do dispositivo gerado que você anotou anteriormente.
Agora você pode executar e depurar o exemplo no Visual Studio.
A saída a seguir mostra o dispositivo registrando e se conectando ao IoT Central. A amostra começa a enviar telemetria:
[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.
Como operador em seu aplicativo do Azure IoT Central, você pode:
Veja a telemetria enviada pelos dois componentes do termostato na página Visão geral :
Exiba as propriedades do dispositivo na página Sobre . Esta página mostra as propriedades do componente de informações do dispositivo e os dois componentes do termostato:
Personalizar o modelo de dispositivo
Como desenvolvedor de soluções, você pode personalizar o modelo de dispositivo que o IoT Central criou automaticamente quando o dispositivo controlador de temperatura se conectou.
Para adicionar uma propriedade de nuvem para armazenar o nome do cliente associado ao dispositivo:
Na sua aplicação IoT Central, navegue até o modelo de dispositivo Controlador de Temperatura na página Modelos de Dispositivos.
No modelo Controlador de temperatura, selecione +Adicionar capacidade.
Digite Nome do cliente como Nome de exibição, selecione Propriedade de Cloud como o Tipo de capacidade, expanda aquela entrada e escolha String como o Esquema. Em seguida, selecione Guardar.
Para personalizar como os comandos Get Max-Min report são exibidos em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para getMaxMinReport (termostato1), substitua Get Max-Min report por Get thermostat1 status report.
Para getMaxMinReport (termostato2), substitua Get Max-Min report por relatório de estado do termostato2.
Selecione Guardar.
Para personalizar como as propriedades graváveis da Temperatura de Destino são exibidas em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para targetTemperature (termostato1), substitua Target Temperature por Target Temperature (1).
Para targetTemperature (termostato2), substitua Target Temperature por Target Temperature (2).
Selecione Guardar.
Os componentes do termostato no modelo Temperature Controller incluem a propriedade gravável Temperatura Alvo, o modelo de dispositivo inclui a propriedade na nuvem Nome do Cliente. Crie um modo de exibição que um operador pode usar para editar estas propriedades:
Selecione Vistas e, em seguida, selecione o mosaico Editar dispositivo e dados na nuvem.
Insira Propriedades como o nome do formulário.
Selecione as propriedades Temperatura alvo (1), Temperatura alvo (2) e Nome do cliente. Em seguida, selecione Adicionar seção.
Guardar as suas alterações.
Publicar o modelo de dispositivo
Antes que um operador possa ver e usar as personalizações feitas, você deve publicar o modelo de dispositivo.
Selecione Publicar no modelo de dispositivo Termostato. No painel Publicar este modelo de dispositivo na aplicação, selecione Publicar.
Um operador agora pode usar a visualização Propriedades para atualizar os valores de propriedade e chamar comandos chamados Obter relatório de status do termostato1 e Obter relatório de status do termostato2 na página de comandos do dispositivo:
Atualize os valores das propriedades graváveis na página Propriedades:
Execute os comandos na página Comandos. Se você executar o comando de relatório de status, selecione uma data e hora para o parâmetro Since antes de executá-lo:
Você pode ver como o dispositivo responde a comandos e atualizações de propriedade:
[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.
Importante
Este artigo inclui etapas para conectar um dispositivo usando uma assinatura de acesso compartilhado, também chamada de autenticação de chave simétrica. Esse método de autenticação é conveniente para testes e avaliações, mas autenticar um dispositivo usando certificados X.509 é uma abordagem mais segura. Para saber mais, consulte Práticas recomendadas de segurança para soluções > IoT Segurança de conexão.
Pré-requisitos
Para concluir as etapas neste artigo, você precisa dos seguintes recursos:
Uma subscrição ativa do Azure. Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar.
Um aplicativo IoT Central criado a partir do modelo de aplicativo personalizado. Para saber mais, consulte Criar uma aplicação IoT Central e Como posso obter informações sobre a minha aplicação?
Uma máquina de desenvolvimento com Node.js versão 6 ou posterior instalada. Você pode executar
node --versionna linha de comando para verificar sua versão. As instruções neste tutorial pressupõem que esteja a executar o comando node no prompt de comando do Windows. No entanto, você pode usá Node.js em muitos outros sistemas operacionais.Uma cópia local do SDK do Microsoft Azure IoT para Node.js repositório GitHub que contém o código de exemplo. Use este link para baixar uma cópia do repositório: Download ZIP. Em seguida, descompacte o arquivo para um local adequado em sua máquina local.
Rever o código
Na cópia do SDK do Microsoft Azure IoT para Node.js que descarregou anteriormente, abra o ficheiro azure-iot-sdk-node/device/samples/javascript/pnp_temperature_controller.js num editor de texto.
O exemplo implementa o modelo de Linguagem de Definição de Gémeo Digital do Controlador de Temperatura de Múltiplos Componentes.
Quando você executa o exemplo para se conectar ao IoT Central, ele usa o Serviço de Provisionamento de Dispositivo (DPS) para registrar o dispositivo e gerar uma cadeia de conexão. O exemplo recupera as informações de conexão DPS necessárias do ambiente de linha de comando.
O main método:
- Cria um objeto
cliente define o identificador do modelodtmi:com:example:TemperatureController;2antes de abrir a conexão. O IoT Central usa o ID do modelo para identificar ou gerar o modelo de dispositivo para esse dispositivo. Para saber mais, consulte Atribuir um dispositivo a um modelo de dispositivo. - Cria manipuladores de comando para três comandos.
- Inicia um loop para cada componente do termostato para enviar telemetria de temperatura a cada 5 segundos.
- Inicia um loop para que o componente padrão envie telemetria do tamanho do conjunto de trabalho a cada 6 segundos.
- Envia a propriedade
maxTempSinceLastRebootpara cada componente do termostato. - Envia as propriedades de informação do dispositivo.
- Cria manipuladores de propriedades graváveis para os três componentes.
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());
}
}
A provisionDevice função mostra como o dispositivo usa o DPS para se registrar e se conectar ao IoT Central. A carga útil inclui o ID do modelo que o IoT Central usa para Atribuir um dispositivo a um modelo de dispositivo:
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());
}
}
A sendTelemetry função mostra como o dispositivo envia a telemetria de temperatura para o IoT Central. Para telemetria de componentes, ele adiciona uma propriedade chamada $.sub com o nome do componente:
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);
}
O main método usa um método auxiliar chamado helperCreateReportedPropertiesPatch para criar mensagens de atualização de propriedade. Este método usa um parâmetro opcional para especificar o componente que envia a propriedade:
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;
};
O main método usa o seguinte procedimento para manipular atualizações para propriedades graváveis do IoT Central. Observe como o método cria a resposta com a versão e o código de status:
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);
}
});
});
};
O main método usa os seguintes métodos para manipular comandos do 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());
}
};
Obter informações da ligação
Ao executar o aplicativo de dispositivo de exemplo posteriormente neste tutorial, você precisa dos seguintes valores de configuração:
- Escopo de ID: no seu aplicativo IoT Central, navegue até Permissões > Grupos de conexão de dispositivo. Anote o valor do escopo de ID.
- Chave primária do grupo: em seu aplicativo IoT Central, navegue até Permissões > Grupos > de conexão de dispositivos SAS-IoT-Devices. Anote o valor da chave primária da assinatura de acesso compartilhado.
Use o Azure Cloud Shell para gerar uma chave de dispositivo a partir da chave primária do grupo que você recuperou:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Anote a chave do dispositivo gerada, você a usará mais tarde neste tutorial.
Nota
Para executar este exemplo, você não precisa registrar o dispositivo com antecedência em seu aplicativo IoT Central. O exemplo usa o recurso IoT Central para registrar automaticamente dispositivos quando eles se conectam pela primeira vez.
Executar o código
Para executar o aplicativo de exemplo, abra um ambiente de linha de comando e navegue até a pasta azure-iot-sdk-node/device/samples/javascript que contém o arquivo de exemplo pnp_temperature_controller.js .
Defina as variáveis de ambiente para configurar o exemplo. O trecho a seguir mostra como definir as variáveis de ambiente no prompt de comando do Windows. Se você estiver usando um shell bash , substitua os set comandos por export comandos:
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
Instale os pacotes necessários:
npm install
Execute o exemplo:
node pnp_temperature_controller.js
A saída a seguir mostra o dispositivo registrando e se conectando ao IoT Central. Em seguida, a amostra envia a propriedade de ambos os componentes do termostato antes de maxTempSinceLastReboot começar a enviar a telemetria.
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
Como operador em seu aplicativo do Azure IoT Central, você pode:
Veja a telemetria enviada pelos dois componentes do termostato na página Visão geral :
Exiba as propriedades do dispositivo na página Sobre . Esta página mostra as propriedades do componente de informações do dispositivo e os dois componentes do termostato:
Personalizar o modelo de dispositivo
Como desenvolvedor de soluções, você pode personalizar o modelo de dispositivo que o IoT Central criou automaticamente quando o dispositivo controlador de temperatura se conectou.
Para adicionar uma propriedade de nuvem para armazenar o nome do cliente associado ao dispositivo:
Na sua aplicação IoT Central, navegue até o modelo de dispositivo Controlador de Temperatura na página Modelos de Dispositivos.
No modelo Controlador de temperatura, selecione +Adicionar capacidade.
Digite Nome do cliente como Nome de exibição, selecione Propriedade de Cloud como o Tipo de capacidade, expanda aquela entrada e escolha String como o Esquema. Em seguida, selecione Guardar.
Para personalizar como os comandos Get Max-Min report são exibidos em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para getMaxMinReport (termostato1), substitua Get Max-Min report por Get thermostat1 status report.
Para getMaxMinReport (termostato2), substitua Get Max-Min report por relatório de estado do termostato2.
Selecione Guardar.
Para personalizar como as propriedades graváveis da Temperatura de Destino são exibidas em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para targetTemperature (termostato1), substitua Target Temperature por Target Temperature (1).
Para targetTemperature (termostato2), substitua Target Temperature por Target Temperature (2).
Selecione Guardar.
Os componentes do termostato no modelo Temperature Controller incluem a propriedade gravável Temperatura Alvo, o modelo de dispositivo inclui a propriedade na nuvem Nome do Cliente. Crie um modo de exibição que um operador pode usar para editar estas propriedades:
Selecione Vistas e, em seguida, selecione o mosaico Editar dispositivo e dados na nuvem.
Insira Propriedades como o nome do formulário.
Selecione as propriedades Temperatura alvo (1), Temperatura alvo (2) e Nome do cliente. Em seguida, selecione Adicionar seção.
Guardar as suas alterações.
Publicar o modelo de dispositivo
Antes que um operador possa ver e usar as personalizações feitas, você deve publicar o modelo de dispositivo.
Selecione Publicar no modelo de dispositivo Termostato. No painel Publicar este modelo de dispositivo na aplicação, selecione Publicar.
Um operador agora pode usar a visualização Propriedades para atualizar os valores de propriedade e chamar comandos chamados Obter relatório de status do termostato1 e Obter relatório de status do termostato2 na página de comandos do dispositivo:
Atualize os valores das propriedades graváveis na página Propriedades:
Execute os comandos na página Comandos. Se você executar o comando de relatório de status, selecione uma data e hora para o parâmetro Since antes de executá-lo:
Você pode ver como o dispositivo responde a comandos e atualizações de propriedade. O getMaxMinReport comando está no thermostat2 componente, o reboot comando está no componente padrão. A propriedade targetTemperature foi definida como gravável para o componente thermostat2.
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
Importante
Este artigo inclui etapas para conectar um dispositivo usando uma assinatura de acesso compartilhado, também chamada de autenticação de chave simétrica. Esse método de autenticação é conveniente para testes e avaliações, mas autenticar um dispositivo usando certificados X.509 é uma abordagem mais segura. Para saber mais, consulte Práticas recomendadas de segurança para soluções > IoT Segurança de conexão.
Pré-requisitos
Para concluir as etapas neste artigo, você precisa dos seguintes recursos:
Uma subscrição ativa do Azure. Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar.
Um aplicativo IoT Central criado a partir do modelo de aplicativo personalizado. Para saber mais, consulte Criar uma aplicação IoT Central e Como posso obter informações sobre a minha aplicação?
Uma máquina de desenvolvimento com Python instalado. Verifique o SDK do Python do Azure IoT para obter os requisitos de versão atuais do Python. Você pode executar
python --versionna linha de comando para verificar sua versão. Python está disponível para uma grande variedade de sistemas operacionais. As instruções neste tutorial pressupõem que você esteja executando o comando python no prompt de comando do Windows.Uma cópia local do repositório GitHub do SDK do Microsoft Azure IoT para Python que contém o código de exemplo. Use este link para baixar uma cópia do repositório: Download ZIP. Em seguida, descompacte o arquivo para um local adequado em sua máquina local.
Rever o código
Na cópia do SDK do Microsoft Azure IoT para Python que você baixou anteriormente, abra o arquivo azure-iot-sdk-python/samples/pnp/temp_controller_with_thermostats.py em um editor de texto.
O exemplo implementa o modelo de Linguagem de Definição de Gémeo Digital do Controlador de Temperatura de Múltiplos Componentes.
Quando você executa o exemplo para se conectar ao IoT Central, ele usa o Serviço de Provisionamento de Dispositivo (DPS) para registrar o dispositivo e gerar uma cadeia de conexão. O exemplo recupera as informações de conexão DPS necessárias do ambiente de linha de comando.
A main função:
- Usa DPS para provisionar o dispositivo. As informações de provisionamento incluem a ID do modelo. O IoT Central usa o ID do modelo para identificar ou gerar o modelo de dispositivo para esse dispositivo. Para saber mais, consulte Atribuir um dispositivo a um modelo de dispositivo.
- Cria um objeto
Device_cliente define o identificador do modelodtmi:com:example:TemperatureController;2antes de abrir a conexão. - Envia valores de propriedade iniciais para o IoT Central. Ele usa o
pnp_helperpara criar os patches. - Cria ouvintes para os comandos
getMaxMinReportereboot. Cada componente do termostato tem seu própriogetMaxMinReportcomando. - Cria um ouvinte de propriedade para monitorizar atualizações em propriedades graváveis.
- Inicia um ciclo para enviar telemetria de temperatura a partir dos dois componentes de termostato e telemetria do conjunto de trabalho a partir do componente padrão a cada 8 segundos.
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())
# ...
A provision_device função usa DPS para provisionar o dispositivo e registrá-lo com o IoT Central. A função inclui o ID do modelo do dispositivo, que o IoT Central usa para atribuir um dispositivo a um modelo de dispositivo, na carga útil de provisionamento:
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()
A execute_command_listener função lida com solicitações de comando, executa a max_min_handler função quando o dispositivo recebe o getMaxMinReport comando para os componentes do termostato e a reboot_handler função quando o dispositivo recebe o reboot comando. Ele usa o pnp_helper módulo para construir a resposta:
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))
O async def execute_property_listener atualiza propriedades graváveis, como targetTemperature para os componentes do termostato e gera a resposta JSON. Ele usa o pnp_helper módulo para construir a resposta:
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)
A send_telemetry_from_temp_controller função envia as mensagens de telemetria dos componentes do termostato para o IoT Central. Ele usa o pnp_helper módulo para construir as mensagens:
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)
Obter informações da ligação
Ao executar o aplicativo de dispositivo de exemplo posteriormente neste tutorial, você precisa dos seguintes valores de configuração:
- Escopo de ID: no seu aplicativo IoT Central, navegue até Permissões > Grupos de conexão de dispositivo. Anote o valor do escopo de ID.
- Chave primária do grupo: em seu aplicativo IoT Central, navegue até Permissões > Grupos > de conexão de dispositivos SAS-IoT-Devices. Anote o valor da chave primária da assinatura de acesso compartilhado.
Use o Azure Cloud Shell para gerar uma chave de dispositivo a partir da chave primária do grupo que você recuperou:
az extension add --name azure-iot
az iot central device compute-device-key --device-id sample-device-01 --pk <the group primary key value>
Anote a chave do dispositivo gerada, você a usará mais tarde neste tutorial.
Nota
Para executar este exemplo, você não precisa registrar o dispositivo com antecedência em seu aplicativo IoT Central. O exemplo usa o recurso IoT Central para registrar automaticamente dispositivos quando eles se conectam pela primeira vez.
Executar o código
Para executar o aplicativo de exemplo, abra um ambiente de linha de comando e navegue até a pasta azure-iot-sdk-python-2/samples/pnp que contém o arquivo de exemplo temp_controller_with_thermostats.py .
Defina as variáveis de ambiente para configurar o exemplo. O trecho a seguir mostra como definir as variáveis de ambiente no prompt de comando do Windows. Se você estiver usando um shell bash , substitua os set comandos por export comandos:
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
Instale os pacotes necessários:
pip install azure-iot-device
Execute o exemplo:
python temp_controller_with_thermostats.py
A saída a seguir mostra o dispositivo registrando e se conectando ao IoT Central. A amostra envia as maxTempSinceLastReboot propriedades dos dois componentes do termostato antes de começar a enviar a telemetria:
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}
Como operador em seu aplicativo do Azure IoT Central, você pode:
Veja a telemetria enviada pelos dois componentes do termostato na página Visão geral :
Exiba as propriedades do dispositivo na página Sobre . Esta página mostra as propriedades do componente de informações do dispositivo e os dois componentes do termostato:
Personalizar o modelo de dispositivo
Como desenvolvedor de soluções, você pode personalizar o modelo de dispositivo que o IoT Central criou automaticamente quando o dispositivo controlador de temperatura se conectou.
Para adicionar uma propriedade de nuvem para armazenar o nome do cliente associado ao dispositivo:
Na sua aplicação IoT Central, navegue até o modelo de dispositivo Controlador de Temperatura na página Modelos de Dispositivos.
No modelo Controlador de temperatura, selecione +Adicionar capacidade.
Digite Nome do cliente como Nome de exibição, selecione Propriedade de Cloud como o Tipo de capacidade, expanda aquela entrada e escolha String como o Esquema. Em seguida, selecione Guardar.
Para personalizar como os comandos Get Max-Min report são exibidos em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para getMaxMinReport (termostato1), substitua Get Max-Min report por Get thermostat1 status report.
Para getMaxMinReport (termostato2), substitua Get Max-Min report por relatório de estado do termostato2.
Selecione Guardar.
Para personalizar como as propriedades graváveis da Temperatura de Destino são exibidas em seu aplicativo IoT Central:
Navegue até o modelo de Controlador de temperatura do dispositivo na página de Modelos de Dispositivos.
Para targetTemperature (termostato1), substitua Target Temperature por Target Temperature (1).
Para targetTemperature (termostato2), substitua Target Temperature por Target Temperature (2).
Selecione Guardar.
Os componentes do termostato no modelo Temperature Controller incluem a propriedade gravável Temperatura Alvo, o modelo de dispositivo inclui a propriedade na nuvem Nome do Cliente. Crie um modo de exibição que um operador pode usar para editar estas propriedades:
Selecione Vistas e, em seguida, selecione o mosaico Editar dispositivo e dados na nuvem.
Insira Propriedades como o nome do formulário.
Selecione as propriedades Temperatura alvo (1), Temperatura alvo (2) e Nome do cliente. Em seguida, selecione Adicionar seção.
Guardar as suas alterações.
Publicar o modelo de dispositivo
Antes que um operador possa ver e usar as personalizações feitas, você deve publicar o modelo de dispositivo.
Selecione Publicar no modelo de dispositivo Termostato. No painel Publicar este modelo de dispositivo na aplicação, selecione Publicar.
Um operador agora pode usar a visualização Propriedades para atualizar os valores de propriedade e chamar comandos chamados Obter relatório de status do termostato1 e Obter relatório de status do termostato2 na página de comandos do dispositivo:
Atualize os valores das propriedades graváveis na página Propriedades:
Execute os comandos na página Comandos. Se você executar o comando de relatório de status, selecione uma data e hora para o parâmetro Since antes de executá-lo:
Você pode ver como o dispositivo responde a comandos e atualizações de propriedade:
{'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"}
Exibir dados brutos
Você pode usar a visualização de dados brutos para examinar os dados brutos que seu dispositivo está enviando para o IoT Central:
Nessa exibição, você pode selecionar as colunas a serem exibidas e definir um intervalo de tempo para exibir. A coluna Dados não modelados mostra dados do dispositivo que não correspondem a nenhuma propriedade ou definições de telemetria no modelo de dispositivo.
Limpar recursos
Se você não planeja concluir mais tutoriais ou inícios rápidos do IoT Central, pode excluir seu aplicativo do IoT Central:
- Em seu aplicativo IoT Central, navegue até Gerenciamento de Aplicativos>.
- Selecione Excluir e confirme sua ação.
Próximos passos
Se preferir continuar com o conjunto de tutoriais do IoT Central e saber mais sobre como criar uma solução do IoT Central, consulte: