For a long time now I’ve wanted wireless temperature sensors scattered around the house and garden reporting their temperatures regularly to a central server. It’s not something I really need, but something nice to have. I’d originally planned to do it with a RasPiO Duino or Arduino nano and inexpensive NRF24L01 radio boards. Albert @winkleink Hickey, a friend of mine, who also runs the Egham Jam put me onto these when he did his buttonflash game. Albert has a useful hobby of trawling ebay for bargain-basement electronics. A few weeks ago he showed me the Wemos D1 mini.

On inspection, it ticked all my boxes for this project.

Small

Cheap

Built-in wifi (via an ESP8266)

Has an ADC input (I love my TMP-36 sensors)

Supports Arduino IDE

So I ordered some to try out. They arrived recently and I took a little time to have a play. (I’ve been heavily into a development cycle on a top-secret new project that I hope to be able to announce within the next few weeks. So a little ‘playtime’ was very welcome.)

Installation

Installation was fairly straightforward. A driver for the CH340 USB interface is provided (I already had this installed from previous Arduino nano clone usage). There’s also a link you can copy into the Arduino IDE to install all the relevant libraries and examples specific to these boards. It all “just worked”. This is what we like. WIN!

Looking through the examples is quite an eye-opening experience. There are quite a lot of them (each of the items in the screenshot is a menu), but it gives you a flavour of what these boards can do.

You can have them working as web client, web server, or access point (to name but three modes).

Port Numbering Can Be Tricky!

The only caveat is that the port numbering is a bit confusing. For digital pins you need to use D1, D2, D3 instead of just the 1, 2, 3 for your digitalRead() and digitalWrite() commands. If you use just the integers, it defaults to the ESP8266’s GPIO numbers.

pinMode(D4, OUTPUT); //These two lines digitalWrite(D4, 1); pinMode(2, OUTPUT); //do the same thing as digitalWrite(2, 1); //these two pinMode(D4, INPUT); //These two lines digitalRead(D4); pinMode(2, INPUT); //do the same thing as digitalRead(2); //these two

The pinouts are here in the table. That’s really the only “gotcha” though.

If you are familiar with the Arduino IDE, these boards are a breeze to use. You can even update them wirelessly, although I haven’t tried that yet (it screams “security hazard” to me, but would be OK if done well).

WiFiWebServer

The first sketch I tried was the WiFiWebserver sketch. The only modification you have to make is to add your WiFi login credentials. This sketch is very simple. It enables you to type a URL into your browser to switch the onboard LED on and off. You use the Arduino IDE’s serial monitor to get the Wemos’s ip address, then http://192.168.x.y/gpio/1 and http://192.168.x.y/gpio/0 toggle the LED on and off. Having done that, I modified the sketch to read the TMP-36 and report the results when accessed. That was pretty easy, but the connection was not persistent and kept dropping out. This is why I decided to use the Pi as a server and have the Wemos ‘nodes’ report in to it.

Temperature Logging

So once I’d proved the concept and that WiFi was working, I did a quick google to see if anyone else had already done the temperature sensor network before. It’s always good to do this so you can crib ideas and sometimes even borrow some bits of code. In this case I found exactly what I was looking for here. Someone had done a similar thing with the Wemos, but using different temperature sensors (DS18B20). The temperature sensor part was easy for me to change, but I used the rest of the method, which was in turn based on parts of the Wemos examples.

How Does It Work?

Before I go any further with the details and procedures, here’s an overview of how the whole system works.

I have multiple Wemos D1 minis. Each one has a TMP-36 sensor being read by the analog port. Every minute, each Wemos reads its sensor and reports the value, via WiFi to a Raspberry Pi on the local network.

The Raspberry Pi is running a lighttpd web server and php5. A short php script is used (a first for me) to log the data from the incoming http “GET” commands from each of the Wemos boards.

That takes care of the data logging. I wanted to be able to view the current data on a web page, so I wrote a short Python script to generate an html page from the most recent data. This script is run every minute using a cron job on the Pi. If I knew php, it could probably be done dynamically using php. But I don’t, so meh!

So the outcome is that, every minute, each sensor sends in its new data, which is logged, a new html file is created and I can always view data in my browser which is never more than a couple of minutes old. All I have to do is visit http://ip.of.my.pi/temps.html

It wouldn’t be hard to open up a port on the router and make this viewable from the outside world, but I haven’t done that at this point.

How Reliable Is It?

It seems pretty solid to me. It’s not internet dependent, so even if your external connection goes down, your data should still be logged as long as your router(s) are behaving. I’ve only been running it a couple of days but it’s looking good at this point.

I Want To Have a GO!

Hardware

OK. The hardware is simple. For each temperature reporting node, you need a Wemos D1 mini, a TMP-36 and wires to connect them. I’ve found that it’s best not to have the sensor too close to the board because it generates some heat. I’m using 10cm wires. Attach the TMP-36 power pin to 3V3 (it will also work fine on 5V), ground pin to G and signal pin to A0.

The only other hardware requirement is a computer on your local network running a web server and php. I’m using a Pi3. Because you have to hard code an ip address into your Wemos script, it’s a good idea if the Pi has either a static ip address or you fiddle with the settings in your router to give it a reserved ip address, so it doesn’t change.

Software on the Server

I installed lighttpd on the Pi following instructions I got from here

sudo apt-get -y install lighttpd

sudo apt-get -y install php5-common php5-cgi php5 (obsolete now use next line instead)

sudo apt-get -y install php7.3-common php7.3-cgi php7.3

sudo lighty-enable-mod fastcgi-php

sudo service lighttpd force-reload



The root directory of the website /var/www is currently owned by the “root” user. We must ensure the www-data user account can write files to /var/www directory (or our php script won’t work – this was NOT in the instructions).

sudo chown www-data:www-data /var/www

sudo chown www-data:www-data /var/www/html

sudo chmod 775 /var/www permission to write to this directory

sudo usermod -a -G www-data pi add “pi” user to the “www-data” group

sudo reboot Reboot the Raspberry Pi, your Raspberry Pi web server is ready.

I snagged the following php script from here

<?php if(!empty($_GET["temperature"]) && !empty($_GET["humidity"]) && !empty($_GET["voltage"]) && !empty($_GET["ipsrc"])){ $csvData = array($_GET["ipsrc"],$_GET["temperature"],$_GET["humidity"],$_GET["voltage"],date("Ymd"),date("H:i:s")); $fp = fopen("order.csv","a"); if($fp) { fputcsv($fp,$csvData); // Write information to the file fclose($fp); // Close the file } } ?>

Save it as /var/www/html/test.php , then

sudo chmod 755 test.php make your file executable

sudo chown www-data:www-data /var/www/html/test.php

I had an unexpected issue with writing to the data file, so I had to…

sudo chown www-data:www-data order.csv

sudo chown www-data:www-data /var/www/html

This may have been because I created the file order.csv manually from the root id or it may have been because I hadn’t “chown”ed the /var/www directory at the time (I don’t remember – sorry!)

Once you’ve done all that you should be able to test the php script using this url

http://ip.of.your.pi:portnumber/test.php?ipsrc=2&temperature=-22.75&humidity=10&voltage=11

It should create a file called order.csv in /var/www/html

The above should create an entry in order.csv looking something like this…

2,-22.75,10,11,20170126,10:10:09

You can obviously tweak the php script to log only the data you want. You can also tweak your Wemos sketch to send only the data you want. (But if you change either, it will probably break the Python script further down, so you will have to tweak it.)

Software on the Wemos

Flash the following sketch to your Wemos. You’ll need to tweak it so http://ip.of.your.pi/test.php?ipsrc=Test2 reflects the correct ip address of your php server and tweak the value of ipsrc to the name of your node. (e.g. Lounge, Workshop, Hall).

// Libraries #include <ESP8266WiFi.h> #include <ESP8266WiFiMulti.h> #include <ESP8266HTTPClient.h> #define USE_SERIAL Serial ESP8266WiFiMulti WiFiMulti; int reading = 0; int iterations = 10; float voltage = 0.0; float temperature = 0.0; void setup() { Serial.begin(115200); // Start Serial USE_SERIAL.begin(115200); // USE_SERIAL.setDebugOutput(true); USE_SERIAL.println(); USE_SERIAL.println(); USE_SERIAL.println(); for(uint8_t t = 8; t > 0; t--) { USE_SERIAL.printf("[SETUP] WAIT %d...

", t); USE_SERIAL.flush(); delay(1000); } WiFiMulti.addAP("Router1-SSI", "Router1-password"); WiFiMulti.addAP("Router2-SSI", "Router2-password"); } void loop() { analogRead(0); // chuck the first reading away to clear the ADC delay(20); reading = 0; // then read ADC pin 10 times and average for (int loop = 0; loop < iterations; loop++) { reading += analogRead(0); delay(20); } voltage = (reading / iterations / 1023.0) * 3.3; temperature = (voltage - 0.5) * 100; String temp; temp = String(temperature); Serial.println(temp); Serial.println(WiFi.localIP()); HTTPClient http; USE_SERIAL.print("[HTTP] begin...

"); // configure traged server and url http.begin("http://ip.of.your.pi/test.php?ipsrc=Test2&temperature="+ temp + "&humidity=1&voltage=1"); //HTTP USE_SERIAL.print("[HTTP] GET...

"); // start connection and send HTTP header int httpCode = http.GET(); // httpCode will be negative on error if(httpCode > 0) { // HTTP header has been send and Server response header has been handled USE_SERIAL.printf("[HTTP] GET... code: %d

", httpCode); // file found at server if(httpCode == HTTP_CODE_OK) { String payload = http.getString(); USE_SERIAL.println(payload); } } else { USE_SERIAL.printf("[HTTP] GET... failed, error: %s

", http.errorToString(httpCode).c_str()); } http.end(); delay(60000); // wait a minute }

Once flashed, monitor the script’s output using the Arduino IDE’s serial monitor. If your Wemos fails to get an ip address (it will show 0.0.0.0 if it fails) run the WiFiWebserver sketch to get an ip address, then “reserve” it on your router configuration.

The original script didn’t always connect, so I upped the wait time from 4s to 8s.

All being well, now you have flashed your Wemos D1 mini and, when powered up, it will send a temperature reading every minute to your Pi’s php web server. YAY!

Now all we need to do is make the data accessible…

The Python Script on the Pi

The following Python code will take the most recent X readings from your sensor(s) and create an html file which you can access using http://ip.of.your.pi:portnumber/temps.html

The value of X is tweakable in line 6 sensor_qty = 3

#!/usr/bin/python data_log = open('/var/www/html/order.csv','r') lines = data_log.readlines() data_log.close() sensor_qty = 3 # how many sensor lines to read in from log html_string = '<html>

<body>

<style>

table {

border-spacing: 10px;

' html_string += ' border-collapse: separate;

}

</style>

' html_string += '

<table>

<tr align="center">

<th>Location</th>' html_string += '<th>Temp</th><th>Date</th><th>Time</th></tr>

' for x in range(-sensor_qty, 0, 1): line = lines[x].split(',') html_string += '<tr><td align="right">' html_string += line[0] html_string += '</td><td align="right">' html_string += line[1] html_string += '°C </td><td>' html_string += line[4] html_string += '</td><td> ' html_string += line[5] html_string += '</td></tr>

' html_string += '</table>



</body>

</html>' html_file = open('/var/www/html/temps.html','w') html_file.write(html_string) html_file.close()

Save the above script in /home/pi/temperatures.py , then…

sudo touch /var/www/html/temps.html

sudo chmod 775 /var/www/html/temps.html

sudo chown www-data:www-data /var/www/html/temps.html

chmod 755 /home/pi/temperatures.py , then check that it works (once you have some data in /var/www/html/order.csv )…

python3 /home/pi/temperatures.py

Once you’re happy that it works OK, you can add it to a cron job

crontab -e

add this line…

* * * * * /usr/bin/python /home/pi/temperatures.py

And We’re Done!

That should be it. Now you should be able to access your temperature data using…

http://ip.of.your.pi:portnumber/temps.html

Have fun. If you try it, let us know how you get on.

You can get Wemos D1 mini here and TMP36 here.