12 KiB
Connect your IoT device to di cloud - Wio Terminal
For dis part of di lesson, you go connect your Wio Terminal to your IoT Hub, so e fit dey send telemetry and receive commands.
Connect your device to IoT Hub
Di next step na to connect your device to IoT Hub.
Task - connect to IoT Hub
-
Open di
soil-moisture-sensorproject for VS Code. -
Open di
platformio.inifile. Comot diknolleary/PubSubClientlibrary dependency. Dem bin use am to connect to di public MQTT broker, but e no dey needed to connect to IoT Hub. -
Add di following library dependencies:
seeed-studio/Seeed Arduino RTC @ 2.0.0 arduino-libraries/AzureIoTHub @ 1.6.0 azure/AzureIoTUtility @ 1.6.1 azure/AzureIoTProtocol_MQTT @ 1.6.0 azure/AzureIoTProtocol_HTTP @ 1.6.0 azure/AzureIoTSocket_WiFi @ 1.0.2Di
Seeed Arduino RTClibrary dey provide code to interact with di real-time clock wey dey Wio Terminal, wey dem dey use track time. Di remaining libraries go allow your IoT device connect to IoT Hub. -
Add di following to di bottom of di
platformio.inifile:build_flags = -DDONT_USE_UPLOADTOBLOBDis one go set compiler flag wey dem need when dem dey compile di Arduino IoT Hub code.
-
Open di
config.hheader file. Comot all di MQTT settings and add di following constant for di device connection string:// IoT Hub settings const char *CONNECTION_STRING = "<connection string>";Replace
<connection string>with di connection string for your device wey you copy before. -
Di connection to IoT Hub dey use time-based token. Dis mean say di IoT device need sabi di current time. Unlike operating systems like Windows, macOS or Linux, microcontrollers no dey automatically synchronize di current time over di Internet. Dis mean say you go need add code to get di current time from one NTP server. Once di time don dey retrieved, e fit dey stored for di real-time clock wey dey Wio Terminal, so di correct time fit dey requested later, as long as di device no lose power. Add new file wey you go call
ntp.hwith di following code:#pragma once #include "DateTime.h" #include <time.h> #include "samd/NTPClientAz.h" #include <sys/time.h> static void initTime() { WiFiUDP _udp; time_t epochTime = (time_t)-1; NTPClientAz ntpClient; ntpClient.begin(); while (true) { epochTime = ntpClient.getEpochTime("0.pool.ntp.org"); if (epochTime == (time_t)-1) { Serial.println("Fetching NTP epoch time failed! Waiting 2 seconds to retry."); delay(2000); } else { Serial.print("Fetched NTP epoch time is: "); char buff[32]; sprintf(buff, "%.f", difftime(epochTime, (time_t)0)); Serial.println(buff); break; } } ntpClient.end(); struct timeval tv; tv.tv_sec = epochTime; tv.tv_usec = 0; settimeofday(&tv, NULL); }Di details of dis code no dey inside di scope of dis lesson. E dey define one function wey dem call
initTimewey go get di current time from one NTP server and use am set di clock wey dey Wio Terminal. -
Open di
main.cppfile and comot all di MQTT code, including diPubSubClient.hheader file, di declaration of diPubSubClientvariable, direconnectMQTTClientandcreateMQTTClientmethods, and any calls to dis variables and methods. Dis file suppose only contain code to connect to WiFi, get di soil moisture and create JSON document with am. -
Add di following
#includedirectives to di top of dimain.cppfile to include header files for di IoT Hub libraries, and for setting di time:#include <AzureIoTHub.h> #include <AzureIoTProtocol_MQTT.h> #include <iothubtransportmqtt.h> #include "ntp.h" -
Add di following call to di end of di
setupfunction to set di current time:initTime(); -
Add di following variable declaration to di top of di file, just below di include directives:
IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;Dis one dey declare
IOTHUB_DEVICE_CLIENT_LL_HANDLE, wey be handle to di connection to di IoT Hub. -
Below dis one, add di following code:
static void connectionStatusCallback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void *user_context) { if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED) { Serial.println("The device client is connected to iothub"); } else { Serial.println("The device client has been disconnected"); } }Dis one dey declare callback function wey dem go call when di connection to di IoT Hub change status, like when e connect or disconnect. Di status go dey sent to di serial port.
-
Below dis one, add function to connect to IoT Hub:
void connectIoTHub() { IoTHub_Init(); _device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(CONNECTION_STRING, MQTT_Protocol); if (_device_ll_handle == NULL) { Serial.println("Failure creating Iothub device. Hint: Check your connection string."); return; } IoTHubDeviceClient_LL_SetConnectionStatusCallback(_device_ll_handle, connectionStatusCallback, NULL); }Dis code dey initialize di IoT Hub library code, then e go create connection using di connection string wey dey
config.hheader file. Dis connection dey based on MQTT. If di connection fail, e go send am to di serial port - if you see dis for di output, check di connection string. Finally, di connection status callback go dey set up. -
Call dis function for di
setupfunction below di call toinitTime:connectIoTHub(); -
Just like di MQTT client, dis code dey run for one single thread so e need time to process messages wey di hub dey send, and messages wey di hub dey receive. Add di following to di top of di
loopfunction to do dis:IoTHubDeviceClient_LL_DoWork(_device_ll_handle); -
Build and upload dis code. You go see di connection for di serial monitor:
Connecting to WiFi.. Connected! Fetched NTP epoch time is: 1619983687 Sending telemetry {"soil_moisture":391} The device client is connected to iothubFor di output, you go see di NTP time wey dem dey fetch, followed by di device client wey dey connect. E fit take few seconds to connect, so you fit see di soil moisture for di output while di device dey connect.
💁 You fit convert di UNIX time for di NTP to di one wey you fit read well well using website like unixtimestamp.com
Send telemetry
Now wey your device don connect, you fit send telemetry to di IoT Hub instead of di MQTT broker.
Task - send telemetry
-
Add di following function above di
setupfunction:void sendTelemetry(const char *telemetry) { IOTHUB_MESSAGE_HANDLE message_handle = IoTHubMessage_CreateFromString(telemetry); IoTHubDeviceClient_LL_SendEventAsync(_device_ll_handle, message_handle, NULL, NULL); IoTHubMessage_Destroy(message_handle); }Dis code dey create IoT Hub message from string wey dem pass as parameter, send am to di hub, then e go clean di message object.
-
Call dis code for di
loopfunction, just after di line wey di telemetry dey sent to di serial port:sendTelemetry(telemetry.c_str());
Handle commands
Your device need handle command from di server code to control di relay. Dis one dey sent as direct method request.
Task - handle direct method request
-
Add di following code before di
connectIoTHubfunction:int directMethodCallback(const char *method_name, const unsigned char *payload, size_t size, unsigned char **response, size_t *response_size, void *userContextCallback) { Serial.printf("Direct method received %s\r\n", method_name); if (strcmp(method_name, "relay_on") == 0) { digitalWrite(PIN_WIRE_SCL, HIGH); } else if (strcmp(method_name, "relay_off") == 0) { digitalWrite(PIN_WIRE_SCL, LOW); } }Dis code dey define callback method wey di IoT Hub library fit call when e receive direct method request. Di method wey dem request dey sent for di
method_nameparameter. Dis function go print di method wey dem call to di serial port, then e go turn di relay on or off depending on di method name.💁 You fit also implement dis one for one single direct method request, pass di desired state of di relay for payload wey dem fit pass with di method request and dey available from di
payloadparameter. -
Add di following code to di end of di
directMethodCallbackfunction:char resultBuff[16]; sprintf(resultBuff, "{\"Result\":\"\"}"); *response_size = strlen(resultBuff); *response = (unsigned char *)malloc(*response_size); memcpy(*response, resultBuff, *response_size); return IOTHUB_CLIENT_OK;Direct method requests dey need response, and di response dey two parts - response as text, and return code. Dis code go create result as di following JSON document:
{ "Result": "" }Dis one go then copy am into di
responseparameter, and di size of dis response go dey set for diresponse_sizeparameter. Dis code go then returnIOTHUB_CLIENT_OKto show say di method handle well. -
Wire up di callback by adding di following to di end of di
connectIoTHubfunction:IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL); -
Di
loopfunction go call diIoTHubDeviceClient_LL_DoWorkfunction to process events wey IoT Hub dey send. Dis one dey only called every 10 seconds because of didelay, meaning direct methods dey only process every 10 seconds. To make dis one more efficient, di 10 seconds delay fit dey implemented as many shorter delays, dey callIoTHubDeviceClient_LL_DoWorkeach time. To do dis, add di following code above diloopfunction:void work_delay(int delay_time) { int current = 0; do { IoTHubDeviceClient_LL_DoWork(_device_ll_handle); delay(100); current += 100; } while (current < delay_time); }Dis code go dey loop repeatedly, dey call
IoTHubDeviceClient_LL_DoWorkand dey delay for 100ms each time. E go do dis as many times as dem need to delay for di amount of time wey dem give for didelay_timeparameter. Dis mean say di device dey wait at most 100ms to process direct method requests. -
For di
loopfunction, comot di call toIoTHubDeviceClient_LL_DoWork, and replace didelay(10000)call with di following to call dis new function:work_delay(10000);
💁 You fit find dis code for di code/wio-terminal folder.
😀 Your soil moisture sensor program don connect to your IoT Hub!
Disclaimer:
Dis dokyument don use AI transle-shon service Co-op Translator do di transle-shon. Even as we dey try make am correct, abeg sabi say transle-shon wey machine do fit get mistake or no dey accurate. Di original dokyument for im native language na di one wey you go take as di correct source. For important mata, e good make professional human transle-shon dey use. We no go fit take blame for any misunderstanding or wrong interpretation wey fit happen because you use dis transle-shon.