This simple holiday project exemplifies how easy getting into the Internet of Things can be. With some inexpensive sensors and basic programming, we connected flame sensors to the internet and were able to publish their current readings. To make things more interesting, we connected candles around Berlin, and published their current states to a map.
There are two parts to this tutorial. We'll start with setting up the hardware, but you can jump to the software tutorial. The whole project is also up in our GitHub repository.
If your family is across the city, country or world this holiday season, you can keep track of one another (and when the candles are lit) on this interactive map.
This could also be the beginning of any IoT project. Switch the candles for vending machines and the flame sensors for gyroscopes and you can set up vandalism detection on machines around the country or globe. Scale up and add more sensors and features for full scale, interactive maps that give you up to date information on whatever you're interested in.
IoT Candle Hardware Supply List
- Candle
- Grove Flame Sensor
- Publishing board: we used a Particle.io Photon (but any other board can be used)
- Text editor
Flame Sensor
The flame sensor is a simple digital sensor which detects a fire source or other light sources whose wavelength ranges between 760nm - 1100 nm. Connect the Flame Sensor to your board. We've used a Photon so the following first steps are relevant for the photon alone. We've used the basic mqtt/relayr example code.
The Process
- Create a relayr account
- In your Devices page click the 'Add a Device' button and select the Add new device option
- Give your prototype a name and hit Start Prototyping
- Make a note of your received credentials.
- Create a Particle account and go to the build section
- Start a new App
Include the Mqtt and SparkJson library
Below the library inclusions define the relayr-mqtt credentials in the following manner:
#define DEVICE_ID "ef805ac8-74b1-4ad9-874f-d08c9f99f20c" #define MQTT_USER "ef805ac8-74b1-4ad9-874f-d08c9f99f20c" #define MQTT_PASSWORD "mperTu8HFWlp" #define MQTT_CLIENTID "T74BayHSxStmHT9CMn5nyDA" //can be anything else #define MQTT_TOPIC "/v1/ef805ac8-74b1-4ad9-874f-d08c9f99f20c/" #define MQTT_SERVER "mqtt.relayr.io"
Define your sensor pin
//pins const int FireSense = A0;
Define additional variables for mqtt publishing
//for publish mutiple times char message_buff[100]; char meaning_buff[50]; const int meaningLen = 50; //mqtt stuff //define LED and Mqtt const int led = D7; int ledState = LOW; unsigned long lastPublishTime = 0; unsigned long lastBlinkTime = 0; // Set here the time in milliseconds between publications int publishingPeriod = 400; // ATTENTION !!! // DO NOT try to set values under 200 ms of the server // will kick you out void callback(char* topic, byte* payload, unsigned int length); //create our instance of MQTT object MQTT client(MQTT_SERVER, 1883, callback);
Implement a callback
//implement our callback method thats called on receiving data from a subscribed topic void callback(char* topic, byte* payload, unsigned int length) { //store the received payload and convert it to string char p[length + 1]; memcpy(p, payload, length); p[length] = NULL; //print the topic and the payload received Serial.println("topic: " + String(topic)); Serial.println("payload: " + String(p)); //call our method to parse and use the payload received handlePayload(p); } void handlePayload(char* payload) { StaticJsonBuffer<200> jsonBuffer; //convert payload to json JsonObject& json = jsonBuffer.parseObject(payload); if (!json.success()) { Serial.println("json parsing failed"); return; } //get value of the key "command" const char* command = json["command"]; Serial.println("parsed command: " + String(command)); if (String(command).equals("color")) { const char* color = json["value"]; Serial.println("parsed color: " + String(color)); String s(color); if (s.equals("red")){ RGB.color(255, 0, 0); } else if (s.equals("blue")) RGB.color(0, 0, 255); else if (s.equals("green")) RGB.color(0, 255, 0); } }
In the setup() define the following
void setup() { RGB.control(true); Serial.begin(9600); Serial.println("Hello There, I'm your photon!"); //setup our LED pin and connect to mqtt broker pinMode(led, OUTPUT); //set 200ms as minimum publishing period publishingPeriod = publishingPeriod > 200 ? publishingPeriod : 200; mqtt_connect(); }
In the loop call publish and check whether publishing is allowed
void loop() { if (client.isConnected()) { client.loop(); //publish within publishing period if (millis() - lastPublishTime > publishingPeriod) { lastPublishTime = millis(); publish(); } blink(publishingPeriod / 2); } else { //if connection lost, reconnect Serial.println("retrying.."); mqtt_connect(); } }
Connect to the cloud:
void mqtt_connect() { Serial.println("Connecting to mqtt server"); if (client.connect(MQTT_CLIENTID, MQTT_USER, MQTT_PASSWORD)) { Serial.println("Connection success, subscribing to topic"); //subscribe to a topic client.subscribe("/v1/"DEVICE_ID"/cmd"); } else { Serial.println("Connection failed, check your credentials or wifi"); } }
Read the data and publish it onto the cloud
void publish() { //create our jsonArray StaticJsonBuffer<300> pubJsonBuffer; JsonArray& root = pubJsonBuffer.createArray(); //First object is value of Fire Sensor JsonObject& leaf1 = root.createNestedObject(); //define a meaning for what we're sending leaf1["meaning"] = "Fire"; //set our value key to the sensor's reading leaf1["value"] = digitalRead(FireSense); char message_buff[128]; root.printTo(message_buff, sizeof(message_buff)); client.publish("/v1/"DEVICE_ID"/data", message_buff); Serial.println("Publishing " + String(message_buff)); }
You probably want to know the location of your friends. We could use a GPS sensor but in order to keep things simpler, we've decided to hardcode our location and publish it to the cloud.
Use http://www.latlong.net, type in your address and copy and paste your latitude and longitude values. Create two more Json leafs under the digtialRead.
//First object is value of Fire Sensor JsonObject& leaf2 = root.createNestedObject(); //define a meaning for what we're sending leaf2["meaning"] = "Lat"; //set our value key to the sensor's reading leaf2["value"] = 52.498526; //First object is value of Fire Sensor JsonObject& leaf3 = root.createNestedObject(); //define a meaning for what we're sending leaf3["meaning"] = "Lon"; //set our value key to the sensor's reading leaf3["value"] = 52.13.383368;
Use the following to make the LED blink
void blink(int interval) { if (millis() - lastBlinkTime > interval) { // save the last time you blinked the LED lastBlinkTime = millis(); if (ledState == LOW) ledState = HIGH; else ledState = LOW; // set the LED with the ledState of the variable: digitalWrite(led, ledState); } }