Introduction: Easy Weather Station Using MQTT, XinaBox and Kibana
I built this weather station using XinaBox xCHIPS, which posts the sensor data to an MQTT broker over WiFi with CW01 (ESP8266 based xCHIP).
Step 1: Things Used in This Project
Hardware components
- XinaBox CW01 xChip x 1
xChip WiFi Core based on ESP8266 - XinaBox SW01 xChip x 1
xChip environmental sensor based on BME280 - XinaBox SL01 xChip x 1
xChip visible light and UV sensor based on TSL45315 and VEML6075 - XinaBox PU02 xChip x 1
xChip USB power supply - XinaBox XC10 xChip x 1
xBUS connectors to interface between xChips - XinaBox IP01 xChip x 1
xChip USB Programming Interface
Software apps and online services
Step 2: Story
Intro
I built this weather station to sense the environment around my home just for fun. It was built using the modular platform, XinaBox. It is an easy to use platform that simply clicks together, no hardware hassles. The system runs on the CW01 xChip, which is an ESP8266 based WiFi core. The CW01 publishes the data to an MQTT broker over my home WiFi, where I can subscribe to the data with a Kibana server to visualize and plot the data.
Weather data plotted in Kibana
Step 3: What You Will Need
Apart from the set of xChips, you will need Arduino installed and the following libraries.
- ESP8266 Board Driver from Arduino Board Manager
- xCore (XinaBox Library)
- xSW01 (XinaBox Library)
- xSL01 (XinaBox Library)
- ESP8266WiFi (Part of the ESP8266 board files in Arduino)
- PubSubClient
- NTPtimeESP
Additional:
- MQTT Server to publish to.
- Any visualization software that can subscribe to the MQTT Broker (I used Kibana).
Step 4: Programming the CW01
Click in an IP01 xChip onto the CW01 using an XC10 connector and plug into a USB port on your computer. Open Arduino, select the correct COM port, set the switches on the IP01 to "B" and "DCE" positions. Under Tools select "Generic ESP8266 Module" and set Flash Size to "4M (1M SPIFFS)", the rest can be left as default, then upload the sketch, which I will provide in the code section of this page. (Remember to change the WiFi and MQTT Server details to your own). Connect similar to the picture below.
CW02 and IP01 connected together for programming over USB.
Step 5: Building It
What build? Lol. The xChips make it very easy, simply click them together with the XC10 connectors until it looks like the picture at the top of the page. The only thing to bare in mind, the small XinaBox logos with chip name must all face the same direction, the bus at the top and bottom of the board are NOT the same. Usually the boards have a large logo at the bottom.
Step 6: Running It
Put the device where-ever you want to measure the environment, simply plug a micro-USB cable into the PU02 and power it from a USB phone charger or computer USB port.
Step 7: Code
CW01_Simple_Weather_MQTT C/C++
This is the main file of the Arduino Sketch (ino file). Has to be placed in a folder with the same name.
#include <xCore.h> #include <xSW01.h> #include <xSL01.h> #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <NTPtimeESP.h> #define RED 12 #define GREEN 13 #define BLUE 5 char topic_WS[40]; const char* ssid = "YourWifiName"; const char* password = "YourWifiPassword"; String server = "mqtt.xinabox.cc"; //Use your own mqtt server here uint16_t port = 80; const char* client_id = "ben_weather_station"; const char* username = "admin"; const char* MQTT_password = "YourMQTTServerPassword"; String DEVICE = "Hackster_Station"; String ORGANIZATION = "XinaBox"; float SW01_Temperature, SW01_Humidity, SW01_Pressure, SL01_Lux, SL01_UVA, SL01_UVB, SL01_UVIndex; long tick_sensor_poll = 0, tick_publish_mqtt = 0, tick_serial_print = 0; int sensor_poll_interval = 1000, publish_mqtt_interval = 5000, serial_print_interval = 5000; String timeStamp; // Use WiFiClient class to create TCP connections WiFiClient CW01_client; // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. PubSubClient client(CW01_client); strDateTime dateTime; /*************************** NTP Server Parameters **************************/ NTPtime NTPch("time.google.com"); // Choose server pool as required void setup() { //Begin Serial bus Serial.begin(115200); //Begin I2C bus Wire.begin(2, 14); //Set LED Outputs pinMode(RED, OUTPUT); pinMode(GREEN, OUTPUT); pinMode(BLUE, OUTPUT); //Set up SL01 SL01.begin(); //Set up SW01 SW01.begin(); //Setup wifi and MQTT Broker setup_wifi(); } void loop() { read_sensors(); publish_mqtt(); yield(); }
CONNECTIONS C/C++
Code to connect to WiFi and MQTT broker, also builds JSON to publish to MQTT. Must be in the same folder as the main Arduino sketch. I included it in the project as a tab named "CONNECTIONS".
void setup_wifi(void) { Serial.print("[STATUS] Starting Wifi Connection"); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { digitalWrite(RED, HIGH); delay(250); digitalWrite(RED, LOW); delay(250); Serial.print("."); } if (WiFi.status() == WL_CONNECTED) { digitalWrite(GREEN, HIGH); } Serial.println(); Serial.println("[STATUS] WiFi connected."); mqtt_connect(); } void mqtt_connect(void) { Serial.println( "[STATUS] Connecting to MQTT Broker." ); client.setServer(server.c_str() , port); if ( client.connect(client_id, username, MQTT_password) ) { Serial.println( "[STATUS] MQTT Broker Connected." ); } //Create MQTT Topic sprintf(topic_WS, "xinabox/data/ws/%s", client_id); //Replace with your own topic for MQTT Broker. } void publish_mqtt(void) { if ((millis() - tick_publish_mqtt) > publish_mqtt_interval) { Serial.println("[STATUS] Publishing to MQTT Server..."); // Prepare a JSON payload string String payload = "{"; payload += "\"Weather_Station\": {"; payload += "\"SW01\": {"; payload += "\"Temperature(C)\":"; payload += SW01_Temperature; payload += ","; payload += "\"Humidity(%)\":"; payload += SW01_Humidity;payload += ","; payload += "\"Pressure(Pa)\":"; payload += SW01_Pressure; payload += "}"; payload += ","; payload += "\"SL01\": {"; payload += "\"Lux\":"; payload += SL01_Lux; payload += ","; payload += "\"UVA(mW/m^2)\":"; payload += SL01_UVA; payload += ","; payload += "\"UVB(mW/m^2)\":"; payload += SL01_UVB; payload += ","; payload += "\"UVI\":"; payload += SL01_UVIndex; payload += "}"; payload += ","; // insert user specific data payload += "\"Input\": {"; payload += "\"Unit Name\":\""; payload += DEVICE; payload += "\""; payload += ","; payload += "\"Organization\":"; payload += "\""; payload += ORGANIZATION; payload += "\""; payload += "},"; // Get TimeStamp getTimeStamp(); payload += "\"Timestamp\":{"; payload += "\"Created\":\""; payload += timeStamp; payload += "\""; payload += "}"; payload += "}"; payload += "}"; // Send payload char demo_data[1024]; payload.toCharArray(demo_data, 1024); Serial.println(); Serial.println("Publishing to MQTT Server..."); Serial.print("Connection State :"); Serial.print(" [RC : "); Serial.print(client.state()); Serial.println("]"); Serial.print("Topic: "); Serial.println(topic_WS); Serial.println("loc_payload : "); Serial.println(demo_data); unsigned int length_WS = strlen(demo_data); if (client.publish(topic_WS, demo_data, length_WS)) { Serial.println("[PUBLISHED]"); digitalWrite(RED, LOW); digitalWrite(GREEN, HIGH); } else { Serial.print("[FAILED]"); Serial.print(" [RC : "); Serial.print(client.state()); Serial.println("]"); digitalWrite(RED, HIGH); digitalWrite(GREEN, LOW); } Serial.println(); tick_publish_mqtt = millis(); } } // Get timestamp void getTimeStamp(void) { dateTime = NTPch.getNTPtime(0.0, 0); if (dateTime.valid) { timeStamp = dateTime.year; timeStamp += "-"; if (dateTime.month < 10) { timeStamp += "0"; timeStamp += dateTime.month; timeStamp += "-"; } else { timeStamp += dateTime.month; timeStamp += "-"; } if (dateTime.day < 10) { timeStamp += "0"; timeStamp += dateTime.day; } else { timeStamp += dateTime.day; } timeStamp += "T"; if (dateTime.hour < 10) { timeStamp += "0"; timeStamp += dateTime.hour; timeStamp += ":"; } else { timeStamp += dateTime.hour; timeStamp += ":"; } if (dateTime.minute < 10) { timeStamp += "0"; timeStamp += dateTime.minute; timeStamp += ":"; } else { timeStamp += dateTime.minute; timeStamp += ":"; } if (dateTime.second < 10) { timeStamp += "0"; timeStamp += dateTime.second; } else { timeStamp += dateTime.second; } } }
SENSORS C/C++
Very simple code to read the XinaBox sensors. Must be in the same folder as the main Arduino sketch. I included it in the project as a tab named "SENSORS".
void read_sensors(void) { if ((millis() - tick_sensor_poll) > sensor_poll_interval) { //Get sensor data SW01.poll(); SL01.poll(); //Move SW01 sensor data into global variables. SW01_Temperature = SW01.getTemperature_C(); SW01_Humidity = SW01.getHumidity(); SW01_Pressure = SW01.getPressure(); //Move SL01 sensor data into global variables. SL01_Lux = SL01.getLUX(); SL01_UVA = SL01.getUVA(); SL01_UVB = SL01.getUVB(); SL01_UVIndex = SL01.getUVIndex(); tick_sensor_poll = millis(); } }