diff --git a/sdk/samples/iot/CMakeLists.txt b/sdk/samples/iot/CMakeLists.txt index 83a2770885..049780fd96 100644 --- a/sdk/samples/iot/CMakeLists.txt +++ b/sdk/samples/iot/CMakeLists.txt @@ -86,7 +86,7 @@ target_link_libraries(paho_iot_hub_pnp_sample # PnP Component Sample add_executable (paho_iot_hub_pnp_component_sample - ${CMAKE_CURRENT_LIST_DIR}/sample_pnp_component_mqtt.c + ${CMAKE_CURRENT_LIST_DIR}/sample_pnp_mqtt_component.c ${CMAKE_CURRENT_LIST_DIR}/sample_pnp_device_info_component.c ${CMAKE_CURRENT_LIST_DIR}/sample_pnp_thermostat_component.c ${CMAKE_CURRENT_LIST_DIR}/paho_iot_hub_pnp_component_sample.c @@ -96,15 +96,7 @@ add_executable (paho_iot_hub_pnp_component_sample # SDK deps target_link_libraries(paho_iot_hub_pnp_component_sample PRIVATE - az::iot::hub -) - -# External deps -target_link_libraries(paho_iot_hub_pnp_component_sample - PRIVATE - eclipse-paho-mqtt-c::paho-mqtt3cs-static - OpenSSL::SSL - OpenSSL::Crypto + az::iot::samples::common ) # Telemetry (Certificates) Sample diff --git a/sdk/samples/iot/iot_samples_common.c b/sdk/samples/iot/iot_samples_common.c index 52b647a06d..7818fc168a 100644 --- a/sdk/samples/iot/iot_samples_common.c +++ b/sdk/samples/iot/iot_samples_common.c @@ -110,6 +110,7 @@ az_result read_environment_variables( { case PAHO_IOT_HUB_C2D_SAMPLE: case PAHO_IOT_HUB_METHODS_SAMPLE: + case PAHO_IOT_HUB_PNP_COMPONENT_SAMPLE: case PAHO_IOT_HUB_PNP_SAMPLE: case PAHO_IOT_HUB_TELEMETRY_SAMPLE: case PAHO_IOT_HUB_TWIN_SAMPLE: @@ -230,7 +231,7 @@ az_result read_environment_variables( env_vars->x509_trust_pem_file_path, &(env_vars->x509_trust_pem_file_path))); - LOG(" "); // Log formatting + LOG(" "); // Formatting. return AZ_OK; } diff --git a/sdk/samples/iot/iot_samples_common.h b/sdk/samples/iot/iot_samples_common.h index c1fc618683..99ce3e78d1 100644 --- a/sdk/samples/iot/iot_samples_common.h +++ b/sdk/samples/iot/iot_samples_common.h @@ -112,6 +112,7 @@ typedef enum { PAHO_IOT_HUB_C2D_SAMPLE, PAHO_IOT_HUB_METHODS_SAMPLE, + PAHO_IOT_HUB_PNP_COMPONENT_SAMPLE, PAHO_IOT_HUB_PNP_SAMPLE, PAHO_IOT_HUB_SAS_TELEMETRY_SAMPLE, PAHO_IOT_HUB_TELEMETRY_SAMPLE, diff --git a/sdk/samples/iot/paho_iot_hub_c2d_sample.c b/sdk/samples/iot/paho_iot_hub_c2d_sample.c index 4e9234d41e..8c4b33deaf 100644 --- a/sdk/samples/iot/paho_iot_hub_c2d_sample.c +++ b/sdk/samples/iot/paho_iot_hub_c2d_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -84,7 +85,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -95,7 +96,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -104,7 +105,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_init( &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, NULL))) { - LOG_ERROR("Failed to initialize hub client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } @@ -114,7 +115,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_get_client_id( &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -141,7 +142,7 @@ static void connect_mqtt_client_to_iot_hub(void) rc = az_iot_hub_client_get_user_name( &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -214,14 +215,14 @@ static void receive_c2d_messages(void) { topic_len = (int)strlen(topic); } - LOG_SUCCESS("Message #%d: Client received message from the service.", message_count + 1); + LOG_SUCCESS("Message #%d: Client received a message from the service.", message_count + 1); // Parse c2d message. az_iot_hub_client_c2d_request c2d_request; parse_c2d_message(topic, topic_len, message, &c2d_request); LOG_SUCCESS("Client parsed message."); - LOG(" "); // formatting + LOG(" "); // formatting. MQTTClient_freeMessage(&message); MQTTClient_free(topic); @@ -247,7 +248,7 @@ static void parse_c2d_message( const MQTTClient_message* message, az_iot_hub_client_c2d_request* c2d_request) { - int rc; + az_result rc; az_span topic_span = az_span_create((uint8_t*)topic, topic_len); az_span message_span = az_span_create((uint8_t*)message->payload, message->payloadlen); @@ -255,7 +256,7 @@ static void parse_c2d_message( if (az_failed( rc = az_iot_hub_client_c2d_parse_received_topic(&hub_client, topic_span, c2d_request))) { - LOG_ERROR("Message from unknown topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); LOG_AZ_SPAN("Topic:", topic_span); exit(rc); } diff --git a/sdk/samples/iot/paho_iot_hub_methods_sample.c b/sdk/samples/iot/paho_iot_hub_methods_sample.c index d70e25f01f..9aa135588a 100644 --- a/sdk/samples/iot/paho_iot_hub_methods_sample.c +++ b/sdk/samples/iot/paho_iot_hub_methods_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -100,7 +101,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -111,7 +112,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -120,7 +121,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_init( &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, NULL))) { - LOG_ERROR("Failed to initialize hub client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } @@ -130,7 +131,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_get_client_id( &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -157,7 +158,7 @@ static void connect_mqtt_client_to_iot_hub(void) rc = az_iot_hub_client_get_user_name( &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -230,7 +231,7 @@ static void receive_method_messages(void) { topic_len = (int)strlen(topic); } - LOG_SUCCESS("Message #%d: Client received message from the service.", message_count + 1); + LOG_SUCCESS("Message #%d: Client received a message from the service.", message_count + 1); // Parse method message and invoke method. az_iot_hub_client_method_request method_request; @@ -238,7 +239,7 @@ static void receive_method_messages(void) LOG_SUCCESS("Client parsed message."); invoke_method(&method_request); - LOG(" "); // formatting + LOG(" "); // formatting. MQTTClient_freeMessage(&message); MQTTClient_free(topic); @@ -264,7 +265,7 @@ static void parse_method_message( const MQTTClient_message* message, az_iot_hub_client_method_request* method_request) { - int rc; + az_result rc; az_span topic_span = az_span_create((uint8_t*)topic, topic_len); az_span message_span = az_span_create((uint8_t*)message->payload, message->payloadlen); @@ -273,7 +274,7 @@ static void parse_method_message( rc = az_iot_hub_client_methods_parse_received_topic( &hub_client, topic_span, method_request))) { - LOG_ERROR("Message from unknown topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); LOG_AZ_SPAN("Topic:", topic_span); exit(rc); } @@ -322,7 +323,7 @@ static void send_method_response( sizeof(methods_response_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Methods response publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Methods response publish topic: az_result return code 0x%08x.", rc); exit(rc); } diff --git a/sdk/samples/iot/paho_iot_hub_pnp_component_sample.c b/sdk/samples/iot/paho_iot_hub_pnp_component_sample.c index 6b3ebd93dc..bac5648532 100644 --- a/sdk/samples/iot/paho_iot_hub_pnp_component_sample.c +++ b/sdk/samples/iot/paho_iot_hub_pnp_component_sample.c @@ -2,8 +2,8 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER -// warning C4201: nonstandard extension used: nameless struct/union #pragma warning(push) +// warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include @@ -11,7 +11,11 @@ #pragma warning(pop) #endif -#include +#include "iot_samples_common.h" + +#include +#include +#include #include #include #include @@ -22,74 +26,25 @@ #include #include "sample_pnp.h" -#include "sample_pnp_component_mqtt.h" #include "sample_pnp_device_info_component.h" +#include "sample_pnp_mqtt_component.h" #include "sample_pnp_thermostat_component.h" -#ifdef _MSC_VER -// "'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead." -#pragma warning(disable : 4996) -#endif - -// DO NOT MODIFY: Device ID Environment Variable Name -#define ENV_DEVICE_ID "AZ_IOT_DEVICE_ID" - -// DO NOT MODIFY: IoT Hub Hostname Environment Variable Name -#define ENV_IOT_HUB_HOSTNAME "AZ_IOT_HUB_HOSTNAME" - -// DO NOT MODIFY: The path to a PEM file containing the device certificate and -// key as well as any intermediate certificates chaining to an uploaded group certificate. -#define ENV_DEVICE_X509_CERT_PEM_FILE "AZ_IOT_DEVICE_X509_CERT_PEM_FILE" - -// DO NOT MODIFY: the path to a PEM file containing the server trusted CA -// This is usually not needed on Linux or Mac but needs to be set on Windows. -#define ENV_DEVICE_X509_TRUST_PEM_FILE "AZ_IOT_DEVICE_X509_TRUST_PEM_FILE" - -// Logging with formatting -#define LOG_ERROR(...) \ - { \ - (void)fprintf(stderr, "ERROR:\t\t%s:%s():%d: ", __FILE__, __func__, __LINE__); \ - (void)fprintf(stderr, __VA_ARGS__); \ - (void)fprintf(stderr, "\n"); \ - fflush(stdout); \ - fflush(stderr); \ - } -#define LOG_SUCCESS(...) \ - { \ - (void)printf("SUCCESS:\t"); \ - (void)printf(__VA_ARGS__); \ - (void)printf("\n"); \ - } -#define LOG(...) \ - { \ - (void)printf("\t\t"); \ - (void)printf(__VA_ARGS__); \ - (void)printf("\n"); \ - } -#define LOG_AZ_SPAN(span_description, span) \ - { \ - (void)printf("\t\t%s ", span_description); \ - char* buffer = (char*)az_span_ptr(span); \ - for (int32_t i = 0; i < az_span_size(span); i++) \ - { \ - putchar(*buffer++); \ - } \ - (void)printf("\n"); \ - } +#define SAMPLE_TYPE PAHO_IOT_HUB +#define SAMPLE_NAME PAHO_IOT_HUB_PNP_COMPONENT_SAMPLE -#define TIMEOUT_WAIT_FOR_RECEIVE_MESSAGE_MS (8 * 1000) -#define TIMEOUT_WAIT_FOR_COMPLETION_MS 1000 -#define TIMEOUT_MQTT_DISCONNECT_MS (10 * 1000) -#define DEVICE_DO_WORK_SLEEP_MS 2 #define TELEMETRY_SEND_INTERVAL 1 +#define TIMEOUT_MQTT_RECEIVE_MAX_MESSAGE_COUNT 3 +#define TIMEOUT_MQTT_RECEIVE_MS (8 * 1000) +#define TIMEOUT_MQTT_DISCONNECT_MS (10 * 1000) +#define TIMEOUT_MQTT_WAIT_FOR_COMPLETION_MS 1000 + +#define DEFAULT_START_TEMP_AVG_COUNT 1 #define DEFAULT_START_TEMP_CELSIUS 22.0 #define DOUBLE_DECIMAL_PLACE_DIGITS 2 -#define SAMPLE_PUBLISH_QOS 0 +#define MQTT_PUBLISH_QOS 0 bool is_device_operational = true; -static const uint8_t null_terminator = '\0'; -static char start_time_str[32]; -static az_span start_time_span; // * PnP Values * // The model id is the JSON document (also called the Digital Twins Model Identifier or DTMI) @@ -99,83 +54,83 @@ static az_span start_time_span; // Please see the sample README for more information on this DTMI. static const az_span model_id = AZ_SPAN_LITERAL_FROM_STR("dtmi:com:example:TemperatureController;1"); -static sample_pnp_thermostat_component sample_thermostat_1; -static const az_span sample_thermostat_1_component_name = AZ_SPAN_LITERAL_FROM_STR("thermostat1"); -static sample_pnp_thermostat_component sample_thermostat_2; -static const az_span sample_thermostat_2_component_name = AZ_SPAN_LITERAL_FROM_STR("thermostat2"); -static const az_span sample_device_info_component = AZ_SPAN_LITERAL_FROM_STR("deviceInformation"); -static const az_span* sample_pnp_components[] = { &sample_thermostat_1_component_name, - &sample_thermostat_2_component_name, - &sample_device_info_component }; -static const int32_t sample_pnp_components_num - = sizeof(sample_pnp_components) / sizeof(sample_pnp_components[0]); - -// Root Component Values -static const az_span working_set_name = AZ_SPAN_LITERAL_FROM_STR("workingSet"); -static int32_t working_set_ram_in_kibibytes; -static const az_span serial_number_name = AZ_SPAN_LITERAL_FROM_STR("serialNumber"); -static az_span serial_number_value = AZ_SPAN_LITERAL_FROM_STR("ABCDEFG"); + +// Components +static pnp_thermostat_component thermostat_1; +static pnp_thermostat_component thermostat_2; +static const az_span thermostat_1_name = AZ_SPAN_LITERAL_FROM_STR("thermostat1"); +static const az_span thermostat_2_name = AZ_SPAN_LITERAL_FROM_STR("thermostat2"); +static const az_span device_info_name = AZ_SPAN_LITERAL_FROM_STR("deviceInformation"); +static const az_span* pnp_components[] + = { &thermostat_1_name, &thermostat_2_name, &device_info_name }; +static const int32_t pnp_components_num = sizeof(pnp_components) / sizeof(pnp_components[0]); + +// IoT Hub Device Twin Values +static const az_span reported_serial_num_property_name = AZ_SPAN_LITERAL_FROM_STR("serialNumber"); +static az_span reported_serial_num_property_value = AZ_SPAN_LITERAL_FROM_STR("ABCDEFG"); static const az_span property_response_description_failed = AZ_SPAN_LITERAL_FROM_STR("failed"); -// ISO8601 Time Format -static const char iso_spec_time_format[] = "%Y-%m-%dT%H:%M:%S%z"; +// IoT Hub Method (Command) Values +static const az_span reboot_command_name = AZ_SPAN_LITERAL_FROM_STR("reboot"); +static const az_span empty_response_payload = AZ_SPAN_LITERAL_FROM_STR("{}"); +static char property_scratch_buffer[64]; -// IoT Hub Connection Values -static az_iot_hub_client client; -static char device_id[64]; -static char iot_hub_hostname[128]; -static char x509_cert_pem_file[512]; -static char x509_trust_pem_file[256]; +// IoT Hub Telemetry Values +static const az_span working_set_name = AZ_SPAN_LITERAL_FROM_STR("workingSet"); -// MQTT Client Values +static iot_sample_environment_variables env_vars; +static az_iot_hub_client hub_client; static MQTTClient mqtt_client; -static char mqtt_client_id[128]; -static char mqtt_username[256]; -static char mqtt_endpoint[128]; -static az_span mqtt_url_prefix = AZ_SPAN_LITERAL_FROM_STR("ssl://"); -static az_span mqtt_url_suffix = AZ_SPAN_LITERAL_FROM_STR(":8883"); - -// Reuse topic and payload buffers since API's are synchronous -static char publish_topic[128]; -static char publish_payload[512]; -static sample_pnp_mqtt_message publish_message; - -// IoT Hub Command -static const az_span reboot_command_name = AZ_SPAN_LITERAL_FROM_STR("reboot"); -static const az_span empty_json_object = AZ_SPAN_LITERAL_FROM_STR("{}"); -static char property_scratch_buffer[64]; +static char mqtt_client_username_buffer[512]; +static pnp_mqtt_message mqtt_message; // -// Configuration and connection functions +// Functions // -static void components_init(void); -static az_result read_configuration_and_init_client(void); -static az_result read_configuration_entry( - const char* env_name, - char* default_value, - bool hide_value, - az_span buffer, - az_span* out_value); -static az_result create_mqtt_endpoint(char* destination, int32_t destination_size, az_span iot_hub); -static void connect_device(void); -static void subscribe(void); +static void create_and_configure_mqtt_client(void); +static void connect_mqtt_client_to_iot_hub(void); +static void subscribe_mqtt_client_to_iot_hub_topics(void); +static void initialize_components(void); +static void send_device_info(void); +static void send_device_serial_number(void); +static void request_device_twin_document(void); +static void receive_messages(void); +static void disconnect_mqtt_client_from_iot_hub(void); -// -// Messaging functions -// -static void mqtt_publish_message(char* topic, az_span payload, int qos); +static void mqtt_publish_message(const char* topic, az_span payload, int qos); static void mqtt_receive_message(void); -static int on_received(char* topicName, int topicLen, MQTTClient_message* message); -static void send_device_serial_number(void); -static void send_device_info(void); -static void send_telemetry_messages(void); -static void send_twin_get_message(void); -static void handle_twin_message( - MQTTClient_message* message, - az_iot_hub_client_twin_response* twin_response); +static void on_message_received(char* topic, int topic_len, const MQTTClient_message* message); + +// Device Twin functions +static void handle_device_twin_message( + const az_span twin_message_span, + const az_iot_hub_client_twin_response* twin_response); + +// Command functions static void handle_command_message( - MQTTClient_message* message, - az_iot_hub_client_method_request* command_request); + const az_span command_message_span, + const az_iot_hub_client_method_request* command_request); +static az_result temp_controller_process_command( + const az_iot_hub_client_method_request* command_request, + az_span component_name, + az_span command_name, + az_span command_payload, + pnp_mqtt_message* mqtt_message, + az_iot_status* status); + +// Telemetry functions +static void send_telemetry_messages(void); +static az_result temp_controller_get_telemetry_message(pnp_mqtt_message* message); + +// Callbacks +static az_result append_string_callback(az_json_writer* jw, void* value); +static az_result append_json_token_callback(az_json_writer* jw, void* value); +static void property_callback( + az_span component_name, + const az_json_token* property_name, + az_json_reader property_value, + int32_t version, + void* user_context_callback); /* * This sample extends the IoT Hub Plug and Play Sample above to mimic a Temperature Controller @@ -317,832 +272,770 @@ static void handle_command_message( * value for the current temperature. */ int main(void) +{ + create_and_configure_mqtt_client(); + LOG_SUCCESS("Client created and configured."); + + connect_mqtt_client_to_iot_hub(); + LOG_SUCCESS("Client connected to IoT Hub."); + + subscribe_mqtt_client_to_iot_hub_topics(); + LOG_SUCCESS("Client subscribed to IoT Hub topics."); + + pnp_mqtt_message_init(&mqtt_message); + + initialize_components(); + LOG_SUCCESS("Client initialized components."); + + send_device_info(); + send_device_serial_number(); + request_device_twin_document(); + + receive_messages(); + LOG_SUCCESS("Client received messages.") + + disconnect_mqtt_client_from_iot_hub(); + LOG_SUCCESS("Client disconnected from IoT Hub."); + + return 0; +} + +static void create_and_configure_mqtt_client(void) { int rc; - // Get the program start time for command response - time_t rawtime; - struct tm* timeinfo; - time(&rawtime); - timeinfo = localtime(&rawtime); - size_t len = strftime(start_time_str, sizeof(start_time_str), iso_spec_time_format, timeinfo); - if (len == 0) + // Reads in environment variables set by user for purposes of running sample. + if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) + { + LOG_ERROR( + "Failed to read configuration from environment variables: az_result return code 0x%08x.", + rc); + exit(rc); + } + + // Build an MQTT endpoint c-string. + char mqtt_endpoint_buffer[128]; + if (az_failed( + rc = create_mqtt_endpoint( + SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Insufficient buffer size for program start time."); - exit(-1); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); + exit(rc); } - start_time_span = az_span_create((uint8_t*)start_time_str, (int32_t)len); - // Read in the necessary environment variables and initialize the az_iot_hub_client - if (az_failed(rc = read_configuration_and_init_client())) + // Initialize the hub client with the connection options. + az_iot_hub_client_options options = az_iot_hub_client_options_default(); + options.model_id = model_id; + if (az_failed( + rc = az_iot_hub_client_init( + &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, &options))) { - LOG_ERROR("Failed to read configuration from environment variables, return code %d", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } - // Get the MQTT client id used for the MQTT connection - size_t client_id_length; + // Get the MQTT client id used for the MQTT connection. + char mqtt_client_id_buffer[128]; if (az_failed( rc = az_iot_hub_client_get_client_id( - &client, mqtt_client_id, sizeof(mqtt_client_id), &client_id_length))) + &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id, return code %d", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } - // Create the Paho MQTT client + // Create the Paho MQTT client. if ((rc = MQTTClient_create( - &mqtt_client, mqtt_endpoint, mqtt_client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL)) + &mqtt_client, + mqtt_endpoint_buffer, + mqtt_client_id_buffer, + MQTTCLIENT_PERSISTENCE_NONE, + NULL)) != MQTTCLIENT_SUCCESS) { - LOG_ERROR("Failed to create MQTT client, return code %d", rc); + LOG_ERROR("Failed to create MQTT client: MQTTClient return code %d.", rc); exit(rc); } +} - // Setup MQTT Message Struct - publish_message.topic = publish_topic; - publish_message.topic_length = sizeof(publish_topic); - publish_message.out_topic_length = 0; - publish_message.payload_span = AZ_SPAN_FROM_BUFFER(publish_payload); - publish_message.out_payload_span = publish_message.payload_span; - - // Connect to IoT Hub - connect_device(); - - // Subscribe to the necessary twin and commands topics to receive twin updates and responses - subscribe(); - - // Initialize PnP Components - components_init(); - - // On device start up, send device info - send_device_info(); - - // On device start up, send device serial number - send_device_serial_number(); - - // Get the twin document to check for updated desired properties. Will then parse desired - // property and update accordingly. - send_twin_get_message(); +static void connect_mqtt_client_to_iot_hub(void) +{ + int rc; - while (is_device_operational) + // Get the MQTT client username. + if (az_failed( + rc = az_iot_hub_client_get_user_name( + &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - // Receive any incoming messages from twin or commands - mqtt_receive_message(); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); + exit(rc); + } - // Send max temp for each component since boot if needed - if (sample_pnp_thermostat_get_max_temp_report(&client, &sample_thermostat_1, &publish_message)) - { - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - } - if (sample_pnp_thermostat_get_max_temp_report(&client, &sample_thermostat_2, &publish_message)) - { - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - } + // Set MQTT connection options. + MQTTClient_connectOptions mqtt_connect_options = MQTTClient_connectOptions_initializer; + mqtt_connect_options.username = mqtt_client_username_buffer; + mqtt_connect_options.password = NULL; // This sample uses x509 authentication. + mqtt_connect_options.cleansession = false; // Set to false so can receive any pending messages. + mqtt_connect_options.keepAliveInterval = AZ_IOT_DEFAULT_MQTT_CONNECT_KEEPALIVE_SECONDS; - // Send a telemetry message - send_telemetry_messages(); + MQTTClient_SSLOptions mqtt_ssl_options = MQTTClient_SSLOptions_initializer; + mqtt_ssl_options.keyStore = (char*)az_span_ptr(env_vars.x509_cert_pem_file_path); + if (az_span_size(env_vars.x509_trust_pem_file_path) != 0) // Is only set if required by OS. + { + mqtt_ssl_options.trustStore = (char*)az_span_ptr(env_vars.x509_trust_pem_file_path); } + mqtt_connect_options.ssl = &mqtt_ssl_options; - // Gracefully disconnect: send the disconnect packet and close the socket - if ((rc = MQTTClient_disconnect(mqtt_client, TIMEOUT_MQTT_DISCONNECT_MS)) != MQTTCLIENT_SUCCESS) + // Connect MQTT client to the Azure IoT Hub. + if ((rc = MQTTClient_connect(mqtt_client, &mqtt_connect_options)) != MQTTCLIENT_SUCCESS) { - LOG_ERROR("Failed to disconnect MQTT client, return code %d", rc); + LOG_ERROR( + "Failed to connect: MQTTClient return code %d.\n" + "If on Windows, confirm the AZ_IOT_DEVICE_X509_TRUST_PEM_FILE_PATH environment variable is " + "set correctly.", + rc); exit(rc); } - else - { - LOG_SUCCESS("Disconnected."); - } - - // Clean up and release resources allocated by the mqtt client - MQTTClient_destroy(&mqtt_client); - - return 0; } -static void components_init() +static void subscribe_mqtt_client_to_iot_hub_topics(void) { - az_result result; + int rc; - if (az_failed( - result = sample_pnp_thermostat_init( - &sample_thermostat_1, - sample_thermostat_1_component_name, - DEFAULT_START_TEMP_CELSIUS))) + // Messages received on the Methods topic will be commands to be invoked. + if ((rc = MQTTClient_subscribe(mqtt_client, AZ_IOT_HUB_CLIENT_METHODS_SUBSCRIBE_TOPIC, 1)) + != MQTTCLIENT_SUCCESS) { - LOG_ERROR("Could not initialize thermostat 1: error code = 0x%08x", result); - exit(result); + LOG_ERROR("Failed to subscribe to the Methods topic: MQTTClient return code %d.", rc); + exit(rc); } - else if (az_failed( - result = sample_pnp_thermostat_init( - &sample_thermostat_2, - sample_thermostat_2_component_name, - DEFAULT_START_TEMP_CELSIUS))) + // Messages received on the Twin Patch topic will be updates to the desired properties. + if ((rc = MQTTClient_subscribe(mqtt_client, AZ_IOT_HUB_CLIENT_TWIN_PATCH_SUBSCRIBE_TOPIC, 1)) + != MQTTCLIENT_SUCCESS) { - LOG_ERROR("Could not initialize thermostat 2: error code = 0x%08x", result); - exit(result); + LOG_ERROR("Failed to subscribe to the Twin Patch topic: MQTTClient return code %d.", rc); + exit(rc); } - LOG_SUCCESS("Initialized PnP components"); - - // Formatting for log - putchar('\n'); + // Messages received on Twin Response topic will be response statuses from the server. + if ((rc = MQTTClient_subscribe(mqtt_client, AZ_IOT_HUB_CLIENT_TWIN_RESPONSE_SUBSCRIBE_TOPIC, 1)) + != MQTTCLIENT_SUCCESS) + { + LOG_ERROR("Failed to subscribe to the Twin Response topic: MQTTClient return code %d.", rc); + exit(rc); + } } -// Read OS environment variables using stdlib function -static az_result read_configuration_entry( - const char* env_name, - char* default_value, - bool hide_value, - az_span buffer, - az_span* out_value) +static void initialize_components(void) { - char* env_value = getenv(env_name); + az_result rc; - if (env_value == NULL && default_value != NULL) + // Initialize thermostats 1 and 2. + if (az_failed( + rc = pnp_thermostat_init(&thermostat_1, thermostat_1_name, DEFAULT_START_TEMP_CELSIUS))) { - env_value = default_value; + LOG_ERROR("Could not initialize Temperature Sensor 1: az_result return code 0x%08x.", rc); + exit(rc); } - if (env_value != NULL) - { - LOG_SUCCESS("%s = %s", env_name, hide_value ? "***" : env_value); - az_span env_span = az_span_create_from_str(env_value); - AZ_RETURN_IF_NOT_ENOUGH_SIZE(buffer, az_span_size(env_span)); - az_span_copy(buffer, env_span); - *out_value = az_span_slice(buffer, 0, az_span_size(env_span)); - } - else + if (az_failed( + rc = pnp_thermostat_init(&thermostat_2, thermostat_2_name, DEFAULT_START_TEMP_CELSIUS))) { - LOG_ERROR("(missing) Please set the %s environment variable.", env_name); - return AZ_ERROR_ARG; + LOG_ERROR("Could not initialize Temperature Sensor 2: az_result return code 0x%08x.", rc); + exit(rc); } - - return AZ_OK; } -static void mqtt_receive_message(void) +static void send_device_info(void) { - char* incoming_message_topic; - int incoming_message_topic_len; - MQTTClient_message* paho_message; - // Receive any incoming messages from twin or commands - if (MQTTClient_receive( - mqtt_client, - &incoming_message_topic, - &incoming_message_topic_len, - &paho_message, - TIMEOUT_WAIT_FOR_RECEIVE_MESSAGE_MS) - == MQTTCLIENT_SUCCESS - && incoming_message_topic != NULL) + // Get the Twin Patch topic to send a reported property update and build the device info + // reported property message. + az_result rc; + if (az_failed(rc = pnp_device_info_get_report_data(&hub_client, &mqtt_message))) { - on_received(incoming_message_topic, incoming_message_topic_len, paho_message); - - MQTTClient_freeMessage(&paho_message); - MQTTClient_free(incoming_message_topic); + LOG_ERROR( + "Failed to get Twin Patch publish topic or build `device info` reported property payload: " + "az_result return code 0x%08x.", + rc); + exit(rc); } + + // Publish the device info reported property update. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent `device info` reported property message."); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); + LOG(" "); // Formatting. + + // Receive the response from the server. + mqtt_receive_message(); } -static void mqtt_publish_message(char* topic, az_span payload, int qos) +static void send_device_serial_number(void) { - int rc; - MQTTClient_deliveryToken token; - if ((rc = MQTTClient_publish( - mqtt_client, topic, az_span_size(payload), az_span_ptr(payload), qos, 0, &token)) - != MQTTCLIENT_SUCCESS) + az_result rc; + + // Get the Twin Patch topic to send a reported property update. + if (az_failed( + rc = az_iot_hub_client_twin_patch_get_publish_topic( + &hub_client, get_request_id(), mqtt_message.topic, mqtt_message.topic_length, NULL))) { - LOG_ERROR("Unable to publish message, return code %d", rc); + LOG_ERROR("Failed to get Twin Patch publish topic: az_result return code 0x%08x.", rc); exit(rc); } - if (qos > 0) + + // Build the serial number reported property message. + if (az_failed( + rc = pnp_create_reported_property( + mqtt_message.payload_span, + AZ_SPAN_NULL, + reported_serial_num_property_name, + append_string_callback, + (void*)&reported_serial_num_property_value, + &mqtt_message.out_payload_span))) { - if ((rc = MQTTClient_waitForCompletion(mqtt_client, token, TIMEOUT_WAIT_FOR_COMPLETION_MS)) - != MQTTCLIENT_SUCCESS) - { - LOG("Wait for message completion timed out, return code %d", rc); - exit(rc); - } + LOG_ERROR( + "Failed to build `serial number` reported property payload: az_result return code 0x%08x.", + rc); + exit(rc); } + + // Publish the serial number reported property update. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent `serial number` reported property message."); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); + LOG(" "); // Formatting. + + // Receive the response from the server. + mqtt_receive_message(); } -// Create mqtt endpoint e.g: ssl//contoso.azure-devices.net:8883 -static az_result create_mqtt_endpoint(char* destination, int32_t destination_size, az_span iot_hub) +static void request_device_twin_document(void) { - int32_t required_size = az_span_size(mqtt_url_prefix) + az_span_size(iot_hub) - + az_span_size(mqtt_url_suffix) + (int32_t)sizeof(null_terminator); + az_result rc; - if (required_size > destination_size) + // Get the Twin Document topic to publish the twin document request. + if (az_failed( + rc = az_iot_hub_client_twin_document_get_publish_topic( + &hub_client, get_request_id(), mqtt_message.topic, mqtt_message.topic_length, NULL))) { - return AZ_ERROR_INSUFFICIENT_SPAN_SIZE; + LOG_ERROR("Failed to get Twin Document publish topic: az_result return code 0x%08x.", rc); + exit(rc); } - az_span destination_span = az_span_create((uint8_t*)destination, destination_size); - az_span remainder = az_span_copy(destination_span, mqtt_url_prefix); - remainder = az_span_copy(remainder, az_span_slice(iot_hub, 0, az_span_size(iot_hub))); - remainder = az_span_copy(remainder, mqtt_url_suffix); - az_span_copy_u8(remainder, null_terminator); + // Publish the twin document request. + mqtt_publish_message(mqtt_message.topic, AZ_SPAN_NULL, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client requested twin document."); + LOG(" "); // Formatting. - return AZ_OK; + // Receive the response from the server. + mqtt_receive_message(); } -// Read the user environment variables used to connect to IoT Hub -static az_result read_configuration_and_init_client(void) +static void receive_messages(void) { - az_span cert = AZ_SPAN_FROM_BUFFER(x509_cert_pem_file); - AZ_RETURN_IF_FAILED( - read_configuration_entry(ENV_DEVICE_X509_CERT_PEM_FILE, NULL, false, cert, &cert)); - - az_span trusted = AZ_SPAN_FROM_BUFFER(x509_trust_pem_file); - AZ_RETURN_IF_FAILED( - read_configuration_entry(ENV_DEVICE_X509_TRUST_PEM_FILE, "", false, trusted, &trusted)); + // Continue to receive commands or device twin messages while device is operational. + while (is_device_operational) + { + // Send max temp for each thermostat since boot if needed. + if (pnp_thermostat_get_max_temp_report(&hub_client, &thermostat_1, &mqtt_message)) + { + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent Temperature Sensor 1 the `maxTempSinceLastReboot` reported property " + "message."); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - az_span device_id_span = AZ_SPAN_FROM_BUFFER(device_id); - AZ_RETURN_IF_FAILED( - read_configuration_entry(ENV_DEVICE_ID, NULL, false, device_id_span, &device_id_span)); + // Receive the response from the server. + mqtt_receive_message(); + } - az_span iot_hub_hostname_span = AZ_SPAN_FROM_BUFFER(iot_hub_hostname); - AZ_RETURN_IF_FAILED(read_configuration_entry( - ENV_IOT_HUB_HOSTNAME, NULL, false, iot_hub_hostname_span, &iot_hub_hostname_span)); + if (pnp_thermostat_get_max_temp_report(&hub_client, &thermostat_2, &mqtt_message)) + { + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent Temperature Sensor 2 the `maxTempSinceLastReboot` reported property " + "message."); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - // Paho requires that the MQTT endpoint be of the form ssl://:8883 - AZ_RETURN_IF_FAILED( - create_mqtt_endpoint(mqtt_endpoint, (int32_t)sizeof(mqtt_endpoint), iot_hub_hostname_span)); + // Receive the response from the server. + mqtt_receive_message(); + } - // Initialize the hub client with the hub host endpoint and the default connection options - az_iot_hub_client_options options = az_iot_hub_client_options_default(); - options.model_id = model_id; - AZ_RETURN_IF_FAILED(az_iot_hub_client_init( - &client, - az_span_slice(iot_hub_hostname_span, 0, (int32_t)strlen(iot_hub_hostname)), - az_span_slice(device_id_span, 0, (int32_t)strlen(device_id)), - &options)); + // Send telemetry messages. No response requested from server. + send_telemetry_messages(); - return AZ_OK; + // Wait for any server-initiated messages. + mqtt_receive_message(); + } } -static az_result append_string(az_json_writer* json_writer, void* value) +static void disconnect_mqtt_client_from_iot_hub(void) { - return az_json_writer_append_string(json_writer, *(az_span*)value); + int rc; + + if ((rc = MQTTClient_disconnect(mqtt_client, TIMEOUT_MQTT_DISCONNECT_MS)) != MQTTCLIENT_SUCCESS) + { + LOG_ERROR("Failed to disconnect MQTT client: MQTTClient return code %d.", rc); + exit(rc); + } + + MQTTClient_destroy(&mqtt_client); } -static az_result append_json_token(az_json_writer* json_writer, void* value) +static void mqtt_publish_message(const char* topic, az_span payload, int qos) { - az_json_token value_token = *(az_json_token*)value; - - double value_as_double; - int32_t string_length; + int rc; + MQTTClient_deliveryToken token; - switch (value_token.kind) + if ((rc = MQTTClient_publish( + mqtt_client, topic, az_span_size(payload), az_span_ptr(payload), qos, 0, &token)) + != MQTTCLIENT_SUCCESS) { - case AZ_JSON_TOKEN_NUMBER: - AZ_RETURN_IF_FAILED(az_json_token_get_double(&value_token, &value_as_double)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_double(json_writer, value_as_double, DOUBLE_DECIMAL_PLACE_DIGITS)); - break; - case AZ_JSON_TOKEN_STRING: - AZ_RETURN_IF_FAILED(az_json_token_get_string( - &value_token, property_scratch_buffer, sizeof(property_scratch_buffer), &string_length)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string( - json_writer, az_span_create((uint8_t*)property_scratch_buffer, string_length))); - break; - default: - return AZ_ERROR_ITEM_NOT_FOUND; + LOG_ERROR("Failed to publish message: MQTTClient return code %d", rc); + exit(rc); } - - return AZ_OK; } -static void send_device_serial_number(void) +static void mqtt_receive_message(void) { - az_result result; + int rc; + char* topic = NULL; + int topic_len = 0; + MQTTClient_message* message = NULL; + static int8_t timeout_counter; - if (az_failed( - result = pnp_create_reported_property( - publish_message.payload_span, - AZ_SPAN_NULL, - serial_number_name, - append_string, - (void*)&serial_number_value, - &publish_message.out_payload_span))) + LOG("Waiting for Command or Device Twin message.\n"); + + if (((rc = MQTTClient_receive(mqtt_client, &topic, &topic_len, &message, TIMEOUT_MQTT_RECEIVE_MS)) + != MQTTCLIENT_SUCCESS) + && (rc != MQTTCLIENT_TOPICNAME_TRUNCATED)) { - LOG_ERROR("Could not get serial number property payload"); - exit(result); + LOG_ERROR("Failed to receive message: MQTTClient return code %d.", rc); + exit(rc); } - else if (az_failed( - result = az_iot_hub_client_twin_patch_get_publish_topic( - &client, - get_request_id(), - publish_message.topic, - publish_message.topic_length, - NULL))) + else if (message == NULL) { - LOG_ERROR("Error to get reported property topic with status: error code = 0x%08x", result); - exit(result); + // Allow up to TIMEOUT_MQTT_RECEIVE_MAX_COUNT before disconnecting. + if (++timeout_counter >= TIMEOUT_MQTT_RECEIVE_MAX_MESSAGE_COUNT) + { + LOG("Receive message timeout count of %d reached.", TIMEOUT_MQTT_RECEIVE_MAX_MESSAGE_COUNT); + is_device_operational = false; + } } + else + { + LOG_SUCCESS("Client received a message from the service."); - LOG_SUCCESS("Sending device serial number property"); + if (rc == MQTTCLIENT_TOPICNAME_TRUNCATED) + { + topic_len = (int)strlen(topic); + } - mqtt_publish_message(publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); + timeout_counter = 0; // Reset. - // Formatting for log - putchar('\n'); -} + on_message_received(topic, topic_len, message); + LOG(" "); // Formatting. -static void send_device_info(void) -{ - // Get the device info in a JSON payload and the topic to which to send it - az_result result; - if (az_failed(result = sample_pnp_device_info_get_report_data(&client, &publish_message))) - { - LOG_ERROR("Could not get the device info data: error code = 0x%08x", result); - exit(result); + MQTTClient_freeMessage(&message); + MQTTClient_free(topic); } - - // Send the MQTT message to the endpoint - mqtt_publish_message(publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - - // Receive response for device info publish - mqtt_receive_message(); } -// Callback invoked by pnp functions each time it finds a property in the twin document -static void sample_property_callback( - az_span component_name, - az_json_token* property_name, - az_json_reader property_value, - int32_t version, - void* user_context_callback) +static void on_message_received(char* topic, int topic_len, const MQTTClient_message* message) { - (void)user_context_callback; - if (az_span_ptr(component_name) == NULL || az_span_size(component_name) == 0) - { - LOG("Property=%.*s arrived for Control component itself. This does not support writable " - "properties on it(all properties are on sub-components) ", - az_span_size(property_name->slice), - az_span_ptr(property_name->slice)); + az_result rc; - az_result err_result; - if (az_failed( - err_result = pnp_create_reported_property_with_status( - publish_message.payload_span, - component_name, - property_name->slice, - append_json_token, - (void*)&property_value, - 404, - version, - property_response_description_failed, - &publish_message.out_payload_span))) - { - LOG_ERROR( - "Could not create root component property error payload: error code = 0x%08x", err_result) - } - else - { - LOG_SUCCESS("Sending error status for root component property"); + az_span topic_span = az_span_create((uint8_t*)topic, topic_len); + az_span message_span = az_span_create((uint8_t*)message->payload, message->payloadlen); - // Send error response to the updated property - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - } - } - else if (az_succeeded(sample_pnp_thermostat_process_property_update( - &client, - &sample_thermostat_1, - component_name, - property_name, - &property_value, - version, - &publish_message))) + az_iot_hub_client_twin_response twin_response; + az_iot_hub_client_method_request command_request; + + // Parse the incoming message topic and check which feature it is for. + if (az_succeeded( + rc + = az_iot_hub_client_twin_parse_received_topic(&hub_client, topic_span, &twin_response))) { - LOG_SUCCESS("Updated property on thermostat 1"); + LOG_SUCCESS("Client received a valid topic response."); + LOG_AZ_SPAN("Topic:", topic_span); + LOG_AZ_SPAN("Payload:", message_span); + LOG("Status: %d", twin_response.status); - // Send response to the updated property - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); + handle_device_twin_message(message_span, &twin_response); } - else if (az_succeeded(sample_pnp_thermostat_process_property_update( - &client, - &sample_thermostat_2, - component_name, - property_name, - &property_value, - version, - &publish_message))) + else if (az_succeeded( + rc = az_iot_hub_client_methods_parse_received_topic( + &hub_client, topic_span, &command_request))) { - LOG_SUCCESS("Updated property on thermostat 2"); + LOG_SUCCESS("Client received a valid topic response."); + LOG_AZ_SPAN("Topic:", topic_span); + LOG_AZ_SPAN("Payload:", message_span); - // Send response to the updated property - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); + handle_command_message(message_span, &command_request); } else { - LOG_ERROR("There was an error updating a property"); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); + LOG_AZ_SPAN("Topic:", topic_span); + exit(rc); } } -// Switch on the type of twin message and handle accordingly -static void handle_twin_message( - MQTTClient_message* message, - az_iot_hub_client_twin_response* twin_response) +static void handle_device_twin_message( + az_span twin_message_span, + const az_iot_hub_client_twin_response* twin_response) { - az_result result; - - az_json_reader json_reader; - az_span twin_payload_span; - - if (message->payloadlen) - { - LOG_SUCCESS("Payload: %.*s", message->payloadlen, (char*)message->payload); - twin_payload_span = az_span_create((uint8_t*)message->payload, (int32_t)message->payloadlen); - if (az_failed(result = az_json_reader_init(&json_reader, twin_payload_span, NULL))) - { - LOG_ERROR("Could not initialize JSON reader"); - return; - } - } - // Determine what type of incoming twin message this is. Print relevant data for the message. + // Invoke appropriate action per response type (3 types only). switch (twin_response->response_type) { // A response from a twin GET publish message with the twin document as a payload. case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_GET: - LOG_SUCCESS("A twin GET response was received"); - pnp_process_twin_data( - &json_reader, - false, - sample_pnp_components, - sample_pnp_components_num, - sample_property_callback, - NULL); + LOG("Message Type: GET"); + (void)pnp_process_device_twin_message( + twin_message_span, false, pnp_components, pnp_components_num, property_callback, NULL); break; - // An update to the desired properties with the properties as a JSON payload. + + // An update to the desired properties with the properties as a payload. case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_DESIRED_PROPERTIES: - LOG_SUCCESS("A twin desired properties message was received"); - pnp_process_twin_data( - &json_reader, - true, - sample_pnp_components, - sample_pnp_components_num, - sample_property_callback, - NULL); + LOG("Message Type: Desired Properties"); + (void)pnp_process_device_twin_message( + twin_message_span, true, pnp_components, pnp_components_num, property_callback, NULL); break; - // A response from a twin reported properties publish message. With a successful update of - // the reported properties, the payload will be empty and the status will be 204. + // A response from a twin reported properties publish message. case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_REPORTED_PROPERTIES: - LOG_SUCCESS("A twin reported properties response message was received"); + LOG("Message Type: Reported Properties"); break; } } -static az_result sample_pnp_temp_controller_process_command( - az_iot_hub_client_method_request* command_request, - az_span component_name, - az_span command_name, - az_span command_payload, - sample_pnp_mqtt_message* mqtt_message) -{ - az_result result; - - (void)command_payload; - - if (az_span_ptr(component_name) == NULL - && az_span_is_content_equal(reboot_command_name, command_name)) - { - // This is a command for the device - if (az_failed( - result = az_iot_hub_client_methods_response_get_publish_topic( - &client, - command_request->request_id, - 200, - mqtt_message->topic, - mqtt_message->topic_length, - NULL))) - { - LOG_ERROR("Unable to get methods response publish topic"); - return result; - } - - mqtt_message->out_payload_span = empty_json_object; - } - else - { - result = AZ_ERROR_ITEM_NOT_FOUND; - } - - return result; -} - -// Invoke the requested command if supported and return status | Return error otherwise static void handle_command_message( - MQTTClient_message* message, - az_iot_hub_client_method_request* command_request) + az_span command_message_span, + const az_iot_hub_client_method_request* command_request) { - az_result result; - - (void)message; - - az_span command_payload = az_span_create(message->payload, message->payloadlen); - az_span component_name; + az_result rc; az_span command_name; - if (az_failed( - result = pnp_parse_command_name(command_request->name, &component_name, &command_name))) - { - LOG_ERROR("Failed to parse command name: error code = 0x%08x", result); - } - else if (az_succeeded( - result = sample_pnp_thermostat_process_command( - &client, - &sample_thermostat_1, - command_request, - component_name, - command_name, - command_payload, - &publish_message))) + az_span component_name; + az_span command_response_payload; + az_iot_status status = AZ_IOT_STATUS_UNKNOWN; + + pnp_parse_command_name(command_request->name, &component_name, &command_name); + + // Invoke command and retrieve response to send to server. + if (az_succeeded(pnp_thermostat_process_command( + &hub_client, + &thermostat_1, + command_request, + component_name, + command_name, + command_message_span, + &mqtt_message, + &status))) { - LOG_SUCCESS( - "Successfully executed command %.*s on thermostat 1", - az_span_size(command_name), - az_span_ptr(command_name)); - - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - - LOG_SUCCESS("Sent response"); + LOG_AZ_SPAN("Client invoked command on Temperature Sensor 1:", command_name); + command_response_payload = mqtt_message.out_payload_span; } - else if (az_succeeded( - result = sample_pnp_thermostat_process_command( - &client, - &sample_thermostat_2, - command_request, - component_name, - command_name, - command_payload, - &publish_message))) + else if (az_succeeded(pnp_thermostat_process_command( + &hub_client, + &thermostat_2, + command_request, + component_name, + command_name, + command_message_span, + &mqtt_message, + &status))) { - LOG_SUCCESS( - "Successfully executed command %.*s on thermostat 2", - az_span_size(command_name), - az_span_ptr(command_name)); - - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - - LOG_SUCCESS("Sent command response"); + LOG_AZ_SPAN("Client invoked command on Temperature Sensor 2:", command_name); + command_response_payload = mqtt_message.out_payload_span; } - else if (az_succeeded( - result = sample_pnp_temp_controller_process_command( - command_request, - component_name, - command_name, - command_payload, - &publish_message))) + else if (az_succeeded(temp_controller_process_command( + command_request, + component_name, + command_name, + command_message_span, + &mqtt_message, + &status))) { - LOG_SUCCESS( - "Successfully executed command %.*s on controller", - az_span_size(command_name), - az_span_ptr(command_name)); - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - - LOG_SUCCESS("Sent command response"); + LOG_AZ_SPAN("Client invoked command on temperature controller:", command_name); + command_response_payload = mqtt_message.out_payload_span; } else { - LOG("Command not supported. Sending 404 response"); - // The command is not for this device + LOG_AZ_SPAN("Command not supported:", command_request->name); + status = AZ_IOT_STATUS_NOT_FOUND; + + // Get the Methods response topic to publish the command response. if (az_failed( - result = az_iot_hub_client_methods_response_get_publish_topic( - &client, + rc = az_iot_hub_client_methods_response_get_publish_topic( + &hub_client, command_request->request_id, - 404, - publish_message.topic, - publish_message.topic_length, + (uint16_t)status, + mqtt_message.topic, + mqtt_message.topic_length, NULL))) { - LOG_ERROR("Unable to get twin document publish topic"); - } - else - { - publish_message.out_payload_span = empty_json_object; - - mqtt_publish_message( - publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - - LOG_SUCCESS("Sent command response"); + LOG_ERROR("Failed to get Methods response publish topic: az_result return code 0x%08x.", rc); + exit(rc); } + command_response_payload = empty_response_payload; } + + // Publish the command response + mqtt_publish_message(mqtt_message.topic, command_response_payload, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client published command response."); + LOG("Status: %d", status); + LOG_AZ_SPAN("Payload:", command_response_payload); } -// Callback for incoming MQTT messages -static int on_received(char* topicName, int topicLen, MQTTClient_message* message) +static az_result temp_controller_process_command( + const az_iot_hub_client_method_request* command_request, + az_span component_name, + az_span command_name, + az_span command_payload, + pnp_mqtt_message* message, + az_iot_status* status) { - if (topicLen == 0) - { - // The length of the topic if there are one or more NULL characters embedded in topicName, - // otherwise topicLen is 0. - topicLen = (int)strlen(topicName); - } - - LOG_SUCCESS("Topic: %s", topicName); + az_result rc; - az_span topic_span = az_span_create((uint8_t*)topicName, topicLen); - - // Parse the incoming message topic and check which feature it is for - az_iot_hub_client_twin_response twin_response; - az_iot_hub_client_method_request command_request; + (void)command_payload; - if (az_succeeded( - az_iot_hub_client_twin_parse_received_topic(&client, topic_span, &twin_response))) + if (az_span_size(component_name) == 0 + && az_span_is_content_equal(reboot_command_name, command_name)) { - LOG_SUCCESS("Twin Message Arrived: status %d", twin_response.status); + *status = AZ_IOT_STATUS_OK; - // Determine what kind of twin message it is and take appropriate actions - handle_twin_message(message, &twin_response); + // Get the Methods response topic to publish the command response. + if (az_failed( + rc = az_iot_hub_client_methods_response_get_publish_topic( + &hub_client, + command_request->request_id, + (uint16_t)*status, + message->topic, + message->topic_length, + NULL))) + { + LOG_ERROR("Failed to get Methods response publish topic: az_result return code 0x%08x.", rc); + return rc; + } + + message->out_payload_span = empty_response_payload; } - else if (az_succeeded(az_iot_hub_client_methods_parse_received_topic( - &client, az_span_create((uint8_t*)topicName, topicLen), &command_request))) + else { - LOG_SUCCESS("Command arrived"); - - // Determine if the command is supported and take appropriate actions - handle_command_message(message, &command_request); + rc = AZ_ERROR_ITEM_NOT_FOUND; } - putchar('\n'); - - return 1; + return rc; } -static void connect_device(void) +static void send_telemetry_messages(void) { - int rc; - - MQTTClient_SSLOptions mqtt_ssl_options = MQTTClient_SSLOptions_initializer; - MQTTClient_connectOptions mqtt_connect_options = MQTTClient_connectOptions_initializer; + az_result rc; - // NOTE: We recommend setting clean session to false in order to receive any pending messages - mqtt_connect_options.cleansession = false; - mqtt_connect_options.keepAliveInterval = AZ_IOT_DEFAULT_MQTT_CONNECT_KEEPALIVE_SECONDS; - - // Get the MQTT username used to connect to IoT Hub + // Get the Telemetry topic to publish the telemetry message and build the telemetry message. if (az_failed( - rc - = az_iot_hub_client_get_user_name(&client, mqtt_username, sizeof(mqtt_username), NULL))) - + rc = pnp_thermostat_get_telemetry_message(&hub_client, &thermostat_1, &mqtt_message))) { - LOG_ERROR("Failed to get MQTT username, return code %d", rc); + LOG_ERROR( + "Failed to get Telemetry publish topic or build telemetry message: az_result return code " + "0x%08x.", + rc); exit(rc); } - LOG_SUCCESS("MQTT username: %s", mqtt_username); + // Publish the telemetry message. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent telemetry message for Temperature Sensor 1:"); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - // This sample uses X509 authentication so the password field is set to NULL - mqtt_connect_options.username = mqtt_username; - mqtt_connect_options.password = NULL; - - // Set the device cert for tls mutual authentication - mqtt_ssl_options.keyStore = (char*)x509_cert_pem_file; - if (*x509_trust_pem_file != '\0') + // Get the Telemetry topic to publish the telemetry message and build the telemetry message. + if (az_failed( + rc = pnp_thermostat_get_telemetry_message(&hub_client, &thermostat_2, &mqtt_message))) { - mqtt_ssl_options.trustStore = (char*)x509_trust_pem_file; + LOG_ERROR( + "Failed to get Telemetry publish topic or build telemetry message: az_result return code " + "0x%08x.", + rc); + exit(rc); } - mqtt_connect_options.ssl = &mqtt_ssl_options; + // Publish the telemetry message. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent telemetry message for Temperature Sensor 2:"); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - // Connect to IoT Hub - if ((rc = MQTTClient_connect(mqtt_client, &mqtt_connect_options)) != MQTTCLIENT_SUCCESS) + // Get the Telemetry topic to publish the telemetry message and build the telemetry message. + if (az_failed(rc = temp_controller_get_telemetry_message(&mqtt_message))) { - LOG_ERROR("Failed to connect, return code %d", rc); + LOG_ERROR( + "Failed to get Telemetry publish topic or build telemetry message: az_result return code " + "0x%08x.", + rc); exit(rc); } - LOG_SUCCESS("Connected to IoT Hub"); + // Publish the telemetry message. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent telemetry message for Temperature Controller:"); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); } -static void subscribe(void) +static az_result temp_controller_get_telemetry_message(pnp_mqtt_message* message) { - int rc; + az_result rc; - // Subscribe to the commands topic. Messages received on this topic are commands to be invoked - // on the device. - if ((rc = MQTTClient_subscribe(mqtt_client, AZ_IOT_HUB_CLIENT_METHODS_SUBSCRIBE_TOPIC, 1)) - != MQTTCLIENT_SUCCESS) + // Get the Telemetry topic to publish the telemetry messages. + if (az_failed( + rc = pnp_get_telemetry_topic( + &hub_client, NULL, AZ_SPAN_NULL, message->topic, message->topic_length, NULL))) { - LOG_ERROR("Failed to subscribe to the commands subscribe topic filter, return code %d", rc); + LOG_ERROR("Failed to get pnp Telemetry publish topic: az_result return code 0x%08x.", rc); exit(rc); } - // Subscribe to the desired properties PATCH topic. Messages received on this topic will be - // updates to the desired properties. - if ((rc = MQTTClient_subscribe(mqtt_client, AZ_IOT_HUB_CLIENT_TWIN_PATCH_SUBSCRIBE_TOPIC, 1)) - != MQTTCLIENT_SUCCESS) - { - LOG_ERROR("Failed to subscribe to the twin patch topic filter, return code %d", rc); - exit(rc); - } + int32_t working_set_ram_in_kibibytes = rand() % 128; - // Subscribe to the twin response topic. Messages received on this topic will be response statuses - // from published reported properties or the requested twin document from twin GET publish - // messages. - if ((rc = MQTTClient_subscribe(mqtt_client, AZ_IOT_HUB_CLIENT_TWIN_RESPONSE_SUBSCRIBE_TOPIC, 1)) - != MQTTCLIENT_SUCCESS) - { - LOG_ERROR("Failed to subscribe to twin response topic filter, return code %d", rc); - exit(rc); - } + // Build the telemetry message. + az_json_writer jw; + AZ_RETURN_IF_FAILED(az_json_writer_init(&jw, message->payload_span, NULL)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, working_set_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_int32(&jw, working_set_ram_in_kibibytes)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); + message->out_payload_span = az_json_writer_get_bytes_used_in_destination(&jw); - LOG_SUCCESS("Subscribed to IoT Hub topics"); + return rc; } -static void send_twin_get_message(void) +static az_result append_string_callback(az_json_writer* jw, void* value) { - int rc; - - az_span request_id_span = get_request_id(); - if (az_failed( - rc = az_iot_hub_client_twin_document_get_publish_topic( - &client, request_id_span, publish_message.topic, publish_message.topic_length, NULL))) - { - LOG_ERROR("Could not get twin get publish topic, az_result %d", rc); - exit(rc); - } - - LOG_SUCCESS("Sending twin get request"); - mqtt_publish_message(publish_message.topic, AZ_SPAN_NULL, SAMPLE_PUBLISH_QOS); - - // Formatting for log - putchar('\n'); + return az_json_writer_append_string(jw, *(az_span*)value); } -static az_result temperature_controller_get_telemetry_message(sample_pnp_mqtt_message* message) +static az_result append_json_token_callback(az_json_writer* jw, void* value) { - az_result result; - if (az_failed( - result = pnp_get_telemetry_topic( - &client, NULL, AZ_SPAN_NULL, message->topic, message->topic_length, NULL))) - { - printf("Could not get pnp telemetry topic: error code = 0x%08x\n", result); - return result; - } + az_json_token value_token = *(az_json_token*)value; - working_set_ram_in_kibibytes = rand() % 128; + double value_as_double; + int32_t string_length; - az_json_writer json_builder; - AZ_RETURN_IF_FAILED(az_json_writer_init(&json_builder, message->payload_span, NULL)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_builder)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&json_builder, working_set_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_int32(&json_builder, working_set_ram_in_kibibytes)); - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_builder)); - message->out_payload_span = az_json_writer_get_bytes_used_in_destination(&json_builder); + switch (value_token.kind) + { + case AZ_JSON_TOKEN_NUMBER: + AZ_RETURN_IF_FAILED(az_json_token_get_double(&value_token, &value_as_double)); + AZ_RETURN_IF_FAILED( + az_json_writer_append_double(jw, value_as_double, DOUBLE_DECIMAL_PLACE_DIGITS)); + break; + case AZ_JSON_TOKEN_STRING: + AZ_RETURN_IF_FAILED(az_json_token_get_string( + &value_token, property_scratch_buffer, sizeof(property_scratch_buffer), &string_length)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string( + jw, az_span_create((uint8_t*)property_scratch_buffer, string_length))); + break; + default: + return AZ_ERROR_ITEM_NOT_FOUND; + } - return result; + return AZ_OK; } -// Send JSON formatted telemetry messages -static void send_telemetry_messages(void) +static void property_callback( + az_span component_name, + const az_json_token* property_name, + az_json_reader property_value, + int32_t version, + void* user_context_callback) { - az_result result; + az_result rc; + (void)user_context_callback; - if (az_failed( - result = sample_pnp_thermostat_get_telemetry_message( - &client, &sample_thermostat_1, &publish_message))) + if (az_span_ptr(component_name) == NULL || az_span_size(component_name) == 0) { - LOG_ERROR("Error getting message and topic for thermostat 1"); - exit(result); - } + LOG_ERROR( + "Temperature Controller does not support writable property \"%.*s\". All writeable " + "properties are on sub-components.", + az_span_size(property_name->slice), + az_span_ptr(property_name->slice)); - LOG_SUCCESS("Sending Telemetry Message for thermostat 1"); + // Get the Twin Patch topic to send a reported property update. + if (az_failed( + rc = az_iot_hub_client_twin_patch_get_publish_topic( + &hub_client, + get_request_id(), + mqtt_message.topic, + mqtt_message.topic_length, + NULL))) + { + LOG_ERROR("Failed to get Twin Patch publish topic: az_result return code 0x%08x.", rc); + exit(rc); + } - mqtt_publish_message(publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); + // Build the root component error reported property message. + if (az_failed( + rc = pnp_create_reported_property_with_status( + mqtt_message.payload_span, + component_name, + property_name->slice, + append_json_token_callback, + (void*)&property_value, + AZ_IOT_STATUS_NOT_FOUND, + version, + property_response_description_failed, + &mqtt_message.out_payload_span))) + { + LOG_ERROR( + "Failed to build Temperature Controller property error payload: az_result return code " + "0x%08x.", + rc) + exit(rc); + } - if (az_failed( - result = sample_pnp_thermostat_get_telemetry_message( - &client, &sample_thermostat_2, &publish_message))) - { - LOG_ERROR("Error getting message and topic for thermostat 2"); - exit(result); - } + // Send error response to the updated property. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent Temperature Controller error status reported property message:"); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - LOG_SUCCESS("Sending Telemetry Message for thermostat 2"); + // Receive the response from the server. + mqtt_receive_message(); + } + else if (az_succeeded( + rc = pnp_thermostat_process_property_update( + &hub_client, + &thermostat_1, + component_name, + property_name, + &property_value, + version, + &mqtt_message))) + { + // Send response to the updated property. + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent Temperature Sensor 1 reported property message:"); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - mqtt_publish_message(publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); + // Receive the response from the server. + mqtt_receive_message(); + } + else if (az_succeeded( + rc = pnp_thermostat_process_property_update( + &hub_client, + &thermostat_2, + component_name, + property_name, + &property_value, + version, + &mqtt_message))) + { + // Send response to the updated property + mqtt_publish_message(mqtt_message.topic, mqtt_message.out_payload_span, MQTT_PUBLISH_QOS); + LOG_SUCCESS("Client sent Temperature Sensor 2 reported property message."); + LOG_AZ_SPAN("Payload:", mqtt_message.out_payload_span); - if (az_failed(result = temperature_controller_get_telemetry_message(&publish_message))) + // Receive the response from the server. + mqtt_receive_message(); + } + else { - LOG_ERROR("Error getting message and topic for root component"); - exit(result); + LOG_ERROR("Failed to update a property: az_result return code 0x%08x.", rc); + exit(rc); } - - LOG_SUCCESS("Sending Telemetry Message for temperature controller"); - - mqtt_publish_message(publish_message.topic, publish_message.out_payload_span, SAMPLE_PUBLISH_QOS); - - // New line to separate messages on the console - putchar('\n'); } diff --git a/sdk/samples/iot/paho_iot_hub_pnp_sample.c b/sdk/samples/iot/paho_iot_hub_pnp_sample.c index 00c3859d89..9d314a8844 100644 --- a/sdk/samples/iot/paho_iot_hub_pnp_sample.c +++ b/sdk/samples/iot/paho_iot_hub_pnp_sample.c @@ -2,17 +2,18 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER -// warning C4201: nonstandard extension used: nameless struct/union -#pragma warning(disable : 4201) // warning C4204: nonstandard extension used: non-constant aggregate initializer #pragma warning(disable : 4204) // warning C4996: 'localtime': This function or variable may be unsafe. Consider using localtime_s // instead. #pragma warning(disable : 4996) +#pragma warning(push) +// warning C4201: nonstandard extension used: nameless struct/union +#pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -33,7 +34,7 @@ #define SAMPLE_NAME PAHO_IOT_HUB_PNP_SAMPLE #define TELEMETRY_SEND_INTERVAL 1 -#define TIMEOUT_MQTT_RECEIVE_MAX_COUNT 3 +#define TIMEOUT_MQTT_RECEIVE_MAX_MESSAGE_COUNT 3 #define TIMEOUT_MQTT_RECEIVE_MS (8 * 1000) #define TIMEOUT_MQTT_DISCONNECT_MS (10 * 1000) #define TIMEOUT_MQTT_WAIT_FOR_COMPLETION_MS 1000 @@ -41,8 +42,9 @@ #define DEFAULT_START_TEMP_AVG_COUNT 1 #define DEFAULT_START_TEMP_CELSIUS 22.0 #define DOUBLE_DECIMAL_PLACE_DIGITS 2 +#define SAMPLE_PUBLISH_QOS 0 -static bool device_operational = true; +static bool is_device_operational = true; static const char iso_spec_time_format[] = "%Y-%m-%dT%H:%M:%S%z"; // ISO8601 Time Format // * PnP Values * @@ -77,7 +79,7 @@ static const az_span command_min_temp_name = AZ_SPAN_LITERAL_FROM_STR("minTemp") static const az_span command_avg_temp_name = AZ_SPAN_LITERAL_FROM_STR("avgTemp"); static const az_span command_start_time_name = AZ_SPAN_LITERAL_FROM_STR("startTime"); static const az_span command_end_time_name = AZ_SPAN_LITERAL_FROM_STR("endTime"); -static const az_span command_error_response_payload = AZ_SPAN_LITERAL_FROM_STR("{}"); +static const az_span command_empty_response_payload = AZ_SPAN_LITERAL_FROM_STR("{}"); static char command_start_time_value_buffer[32]; static char command_end_time_value_buffer[32]; static char command_response_payload_buffer[256]; @@ -109,13 +111,14 @@ static void receive_messages(void); static void disconnect_mqtt_client_from_iot_hub(void); static az_span get_request_id(void); -static void mqtt_publish_message(char* topic, az_span payload, int qos); +static void mqtt_publish_message(const char* topic, az_span payload, int qos); static void on_message_received(char* topic, int topic_len, const MQTTClient_message* message); // Device Twin functions static void handle_device_twin_message( - const az_span twin_message_span, + az_span twin_message_span, const az_iot_hub_client_twin_response* twin_response); +static void process_device_twin_message(az_span twin_message_span, bool is_twin_get); static az_result parse_device_twin_desired_temperature_property( az_span twin_message_span, bool is_twin_get, @@ -126,7 +129,7 @@ static void send_reported_property(az_span name, double value, int32_t version, // Command functions static void handle_command_message( - const az_span command_message_span, + az_span command_message_span, const az_iot_hub_client_method_request* command_request); static void send_command_response( const az_iot_hub_client_method_request* command_request, @@ -202,10 +205,11 @@ static az_result build_property_payload_with_status( * } * } * - * Direct Method (Command): One device command is supported in this sample: `getMaxMinReport`. If any other - * commands are attempted to be invoked, the log will report the command is not found. To invoke a - * command, select your device's Direct Method tab in the Azure IoT Explorer. Enter the command name - * `getMaxMinReport` along with a payload using an ISO8061 time format and select Invoke method. + * Direct Method (Command): One device command is supported in this sample: `getMaxMinReport`. If + * any other commands are attempted to be invoked, the log will report the command is not found. To + * invoke a command, select your device's Direct Method tab in the Azure IoT Explorer. Enter the + * command name `getMaxMinReport` along with a payload using an ISO8061 time format and select + * Invoke method. * * "2020-08-18T17:09:29-0700" * @@ -234,7 +238,7 @@ int main(void) LOG_SUCCESS("Client subscribed to IoT Hub topics."); request_device_twin_document(); - LOG_SUCCESS("Client requested twin document.") + LOG_SUCCESS("Client requested device twin document.") receive_messages(); LOG_SUCCESS("Client received messages.") @@ -253,7 +257,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -264,7 +268,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -275,7 +279,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_init( &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, &options))) { - LOG_ERROR("Failed to initialize hub client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } @@ -285,7 +289,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_get_client_id( &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -312,7 +316,7 @@ static void connect_mqtt_client_to_iot_hub(void) rc = az_iot_hub_client_get_user_name( &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -376,15 +380,12 @@ static void request_device_twin_document(void) { az_result rc; - LOG("Client requesting device twin document from service."); - // Get the Twin Document topic to publish the twin document request. char twin_document_topic_buffer[128]; - az_span request_id = get_request_id(); if (az_failed( rc = az_iot_hub_client_twin_document_get_publish_topic( &hub_client, - request_id, + get_request_id(), twin_document_topic_buffer, sizeof(twin_document_topic_buffer), NULL))) @@ -394,7 +395,7 @@ static void request_device_twin_document(void) } // Publish the twin document request. - mqtt_publish_message(twin_document_topic_buffer, AZ_SPAN_NULL, 0); + mqtt_publish_message(twin_document_topic_buffer, AZ_SPAN_NULL, SAMPLE_PUBLISH_QOS); } static void receive_messages(void) @@ -403,10 +404,10 @@ static void receive_messages(void) char* topic = NULL; int topic_len = 0; MQTTClient_message* message = NULL; - uint8_t timeoutCounter = 0; + uint8_t timeout_counter = 0; - // Continue to receive commands or device twin messages while device is operational - while (device_operational) + // Continue to receive commands or device twin messages while device is operational. + while (is_device_operational) { LOG(" "); // Formatting. LOG("Waiting for Command or Device Twin message.\n"); @@ -421,32 +422,32 @@ static void receive_messages(void) } else if (message == NULL) { - // Allow up to TIMEOUT_MQTT_RECEIVE_MAX_COUNT before disconnecting - if (++timeoutCounter >= TIMEOUT_MQTT_RECEIVE_MAX_COUNT) + // Allow up to TIMEOUT_MQTT_RECEIVE_MAX_COUNT before disconnecting. + if (++timeout_counter >= TIMEOUT_MQTT_RECEIVE_MAX_MESSAGE_COUNT) { - LOG("Receive message timeout count of %d reached.", TIMEOUT_MQTT_RECEIVE_MAX_COUNT); + LOG("Receive message timeout count of %d reached.", TIMEOUT_MQTT_RECEIVE_MAX_MESSAGE_COUNT); return; } } else { - LOG_SUCCESS("Client received message from the service."); + LOG_SUCCESS("Client received a message from the service."); if (rc == MQTTCLIENT_TOPICNAME_TRUNCATED) { topic_len = (int)strlen(topic); } - timeoutCounter = 0; // Reset. + timeout_counter = 0; // Reset. on_message_received(topic, topic_len, message); - LOG(" "); // Formatting + LOG(" "); // Formatting. MQTTClient_freeMessage(&message); MQTTClient_free(topic); } - // Send a telemetry message + // Send a telemetry message. send_telemetry_message(); } } @@ -473,14 +474,14 @@ static az_span get_request_id(void) if (az_failed(rc = az_span_i32toa(destination, connection_request_id_int++, &out_span))) { - LOG_ERROR("Failed to get request id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get request id: az_result return code 0x%08x.", rc); exit(rc); } return az_span_slice(destination, 0, az_span_size(destination) - az_span_size(out_span)); } -static void mqtt_publish_message(char* topic, az_span payload, int qos) +static void mqtt_publish_message(const char* topic, az_span payload, int qos) { int rc; MQTTClient_deliveryToken token; @@ -519,17 +520,18 @@ static void on_message_received(char* topic, int topic_len, const MQTTClient_mes rc = az_iot_hub_client_twin_parse_received_topic(&hub_client, topic_span, &twin_response))) { - LOG_SUCCESS("Client received a valid topic response:"); + LOG_SUCCESS("Client received a valid topic response."); LOG_AZ_SPAN("Topic:", topic_span); LOG_AZ_SPAN("Payload:", message_span); LOG("Status: %d", twin_response.status); handle_device_twin_message(message_span, &twin_response); } - else if (az_succeeded(az_iot_hub_client_methods_parse_received_topic( - &hub_client, topic_span, &command_request))) + else if (az_succeeded( + rc = az_iot_hub_client_methods_parse_received_topic( + &hub_client, topic_span, &command_request))) { - LOG_SUCCESS("Client received a valid topic response:"); + LOG_SUCCESS("Client received a valid topic response."); LOG_AZ_SPAN("Topic:", topic_span); LOG_AZ_SPAN("Payload:", message_span); @@ -537,66 +539,68 @@ static void on_message_received(char* topic, int topic_len, const MQTTClient_mes } else { - LOG_ERROR("Message from unknown topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); LOG_AZ_SPAN("Topic:", topic_span); exit(rc); } } static void handle_device_twin_message( - const az_span twin_message_span, + az_span twin_message_span, const az_iot_hub_client_twin_response* twin_response) { - // Invoke appropriate action per response type (3 Types only). bool is_twin_get = false; + // Invoke appropriate action per response type (3 types only). switch (twin_response->response_type) { + // A response from a twin GET publish message with the twin document as a payload. case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_GET: - LOG("Type: GET"); + LOG("Message Type: GET"); is_twin_get = true; + process_device_twin_message(twin_message_span, is_twin_get); break; + // An update to the desired properties with the properties as a payload. case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_DESIRED_PROPERTIES: - LOG("Type: Desired Properties"); + LOG("Message Type: Desired Properties"); + process_device_twin_message(twin_message_span, is_twin_get); break; + // A response from a twin reported properties publish message. case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_REPORTED_PROPERTIES: - LOG("Type: Reported Properties"); + LOG("Message Type: Reported Properties"); break; } +} - // For a GET response OR a Desired Properties response from the server: - // 1. Parse for the desired temperature - // 2. Update device temperature locally - // 3. Report updated temperature to server - if (twin_response->response_type == AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_GET - || twin_response->response_type == AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_DESIRED_PROPERTIES) - { - double desired_temp; - int32_t version_num; +static void process_device_twin_message(az_span twin_message_span, bool is_twin_get) +{ + double desired_temp; + int32_t version_num; - if (az_succeeded(parse_device_twin_desired_temperature_property( - twin_message_span, is_twin_get, &desired_temp, &version_num))) - { - bool confirm = true; - bool is_max_temp_changed = false; + // Parse for the desired temperature + if (az_succeeded(parse_device_twin_desired_temperature_property( + twin_message_span, is_twin_get, &desired_temp, &version_num))) + { + bool confirm = true; + bool is_max_temp_changed = false; - update_device_temp(desired_temp, &is_max_temp_changed); - send_reported_property(twin_desired_temp_property_name, desired_temp, version_num, confirm); + // Update device temperature locally and report update to server + update_device_temp(desired_temp, &is_max_temp_changed); + send_reported_property(twin_desired_temp_property_name, desired_temp, version_num, confirm); - if (is_max_temp_changed) - { - confirm = false; - send_reported_property(twin_reported_max_temp_property_name, device_max_temp, -1, confirm); - } + if (is_max_temp_changed) + { + confirm = false; + send_reported_property(twin_reported_max_temp_property_name, device_max_temp, -1, confirm); } - // else Desired property not found in payload. Do nothing. } + // Else desired property not found in payload. Do nothing. } static az_result parse_device_twin_desired_temperature_property( - const az_span twin_message_span, + az_span twin_message_span, bool is_twin_get, double* parsed_temp, int32_t* version_number) @@ -708,16 +712,15 @@ static void send_reported_property(az_span name, double value, int32_t version, // Get the Twin Patch topic to send a reported property update. char twin_patch_topic_buffer[128]; - az_span request_id_span = get_request_id(); if (az_failed( rc = az_iot_hub_client_twin_patch_get_publish_topic( &hub_client, - request_id_span, + get_request_id(), twin_patch_topic_buffer, sizeof(twin_patch_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Twin Patch publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Twin Patch publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -736,7 +739,9 @@ static void send_reported_property(az_span name, double value, int32_t version, reported_property_payload, &reported_property_payload))) { - LOG_ERROR("Failed to build confirmed payload : az_result return code 0x%04x.", rc); + LOG_ERROR( + "Failed to build reported property confirmed payload : az_result return code 0x%08x.", + rc); exit(rc); } } @@ -750,14 +755,14 @@ static void send_reported_property(az_span name, double value, int32_t version, rc = build_property_payload( count, names, values, NULL, reported_property_payload, &reported_property_payload))) { - LOG_ERROR("Failed to build payload: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to build reported property payload: az_result return code 0x%08x.", rc); exit(rc); } } // Publish the reported property update. - mqtt_publish_message(twin_patch_topic_buffer, reported_property_payload, 0); - LOG_SUCCESS("Client sent reported property message:"); + mqtt_publish_message(twin_patch_topic_buffer, reported_property_payload, SAMPLE_PUBLISH_QOS); + LOG_SUCCESS("Client sent reported property message."); LOG_AZ_SPAN("Payload:", reported_property_payload); } @@ -786,8 +791,8 @@ static void handle_command_message( } else { - LOG_AZ_SPAN("command not supported:", command_request->name); - send_command_response(command_request, AZ_IOT_STATUS_NOT_FOUND, command_error_response_payload); + LOG_AZ_SPAN("Command not supported:", command_request->name); + send_command_response(command_request, AZ_IOT_STATUS_NOT_FOUND, command_empty_response_payload); } } @@ -796,7 +801,7 @@ static void send_command_response( az_iot_status status, az_span response_payload) { - int rc; + az_result rc; // Get the Methods response topic to publish the command response. char methods_response_topic_buffer[128]; @@ -809,12 +814,12 @@ static void send_command_response( sizeof(methods_response_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Methods response publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Methods response publish topic: az_result return code 0x%08x.", rc); exit(rc); } // Publish the command response. - mqtt_publish_message(methods_response_topic_buffer, response_payload, 0); + mqtt_publish_message(methods_response_topic_buffer, response_payload, SAMPLE_PUBLISH_QOS); LOG_SUCCESS("Client published command response:"); LOG("Status: %d", status); LOG_AZ_SPAN("Payload:", response_payload); @@ -844,7 +849,7 @@ static az_result invoke_getMaxMinReport( // Set the response payload to error if the "since" value was empty. if (az_span_ptr(start_time_span) == NULL) { - *out_response = command_error_response_payload; + *out_response = command_empty_response_payload; return AZ_ERROR_ITEM_NOT_FOUND; } @@ -868,12 +873,12 @@ static az_result invoke_getMaxMinReport( const double values[3] = { device_max_temp, device_min_temp, device_avg_temp }; const az_span times[2] = { start_time_span, end_time_span }; - int rc; + az_result rc; if (az_failed( rc = build_property_payload( count, names, values, times, response_destination, out_response))) { - LOG_ERROR("Failed to build command response payload: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to build command response payload: az_result return code 0x%08x.", rc); exit(rc); } @@ -882,7 +887,7 @@ static az_result invoke_getMaxMinReport( static void send_telemetry_message(void) { - int rc; + az_result rc; // Get the Telemetry topic to publish the telemetry message. char telemetry_topic_buffer[128]; @@ -890,7 +895,7 @@ static void send_telemetry_message(void) rc = az_iot_hub_client_telemetry_get_publish_topic( &hub_client, NULL, telemetry_topic_buffer, sizeof(telemetry_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Telemetry publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Telemetry publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -905,12 +910,12 @@ static void send_telemetry_message(void) rc = build_property_payload( count, names, values, NULL, telemetry_payload, &telemetry_payload))) { - LOG_ERROR("Failed to build telemetry payload: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to build telemetry payload: az_result return code 0x%08x.", rc); exit(rc); } // Publish the telemetry message. - mqtt_publish_message(telemetry_topic_buffer, telemetry_payload, 0); + mqtt_publish_message(telemetry_topic_buffer, telemetry_payload, SAMPLE_PUBLISH_QOS); LOG_SUCCESS("Client sent telemetry message to the service:"); LOG_AZ_SPAN("Payload:", telemetry_payload); } diff --git a/sdk/samples/iot/paho_iot_hub_sas_telemetry_sample.c b/sdk/samples/iot/paho_iot_hub_sas_telemetry_sample.c index 7cdb99a1ff..608ade2bf0 100644 --- a/sdk/samples/iot/paho_iot_hub_sas_telemetry_sample.c +++ b/sdk/samples/iot/paho_iot_hub_sas_telemetry_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -76,7 +77,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -87,7 +88,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -96,7 +97,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_init( &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, NULL))) { - LOG_ERROR("Failed to initialize hub client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } @@ -106,7 +107,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_get_client_id( &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -136,7 +137,7 @@ static void connect_mqtt_client_to_iot_hub(void) rc = az_iot_hub_client_get_user_name( &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -176,7 +177,7 @@ static void send_telemetry_messages_to_iot_hub(void) rc = az_iot_hub_client_telemetry_get_publish_topic( &hub_client, NULL, telemetry_topic_buffer, sizeof(telemetry_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Telemetry publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Telemetry publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -220,7 +221,7 @@ static void disconnect_mqtt_client_from_iot_hub(void) static void generate_sas_key(void) { - int rc; + az_result rc; // Create the POSIX expiration time from input minutes. uint64_t sas_duration = get_epoch_expiration_time_from_minutes(env_vars.sas_key_duration_minutes); @@ -231,14 +232,17 @@ static void generate_sas_key(void) rc = az_iot_hub_client_sas_get_signature( &hub_client, sas_duration, sas_signature, &sas_signature))) { - LOG_ERROR("Could not get the signature for SAS key: az_result return code 0x%04x.", rc); + LOG_ERROR("Could not get the signature for SAS key: az_result return code 0x%08x.", rc); exit(rc); } // Generate the encoded, signed signature (b64 encoded, HMAC-SHA256 signing) az_span sas_encoded_signed_signature = AZ_SPAN_FROM_BUFFER(sas_encoded_signed_signature_buffer); sas_generate_encoded_signed_signature( - env_vars.hub_sas_key, sas_signature, sas_encoded_signed_signature, &sas_encoded_signed_signature); + env_vars.hub_sas_key, + sas_signature, + sas_encoded_signed_signature, + &sas_encoded_signed_signature); // Get the resulting MQTT password, passing the base64 encoded, HMAC signed bytes size_t mqtt_password_length; @@ -252,7 +256,7 @@ static void generate_sas_key(void) sizeof(mqtt_password_buffer), &mqtt_password_length))) { - LOG_ERROR("Could not get the password: az_result return code 0x%04x.", rc); + LOG_ERROR("Could not get the password: az_result return code 0x%08x.", rc); exit(rc); } } diff --git a/sdk/samples/iot/paho_iot_hub_telemetry_sample.c b/sdk/samples/iot/paho_iot_hub_telemetry_sample.c index 88bae3b940..afc8f3b2c8 100644 --- a/sdk/samples/iot/paho_iot_hub_telemetry_sample.c +++ b/sdk/samples/iot/paho_iot_hub_telemetry_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -69,7 +70,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -80,7 +81,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -89,7 +90,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_init( &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, NULL))) { - LOG_ERROR("Failed to initialize hub client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } @@ -99,7 +100,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_get_client_id( &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -126,7 +127,7 @@ static void connect_mqtt_client_to_iot_hub(void) rc = az_iot_hub_client_get_user_name( &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT username: az_result return code 0x%08x.", rc); exit(rc); } @@ -167,7 +168,7 @@ static void send_telemetry_messages_to_iot_hub(void) rc = az_iot_hub_client_telemetry_get_publish_topic( &hub_client, NULL, telemetry_topic_buffer, sizeof(telemetry_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Telemetry publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Telemetry publish topic: az_result return code 0x%08x.", rc); exit(rc); } diff --git a/sdk/samples/iot/paho_iot_hub_twin_sample.c b/sdk/samples/iot/paho_iot_hub_twin_sample.c index b2b1121b6d..e17ed41774 100644 --- a/sdk/samples/iot/paho_iot_hub_twin_sample.c +++ b/sdk/samples/iot/paho_iot_hub_twin_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -94,7 +95,7 @@ int main(void) LOG_SUCCESS("Client subscribed to IoT Hub topics."); get_device_twin_document(); - LOG_SUCCESS("Client got twin document."); + LOG_SUCCESS("Client received device twin document."); send_reported_property(); LOG_SUCCESS("Client sent reported property."); @@ -116,7 +117,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -127,7 +128,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -136,7 +137,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_init( &hub_client, env_vars.hub_hostname, env_vars.hub_device_id, NULL))) { - LOG_ERROR("Failed to initialize hub client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize hub client: az_result return code 0x%08x.", rc); exit(rc); } @@ -146,7 +147,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_hub_client_get_client_id( &hub_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -173,7 +174,7 @@ static void connect_mqtt_client_to_iot_hub(void) rc = az_iot_hub_client_get_user_name( &hub_client, mqtt_client_username_buffer, sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -241,7 +242,7 @@ static void get_device_twin_document(void) sizeof(twin_document_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Twin Document publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Twin Document publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -273,16 +274,17 @@ static void send_reported_property(void) sizeof(twin_patch_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Twin Patch publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Twin Patch publish topic: az_result return code 0x%08x.", rc); exit(rc); } // Build the updated reported property message. char reported_property_payload_buffer[128]; az_span reported_property_payload = AZ_SPAN_FROM_BUFFER(reported_property_payload_buffer); - if (az_failed(rc = build_reported_property(reported_property_payload, &reported_property_payload))) + if (az_failed( + rc = build_reported_property(reported_property_payload, &reported_property_payload))) { - LOG_ERROR("Failed to build reported property payload: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to build reported property payload: az_result return code 0x%08x.", rc); exit(rc); } @@ -355,14 +357,14 @@ static void receive_device_twin_message(void) { topic_len = (int)strlen(topic); } - LOG_SUCCESS("Client received device twin message from the service."); + LOG_SUCCESS("Client received a device twin message from the service."); // Parse device twin message. az_iot_hub_client_twin_response twin_response; parse_device_twin_message(topic, topic_len, message, &twin_response); LOG_SUCCESS("Client parsed device twin message."); - LOG(" "); // Formatting + LOG(" "); // Formatting. MQTTClient_freeMessage(&message); MQTTClient_free(topic); @@ -374,7 +376,7 @@ static void parse_device_twin_message( const MQTTClient_message* message, az_iot_hub_client_twin_response* twin_response) { - int rc; + az_result rc; az_span topic_span = az_span_create((uint8_t*)topic, topic_len); az_span message_span = az_span_create((uint8_t*)message->payload, message->payloadlen); @@ -382,7 +384,7 @@ static void parse_device_twin_message( if (az_failed( rc = az_iot_hub_client_twin_parse_received_topic(&hub_client, topic_span, twin_response))) { - LOG_ERROR("Message from unknown topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); LOG_AZ_SPAN("Topic:", topic_span); exit(rc); } @@ -391,23 +393,23 @@ static void parse_device_twin_message( LOG_AZ_SPAN("Payload:", message_span); LOG("Status: %d", twin_response->status); - // Invoke appropriate action per response type (3 Types only). + // Invoke appropriate action per response type (3 types only). switch (twin_response->response_type) { case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_GET: - LOG("Type: GET"); + LOG("Message Type: GET"); break; case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_REPORTED_PROPERTIES: - LOG("Type: Reported Properties"); + LOG("Message Type: Reported Properties"); break; case AZ_IOT_CLIENT_TWIN_RESPONSE_TYPE_DESIRED_PROPERTIES: - LOG("Type: Desired Properties"); + LOG("Message Type: Desired Properties"); if (az_failed(rc = update_property(message_span))) { - LOG_ERROR("Failed to update property locally: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to update property locally: az_result return code 0x%08x.", rc); exit(rc); } break; diff --git a/sdk/samples/iot/paho_iot_provisioning_sample.c b/sdk/samples/iot/paho_iot_provisioning_sample.c index c2ef60a71c..333bfcce92 100644 --- a/sdk/samples/iot/paho_iot_provisioning_sample.c +++ b/sdk/samples/iot/paho_iot_provisioning_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -47,7 +48,8 @@ static void parse_registration_message( const MQTTClient_message* message, az_iot_provisioning_client_register_response* response, az_iot_provisioning_client_operation_status* operation_status); -static void send_operation_query_message(const az_iot_provisioning_client_register_response* response); +static void send_operation_query_message( + const az_iot_provisioning_client_register_response* response); /* * This sample registers a device with the Azure IoT Device Provisioning Service. @@ -84,7 +86,7 @@ static void create_and_configure_mqtt_client(void) // Reads in environment variables set by user for purposes of running sample. if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { - LOG_ERROR("Failed to read environment variables: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to read environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -94,7 +96,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -108,7 +110,7 @@ static void create_and_configure_mqtt_client(void) env_vars.provisioning_registration_id, NULL))) { - LOG_ERROR("Failed to initialize provisioning client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize provisioning client: az_result return code 0x%08x.", rc); exit(rc); } @@ -118,7 +120,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_provisioning_client_get_client_id( &provisioning_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -148,7 +150,7 @@ static void connect_mqtt_client_to_provisioning_service(void) sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -206,7 +208,7 @@ static void register_device_with_provisioning_service(void) sizeof(register_publish_topic_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT register publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT register publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -257,7 +259,7 @@ static void receive_device_registration_status(void) { topic_len = (int)strlen(topic); } - LOG_SUCCESS("Client received a message from provisioning service."); + LOG_SUCCESS("Client received a message from the provisioning service."); // Parse registration message. parse_registration_message(topic, topic_len, message, ®ister_response, &operation_status); @@ -321,7 +323,7 @@ static void parse_registration_message( az_iot_provisioning_client_register_response* register_response, az_iot_provisioning_client_operation_status* operation_status) { - int rc; + az_result rc; az_span topic_span = az_span_create((uint8_t*)topic, topic_len); az_span message_span = az_span_create((uint8_t*)message->payload, message->payloadlen); @@ -330,7 +332,7 @@ static void parse_registration_message( rc = az_iot_provisioning_client_parse_received_topic_and_payload( &provisioning_client, topic_span, message_span, register_response))) { - LOG_ERROR("Message from unknown topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); LOG_AZ_SPAN("Topic:", topic_span); exit(rc); } @@ -344,7 +346,7 @@ static void parse_registration_message( rc = az_iot_provisioning_client_parse_operation_status(register_response, operation_status))) { - LOG_ERROR("Failed to parse operation_status: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to parse operation_status: az_result return code 0x%08x.", rc); exit(rc); } } @@ -364,7 +366,7 @@ static void send_operation_query_message( sizeof(query_topic_buffer), NULL))) { - LOG_ERROR("Unable to get query status publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Unable to get query status publish topic: az_result return code 0x%08x.", rc); exit(rc); } diff --git a/sdk/samples/iot/paho_iot_provisioning_sas_sample.c b/sdk/samples/iot/paho_iot_provisioning_sas_sample.c index 07db5312c1..18a3b5eda7 100644 --- a/sdk/samples/iot/paho_iot_provisioning_sas_sample.c +++ b/sdk/samples/iot/paho_iot_provisioning_sas_sample.c @@ -2,12 +2,13 @@ // SPDX-License-Identifier: MIT #ifdef _MSC_VER +#pragma warning(push) // warning C4201: nonstandard extension used: nameless struct/union #pragma warning(disable : 4201) #endif #include #ifdef _MSC_VER -#pragma warning(default : 4201) +#pragma warning(pop) #endif #include "iot_samples_common.h" @@ -52,7 +53,8 @@ static void parse_registration_message( const MQTTClient_message* message, az_iot_provisioning_client_register_response* response, az_iot_provisioning_client_operation_status* operation_status); -static void send_operation_query_message(const az_iot_provisioning_client_register_response* response); +static void send_operation_query_message( + const az_iot_provisioning_client_register_response* response); static void generate_sas_key(void); /* @@ -91,7 +93,7 @@ static void create_and_configure_mqtt_client(void) if (az_failed(rc = read_environment_variables(SAMPLE_TYPE, SAMPLE_NAME, &env_vars))) { LOG_ERROR( - "Failed to read configuration from environment variables: az_result return code 0x%04x.", + "Failed to read configuration from environment variables: az_result return code 0x%08x.", rc); exit(rc); } @@ -102,7 +104,7 @@ static void create_and_configure_mqtt_client(void) rc = create_mqtt_endpoint( SAMPLE_TYPE, &env_vars, mqtt_endpoint_buffer, sizeof(mqtt_endpoint_buffer)))) { - LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to create MQTT endpoint: az_result return code 0x%08x.", rc); exit(rc); } @@ -115,7 +117,7 @@ static void create_and_configure_mqtt_client(void) env_vars.provisioning_registration_id, NULL))) { - LOG_ERROR("Failed to initialize provisioning client: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to initialize provisioning client: az_result return code 0x%08x.", rc); exit(rc); } @@ -125,7 +127,7 @@ static void create_and_configure_mqtt_client(void) rc = az_iot_provisioning_client_get_client_id( &provisioning_client, mqtt_client_id_buffer, sizeof(mqtt_client_id_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client id: az_result return code 0x%08x.", rc); exit(rc); } @@ -158,7 +160,7 @@ static void connect_mqtt_client_to_provisioning_service(void) sizeof(mqtt_client_username_buffer), NULL))) { - LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get MQTT client username: az_result return code 0x%08x.", rc); exit(rc); } @@ -212,7 +214,7 @@ static void register_device_with_provisioning_service(void) rc = az_iot_provisioning_client_register_get_publish_topic( &provisioning_client, register_topic_buffer, sizeof(register_topic_buffer), NULL))) { - LOG_ERROR("Failed to get Register publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to get Register publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -263,7 +265,7 @@ static void receive_device_registration_status(void) { topic_len = (int)strlen(topic); } - LOG_SUCCESS("Client received a message from provisioning service."); + LOG_SUCCESS("Client received a message from the provisioning service."); // Parse registration message. parse_registration_message(topic, topic_len, message, ®ister_response, &operation_status); @@ -327,7 +329,7 @@ static void parse_registration_message( az_iot_provisioning_client_register_response* register_response, az_iot_provisioning_client_operation_status* operation_status) { - int rc; + az_result rc; az_span topic_span = az_span_create((uint8_t*)topic, topic_len); az_span message_span = az_span_create((uint8_t*)message->payload, message->payloadlen); @@ -336,7 +338,7 @@ static void parse_registration_message( rc = az_iot_provisioning_client_parse_received_topic_and_payload( &provisioning_client, topic_span, message_span, register_response))) { - LOG_ERROR("Message from unknown topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Message from unknown topic: az_result return code 0x%08x.", rc); LOG_AZ_SPAN("Topic:", topic_span); exit(rc); } @@ -350,7 +352,7 @@ static void parse_registration_message( rc = az_iot_provisioning_client_parse_operation_status(register_response, operation_status))) { - LOG_ERROR("Failed to parse operation_status: az_result return code 0x%04x.", rc); + LOG_ERROR("Failed to parse operation_status: az_result return code 0x%08x.", rc); exit(rc); } } @@ -370,7 +372,7 @@ static void send_operation_query_message( sizeof(query_status_topic_buffer), NULL))) { - LOG_ERROR("Unable to get query status publish topic: az_result return code 0x%04x.", rc); + LOG_ERROR("Unable to get query status publish topic: az_result return code 0x%08x.", rc); exit(rc); } @@ -389,7 +391,7 @@ static void send_operation_query_message( static void generate_sas_key(void) { - int rc; + az_result rc; // Create the POSIX expiration time from input minutes. uint64_t sas_duration = get_epoch_expiration_time_from_minutes(env_vars.sas_key_duration_minutes); @@ -400,14 +402,17 @@ static void generate_sas_key(void) rc = az_iot_provisioning_client_sas_get_signature( &provisioning_client, sas_duration, sas_signature, &sas_signature))) { - LOG_ERROR("Could not get the signature for SAS key: az_result return code 0x%04x.", rc); + LOG_ERROR("Could not get the signature for SAS key: az_result return code 0x%08x.", rc); exit(rc); } // Generate the encoded, signed signature (b64 encoded, HMAC-SHA256 signing) az_span sas_encoded_signed_signature = AZ_SPAN_FROM_BUFFER(sas_encoded_signed_signature_buffer); sas_generate_encoded_signed_signature( - env_vars.provisioning_sas_key, sas_signature, sas_encoded_signed_signature, &sas_encoded_signed_signature); + env_vars.provisioning_sas_key, + sas_signature, + sas_encoded_signed_signature, + &sas_encoded_signed_signature); // Get the resulting MQTT password, passing the base64 encoded, HMAC signed bytes size_t mqtt_password_length; @@ -421,7 +426,7 @@ static void generate_sas_key(void) sizeof(mqtt_password_buffer), &mqtt_password_length))) { - LOG_ERROR("Could not get the password: az_result return code 0x%04x.", rc); + LOG_ERROR("Could not get the password: az_result return code 0x%08x.", rc); exit(rc); } } diff --git a/sdk/samples/iot/sample_pnp.c b/sdk/samples/iot/sample_pnp.c index 1784077007..bf92d0403f 100644 --- a/sdk/samples/iot/sample_pnp.c +++ b/sdk/samples/iot/sample_pnp.c @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT +#include "iot_samples_common.h" #include "sample_pnp.h" +#include +#include #include -#include #include #include @@ -24,54 +26,53 @@ static const az_span desired_temp_ack_version_name = AZ_SPAN_LITERAL_FROM_STR("a static const az_span desired_temp_ack_description_name = AZ_SPAN_LITERAL_FROM_STR("ad"); static const az_span component_specifier_name = AZ_SPAN_LITERAL_FROM_STR("__t"); static const az_span component_specifier_value = AZ_SPAN_LITERAL_FROM_STR("c"); -static const az_span command_separator = AZ_SPAN_LITERAL_FROM_STR("*"); -static const az_span sample_iot_hub_twin_desired_version = AZ_SPAN_LITERAL_FROM_STR("$version"); -static const az_span sample_iot_hub_twin_desired = AZ_SPAN_LITERAL_FROM_STR("desired"); +static const az_span command_separator = AZ_SPAN_LITERAL_FROM_STR("/"); +static const az_span iot_hub_twin_desired_version = AZ_SPAN_LITERAL_FROM_STR("$version"); +static const az_span iot_hub_twin_desired = AZ_SPAN_LITERAL_FROM_STR("desired"); // Visit each valid property for the component static az_result visit_component_properties( az_span component_name, - az_json_reader* json_reader, + az_json_reader* jr, int32_t version, pnp_property_callback property_callback, void* context_ptr) { - while (az_succeeded(az_json_reader_next_token(json_reader))) + while (az_succeeded(az_json_reader_next_token(jr))) { - if (json_reader->token.kind == AZ_JSON_TOKEN_PROPERTY_NAME) + if (jr->token.kind == AZ_JSON_TOKEN_PROPERTY_NAME) { - if (az_json_token_is_text_equal(&(json_reader->token), component_specifier_name) - || az_json_token_is_text_equal( - &(json_reader->token), sample_iot_hub_twin_desired_version)) + if (az_json_token_is_text_equal(&(jr->token), component_specifier_name) + || az_json_token_is_text_equal(&(jr->token), iot_hub_twin_desired_version)) { - if (az_failed(az_json_reader_next_token(json_reader))) + if (az_failed(az_json_reader_next_token(jr))) { - printf("Failed to next token\r\n"); + LOG_ERROR("Failed to get next token."); return AZ_ERROR_UNEXPECTED_CHAR; } continue; } - az_json_token property_name = json_reader->token; + az_json_token property_name = jr->token; - if (az_failed(az_json_reader_next_token(json_reader))) + if (az_failed(az_json_reader_next_token(jr))) { - printf("Failed to get next token\r\n"); + LOG_ERROR("Failed to get next token."); return AZ_ERROR_UNEXPECTED_CHAR; } - property_callback(component_name, &property_name, *json_reader, version, context_ptr); + property_callback(component_name, &property_name, *jr, version, context_ptr); } - if (json_reader->token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT) + if (jr->token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT) { - if (az_failed(az_json_reader_skip_children(json_reader))) + if (az_failed(az_json_reader_skip_children(jr))) { - printf("Failed to skip children of object\r\n"); + LOG_ERROR("Failed to skip children of object."); return AZ_ERROR_UNEXPECTED_CHAR; } } - else if (json_reader->token.kind == AZ_JSON_TOKEN_END_OBJECT) + else if (jr->token.kind == AZ_JSON_TOKEN_END_OBJECT) { break; } @@ -81,30 +82,29 @@ static az_result visit_component_properties( } // Move reader to the value of property name -static az_result sample_json_child_token_move(az_json_reader* json_reader, az_span property_name) +static az_result json_child_token_move(az_json_reader* jr, az_span property_name) { - while (az_succeeded(az_json_reader_next_token(json_reader))) + while (az_succeeded(az_json_reader_next_token(jr))) { - if ((json_reader->token.kind == AZ_JSON_TOKEN_PROPERTY_NAME) - && az_json_token_is_text_equal(&(json_reader->token), property_name)) + if ((jr->token.kind == AZ_JSON_TOKEN_PROPERTY_NAME) && az_json_token_is_text_equal(&(jr->token), property_name)) { - if (az_failed(az_json_reader_next_token(json_reader))) + if (az_failed(az_json_reader_next_token(jr))) { - printf("Failed to read next token\r\n"); + LOG_ERROR("Failed to get next token."); return AZ_ERROR_UNEXPECTED_CHAR; } return AZ_OK; } - else if (json_reader->token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT) + else if (jr->token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT) { - if (az_failed(az_json_reader_skip_children(json_reader))) + if (az_failed(az_json_reader_skip_children(jr))) { - printf("Failed to skip child of complex object\r\n"); + LOG_ERROR("Failed to skip child of complex object."); return AZ_ERROR_UNEXPECTED_CHAR; } } - else if (json_reader->token.kind == AZ_JSON_TOKEN_END_OBJECT) + else if (jr->token.kind == AZ_JSON_TOKEN_END_OBJECT) { return AZ_ERROR_ITEM_NOT_FOUND; } @@ -116,8 +116,8 @@ static az_result sample_json_child_token_move(az_json_reader* json_reader, az_sp // Check if the component name is in the model static az_result is_component_in_model( az_span component_name, - const az_span** sample_components_ptr, - int32_t sample_components_num, + const az_span** components_ptr, + int32_t components_num, int32_t* out_index) { int32_t index = 0; @@ -127,9 +127,9 @@ static az_result is_component_in_model( return AZ_ERROR_UNEXPECTED_CHAR; } - while (index < sample_components_num) + while (index < components_num) { - if (az_span_is_content_equal(component_name, *sample_components_ptr[index])) + if (az_span_is_content_equal(component_name, *components_ptr[index])) { *out_index = index; return AZ_OK; @@ -143,7 +143,7 @@ static az_result is_component_in_model( // Get the telemetry topic for PnP az_result pnp_get_telemetry_topic( - az_iot_hub_client const* client, + const az_iot_hub_client* client, az_iot_hub_client_properties* properties, az_span component_name, char* mqtt_topic, @@ -177,7 +177,7 @@ az_result pnp_get_telemetry_topic( } // Parse the component name and command name from a span -az_result pnp_parse_command_name( +void pnp_parse_command_name( az_span component_command, az_span* component_name, az_span* pnp_command_name) @@ -194,8 +194,6 @@ az_result pnp_parse_command_name( *component_name = AZ_SPAN_NULL; *pnp_command_name = component_command; } - - return AZ_OK; } // Create a reported property payload @@ -207,31 +205,30 @@ az_result pnp_create_reported_property( void* context, az_span* out_span) { - az_json_writer json_writer; - AZ_RETURN_IF_FAILED(az_json_writer_init(&json_writer, json_buffer, NULL)); + az_json_writer jw; + AZ_RETURN_IF_FAILED(az_json_writer_init(&jw, json_buffer, NULL)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); if (az_span_ptr(component_name) != NULL) { - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&json_writer, component_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_writer)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(&json_writer, component_specifier_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string(&json_writer, component_specifier_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, component_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, component_specifier_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, component_specifier_value)); } - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&json_writer, property_name)); - AZ_RETURN_IF_FAILED(append_callback(&json_writer, context)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, property_name)); + AZ_RETURN_IF_FAILED(append_callback(&jw, context)); if (az_span_ptr(component_name) != NULL) { - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); } - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); - *out_span = az_json_writer_get_bytes_used_in_destination(&json_writer); + *out_span = az_json_writer_get_bytes_used_in_destination(&jw); return AZ_OK; } @@ -248,135 +245,129 @@ az_result pnp_create_reported_property_with_status( az_span ack_description, az_span* out_span) { - az_json_writer json_writer; + az_json_writer jw; - AZ_RETURN_IF_FAILED(az_json_writer_init(&json_writer, json_buffer, NULL)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_init(&jw, json_buffer, NULL)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); if (az_span_ptr(component_name) != NULL) { - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&json_writer, component_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_writer)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(&json_writer, component_specifier_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string(&json_writer, component_specifier_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, component_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, component_specifier_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, component_specifier_value)); } - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&json_writer, property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_writer)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(&json_writer, desired_temp_response_value_name)); - AZ_RETURN_IF_FAILED(append_callback(&json_writer, context)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(&json_writer, desired_temp_ack_code_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_int32(&json_writer, ack_code)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(&json_writer, desired_temp_ack_version_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_int32(&json_writer, ack_version)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, desired_temp_response_value_name)); + AZ_RETURN_IF_FAILED(append_callback(&jw, context)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, desired_temp_ack_code_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_int32(&jw, ack_code)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, desired_temp_ack_version_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_int32(&jw, ack_version)); if (az_span_ptr(ack_description) != NULL) { - AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(&json_writer, desired_temp_ack_description_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string(&json_writer, ack_description)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, desired_temp_ack_description_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, ack_description)); } - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_writer)); - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); if (az_span_ptr(component_name) != NULL) { - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); } - *out_span = az_json_writer_get_bytes_used_in_destination(&json_writer); + *out_span = az_json_writer_get_bytes_used_in_destination(&jw); return AZ_OK; } // Process the twin properties and invoke user callback for each property -az_result pnp_process_twin_data( - az_json_reader* json_reader, +az_result pnp_process_device_twin_message( + az_span twin_message_span, bool is_partial, - const az_span** sample_components_ptr, - int32_t sample_components_num, + const az_span** components_ptr, + int32_t components_num, pnp_property_callback property_callback, void* context_ptr) { - az_json_reader copy_json_reader; + az_json_reader jr; + az_json_reader copy_jr; int32_t version; int32_t index; - AZ_RETURN_IF_FAILED(az_json_reader_next_token(json_reader)); + AZ_RETURN_IF_FAILED(az_json_reader_init(&jr, twin_message_span, NULL)); + AZ_RETURN_IF_FAILED(az_json_reader_next_token(&jr)); - if (!is_partial - && az_failed(sample_json_child_token_move(json_reader, sample_iot_hub_twin_desired))) + if (!is_partial && az_failed(json_child_token_move(&jr, iot_hub_twin_desired))) { - printf("Failed to get desired property\r\n"); + LOG_ERROR("Failed to get desired property."); return AZ_ERROR_UNEXPECTED_CHAR; } - copy_json_reader = *json_reader; - if (az_failed( - sample_json_child_token_move(©_json_reader, sample_iot_hub_twin_desired_version)) - || az_failed(az_json_token_get_int32(&(copy_json_reader.token), (int32_t*)&version))) + copy_jr = jr; + if (az_failed(json_child_token_move(©_jr, iot_hub_twin_desired_version)) + || az_failed(az_json_token_get_int32(&(copy_jr.token), (int32_t*)&version))) { - printf("Failed to get version\r\n"); + LOG_ERROR("Failed to get version."); return AZ_ERROR_UNEXPECTED_CHAR; } az_json_token property_name; - while (az_succeeded(az_json_reader_next_token(json_reader))) + while (az_succeeded(az_json_reader_next_token(&jr))) { - if (json_reader->token.kind == AZ_JSON_TOKEN_PROPERTY_NAME) + if (jr.token.kind == AZ_JSON_TOKEN_PROPERTY_NAME) { - if (az_json_token_is_text_equal(&(json_reader->token), sample_iot_hub_twin_desired_version)) + if (az_json_token_is_text_equal(&(jr.token), iot_hub_twin_desired_version)) { - if (az_failed(az_json_reader_next_token(json_reader))) + if (az_failed(az_json_reader_next_token(&jr))) { - printf("Failed to next token\r\n"); + LOG_ERROR("Failed to get next token."); return AZ_ERROR_UNEXPECTED_CHAR; } continue; } - property_name = json_reader->token; + property_name = jr.token; - if (az_failed(az_json_reader_next_token(json_reader))) + if (az_failed(az_json_reader_next_token(&jr))) { - printf("Failed to next token\r\n"); + LOG_ERROR("Failed to get next token."); return AZ_ERROR_UNEXPECTED_CHAR; } - if (json_reader->token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT && sample_components_ptr != NULL - && (az_succeeded(is_component_in_model( - property_name.slice, sample_components_ptr, sample_components_num, &index)))) + if (jr.token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT && components_ptr != NULL + && (az_succeeded(is_component_in_model(property_name.slice, components_ptr, components_num, &index)))) { if (az_failed(visit_component_properties( - *sample_components_ptr[index], - json_reader, + *components_ptr[index], + &jr, version, property_callback, context_ptr))) { - printf("Failed to visit component properties\r\n"); + LOG_ERROR("Failed to visit component properties."); return AZ_ERROR_UNEXPECTED_CHAR; } } else { - property_callback(AZ_SPAN_NULL, &property_name, *json_reader, version, context_ptr); + property_callback(AZ_SPAN_NULL, &property_name, jr, version, context_ptr); } } - else if (json_reader->token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT) + else if (jr.token.kind == AZ_JSON_TOKEN_BEGIN_OBJECT) { - if (az_failed(az_json_reader_skip_children(json_reader))) + if (az_failed(az_json_reader_skip_children(&jr))) { - printf("Failed to skip children of object\r\n"); + LOG_ERROR("Failed to skip children of object."); return AZ_ERROR_UNEXPECTED_CHAR; } } - else if (json_reader->token.kind == AZ_JSON_TOKEN_END_OBJECT) + else if (jr.token.kind == AZ_JSON_TOKEN_END_OBJECT) { break; } diff --git a/sdk/samples/iot/sample_pnp.h b/sdk/samples/iot/sample_pnp.h index 227a746272..b9db8a32ee 100644 --- a/sdk/samples/iot/sample_pnp.h +++ b/sdk/samples/iot/sample_pnp.h @@ -4,6 +4,8 @@ #ifndef SAMPLE_PNP_H #define SAMPLE_PNP_H +#include +#include #include #include @@ -11,18 +13,13 @@ #include #include -#define PNP_STATUS_SUCCESS 200 -#define PNP_STATUS_BAD_FORMAT 400 -#define PNP_STATUS_NOT_FOUND 404 -#define PNP_STATUS_INTERNAL_ERROR 500 - /** * @brief Callback which is called for each property found by the #pnp_process_twin_data() * API. */ typedef void (*pnp_property_callback)( az_span component_name, - az_json_token* property_name, + const az_json_token* property_name, az_json_reader property_value_as_json, int32_t version, void* user_context_callback); @@ -30,7 +27,7 @@ typedef void (*pnp_property_callback)( /** * @brief Callback which is invoked to append user properties to a payload. */ -typedef az_result (*pnp_append_property_callback)(az_json_writer* json_writer, void* context); +typedef az_result (*pnp_append_property_callback)(az_json_writer* jw, void* context); /** * @brief Gets the MQTT topic that must be used for device to cloud telemetry messages. @@ -50,7 +47,7 @@ typedef az_result (*pnp_append_property_callback)(az_json_writer* json_writer, v * @return #az_result */ az_result pnp_get_telemetry_topic( - az_iot_hub_client const* client, + const az_iot_hub_client* client, az_iot_hub_client_properties* properties, az_span component_name, char* mqtt_topic, @@ -64,7 +61,7 @@ az_result pnp_get_telemetry_topic( * @param[out] component_name The parsed component name (if it exists). * @param[out] command_name The parsed command name. */ -az_result pnp_parse_command_name( +void pnp_parse_command_name( az_span component_command, az_span* component_name, az_span* command_name); @@ -114,20 +111,20 @@ az_result pnp_create_reported_property_with_status( /** * @brief Iteratively get the next desired property. * - * @param[in] json_reader A pointer to the json reader from which the properties will be retrieved. + * @param[in] twin_message_span The #az_span of the received message to process. * @param[in] is_partial Boolean stating whether the JSON document is partial or not. - * @param[in] sample_components_ptr A pointer to a set of `az_span` pointers containing all the + * @param[in] components_ptr A pointer to a set of `az_span` pointers containing all the * names for components. - * @param[in] sample_components_num Number of components in the set pointed to by - * `sample_components_ptr`. + * @param[in] components_num Number of components in the set pointed to by + * `components_ptr`. * @param[in] property_callback The callback which is called on each twin property. * @param[in] context_ptr Pointer to user context. */ -az_result pnp_process_twin_data( - az_json_reader* json_reader, +az_result pnp_process_device_twin_message( + az_span twin_message_span, bool is_partial, - const az_span** sample_components_ptr, - int32_t sample_components_num, + const az_span** components_ptr, + int32_t components_num, pnp_property_callback property_callback, void* context_ptr); diff --git a/sdk/samples/iot/sample_pnp_device_info_component.c b/sdk/samples/iot/sample_pnp_device_info_component.c index 530085c8b2..bee40a55c1 100644 --- a/sdk/samples/iot/sample_pnp_device_info_component.c +++ b/sdk/samples/iot/sample_pnp_device_info_component.c @@ -1,83 +1,63 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT +#include "sample_pnp_device_info_component.h" +#include "sample_pnp_mqtt_component.h" + #include #include #include #include -#include "sample_pnp_component_mqtt.h" -#include "sample_pnp_device_info_component.h" - #define DOUBLE_DECIMAL_PLACE_DIGITS 2 /* Reported property keys and values */ -static const az_span sample_pnp_device_info_software_version_property_name = AZ_SPAN_LITERAL_FROM_STR("swVersion"); -static const az_span sample_pnp_device_info_software_version_property_value = AZ_SPAN_LITERAL_FROM_STR("1.0.0.0"); -static const az_span sample_pnp_device_info_manufacturer_property_name = AZ_SPAN_LITERAL_FROM_STR("manufacturer"); -static const az_span sample_pnp_device_info_manufacturer_property_value = AZ_SPAN_LITERAL_FROM_STR("Sample-Manufacturer"); -static const az_span sample_pnp_device_info_model_property_name = AZ_SPAN_LITERAL_FROM_STR("model"); -static const az_span sample_pnp_device_info_model_property_value = AZ_SPAN_LITERAL_FROM_STR("pnp-sample-Model-123"); -static const az_span sample_pnp_device_info_os_name_property_name = AZ_SPAN_LITERAL_FROM_STR("osName"); -static const az_span sample_pnp_device_info_os_name_property_value = AZ_SPAN_LITERAL_FROM_STR("Contoso"); -static const az_span sample_pnp_device_info_processor_architecture_property_name = AZ_SPAN_LITERAL_FROM_STR("processorArchitecture"); -static const az_span sample_pnp_device_info_processor_architecture_property_value = AZ_SPAN_LITERAL_FROM_STR("Contoso-Arch-64bit"); -static const az_span sample_pnp_device_info_processor_manufacturer_property_name = AZ_SPAN_LITERAL_FROM_STR("processorManufacturer"); -static const az_span sample_pnp_device_info_processor_manufacturer_property_value = AZ_SPAN_LITERAL_FROM_STR("Processor Manufacturer(TM)"); -static const az_span sample_pnp_device_info_total_storage_property_name +static const az_span pnp_device_info_software_version_property_name = AZ_SPAN_LITERAL_FROM_STR("swVersion"); +static const az_span pnp_device_info_software_version_property_value = AZ_SPAN_LITERAL_FROM_STR("1.0.0.0"); +static const az_span pnp_device_info_manufacturer_property_name = AZ_SPAN_LITERAL_FROM_STR("manufacturer"); +static const az_span pnp_device_info_manufacturer_property_value = AZ_SPAN_LITERAL_FROM_STR("Sample-Manufacturer"); +static const az_span pnp_device_info_model_property_name = AZ_SPAN_LITERAL_FROM_STR("model"); +static const az_span pnp_device_info_model_property_value = AZ_SPAN_LITERAL_FROM_STR("pnp-sample-Model-123"); +static const az_span pnp_device_info_os_name_property_name = AZ_SPAN_LITERAL_FROM_STR("osName"); +static const az_span pnp_device_info_os_name_property_value = AZ_SPAN_LITERAL_FROM_STR("Contoso"); +static const az_span pnp_device_info_processor_architecture_property_name = AZ_SPAN_LITERAL_FROM_STR("processorArchitecture"); +static const az_span pnp_device_info_processor_architecture_property_value = AZ_SPAN_LITERAL_FROM_STR("Contoso-Arch-64bit"); +static const az_span pnp_device_info_processor_manufacturer_property_name = AZ_SPAN_LITERAL_FROM_STR("processorManufacturer"); +static const az_span pnp_device_info_processor_manufacturer_property_value = AZ_SPAN_LITERAL_FROM_STR("Processor Manufacturer(TM)"); +static const az_span pnp_device_info_total_storage_property_name = AZ_SPAN_LITERAL_FROM_STR("totalStorage"); -static const double sample_pnp_device_info_total_storage_property_value = 1024.0; -static const az_span sample_pnp_device_info_total_memory_property_name +static const double pnp_device_info_total_storage_property_value = 1024.0; +static const az_span pnp_device_info_total_memory_property_name = AZ_SPAN_LITERAL_FROM_STR("totalMemory"); -static const double sample_pnp_device_info_total_memory_property_value = 128; +static const double pnp_device_info_total_memory_property_value = 128; -az_result sample_pnp_device_info_get_report_data( - az_iot_hub_client* client, - sample_pnp_mqtt_message* mqtt_message) +az_result pnp_device_info_get_report_data( + const az_iot_hub_client* client, + pnp_mqtt_message* mqtt_message) { - az_json_writer json_writer; - AZ_RETURN_IF_FAILED(az_json_writer_init(&json_writer, mqtt_message->payload_span, NULL)); + az_json_writer jw; + AZ_RETURN_IF_FAILED(az_json_writer_init(&jw, mqtt_message->payload_span, NULL)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_writer)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_manufacturer_property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string( - &json_writer, sample_pnp_device_info_manufacturer_property_value)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_model_property_name)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_string(&json_writer, sample_pnp_device_info_model_property_value)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_software_version_property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string( - &json_writer, sample_pnp_device_info_software_version_property_value)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_os_name_property_name)); - AZ_RETURN_IF_FAILED( - az_json_writer_append_string(&json_writer, sample_pnp_device_info_os_name_property_value)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_processor_architecture_property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string( - &json_writer, sample_pnp_device_info_processor_architecture_property_value)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_processor_manufacturer_property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string( - &json_writer, sample_pnp_device_info_processor_manufacturer_property_value)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_total_storage_property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_double( - &json_writer, - sample_pnp_device_info_total_storage_property_value, - DOUBLE_DECIMAL_PLACE_DIGITS)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name( - &json_writer, sample_pnp_device_info_total_memory_property_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_double( - &json_writer, - sample_pnp_device_info_total_memory_property_value, - DOUBLE_DECIMAL_PLACE_DIGITS)); - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_writer)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_manufacturer_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, pnp_device_info_manufacturer_property_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_model_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, pnp_device_info_model_property_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_software_version_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, pnp_device_info_software_version_property_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_os_name_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, pnp_device_info_os_name_property_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_processor_architecture_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, pnp_device_info_processor_architecture_property_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_processor_manufacturer_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, pnp_device_info_processor_manufacturer_property_value)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_total_storage_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_double(&jw, pnp_device_info_total_storage_property_value, DOUBLE_DECIMAL_PLACE_DIGITS)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, pnp_device_info_total_memory_property_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_double(&jw, pnp_device_info_total_memory_property_value, DOUBLE_DECIMAL_PLACE_DIGITS)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); - mqtt_message->out_payload_span = az_json_writer_get_bytes_used_in_destination(&json_writer); + mqtt_message->out_payload_span = az_json_writer_get_bytes_used_in_destination(&jw); AZ_RETURN_IF_FAILED(az_iot_hub_client_twin_patch_get_publish_topic( client, diff --git a/sdk/samples/iot/sample_pnp_device_info_component.h b/sdk/samples/iot/sample_pnp_device_info_component.h index 9a5560ba09..f7fc78c564 100644 --- a/sdk/samples/iot/sample_pnp_device_info_component.h +++ b/sdk/samples/iot/sample_pnp_device_info_component.h @@ -4,8 +4,9 @@ #ifndef SAMPLE_PNP_DEVICE_INFO_COMPONENT_H #define SAMPLE_PNP_DEVICE_INFO_COMPONENT_H +#include "sample_pnp_mqtt_component.h" + #include -#include #include /** @@ -13,11 +14,11 @@ * * @param client The `az_iot_hub_client` pointer to the hub client. * @param mqtt_message The `sample_pnp_mqtt_message` pointer to the struct to be populated. - * + * * @return An #az_result with the result of the operation. */ -az_result sample_pnp_device_info_get_report_data( - az_iot_hub_client* client, - sample_pnp_mqtt_message* mqtt_message); +az_result pnp_device_info_get_report_data( + const az_iot_hub_client* client, + pnp_mqtt_message* mqtt_message); #endif // SAMPLE_PNP_DEVICE_INFO_COMPONENT_H diff --git a/sdk/samples/iot/sample_pnp_component_mqtt.c b/sdk/samples/iot/sample_pnp_mqtt_component.c similarity index 56% rename from sdk/samples/iot/sample_pnp_component_mqtt.c rename to sdk/samples/iot/sample_pnp_mqtt_component.c index 8beefc3719..62bb3f1452 100644 --- a/sdk/samples/iot/sample_pnp_component_mqtt.c +++ b/sdk/samples/iot/sample_pnp_mqtt_component.c @@ -1,15 +1,35 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT -#include "sample_pnp_component_mqtt.h" +#include "sample_pnp_mqtt_component.h" +#include #include +#include +#include #include static uint32_t request_id_int; static char request_id_buf[10]; +static char publish_topic[128]; +static char publish_payload[512]; + + void pnp_mqtt_message_init(pnp_mqtt_message* mqtt_message) +{ + if (mqtt_message == NULL) + { + exit(1); + } + + mqtt_message->topic = publish_topic; + mqtt_message->topic_length = sizeof(publish_topic); + mqtt_message->out_topic_length = 0; + mqtt_message->payload_span = AZ_SPAN_FROM_BUFFER(publish_payload); + mqtt_message->out_payload_span = mqtt_message->payload_span; +} + // Create request id span which increments request id integer each call. Capable of holding 8 digit // number. az_span get_request_id(void) diff --git a/sdk/samples/iot/sample_pnp_component_mqtt.h b/sdk/samples/iot/sample_pnp_mqtt_component.h similarity index 62% rename from sdk/samples/iot/sample_pnp_component_mqtt.h rename to sdk/samples/iot/sample_pnp_mqtt_component.h index 851cbc63c7..48a4c13919 100644 --- a/sdk/samples/iot/sample_pnp_component_mqtt.h +++ b/sdk/samples/iot/sample_pnp_mqtt_component.h @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT -#ifndef SAMPLE_PNP_COMPONENT_MQTT_H -#define SAMPLE_PNP_COMPONENT_MQTT_H +#ifndef SAMPLE_PNP_MQTT_COMPONENT_H +#define SAMPLE_PNP_MQTT_COMPONENT_H -#include +#include +#include #include typedef struct @@ -15,10 +16,12 @@ typedef struct size_t* out_topic_length; az_span payload_span; az_span out_payload_span; -} sample_pnp_mqtt_message; +} pnp_mqtt_message; + +void pnp_mqtt_message_init(pnp_mqtt_message* mqtt_message); // Create request id span which increments request id integer each call. Capable of holding 8 digit // number. az_span get_request_id(void); -#endif // SAMPLE_PNP_COMPONENT_MQTT_H +#endif // SAMPLE_PNP_MQTT_COMPONENT_H diff --git a/sdk/samples/iot/sample_pnp_thermostat_component.c b/sdk/samples/iot/sample_pnp_thermostat_component.c index 39856ddb60..47e32b6ad6 100644 --- a/sdk/samples/iot/sample_pnp_thermostat_component.c +++ b/sdk/samples/iot/sample_pnp_thermostat_component.c @@ -1,22 +1,25 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT +#ifdef _MSC_VER +// warning C4996: 'localtime': This function or variable may be unsafe. Consider using localtime_s instead. +#pragma warning(disable : 4996) +#endif + +#include "iot_samples_common.h" +#include "sample_pnp.h" +#include "sample_pnp_mqtt_component.h" +#include "sample_pnp_thermostat_component.h" + +#include +#include #include -#include #include #include #include #include -#include "sample_pnp.h" -#include "sample_pnp_thermostat_component.h" - -#ifdef _MSC_VER -// "'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead." -#pragma warning(disable : 4996) -#endif - #define DOUBLE_DECIMAL_PLACE_DIGITS 2 // IoT Telemetry Values @@ -44,34 +47,53 @@ static const az_span max_temp_reported_property_name static const char iso_spec_time_format[] = "%Y-%m-%dT%H:%M:%S%z"; static az_result build_command_response_payload( - sample_pnp_thermostat_component* thermostat_component, - az_json_writer* json_builder, + const pnp_thermostat_component* thermostat_component, az_span start_time_span, az_span end_time_span, - az_span* response_payload) + az_span payload, + az_span* out_payload) { double avg_temp = thermostat_component->device_temperature_avg_total / thermostat_component->device_temperature_avg_count; // Build the command response payload - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(json_builder)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(json_builder, report_max_temp_name_span)); + az_json_writer jw; + AZ_RETURN_IF_FAILED(az_json_writer_init(&jw, payload, NULL)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, report_max_temp_name_span)); AZ_RETURN_IF_FAILED(az_json_writer_append_double( - json_builder, thermostat_component->max_temperature, DOUBLE_DECIMAL_PLACE_DIGITS)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(json_builder, report_min_temp_name_span)); + &jw, thermostat_component->max_temperature, DOUBLE_DECIMAL_PLACE_DIGITS)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, report_min_temp_name_span)); AZ_RETURN_IF_FAILED(az_json_writer_append_double( - json_builder, thermostat_component->min_temperature, DOUBLE_DECIMAL_PLACE_DIGITS)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(json_builder, report_avg_temp_name_span)); + &jw, thermostat_component->min_temperature, DOUBLE_DECIMAL_PLACE_DIGITS)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, report_avg_temp_name_span)); AZ_RETURN_IF_FAILED( - az_json_writer_append_double(json_builder, avg_temp, DOUBLE_DECIMAL_PLACE_DIGITS)); + az_json_writer_append_double(&jw, avg_temp, DOUBLE_DECIMAL_PLACE_DIGITS)); AZ_RETURN_IF_FAILED( - az_json_writer_append_property_name(json_builder, report_start_time_name_span)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string(json_builder, start_time_span)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(json_builder, report_end_time_name_span)); - AZ_RETURN_IF_FAILED(az_json_writer_append_string(json_builder, end_time_span)); - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(json_builder)); + az_json_writer_append_property_name(&jw, report_start_time_name_span)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, start_time_span)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, report_end_time_name_span)); + AZ_RETURN_IF_FAILED(az_json_writer_append_string(&jw, end_time_span)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); - *response_payload = az_json_writer_get_bytes_used_in_destination(json_builder); + *out_payload = az_json_writer_get_bytes_used_in_destination(&jw); + + return AZ_OK; +} + +static az_result build_telemetry_message( + const pnp_thermostat_component* thermostat_component, + az_span payload, + az_span* out_payload) +{ + az_json_writer jw; + AZ_RETURN_IF_FAILED(az_json_writer_init(&jw, payload, NULL)); + AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&jw)); + AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&jw, telemetry_name)); + AZ_RETURN_IF_FAILED(az_json_writer_append_double( + &jw, thermostat_component->current_temperature, DOUBLE_DECIMAL_PLACE_DIGITS)); + AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&jw)); + *out_payload = az_json_writer_get_bytes_used_in_destination(&jw); return AZ_OK; } @@ -79,7 +101,7 @@ static az_result build_command_response_payload( // Invoke the command requested from the service. Here, it generates a report for max, min, and avg // temperatures. static az_result invoke_getMaxMinReport( - sample_pnp_thermostat_component* thermostat_component, + const pnp_thermostat_component* thermostat_component, az_span payload, az_span response, az_span* out_response) @@ -87,12 +109,12 @@ static az_result invoke_getMaxMinReport( // az_result result; // Parse the "since" field in the payload. az_span start_time_span = AZ_SPAN_NULL; - az_json_reader jp; - AZ_RETURN_IF_FAILED(az_json_reader_init(&jp, payload, NULL)); - AZ_RETURN_IF_FAILED(az_json_reader_next_token(&jp)); + az_json_reader jr; + AZ_RETURN_IF_FAILED(az_json_reader_init(&jr, payload, NULL)); + AZ_RETURN_IF_FAILED(az_json_reader_next_token(&jr)); int32_t incoming_since_value_buffer_len; AZ_RETURN_IF_FAILED(az_json_token_get_string( - &jp.token, + &jr.token, incoming_since_value_buffer, sizeof(incoming_since_value_buffer), &incoming_since_value_buffer_len)); @@ -114,40 +136,21 @@ static az_result invoke_getMaxMinReport( size_t len = strftime(end_time_buffer, sizeof(end_time_buffer), iso_spec_time_format, timeinfo); az_span end_time_span = az_span_create((uint8_t*)end_time_buffer, (int32_t)len); - az_json_writer json_builder; - AZ_RETURN_IF_FAILED(az_json_writer_init(&json_builder, response, NULL)); AZ_RETURN_IF_FAILED(build_command_response_payload( - thermostat_component, &json_builder, start_time_span, end_time_span, out_response)); - - return AZ_OK; -} - -static az_result build_telemetry_message( - sample_pnp_thermostat_component* thermostat_component, - az_span payload, - az_span* out_payload) -{ - az_json_writer json_builder; - AZ_RETURN_IF_FAILED(az_json_writer_init(&json_builder, payload, NULL)); - AZ_RETURN_IF_FAILED(az_json_writer_append_begin_object(&json_builder)); - AZ_RETURN_IF_FAILED(az_json_writer_append_property_name(&json_builder, telemetry_name)); - AZ_RETURN_IF_FAILED(az_json_writer_append_double( - &json_builder, thermostat_component->current_temperature, DOUBLE_DECIMAL_PLACE_DIGITS)); - AZ_RETURN_IF_FAILED(az_json_writer_append_end_object(&json_builder)); - *out_payload = az_json_writer_get_bytes_used_in_destination(&json_builder); + thermostat_component, start_time_span, end_time_span, response, out_response)); return AZ_OK; } -static az_result append_double(az_json_writer* json_writer, void* value) +static az_result append_double(az_json_writer* jw, void* value) { double value_as_double = *(double*)value; - return az_json_writer_append_double(json_writer, value_as_double, DOUBLE_DECIMAL_PLACE_DIGITS); + return az_json_writer_append_double(jw, value_as_double, DOUBLE_DECIMAL_PLACE_DIGITS); } -az_result sample_pnp_thermostat_init( - sample_pnp_thermostat_component* thermostat_component, +az_result pnp_thermostat_init( + pnp_thermostat_component* thermostat_component, az_span component_name, double initial_temp) { @@ -168,12 +171,42 @@ az_result sample_pnp_thermostat_init( return AZ_OK; } -bool sample_pnp_thermostat_get_max_temp_report( - az_iot_hub_client* client, - sample_pnp_thermostat_component* thermostat_component, - sample_pnp_mqtt_message* mqtt_message) +az_result pnp_thermostat_get_telemetry_message( + const az_iot_hub_client* client, + const pnp_thermostat_component* thermostat_component, + pnp_mqtt_message* mqtt_message) { - az_result result; + az_result rc; + if (az_failed( + rc = pnp_get_telemetry_topic( + client, + NULL, + thermostat_component->component_name, + mqtt_message->topic, + mqtt_message->topic_length, + NULL))) + { + LOG_ERROR("Failed to get pnp Telemetry topic: az_result return code 0x%08x.", rc); + return rc; + } + + if (az_failed( + rc = build_telemetry_message( + thermostat_component, mqtt_message->payload_span, &mqtt_message->out_payload_span))) + { + LOG_ERROR("Failed to build telemetry payload: az_result return code 0x%08x.", rc); + return rc; + } + + return rc; +} + +bool pnp_thermostat_get_max_temp_report( + const az_iot_hub_client* client, + pnp_thermostat_component* thermostat_component, + pnp_mqtt_message* mqtt_message) +{ + az_result rc; if (!thermostat_component->send_max_temp_property) { @@ -181,7 +214,7 @@ bool sample_pnp_thermostat_get_max_temp_report( } if (az_failed( - result = pnp_create_reported_property( + rc = pnp_create_reported_property( mqtt_message->payload_span, thermostat_component->component_name, max_temp_reported_property_name, @@ -189,18 +222,18 @@ bool sample_pnp_thermostat_get_max_temp_report( &thermostat_component->max_temperature, &mqtt_message->out_payload_span))) { - printf("Could not get reported property: error code = 0x%08x\n", result); + LOG_ERROR("Failed to get reported property: az_result return code 0x%08x.", rc); return false; } else if (az_failed( - result = az_iot_hub_client_twin_patch_get_publish_topic( + rc = az_iot_hub_client_twin_patch_get_publish_topic( client, get_request_id(), mqtt_message->topic, mqtt_message->topic_length, NULL))) { - printf("Error to get reported property topic with status: error code = 0x%08x\n", result); + LOG_ERROR("Failed to get reported property topic with status: az_result return code 0x%08x.", rc); return false; } @@ -209,44 +242,14 @@ bool sample_pnp_thermostat_get_max_temp_report( return true; } -az_result sample_pnp_thermostat_get_telemetry_message( - az_iot_hub_client* client, - sample_pnp_thermostat_component* thermostat_component, - sample_pnp_mqtt_message* mqtt_message) -{ - az_result result; - if (az_failed( - result = pnp_get_telemetry_topic( - client, - NULL, - thermostat_component->component_name, - mqtt_message->topic, - mqtt_message->topic_length, - NULL))) - { - printf("Could not get pnp telemetry topic: error code = 0x%08x\n", result); - return result; - } - - if (az_failed( - result = build_telemetry_message( - thermostat_component, mqtt_message->payload_span, &mqtt_message->out_payload_span))) - { - printf("Could not build telemetry payload: error code = 0x%08x\n", result); - return result; - } - - return result; -} - -az_result sample_pnp_thermostat_process_property_update( - az_iot_hub_client* client, - sample_pnp_thermostat_component* thermostat_component, +az_result pnp_thermostat_process_property_update( + const az_iot_hub_client* client, + pnp_thermostat_component* thermostat_component, az_span component_name, - az_json_token* property_name, - az_json_reader* property_value, + const az_json_token* property_name, + const az_json_reader* property_value, int32_t version, - sample_pnp_mqtt_message* mqtt_message) + pnp_mqtt_message* mqtt_message) { az_result result; @@ -257,10 +260,7 @@ az_result sample_pnp_thermostat_process_property_update( if (!az_json_token_is_text_equal(property_name, desired_temp_property_name)) { - printf( - "PnP property=%.*s is not supported on thermostat component\n", - az_span_size(property_name->slice), - az_span_ptr(property_name->slice)); + LOG_AZ_SPAN("PnP property is not supported on thermostat component:", property_name->slice); } double parsed_value = 0; @@ -309,7 +309,7 @@ az_result sample_pnp_thermostat_process_property_update( temp_response_description_success, &mqtt_message->out_payload_span))) { - printf("Error to get reported property payload with status: error code = 0x%08x\n", result); + LOG_ERROR("Failed to get reported property payload with status: az_result return code 0x%08x.", result); } } @@ -317,20 +317,21 @@ az_result sample_pnp_thermostat_process_property_update( result = az_iot_hub_client_twin_patch_get_publish_topic( client, get_request_id(), mqtt_message->topic, mqtt_message->topic_length, NULL))) { - printf("Error to get reported property topic with status: error code = 0x%08x\n", result); + LOG_ERROR("Failed to get reported property topic with status: az_result return code 0x%08x.", result); } return result; } -az_result sample_pnp_thermostat_process_command( - az_iot_hub_client* client, - sample_pnp_thermostat_component* thermostat_component, - az_iot_hub_client_method_request* command_request, +az_result pnp_thermostat_process_command( + const az_iot_hub_client* client, + const pnp_thermostat_component* thermostat_component, + const az_iot_hub_client_method_request* command_request, az_span component_name, az_span command_name, az_span command_payload, - sample_pnp_mqtt_message* mqtt_message) + pnp_mqtt_message* mqtt_message, + az_iot_status* status) { az_result result; @@ -338,7 +339,6 @@ az_result sample_pnp_thermostat_process_command( && az_span_is_content_equal(report_command_name_span, command_name)) { // Invoke command - uint16_t return_code; az_result response = invoke_getMaxMinReport( thermostat_component, command_payload, @@ -346,23 +346,23 @@ az_result sample_pnp_thermostat_process_command( &mqtt_message->out_payload_span); if (response != AZ_OK) { - return_code = 400; + *status = AZ_IOT_STATUS_BAD_REQUEST; } else { - return_code = 200; + *status = AZ_IOT_STATUS_OK; } if (az_failed( result = az_iot_hub_client_methods_response_get_publish_topic( client, command_request->request_id, - return_code, + (uint16_t)*status, mqtt_message->topic, mqtt_message->topic_length, mqtt_message->out_topic_length))) { - printf("Unable to get methods response publish topic: error code = 0x%08x\n", result); + LOG_ERROR("Failed to get methods response publish topic: az_result return code 0x%08x.", result); return result; } } diff --git a/sdk/samples/iot/sample_pnp_thermostat_component.h b/sdk/samples/iot/sample_pnp_thermostat_component.h index 9a2be57959..0c6c921dfd 100644 --- a/sdk/samples/iot/sample_pnp_thermostat_component.h +++ b/sdk/samples/iot/sample_pnp_thermostat_component.h @@ -4,15 +4,15 @@ #ifndef SAMPLE_PNP_THERMOSTAT_COMPONENT_H #define SAMPLE_PNP_THERMOSTAT_COMPONENT_H +#include "sample_pnp_mqtt_component.h" + +#include #include -#include #include #include #include -#include "sample_pnp_component_mqtt.h" - typedef struct { az_span component_name; @@ -23,39 +23,40 @@ typedef struct double device_temperature_avg_total; double avg_temperature; bool send_max_temp_property; -} sample_pnp_thermostat_component; +} pnp_thermostat_component; -az_result sample_pnp_thermostat_init( - sample_pnp_thermostat_component* handle, +az_result pnp_thermostat_init( + pnp_thermostat_component* thermostat_component, az_span component_name, double initial_temp); -az_result sample_pnp_thermostat_get_telemetry_message( - az_iot_hub_client* client, - sample_pnp_thermostat_component* handle, - sample_pnp_mqtt_message* mqtt_message); +az_result pnp_thermostat_get_telemetry_message( + const az_iot_hub_client* client, + const pnp_thermostat_component* thermostat_component, + pnp_mqtt_message* mqtt_message); -bool sample_pnp_thermostat_get_max_temp_report( - az_iot_hub_client* client, - sample_pnp_thermostat_component* handle, - sample_pnp_mqtt_message* mqtt_message); +bool pnp_thermostat_get_max_temp_report( + const az_iot_hub_client* client, + pnp_thermostat_component* thermostat_component, + pnp_mqtt_message* mqtt_message); -az_result sample_pnp_thermostat_process_property_update( - az_iot_hub_client* client, - sample_pnp_thermostat_component* handle, +az_result pnp_thermostat_process_property_update( + const az_iot_hub_client* client, + pnp_thermostat_component* thermostat_component, az_span component_name, - az_json_token* property_name, - az_json_reader* property_value, + const az_json_token* property_name, + const az_json_reader* property_value, int32_t version, - sample_pnp_mqtt_message* mqtt_message); + pnp_mqtt_message* mqtt_message); -az_result sample_pnp_thermostat_process_command( - az_iot_hub_client* client, - sample_pnp_thermostat_component* handle, - az_iot_hub_client_method_request* command_request, +az_result pnp_thermostat_process_command( + const az_iot_hub_client* client, + const pnp_thermostat_component* thermostat_component, + const az_iot_hub_client_method_request* command_request, az_span component_name, az_span command_name, az_span command_payload, - sample_pnp_mqtt_message* mqtt_message); + pnp_mqtt_message* mqtt_message, + az_iot_status* status); #endif // SAMPLE_PNP_THERMOSTAT_COMPONENT_H