Skip to content

Instantly share code, notes, and snippets.

@wduraes
Last active March 11, 2022 05:49
Show Gist options
  • Save wduraes/8a688183e46b09d5fecbdd04dbaa1e66 to your computer and use it in GitHub Desktop.
Save wduraes/8a688183e46b09d5fecbdd04dbaa1e66 to your computer and use it in GitHub Desktop.
Telemetry and Command sample for a grain silo with the ESP8266
/*
*
* 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