Arek Jurasz

Software Engineer

Homemade central heating temperature monitoring

December 15, 2016

Over the weekend I decided to once and for all resolve issue with boiling water in our central heating system. For people who don’t know what I’m writing about here, you will find nice ilustration that should make it clear. In my case the problem is that when I focus on something I forgot about the world around me and then after some time the sound of boiling water in pipes immediately pulls me out of my work and in few seconds I’m in the basement trying to resolve issue in different ways and this isn’t a pleasant operation. Please notice that this situation is very dangerous because boiling water can damage pipes and in few minutes your home can be flooded and repair costs probably will be very high. Solution to my issue would be replacing the old furnace with new one that can automatically take care of temperature adjustments, but I have got much more cheaper and more interensting solution for this one.

Idea

My idea is to use ESP8266 that will send temperature readings to MQTT broker running in the cloud and then business logic will be handled by lightweight nodejs application running on Heroku. Logic is simple, display the current temperature in real time one web page using WebSocket protocol, expose REST endpoint with current temperature and send a notification to registered Android devices when the temperature is over 80 Celcius degrees. Registered devices will be stored in MongoDB hosted by mLab. Here is top level architecture diagram:

esp8266_remote_temperature_diagram

Costs

Only costs I had to bear were for physical devices:

  • ESP8266 bought here for about 4$
  • Converter USB UART/RS232 bought here for about 1$
  • DS18B20 digital temperature sensor bought here for about 1,8 $
  • Power supply bought here 4$

Total: 10,8 $

If it comes to MQTT broker, application and database hosting I’m using free plans as they are sufficient for my needs.

Implementation

Complete project can be found on github. In this post, I will only focus on core parts of each component. So what are the components:

  • ESP8226 device
  • Nodejs application
  • Android application

Regarding Eclipse IoT White Paper I would say that in my simple architecture ESP8266 act as both field device and gateway. Nodejs is an application that only performs business logic on data delivered by devices (in my case just one device). Android application is for the end user, where that user can check current temperature and be notified when the temperature is too high.

ESP8226

If it comes to ESP8266 there are two main things that you need to know when playing with this device. There are different wirings for deploying and running your program. When you want to deploy your program to the device you need to set up wirings in following way:

ESP8266_upload

when you want to run your program, wirings should be set up in the following way (scheme contains temperature sensor connected to ESP8266):

ESP8266_run

Main responsibilities of ESP8226 device are:

  1. establish and keep a connection to local network (to gain access to the internet)
#include <ESP8266WiFi.h>

#define wifi_ssid "<your ssid>"
#define wifi_password "<ssid password>"

void setup() {

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
  1. read data from the temperature sensor
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

void setup() {

  sensors.requestTemperatures();
  float tempC = sensors.getTempCByIndex(0);

}
  1. push readings to MQTT broker
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define mqtt_server "<server ip or hostname>"
#define mqtt_port "<server port>"
#define mqtt_user "<user name>"
#define mqtt_password "<user password>"
#define temperature_topic "temperature/home/basement"

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {

  client.setServer(mqtt_server, mqtt_port);

}

void reconnect() {

  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP8266BasementClient", mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }

}

void loop() {

  if (!client.connected()) {
    reconnect(); 
  }
  client.loop();

  client.publish(temperature_topic, "80.0", true);

  // Wait 30 seconds
  delay(30000);

}

You can run above snippets independently or combine them together. At this point I need to say that it was so easy only thanks to these great libraries (as I have basically no experience in C language):

ESP8266WiFi

PubSubClient

DallasTemperature

Nodejs

I wanted to have something very light on the back end and to be able to host it for free so I decided to accomplish my requirements using nodejs which will run on Heroku. Another reason to choose Nodejs was that I wanted to check it out as I heard a lot of good about it.

Main responsibilities of the Nodejs application:

  1. expose REST endpoints to handle device registration, update and delete:
app.post('/device', function(req, res) {
    var deviceName = req.body.deviceName;
    var deviceId   = req.body.deviceId;
    var registrationId = req.body.registrationId;    

    Device.find({deviceId : deviceId}, function(err, devices) {
        if (err) {
            console.error(err);
            res.sendStatus(500);
        }

        if (devices.length == 0) {
            Device.create({
                deviceName: deviceName,
                deviceId: deviceId,
                registrationId: registrationId
            }, function(err, device) {
                if (err) {
                    console.error(err);
                    res.sendStatus(500);
                }
                res.sendStatus(200);
            });            
        } else {
            res.sendStatus(200);
        }        
    });
});

app.put('/device', function(req, res) {
    var deviceId   = req.body.deviceId;
    var registrationId = req.body.registrationId;

    Device.findOneAndUpdate(
        { deviceId: deviceId }, 
        { registrationId: registrationId }, 
        function(err, device) {
            if (err) {
                console.error(err);
                res.sendStatus(500);
            }
            res.sendStatus(200);
        });
});

app.delete('/device/:deviceId', function(req, res) {
    var deviceId   = req.params.deviceId;
    Device.findOneAndRemove({deviceId : deviceId}, function(err) {
        if (err) {
            console.error(err);
            res.sendStatus(500);
        }
        res.sendStatus(200);
    });
});
  1. expose WebSocket endpoint using express-ws
  2. subscribe to MQTT topic and update lastTemp object with current temperature and notify registered devices if the temperature is above 80 degrees:
mqttClient.on('message', (topic, message) => {
    console.log('received message %s %s', topic, message)
    lastTemp.temperature = message.toString();
    aWss.clients.forEach(function (client) {
        client.send(JSON.stringify({
            topic: topic,
            temperature: message.toString()
        }));
    });

    if (parseFloat(lastTemp.temperature) > 80.0) {
        var message = 'Warning temperature is very high ' + lastTemp.temperature + '°C';
        console.log(message);
        if (moment().diff(lastUpdateDate, 'minutes') > 5) {
            gcm.pushAll(message, function() {
                lastUpdateDate = moment()
            });
        }
    }
})

above was accomplished with MQTT and FCM libraries. Documentation is very good even for Noob as I’m (in the case of Node.js) so no more explanation is required.

Android

For Android system, I created a simple widget which displays current temperature and is also able to receive messages from Firebase Cloud Messaging and display them as notifications. Because this is my first experience with Android SDK and I did all the research and implementation over the weekend I beat that there are better patterns for handling my requirements. Here are two screenshots of this application:

  1. widget

android_widget

  1. notification

android_notification

Integration with FCM was kind of tricky but “Set Up a Firebase Cloud Messaging Client App on Android” article helped me a lot. It will take you step by step how to set up FCM client.

Future work

I will try to replace Nodejs application with application that use Vert.x library.

Share This Post