1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 /**
12  * @file nx_azure_iot_hub_client.h
13  *
14  * @brief Definition for the Azure IoT Hub client.
15  * @remark The IoT Hub MQTT protocol is described at
16  * https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support.
17  *
18  */
19 
20 #ifndef NX_AZURE_IOT_HUB_CLIENT_PROPERTIES_H
21 #define NX_AZURE_IOT_HUB_CLIENT_PROPERTIES_H
22 
23 #ifdef __cplusplus
24 extern   "C" {
25 #endif
26 
27 #include "azure/iot/az_iot_hub_client_properties.h"
28 #include "nx_azure_iot_hub_client.h"
29 #include "nx_azure_iot_json_reader.h"
30 #include "nx_azure_iot_json_writer.h"
31 
32 /* Property type.  */
33 #define NX_AZURE_IOT_HUB_CLIENT_PROPERTY_REPORTED_FROM_DEVICE       0
34 #define NX_AZURE_IOT_HUB_CLIENT_PROPERTY_WRITABLE                   1
35 
36 /**
37  * @brief Append the necessary characters to a reported property JSON payload belonging to a
38  * subcomponent.
39  *
40  * The payload will be of the form:
41  *
42  * @code
43  * "reported": {
44  *     "<component_name>": {
45  *         "__t": "c",
46  *         "temperature": 23
47  *     }
48  * }
49  * @endcode
50  *
51  * @note This API should be used in conjunction with
52  * nx_azure_iot_hub_client_reported_properties_component_end().
53  *
54  * @param[in] hub_client_ptr A pointer to a #NX_AZURE_IOT_HUB_CLIENT.
55  * @param[in] writer_ptr A pointer to a #NX_AZURE_IOT_JSON_WRITER
56  * @param[in] component_name_ptr A pointer to a component name
57  * @param[in] component_name_length Length of `component_name_ptr`
58  * @return A `UINT` with the result of the API.
59  *   @retval #NX_AZURE_IOT_SUCCESS Successful if JSON payload was prefixed successfully.
60  */
61 UINT nx_azure_iot_hub_client_reported_properties_component_begin(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
62                                                                  NX_AZURE_IOT_JSON_WRITER *writer_ptr,
63                                                                  const UCHAR *component_name_ptr,
64                                                                  USHORT component_name_length);
65 
66 /**
67  * @brief Append the necessary characters to end a reported property JSON payload belonging to a
68  * subcomponent.
69  *
70  * @note This API should be used in conjunction with
71  * nx_azure_iot_hub_client_reported_properties_component_begin().
72  *
73  * @param[in] hub_client_ptr A pointer to a #NX_AZURE_IOT_HUB_CLIENT.
74  * @param[in] writer_ptr A pointer to a #NX_AZURE_IOT_JSON_WRITER
75  * @return A `UINT` with the result of the API.
76  *   @retval #NX_AZURE_IOT_SUCCESS The JSON payload was suffixed successfully.
77  */
78 UINT nx_azure_iot_hub_client_reported_properties_component_end(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
79                                                                NX_AZURE_IOT_JSON_WRITER *writer_ptr);
80 
81 /**
82  * @brief Begin a property response payload with confirmation status.
83  *
84  * This API should be used in response to an incoming writable property. More details can be found
85  * here:
86  *
87  * https://docs.microsoft.com/en-us/azure/iot-pnp/concepts-convention#writable-properties
88  *
89  * The payload will be of the form:
90  *
91  * **Without component**
92  * @code
93  * //{
94  * //  "<property_name>":{
95  * //    "ac": <status_code>,
96  * //    "av": <version>,
97  * //    "ad": "<description>",
98  * //    "value": <user_value>
99  * //  }
100  * //}
101  * @endcode
102  *
103  * To send a status for a property belonging to a component, first call the
104  * nx_azure_iot_hub_client_reported_property_status_begin() API to prefix the payload with the
105  * necessary identification. The API call flow would look like the following with the listed JSON
106  * payload being generated.
107  *
108  * **With component**
109  * @code
110  *
111  * nx_azure_iot_hub_client_reported_properties_component_begin()
112  * nx_azure_iot_hub_client_reported_properties_status_begin()
113  * // Append user value here (<user_value>)
114  * nx_azure_iot_hub_client_reported_properties_status_end()
115  * nx_azure_iot_hub_client_reported_properties_component_end()
116  *
117  * //{
118  * //  "<component_name>": {
119  * //    "__t": "c",
120  * //    "<property_name>": {
121  * //      "ac": <status_code>,
122  * //      "av": <version>,
123  * //      "ad": "<description>",
124  * //      "value": <user_value>
125  * //    }
126  * //  }
127  * //}
128  * @endcode
129  *
130  * @note This API should be used in conjunction with
131  * nx_azure_iot_hub_client_reported_properties_status_end().
132  *
133  * @param[in] hub_client_ptr A pointer to a #NX_AZURE_IOT_HUB_CLIENT.
134  * @param[in] writer_ptr A pointer to a #NX_AZURE_IOT_JSON_WRITER
135  * @param[in] property_name_ptr A pointer to property name.
136  * @param[in] property_name_length Length of `property_name_ptr`.
137  * @param[in] status_code The HTTP-like status code to respond with.
138  * @param[in] version The version of the property the application is acknowledging.
139  * This can be retrieved from the service request by calling nx_azure_iot_hub_client_properties_version_get.
140  * @param[in] description_ptr An optional pointer to description detailing the context or any details about
141  *            the acknowledgement. This can be empty string.
142  * @param[in] description_length Length of description_ptr
143  *
144  * @return A `UINT` with the result of the API.
145  *   @retval #NX_AZURE_IOT_SUCCESS Successful appended JSON prefix.
146  */
147 UINT nx_azure_iot_hub_client_reported_properties_status_begin(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
148                                                               NX_AZURE_IOT_JSON_WRITER *writer_ptr,
149                                                               const UCHAR *property_name_ptr, UINT property_name_length,
150                                                               UINT status_code, ULONG version,
151                                                               const UCHAR *description_ptr, UINT description_length);
152 
153 /**
154  * @brief End a property response payload with confirmation status.
155  *
156  * @note This API should be used in conjunction with
157  * nx_azure_iot_hub_client_reported_properties_status_begin().
158  *
159  * @param[in] hub_client_ptr A pointer to a #NX_AZURE_IOT_HUB_CLIENT.
160  * @param[in] writer_ptr A pointer to a #NX_AZURE_IOT_JSON_WRITER
161  *
162  * @return A `UINT` with the result of the API.
163  *   @retval #NX_AZURE_IOT_SUCCESS Successful appended JSON suffix.
164  */
165 UINT nx_azure_iot_hub_client_reported_properties_status_end(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
166                                                             NX_AZURE_IOT_JSON_WRITER *writer_ptr);
167 
168 
169 /**
170  * @brief Get the property version. the next writable property in the property document passed.
171  *
172  * @warning This modifies the state of the json reader. To then use the same json reader
173  * with nx_azure_iot_hub_client_properties_component_property_next_get(), you must call
174  * nx_azure_iot_json_reader_init() again after this call and before the call to
175  * nx_azure_iot_hub_client_properties_component_property_next_get() or make an additional copy before
176  * calling this API.
177  *
178  * @param[in] hub_client_ptr A pointer to a #NX_AZURE_IOT_HUB_CLIENT.
179  * @param[in] reader_ptr A pointer to a #NX_AZURE_IOT_JSON_READER containing properties document
180  * @param[in] message_type Type of message repsonse, only valid value are NX_AZURE_IOT_HUB_PROPERTIES or NX_AZURE_IOT_HUB_WRITABLE_PROPERTIES
181  * @param[out] version_ptr The numeric version of the properties in JSON payload
182  * @return A `UINT` with the result of the API.
183  *   @retval #NX_AZURE_IOT_SUCCESS Successful if next writable property is found.
184  */
185 UINT nx_azure_iot_hub_client_properties_version_get(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
186                                                     NX_AZURE_IOT_JSON_READER *reader_ptr,
187                                                     UINT message_type, ULONG *version_ptr);
188 
189 /**
190  * @brief Iteratively read the Azure IoT Plug and Play component properties.
191  *
192  * Note that between calls, the UCHAR* pointed to by \p component_name_pptr shall not be modified,
193  * only checked and compared. Internally, the pointer is only changed if the component name changes
194  * in the JSON document and is not necessarily set every invocation of the function.
195  *
196  * On success, the `reader_ptr` will be set on a valid property name. After checking the
197  * property name, the reader can be advanced to the property value by calling
198  * nx_azure_iot_json_reader_next_token(). Note that on the subsequent call to this API, it is expected that
199  * the json reader will be placed AFTER the read property name and value. That means that after
200  * reading the property value (including single values or complex objects), the user must call
201  * nx_azure_iot_json_reader_next_token().
202  *
203  * Below is a code snippet which you can use as a starting point:
204  *
205  * @code
206  *
207  * while ((status = nx_azure_iot_hub_client_properties_component_property_next_get(&iothub_client,
208  *                                                                                 &json_reader,
209  *                                                                                 message_type,
210  *                                                                                 NX_AZURE_IOT_HUB_CLIENT_PROPERTY_WRITABLE,
211  *                                                                                 &component_name_ptr, &component_length)) == NX_AZURE_IOT_SUCCESS)
212  * {
213  *
214  *     // Check if property is of interest (substitute user_property for your own property name)
215  *     if (nx_azure_iot_json_reader_token_is_text_equal(&json_reader, user_property, user_property_length))
216  *     {
217  *         nx_azure_iot_json_reader_next_token(&json_reader);
218  *
219  *         // Get the property value here
220  *         // Example: nx_azure_iot_json_reader_token_int32_get(&json_reader, &user_int);
221  *
222  *         // Skip to next property value
223  *         nx_azure_iot_json_reader_next_token(&json_reader);
224  *     }
225  *     else
226  *     {
227  *         // The JSON reader must be advanced regardless of whether the property
228  *         // is of interest or not.
229  *         nx_azure_iot_json_reader_next_token(&json_reader);
230  *
231  *         // Skip children in case the property value is an object
232  *         nx_azure_iot_json_reader_skip_children(&json_reader);
233  *         nx_azure_iot_json_reader_next_token(&json_reader);
234  *     }
235  * }
236  *
237  * @endcode
238  *
239  * @warning If you need to retrieve more than one \p property_type, you should first complete the
240  * scan of all components for the first property type (until the API returns
241  * NX_AZURE_IOT_NOT_FOUND). Then you must call nx_azure_iot_json_reader_init() again after this call
242  * and before the next call to `nx_azure_iot_hub_client_properties_component_property_next_get` with the
243  * different \p property_type.
244  *
245  * @param[in] hub_client_ptr A pointer to a #NX_AZURE_IOT_HUB_CLIENT.
246  * @param[in] reader_ptr A pointer to a #NX_AZURE_IOT_JSON_READER containing properties document
247  * @param[in] message_type Type of message repsonse, only valid value are NX_AZURE_IOT_HUB_PROPERTIES or NX_AZURE_IOT_HUB_WRITABLE_PROPERTIES
248  * @param[in] property_type Type of property, only valid value are NX_AZURE_IOT_HUB_CLIENT_PROPERTY_REPORTED_FROM_DEVICE or NX_AZURE_IOT_HUB_CLIENT_PROPERTY_WRITABLE
249  * @param[out] component_name_pptr A pointer to component name for the property returned using reader_ptr
250  * @param[out] component_name_length_ptr Length of the component name
251  * @return A `UINT` with the result of the API.
252  *   @retval #NX_AZURE_IOT_SUCCESS Successful if next writable property is found.
253  */
254 UINT nx_azure_iot_hub_client_properties_component_property_next_get(NX_AZURE_IOT_HUB_CLIENT *hub_client_ptr,
255                                                                     NX_AZURE_IOT_JSON_READER *reader_ptr,
256                                                                     UINT message_type, UINT property_type,
257                                                                     const UCHAR **component_name_pptr,
258                                                                     USHORT *component_name_length_ptr);
259 
260 #ifdef __cplusplus
261 }
262 #endif
263 #endif /* NX_AZURE_IOT_HUB_CLIENT_PROPERTIES_H */
264