Skip to content

Commit d4df00a

Browse files
add new exercise
1 parent 46ac2d2 commit d4df00a

File tree

3 files changed

+478
-0
lines changed

3 files changed

+478
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const char* rootCACertificate PROGMEM = R"EOF(
2+
-----BEGIN CERTIFICATE-----
3+
MIIDmTCCAoGgAwIBAgIJAMPWVA80Rf38MA0GCSqGSIb3DQEBDQUAMGMxGzAZBgNV
4+
BAMMElNlY3VyZSBNUVRUIGJyb2tlcjERMA8GA1UECgwIRmF2b3Jpb3QxDDAKBgNV
5+
BAsMA0lvVDEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmYXZvcmlvdC5jb20wHhcN
6+
MTcwNjIwMDcxMjQyWhcNMzIwNjE2MDcxMjQyWjBjMRswGQYDVQQDDBJTZWN1cmUg
7+
TVFUVCBicm9rZXIxETAPBgNVBAoMCEZhdm9yaW90MQwwCgYDVQQLDANJb1QxIzAh
8+
BgkqhkiG9w0BCQEWFHN1cHBvcnRAZmF2b3Jpb3QuY29tMIIBIjANBgkqhkiG9w0B
9+
AQEFAAOCAQ8AMIIBCgKCAQEAw6jfao9GPyXR2oIjFseVN2wGHHf321VaOB21NwS9
10+
hobsh7o37mOJUurDon2j2cnwj3PzRLxr5+1jtMlTh18KR7YvtI4QNVC0yZ1kfeYw
11+
doTVZ0JMm7kKqcwG75/HYTNehFTnTOKlCHcNG/lALOBUaF0Q8gccuP8w7mKsB/WY
12+
Kct7sG3Kom09vHpg14QML/4BqfBso3nMy2UpilmFqkd3iBZOc3OP93wbfoMdv+TY
13+
f3NuMC8GvjVj6w3y/ThVT5v9nW0hIOxnH0Z7/Z+StpKf66LEYrVK6wqrE+QOyPbt
14+
7egm7xzufeMFYRG9D8yq1cdkgv91D+d0WZcGJ1WuhGmyGQIDAQABo1AwTjAdBgNV
15+
HQ4EFgQU92lSlWRQCgYvnDR+yKqbrJhXH8cwHwYDVR0jBBgwFoAU92lSlWRQCgYv
16+
nDR+yKqbrJhXH8cwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAQEAA0HF
17+
TipnY6COyJX9fPH9ZCW9+FitArf0liTJTOci2Wga6f7AWAvaqgEAYtOEwGmARTK8
18+
i8MkAnf3rncvy/tegHIlklkmVHAnE8DaJIw+GwIQqg+CG+zW96M9ZicE2gP78I2d
19+
oMTKznk4POPzZOs5GnsFD50y49TY/gy7YEsmRhsyegnew9Ny45ZvAEsI1CD4QDZN
20+
nifCffGE5nNp7gcIlW5u66FvQ32deO9/Ag/83Qzj+MKvXtdkW+2PTG++g8qZnuZ6
21+
51NjwKNY6DApQ5f7QN9WZHRs82s/SrWkMxv9HgIHMyQ6PxiRYZfaLdjTKgwv92P6
22+
cDpPSjaUgpEJwiMvpQ==
23+
-----END CERTIFICATE-----
24+
)EOF";

0 commit comments

Comments
 (0)