Monitor Sensor Data from Anywhere
Step 2: Uploading Your Code
KaaIoT has a number of examples to get you started, so weâre going to begin there. But before we can do that, we need to create a project from within the KaaIoT dashboard:
- Sign into or create a free account with KaaIoT
- Go to the cloud, and log into your Root account
- You need to create a new Solution (KaaIoTâs name for a project). Give it a name and description.
- Navigate to Device Management/Devices, and add a device. This will create a new endpoint instance, with a unique Application Version - basically a UUID.
- Get an Endpoint Token, you can create yourself, or allow Kaa to create randomly. The Token is used to verify the identity of your endpoints, so any communication request must be made from a known source. Whichever way you decide to go, it is imperative that you copy or write it down! Youâll need both the App Version and Token for your Arduino code, and KaaIoT does not put it in a secret, retrievable place for you.
For the code itself, I used code from Kaaâs GitHub repository, then pulled our own basic demo code for the BME280 and the SPG40 and melded the three.
/* * Monitor Sensor Data from Anywhere * * Rob Reynolds, Mariah Kelly, SparkFun Electronics, 2022 * * This sketch will collect data from a BME280, a SGP40, and use a * SparkFun ESP32 Thing Plus ESP32 WROOM to send the data * over WiFi to a KaaIoT dashboard. * https://www.kaaiot.com/ * Want to support open source hardware and software? * Why not buy a board from us! * Thing Plus ESP32 WROOM - https://www.sparkfun.com/products/17381 * SparkFun Air Quality Sensor - SGP40 (Qwiic) - https://www.sparkfun.com/products/18345 * SparkFun Atmospheric Sensor Breakout - BME280 (Qwiic) - https://www.sparkfun.com/products/15440 * * License: This code is public domain but you can buy us a beer if you use * this and we meet someday at the local (Beerware License). * */ // First we'll install all of the necessary libraries #include <Wire.h> #include <WiFi.h> #include "SparkFun_SGP40_Arduino_Library.h" // Go here to get the library: http://librarymanager/All#SparkFun_SGP40 #include "SparkFunBME280.h" #include <PubSubClient.h> // Download here: https://github.com/knolleary/pubsubclient/archive/refs/tags/v2.8.zip #include <ArduinoJson.h> // This library can be found in the library manager search bar! #include "kaa.h" // This one can be found in the LM search bar as well! #define KAA_SERVER "mqtt.cloud.kaaiot.com" #define KAA_PORT 1883 #define KAA_TOKEN "ESP32DemoToken" //Put your KaaIoT Token here (Created in KaaIoT) #define KAA_APP_VERSION "*******************-v1" //Put your auto-generated App Version here #define RECONNECT_TIME 5000 //ms #define SEND_TIME 3000 //ms // Define output names for our sensor data here #define COMMAND_TYPE "OUTPUT_SWITCH" #define OUTPUT_1_NAME "temperature" #define OUTPUT_2_NAME "humidity" #define OUTPUT_3_NAME "VOC" #define OUTPUT_4_NAME "altitude" #define OUTPUT_5_NAME "pressure" const char* ssid = "WirelessNetworkName"; //WiFi network goes here const char* password = "WirelessNetworkPassword"; //WiFi Password goes here char mqtt_host[] = KAA_SERVER; unsigned int mqtt_port = KAA_PORT; unsigned long now = 0; unsigned long last_reconnect = 0; unsigned long last_msg = 0; WiFiClient espClient; PubSubClient client(espClient); Kaa kaa(&client, KAA_TOKEN, KAA_APP_VERSION); #define PRINT_DBG(...) printMsg(__VA_ARGS__) BME280 mySensor; SGP40 myVOCSensor; //create an object of the SGP40 class void setup() { Serial.begin(115200); Serial.println("Reading basic values from BME280 and SGP40"); //mySensor.enableDebugging(); // Uncomment this line to print useful debug messages to Serial setupWifi(); client.setServer(mqtt_host, mqtt_port); client.setCallback(callback); Wire.begin(); //Initialize sensors if (myVOCSensor.begin() == false) { Serial.println(F("SGP40 not detected. Check connections. Freezing...")); while (1); // Do nothing more } if (mySensor.beginI2C() == false) { //Begin communication over I2C Serial.println("The sensor did not respond. Please check wiring."); while (1); //Freeze } } void loop() { if (!client.connected()) { //Checking connection now = millis(); if ( ((now - last_reconnect) > RECONNECT_TIME) || (now < last_reconnect) ) { last_reconnect = now; reconnect(); } return; } client.loop(); //Sending something now = millis(); if ( ((now - last_msg) > SEND_TIME) || (now < last_msg) ) { last_msg = now; //Send something here sendOutputsState(); } } void printMsg(const char * msg, ...) { char buff[256]; va_list args; va_start(args, msg); vsnprintf(buff, sizeof(buff) - 2, msg, args); buff[sizeof(buff) - 1] = '\0'; Serial.print(buff); } String getChipId() { char buf[20]; uint64_t chipid = ESP.getEfuseMac(); sprintf(buf, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid); return String(buf); } void composeAndSendMetadata() { StaticJsonDocument<255> doc_data; String ipstring = ( String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]) ); // Insert any fixed data you want here - board, location, any other metadata doc_data["name"] = "ESP32"; doc_data["model"] = "SparkFun Thing Plus"; doc_data["location"] = "Niwot, CO"; doc_data["longitude"] = "40° 5' 25.5474"; doc_data["latitude"] = "-105° 11' 6.2874"; doc_data["ip"] = ipstring; doc_data["mac"] = String(WiFi.macAddress()); doc_data["serial"] = String(getChipId()); kaa.sendMetadata(doc_data.as<String>().c_str()); } void sendOutputsState() { StaticJsonDocument<255> doc_data; // This is where we get sensor data, asign it to our outputs, send it to our Dashboard doc_data.createNestedObject(); doc_data[0][OUTPUT_1_NAME] = mySensor.readTempF(); // read sensor data for temperature doc_data[1][OUTPUT_2_NAME] = mySensor.readFloatHumidity(); // read sensor data for humidity doc_data[2][OUTPUT_3_NAME] = myVOCSensor.getVOCindex(); // read VOC sensor data doc_data[3][OUTPUT_4_NAME] = mySensor.readFloatAltitudeFeet(); // read sensor data for altitude doc_data[4][OUTPUT_5_NAME] = mySensor.readFloatPressure(); // read sensor data for pressure kaa.sendDataRaw(doc_data.as<String>().c_str()); // send data to Kaa IoT Cloud } void setupWifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.print(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } String ipstring = ( String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]) ); Serial.println(); PRINT_DBG("WiFi connected\n"); PRINT_DBG("IP address: %s\n", ipstring.c_str()); } void callback(char* topic, byte* payload, unsigned int length) { PRINT_DBG("Message arrived [%s] ", topic); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); kaa.messageArrivedCallback(topic, (char*)payload, length); } void reconnect() { PRINT_DBG("Attempting MQTT connection to %s:%u ...", mqtt_host, mqtt_port); // Create client ID String clientId = "ESP8266Client-"; clientId += String(getChipId()); // Attempt to connect if (client.connect(clientId.c_str())) { PRINT_DBG("connected\n"); kaa.connect(); composeAndSendMetadata(); } else { PRINT_DBG("failed, rc=%d try again in %d milliseconds\n", client.state(), RECONNECT_TIME); } }
You can check that your code is working locally by opening the Arduinoâs serial monitor and checking the data flow. Once thatâs been confirmed, youâre ready to jump back over to your dashboard, and make sure youâre receiving the data there as well.
By navigating to the Device Management/Devices page on your KaaIoT page, youâll be able to verify that the sensor data is being received. KaaIoT has some auto detectors for things like temperature, humidity, and barometric pressure.
Now that we have verified that our sensor is reading data, our ESP32 is sending data, and our dashboard is receiving data, it's time to decide how we want to display that data.