Last active
March 11, 2022 05:49
-
-
Save wduraes/8a688183e46b09d5fecbdd04dbaa1e66 to your computer and use it in GitHub Desktop.
Telemetry and Command sample for a grain silo with the ESP8266
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Deprecation note: this Gist is here only for historic purposes. | |
* It was created before the release of the Arduino Library | |
* which is now the preferred way to get Arduino-based devices to get connected to Azure | |
* Please refer to https://aka.ms/arduino for additional guidance | |
* | |
*/ | |
#include <string.h> | |
#include <stdbool.h> | |
#include <time.h> | |
#include <cstdlib> | |
#include <ESP8266WiFi.h> | |
#include <PubSubClient.h> | |
#include <WiFiClientSecure.h> | |
#include <base64.h> | |
#include <bearssl/bearssl.h> | |
#include <bearssl/bearssl_hmac.h> | |
#include <libb64/cdecode.h> | |
#include <az_result.h> | |
#include <az_span.h> | |
#include <az_iot_hub_client.h> | |
#include "iot_configs.h" | |
#include <Adafruit_Sensor.h> | |
#include <DHT.h> | |
#include <DHT_U.h> | |
#include "SPI.h" | |
#define DHTPIN 10 // pin connected to the temperature sensor | |
#define DHTTYPE DHT11 | |
#define sizeofarray(a) (sizeof(a) / sizeof(a[0])) | |
#define EXPIRATION_IN_SECS 2592000 //expiration set to 1 month | |
#define NTP_SERVERS "pool.ntp.org", "time.nist.gov" | |
#define MQTT_PACKET_SIZE 1024 | |
DHT_Unified dht(DHTPIN, DHTTYPE); | |
static const char* ssid = IOT_CONFIG_WIFI_SSID; | |
static const char* password = IOT_CONFIG_WIFI_PASSWORD; | |
static const char* host = IOT_CONFIG_IOTHUB_FQDN; | |
static const char* device_id = IOT_CONFIG_DEVICE_ID; | |
static const char* device_key = IOT_CONFIG_DEVICE_KEY; | |
static const int port = 8883; | |
const char* telemetry_msg = ""; | |
char hum[5]; | |
char temp[5]; | |
char light[4]; | |
char payload[61]; | |
char chipid[5]; | |
String Payload =""; | |
float Temp; | |
float Hum; | |
float Light; | |
float ChipID; | |
static WiFiClientSecure wifi_client; | |
static PubSubClient mqtt_client(wifi_client); | |
static az_iot_hub_client client; | |
static bool override_fan = false; | |
static char sas_token[200]; | |
static uint8_t signature[512]; | |
static unsigned char encrypted_signature[32]; | |
static char base64_decoded_device_key[32]; | |
static unsigned long next_telemetry_send_time_ms = 0; | |
static char telemetry_topic[128]; | |
static void connectToWiFi() { | |
Serial.begin(115200); | |
Serial.println(); | |
Serial.print("Connecting to WIFI SSID "); | |
Serial.println(ssid); | |
WiFi.mode(WIFI_STA); | |
WiFi.hostname(host); | |
WiFi.begin(ssid, password); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.print("WiFi connected, IP address: "); | |
Serial.println(WiFi.localIP()); | |
} | |
static void initializeTime() { | |
Serial.print("Setting time using SNTP"); | |
configTime(-5 * 3600, 0, NTP_SERVERS); | |
time_t now = time(NULL); | |
while (now < 1510592825) { | |
delay(500); | |
Serial.print("."); | |
now = time(nullptr); | |
} | |
Serial.println("done!"); | |
} | |
static char* getCurrentLocalTimeString() { | |
time_t now = time(NULL); | |
return ctime(&now); | |
} | |
void receivedCallback(char* topic, byte* payload, unsigned int length) { | |
Serial.print("Received ["); | |
Serial.print(topic); | |
Serial.print("]: "); | |
for (int i = 0; i < length; i++) { | |
Serial.print((char)payload[i]); | |
} | |
if((char)payload[0]=='y') { | |
override_fan = true; | |
} | |
if((char)payload[0]=='n') { | |
override_fan = false; | |
} | |
} | |
static void initializeClients() | |
{ | |
// This disables the client verification of server-side certificate during TLS | |
// negotiation. It is not recommended to be a production-level practice for | |
// connecting with Azure IoT servers. | |
// It has been disabled for simplifying the sample. | |
wifi_client.setInsecure(); | |
if (az_result_failed(az_iot_hub_client_init( | |
&client, | |
az_span_create((uint8_t*)host, strlen(host)), | |
az_span_create((uint8_t*)device_id, strlen(device_id)), | |
NULL))) | |
{ | |
Serial.println("Failed initializing Azure IoT Hub client"); | |
return; | |
} | |
mqtt_client.setServer(host, port); | |
mqtt_client.setCallback(receivedCallback); | |
} | |
static uint32_t getSecondsSinceEpoch(){ | |
return (uint32_t)time(NULL); // Don't do this at home. | |
} | |
static int generateSasToken(char* sas_token, size_t size){ | |
az_span signature_span = az_span_create((uint8_t*)signature, sizeofarray(signature)); | |
az_span out_signature_span; | |
az_span encrypted_signature_span | |
= az_span_create((uint8_t*)encrypted_signature, sizeofarray(encrypted_signature)); | |
uint32_t expiration = getSecondsSinceEpoch() + EXPIRATION_IN_SECS; | |
// Get signature | |
if (az_result_failed(az_iot_hub_client_sas_get_signature( | |
&client, expiration, signature_span, &out_signature_span))) | |
{ | |
Serial.println("Failed getting SAS signature"); | |
return 1; | |
} | |
// Base64-decode device key | |
int base64_decoded_device_key_length | |
= base64_decode_chars(device_key, strlen(device_key), base64_decoded_device_key); | |
if (base64_decoded_device_key_length == 0) { | |
Serial.println("Failed base64 decoding device key"); | |
return 1; | |
} | |
// SHA-256 encrypt | |
br_hmac_key_context kc; | |
br_hmac_key_init( | |
&kc, &br_sha256_vtable, base64_decoded_device_key, base64_decoded_device_key_length); | |
br_hmac_context hmac_ctx; | |
br_hmac_init(&hmac_ctx, &kc, 32); | |
br_hmac_update(&hmac_ctx, az_span_ptr(out_signature_span), az_span_size(out_signature_span)); | |
br_hmac_out(&hmac_ctx, encrypted_signature); | |
// Base64 encode encrypted signature | |
String b64enc_hmacsha256_signature = base64::encode(encrypted_signature, br_hmac_size(&hmac_ctx)); | |
az_span b64enc_hmacsha256_signature_span = az_span_create( | |
(uint8_t*)b64enc_hmacsha256_signature.c_str(), b64enc_hmacsha256_signature.length()); | |
// URl-encode base64 encoded encrypted signature | |
if (az_result_failed(az_iot_hub_client_sas_get_password( | |
&client, | |
expiration, | |
b64enc_hmacsha256_signature_span, | |
AZ_SPAN_EMPTY, | |
sas_token, | |
size, | |
NULL))) | |
{ | |
Serial.println("Failed getting SAS token"); | |
return 1; | |
} | |
return 0; | |
} | |
static int connectToAzureIoTHub() { | |
size_t client_id_length; | |
char mqtt_client_id[128]; | |
if (az_result_failed(az_iot_hub_client_get_client_id( | |
&client, mqtt_client_id, sizeof(mqtt_client_id) - 1, &client_id_length))) | |
{ | |
Serial.println("Failed getting client id"); | |
return 1; | |
} | |
mqtt_client_id[client_id_length] = '\0'; | |
char mqtt_username[128]; | |
// Get the MQTT user name used to connect to IoT Hub | |
if (az_result_failed(az_iot_hub_client_get_user_name( | |
&client, mqtt_username, sizeofarray(mqtt_username), NULL))) | |
{ | |
printf("Failed to get MQTT clientId, return code\n"); | |
return 1; | |
} | |
Serial.print("Client ID: "); | |
Serial.println(mqtt_client_id); | |
Serial.print("Username: "); | |
Serial.println(mqtt_username); | |
mqtt_client.setBufferSize(MQTT_PACKET_SIZE); | |
while (!mqtt_client.connected()) { | |
time_t now = time(NULL); | |
Serial.print("MQTT connecting ... "); | |
if (mqtt_client.connect(mqtt_client_id, mqtt_username, sas_token)) { | |
Serial.println("connected."); | |
} | |
else { | |
Serial.print("failed, status code ="); | |
Serial.print(mqtt_client.state()); | |
Serial.println(". Try again in 5 seconds."); | |
// Wait 5 seconds before retrying | |
delay(5000); | |
} | |
} | |
mqtt_client.subscribe(AZ_IOT_HUB_CLIENT_C2D_SUBSCRIBE_TOPIC); | |
return 0; | |
} | |
void establishConnection() { | |
connectToWiFi(); | |
initializeTime(); | |
initializeClients(); | |
// The SAS token is valid for 1 hour by default in this sample. | |
// After one hour the sample must be restarted, or the client won't be able | |
// to connect/stay connected to the Azure IoT Hub. | |
if (generateSasToken(sas_token, sizeofarray(sas_token)) != 0) { | |
Serial.println("Failed generating MQTT password"); | |
} | |
else { | |
connectToAzureIoTHub(); | |
} | |
} | |
void setup() { | |
establishConnection(); | |
pinMode(A0, INPUT); //set the pin for the light sensor | |
pinMode(5,OUTPUT); //set the motor driver pin | |
dht.begin(); //initialize the ambient sensor | |
} | |
static void sendTelemetry(char* char_array) | |
{ | |
if (az_result_failed(az_iot_hub_client_telemetry_get_publish_topic( | |
&client, NULL, telemetry_topic, sizeof(telemetry_topic), NULL))) | |
{ | |
Serial.println("Failed az_iot_hub_client_telemetry_get_publish_topic"); | |
return; | |
} | |
//mqtt_client.publish(telemetry_topic, getCurrentLocalTimeString(), false); | |
mqtt_client.publish(telemetry_topic, char_array, false); | |
} | |
void loop() | |
{ | |
if (millis() > next_telemetry_send_time_ms) { | |
//check if connected | |
if(!mqtt_client.connected()) { | |
establishConnection(); | |
} | |
//get Chip ID an unique identifier | |
ChipID = ESP.getChipId(); | |
dtostrf(ChipID, 5, 0, chipid); | |
Payload = "{deviceID:'A"; | |
//get temperature and humidity | |
sensors_event_t event; | |
dht.temperature().getEvent(&event); | |
Temp = event.temperature; | |
dtostrf(Temp, 2, 2, temp); | |
Payload = Payload + chipid + "',Temperature:" + temp + ",Humidity:"; | |
dht.humidity().getEvent(&event); | |
Hum = event.relative_humidity; | |
dtostrf(Hum, 2, 2, hum); | |
Payload = Payload + hum + ",Light:"; | |
//get light readings from sensor | |
Light = analogRead(A0); | |
dtostrf(Light, 4, 0, light); | |
Payload = Payload + light + "}"; | |
//convert String Payload to a char array | |
int str_len = Payload.length() + 1; | |
char char_array[str_len]; | |
Payload.toCharArray(char_array, str_len); | |
//print payload | |
Serial.println(" "); | |
Serial.print("Payload: "); | |
Serial.println(char_array); | |
sendTelemetry(char_array); | |
mqtt_client.loop(); | |
next_telemetry_send_time_ms = millis() + TELEMETRY_FREQUENCY_MILLISECS; | |
} | |
if(override_fan) { | |
digitalWrite(5,1); | |
} | |
else { | |
if(Hum > 60) { | |
digitalWrite(5,1); | |
} | |
else { | |
digitalWrite(5,0); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment