|
| 1 | +/* |
| 2 | + * Hibiscus Sense - Exercise 15 IoT using Favoriot MQTTS Protocol with Remote Procedure Call (RPC) |
| 3 | + * |
| 4 | + * Author: Mohamad Ariffin Zulkifli |
| 5 | + * Organization: Myinvent Technologies Sdn Bhd |
| 6 | + * |
| 7 | + * This sketch has 4 summary execution steps: |
| 8 | + * 1. Initialized Wi-Fi conectivity |
| 9 | + * 2. Initialized MQTT connection to Favoriot MQTT broker |
| 10 | + * 3. Data Acquisition - Read data from the sensors |
| 11 | + * 4. Data Ingestion - Send data to Favoriot's data stream using secure MQTT protocol |
| 12 | + * |
| 13 | + * Select the board as ESP32 Dev Module before compiling the sketch |
| 14 | + * (example) Go to menu, Tools > Board > esp32 > ESP32 Dev Module |
| 15 | + * |
| 16 | + * Favoriot's Secure Certificate Validity Expires On: |
| 17 | + * Saturday, 26 April 2025 at 08:54:18 |
| 18 | + * |
| 19 | + */ |
| 20 | + |
| 21 | +#include <WiFi.h> |
| 22 | +#include <MQTT.h> |
| 23 | +#include <NetworkClientSecure.h> |
| 24 | +#include <Adafruit_APDS9960.h> |
| 25 | +#include <Adafruit_BME280.h> |
| 26 | +#include <Adafruit_MPU6050.h> |
| 27 | +#include <Adafruit_NeoPixel.h> |
| 28 | +#include <ArduinoJson.h> |
| 29 | +#include "FavoriotCA.h" |
| 30 | + |
| 31 | +const char ssid[] = "YOUR_WIFI_SSID"; |
| 32 | +const char password[] = "YOUR_WIFI_PASSWORD"; |
| 33 | +const char deviceDeveloperId[] = "YOUR_DEVICE_DEVELOPER_ID"; |
| 34 | +const char deviceAccessToken[] = "YOUR_DEVICE_ACCESS_TOKEN"; |
| 35 | +const char publishTopic[] = "/v2/streams"; |
| 36 | +const char statusTopic[] = "/v2/streams/status"; |
| 37 | +const char rpcTopic[] = "/v2/rpc"; |
| 38 | + |
| 39 | +Adafruit_NeoPixel rgb(1, 16); |
| 40 | + |
| 41 | +Adafruit_APDS9960 apds; |
| 42 | +Adafruit_BME280 bme; |
| 43 | +Adafruit_MPU6050 mpu; |
| 44 | + |
| 45 | +sensors_event_t a, g, temp; |
| 46 | + |
| 47 | +unsigned long lastMillisUpdateInternval = 0; |
| 48 | +unsigned long lastMillisDataInterval = 0; |
| 49 | + |
| 50 | +NetworkClientSecure client; |
| 51 | +MQTTClient mqtt(4096); |
| 52 | + |
| 53 | +void connectToWiFi() { |
| 54 | + Serial.print("Connecting to Wi-Fi '" + String(ssid) + "' ..."); |
| 55 | + |
| 56 | + WiFi.begin(ssid, password); |
| 57 | + |
| 58 | + while (WiFi.status() != WL_CONNECTED) { |
| 59 | + Serial.print("."); |
| 60 | + delay(500); |
| 61 | + } |
| 62 | + |
| 63 | + Serial.println(" connected!"); |
| 64 | +} |
| 65 | + |
| 66 | +void messageReceived(String &topic, String &payload) { |
| 67 | + Serial.println("Incoming Status: " + payload); |
| 68 | + Serial.println(); |
| 69 | + |
| 70 | + JsonDocument doc; |
| 71 | + DeserializationError error = deserializeJson(doc, payload); |
| 72 | + |
| 73 | + bool ledBlue = doc.containsKey("ledBlue"); |
| 74 | + bool ledRGB = doc.containsKey("ledRGB"); |
| 75 | + |
| 76 | + if (ledBlue){ |
| 77 | + int value = doc["ledBlue"]; |
| 78 | + pinMode(2, OUTPUT); digitalWrite(2, value); |
| 79 | + } |
| 80 | + |
| 81 | + if (ledRGB){ |
| 82 | + int value = doc["ledRGB"]; |
| 83 | + rgb.setPixelColor(0, rgb.Color(value, value, value)); rgb.show(); |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +void connectToFavoriotMQTT() { |
| 88 | + Serial.print("Connecting to Favoriot MQTT ..."); |
| 89 | + |
| 90 | + client.setCACert(rootCACertificate); |
| 91 | + |
| 92 | + mqtt.begin("mqtt.favoriot.com", 8883, client); |
| 93 | + mqtt.onMessage(messageReceived); |
| 94 | + |
| 95 | + String uniqueString = String(ssid) + "-" + String(random(1, 98)) + String(random(99, 999)); |
| 96 | + char uniqueClientID[uniqueString.length() + 1]; |
| 97 | + |
| 98 | + uniqueString.toCharArray(uniqueClientID, uniqueString.length() + 1); |
| 99 | + |
| 100 | + while (!mqtt.connect(uniqueClientID, deviceAccessToken, deviceAccessToken)) { |
| 101 | + Serial.print("."); |
| 102 | + delay(500); |
| 103 | + } |
| 104 | + |
| 105 | + Serial.println(" connected!"); |
| 106 | + |
| 107 | + Serial.println("Subscribe to: " + String(deviceAccessToken) + String(statusTopic)); |
| 108 | + Serial.println("Subscribe to: " + String(deviceAccessToken) + String(rpcTopic)); |
| 109 | + |
| 110 | + mqtt.subscribe(String(deviceAccessToken) + String(statusTopic)); |
| 111 | + mqtt.subscribe(String(deviceAccessToken) + String(rpcTopic)); |
| 112 | + Serial.println(); |
| 113 | +} |
| 114 | + |
| 115 | +void setup() { |
| 116 | + Serial.begin(115200); |
| 117 | + |
| 118 | + rgb.begin(); |
| 119 | + rgb.show(); |
| 120 | + |
| 121 | + if (!apds.begin()) { |
| 122 | + Serial.println("Failed to find Hibiscus Sense APDS9960 chip"); |
| 123 | + } |
| 124 | + |
| 125 | + apds.enableProximity(true); |
| 126 | + |
| 127 | + if (!bme.begin()) { |
| 128 | + Serial.println("Failed to find Hibiscus Sense BME280 chip"); |
| 129 | + } |
| 130 | + |
| 131 | + if (!mpu.begin()) { |
| 132 | + Serial.println("Failed to find Hibiscus Sense MPU6050 chip"); |
| 133 | + } |
| 134 | + |
| 135 | + Serial.println(); |
| 136 | + |
| 137 | + // STEP 1: Initialized Wi-Fi conectivity |
| 138 | + connectToWiFi(); |
| 139 | + // STEP 2: Initialized MQTT connection to Favoriot MQTT broker |
| 140 | + connectToFavoriotMQTT(); |
| 141 | +} |
| 142 | + |
| 143 | +void loop() { |
| 144 | + // Check Wi-Fi connection |
| 145 | + if (WiFi.status() != WL_CONNECTED) { |
| 146 | + connectToWiFi(); |
| 147 | + } |
| 148 | + |
| 149 | + // Check MQTT connection |
| 150 | + if (!mqtt.connected()) { |
| 151 | + connectToFavoriotMQTT(); |
| 152 | + } |
| 153 | + |
| 154 | + mqtt.loop(); |
| 155 | + delay(10); // <- fixes some issues with WiFi stability |
| 156 | + |
| 157 | + // STEP 3: Data Acquisition - Read data from the sensors |
| 158 | + int proximity = apds.readProximity(); |
| 159 | + float humidity = bme.readHumidity(); |
| 160 | + float temperature = bme.readTemperature(); |
| 161 | + float barometer = bme.readPressure() / 100.00; |
| 162 | + float altitude = bme.readAltitude(1015); // based on https://aqicn.org/ |
| 163 | + mpu.getEvent(&a, &g, &temp); |
| 164 | + float accx = a.acceleration.x; |
| 165 | + float accy = a.acceleration.y; |
| 166 | + float accz = a.acceleration.z; |
| 167 | + float gyrx = g.gyro.x; |
| 168 | + float gyry = g.gyro.y; |
| 169 | + float gyrz = g.gyro.z; |
| 170 | + |
| 171 | + if (millis() - lastMillisDataInternval > 5000) { |
| 172 | + lastMillisDataInternval = millis(); |
| 173 | + |
| 174 | + Serial.println("Proximity: " + String(proximity)); |
| 175 | + Serial.println("Relative Humidity: " + String(humidity) + " %RH"); |
| 176 | + Serial.println("Approx. Altitude: " + String(altitude) + " m"); |
| 177 | + Serial.println("Barometric Pressure: " + String(barometer) + " hPa"); |
| 178 | + Serial.println("Ambient Temperature: " + String(temperature) + " °C"); |
| 179 | + Serial.println("Acceleration X:" + String(accx) + ", Y:" + String(accy) + ", Z:" + String(accz) + " m/s^2"); |
| 180 | + Serial.println("Rotation X:" + String(gyrx) + ", Y:" + String(gyroy) + ", Z:" + String(gyroz) + " rad/s"); |
| 181 | + Serial.println("============================================="); |
| 182 | + } |
| 183 | + |
| 184 | + // STEP 4: Data Ingestion - Send data to Favoriot's data stream using secure MQTT connection |
| 185 | + // Interval 15 seconds |
| 186 | + if (millis() - lastMillisUpdateInternval > 15000) { |
| 187 | + lastMillisUpdateInternval = millis(); |
| 188 | + |
| 189 | + String favoriotJson = "{\"device_developer_id\":\"" + String(deviceDeveloperId) + "\",\"data\":{"; |
| 190 | + favoriotJson += "\"proximity\":\"" + String(proximity) + "\","; |
| 191 | + favoriotJson += "\"humidity\":\"" + String(humidity) + "\","; |
| 192 | + favoriotJson += "\"altitude\":\"" + String(altitude) + "\","; |
| 193 | + favoriotJson += "\"barometer\":\"" + String(barometer) + "\","; |
| 194 | + favoriotJson += "\"temperature\":\"" + String(temperature) + "\","; |
| 195 | + favoriotJson += "\"accx\":\"" + String(accx) + "\","; |
| 196 | + favoriotJson += "\"accy\":\"" + String(accy) + "\","; |
| 197 | + favoriotJson += "\"accz\":\"" + String(accz) + "\","; |
| 198 | + favoriotJson += "\"gyrox\":\"" + String(gyrx) + "\","; |
| 199 | + favoriotJson += "\"gyroy\":\"" + String(gyry) + "\","; |
| 200 | + favoriotJson += "\"gyroz\":\"" + String(gyrz) + "\""; |
| 201 | + favoriotJson += "}}"; |
| 202 | + |
| 203 | + Serial.println("\nSending data to Favoriot's Data Stream ..."); |
| 204 | + |
| 205 | + Serial.println("Data to Publish: " + favoriotJson); |
| 206 | + Serial.println("Publish to: " + String(deviceAccessToken) + String(publishTopic)); |
| 207 | + |
| 208 | + mqtt.publish(String(deviceAccessToken) + String(publishTopic), favoriotJson); |
| 209 | + } |
| 210 | +} |
0 commit comments