A battery fed MQTT weatherstation

(Note: if you consider building this… I am working on a similar station with a bare ESP12 and a BME280 for even better energy efficiency)

Weatherstations are a popular build for DIY-ers and with the ESP8266 WiFi capabilities that has become very easy.
Here I will present a simple weatherstation (DHT sensor BMP sensor for temperature, humidity and atmospheric pressure) that can be battery fed or mains fed.
It will send the info by MQTT and in order to save batteries, go to sleep most of the time.
Components needed are:

  • A wemos mini D1
  • A DHT11 or DHT22
  • A BMP280
  • A 100k resistor for the battery
  • A small switch or jumper
  • A LithiumIon charger module

Just a word for the wise… the Wemos D1 is not the best option to battery feed, as it has some peripheral components (such as the CH340 chip) that draw current. A better choice would be the bare ESP8266, but it is not for everybody to solder that.

The application has OTA. Using OTA together with deep sleep is always a bit of a tricky situation as you cannot do OTA when the ESP8266 is in deep sleep.
basically there are 3 solutions for that:

  1. Include a pause in which you can do OTA. Problem with that is that you would need some indication of when that pause starts (e.g. once the MQTT messages have come in). Another problem is that that pause in which the processor is not in deep sleep, it wil consume more energy.
  2. Make the deepsleep dependent on the state of a pin. With a jumper or Switch you could make one pin high or low and thus allow deepsleep or not.
  3. By having the software check on a seperate website whether or not there is an update for the software and then download that software. Obviously that requires some more organization and if the Wemos will do that check whenever it awakes, it will do that say every 15 minutes for something that may never happen.

Considering the above, Option 2 seemed the best, so I added a small switch to tell the software whether or not to go into deepsleep.

Software

The program once loaded (get it here) has several tabs in the IDE.
The main program “esp8266_weatherstation” is quite straightforward, it sets up all the usual parameters, variables and the sensors.
It reads the sensors and sends these via MQTT to a broker.
Once that is done, it goes into deepsleep, depending on two parameters:

  • the “FORCE_DEEPSLEEP” variable: if present there will be a 15 min deepsleep. If not set, the deepsleep will be determined by the battery voltage.
  • the state of the ‘SLEEPPIN (D6):  if LOW there will be deepsleep, if HIGH, there will be no deepsleep

If there is no deepsleep, a pause of 30 secs is added to avoid the MQTT messages being send in a frenzy.

You may be puzzled by the following code section:

float h = dht.readHumidity();
float t = dht.readTemperature();
delay(2000);
float h = dht.readHumidity();
float t = dht.readTemperature();

The reason for this is the response time of the DHT22. If you  start a reading, the results you get are from a reading that was started 2 secs before. Usually that is not an issue, but if you put the processor to sleep for 15 minutes, that first reading will give you 15 min old values. If that is not a problem, by all means remove the delay and second reading. It will not make a difference on your battery life as your  DHT22 is not put to sleep.
technically ofcourse it is possible to feed the DHT22 from one of the I/O pins and switch it off when not needed, but the DHT22 also needs a warm-up time of about 2 secs, so you would need to take that into account. No doubt that warm up time could be catered for with the delay(2000) command mentioned above.

The “OTA” section sets up the OTA function. As explained before, OTA and DEEPSLEEP is a bit of an uneasy combination. In order to use OTA, tou would need to put the switch on D6 in the right position (HIGH) and either reset  the WEMOS or wait till the next wake up. Mind you that when DEEPSLEEPing the OTA port  can disappear, but it should come back once the processor is out of DEEPSLEEP.

the “config.h” file defines some variables

the “webconnect” file connects to WiFi. If for some reason that connection cannot be made after 10 times trying, the processor is going back to sleep for 30 more seconds and then tries again.

Libraries

The libaries used are quite standard, with the exception of the PubSubClient library. This is not the well known PubSubclient library from Nick O’Leary, but a fork made by Ian Tester. The reason for using that one is that it is easier to send variables in the MQTT payload.
The DHT library is the DHT sensor Library from Adafruit. If you prefer another DHT library (there are many) you will probably only need to make minor changes.
The BMP280 library is also from Adafruit.

The sensors

DHT22

The DHT22 is the more accurate sibling of the DHT11, but both have a tendency of failure. generally the DHT22 needs a pull up resistor, but one can also use the internal pullup of the I/O pin for that.

There are two specification where the DHT11 is better than the DHT22. That’s the sampling rate which for the DHT11 is 1Hz or one reading every second, while the DHT22 sampling rate is 0,5Hz or one reading every two seconds and also the DHT11 has smaller body size.

If you are using this sensor outside, you can protect it against dirt and  creepy crawlies by covering it with a single layer of teflon tape. Supposedly this is fully permeable for humidity.

The DHT sensors do not have eternal life. they give up working alltogether (and usually permanently) when the humidity is 100%

Properties DHT11 DHT22
Voltage 3-5 Volt 3-5 Volt
Operating current 2.5mA 2.5mA
Temperature range 0 t/m 50 ºC -40 t/m 80 ºC
Temperature accuracy ±2 ºC ±0,5 ºC
Humidity range 20-80% RH 20-95% RH
Humidity accuracy ±5% RH ±2-5% RH
Sampling rate 1Hz 0.5Hz
BMP280

The BMP280 is the successor of the BMP085, BMP 180 and BMP183

Ofcourse it is possible to use one of the above predecessors, but these older sensors are generally more expensive than the BMP280.
The BMP280 can measure barometric pressure with ±1 hPa absolute accuraccy, and temperature with ±1.0°C accuracy. It can be controlled both by SPI and I2C.

Do not mix it up with the BME280. That sensor can also read humidity, but it is slightly more expensive.
The BME280 ofcourse would be a perfect chip to go to if you want to avoid the DHT22 sensor. It can read temperature, humidity and barometric pressure. I just didnt have it lying around, thus couldnt try.

If you are no fan of the DHT11/22 consider the I2C HTU21D, or theSi7021 (replaced by the HTU21D).
If you are only interested in say temperature and not in humidity, the BPM280 is the best choice and you can omit the DHT22. If you only want temperature, the DS18B20 is probably the best choice.

The battery

Lipo Charge module

It is hard to give recommendations for what battery to use. I am using the battery shield to which I connect a LiPo battery. That makes it all very simple but it is not the most efficient way of using the energy from a battery as the battery shield first boosts it up to 5 Volt after which the Wemos makes 3V3 Volt from it.
Another easy way is to use a Lipo battery with a lowdrop 3V3 regulator and a cheap charging module (pictured top). You could combine the charging module with a small solar cell (with a 5-6 Volt max output). The 100k resistor in the  circuit sketch should go directly to the V+batt, to monitor the battery voltage. The choice for the 100k resistor is explained here.  If for power efficiency you decide to use a bare ESP8266 instead, one has the opportunity to increase the resistors of the voltage divider to come to a smaller current through these resistors

Advertisements

Controlling Neopixel or RGB LED with Openhab

Controlling Neopixels or RGB LEDs from an ESP8266, controlled by OpenHab is fairly simple. I will present here a working system with a Colorpicker, some predefined buttons and sliders. It will be updateable by OTA and provide some  feedback to openhab on the node parameters

Using a Colorpicker
The sitemap and items file are fairly easy, just using a Colorpicker. I will describe some additions, but the basic files are quite simple

itemsfile

Group All
Color RGBLed "NeoPixel Color" (All)
String RGBLedColor (All) {mqtt=">[mosquitto:OpenHab/RGB:command:*:default]"}

There are 2 items here. One item contains the HSB value, coming from the colorpicker, The other item, that will not be visible on the screen, will contain the calculated RGB code that will be sent out via MQTT.

sitemap file is as follows:

sitemap NeoPixel label="NeoPixel"
{
	Frame label="NeoPixel" {
		Colorpicker item=RGBLed icon="slider"
	}
}

The colorpicker sends an HSB (Hue, Saturation, Brightness) code, but that isnt anything a regular Neopixel LED or regular RGB LED can use, so I set up a rule that triggers on any change of the RGB item to change the HSB code into a regular RGB code. That RGBcode is joined in 1 string called ’ color’. The rule then assigns that ‘color’ string to a new item called “RGBLedColor”

rules file

import org.eclipse.smarthome.core.library.types.DecimalType
import org.eclipse.smarthome.core.library.types.HSBType

rule "Set HSB value of item RGBLed to RGB color value"
when
	Item RGBLed changed
then
	val hsbValue = RGBLed.state as HSBType

	val brightness = hsbValue.brightness.intValue 
	val redValue = ((((hsbValue.red.intValue * 255) / 100) *brightness) /100).toString
	val greenValue = ((((hsbValue.green.intValue * 255) / 100) *brightness) /100).toString
	val blueValue = ((((hsbValue.blue.intValue * 255) / 100) *brightness) /100).toString

	val color = redValue + "," + greenValue + "," + blueValue

	sendCommand( RGBLedColor, color)
end

//part of Neopixel conf files

On the receiving end, there is a Wemos D1 mini that controls a NeoPix strip. The ‘color’ string is split in its separate RGB values. As such it could also be used for an RGB LED or seperate Red, Green, Blue Led’s.
The code is reacting to one MQTT topic, basically switching the entire strip at one go in the desired color and brightness, but I added a structure catching some other MQTT topics that now go to empty routines but that could be used for patterns like a breathing light or a moving pattern. As illustration I added a simple red-blue pattern that responds to MQTT “OpenHab/RGB/scene” with payload “2”  I am using the broker name ‘mosquitto’, if your broker has a different name you needto modify that.

I have to say though that this is not the most efficient way of adding topics, but for beginners it is easiest to follow.
A much more efficient way is to keep the topics of one specified length with only say the last 2 or 3 characters defining the desired action and then only checking for those last characters. A good example of this is for instance in the gateway or sonoff code on https://github.com/computourist/ESP8266-MQTT-client4. For readability sake however, in this example I have chosen to use a more traditional approch and as long as you just want to control some LEDs it is easier.

The ESP8266 code does send some information back: it returns the software version, the IP number and the RSSI.
With regard to the software version and IP number… if you have several ESP8266’s and or Arduino’s in your system, it is easy to lose track which one does what and with what software.

The ESP8266 code is OTA updateable
I have used a fork of the O’Leary PubSub library that makes it easier to send variables as the MQTT payload without having to resort to setting up buffer space and using c_string. Library is here4: https://github.com/Imroy/pubsubclient4.
If you already have the O’Leary PubSub library installed, you will need to put the library files in your sketch folder and change #include <PubSubClient.h> into #include “PubSubClient.h”

Sending predefined colors
If next to the Colorpicker you also want to be able to send predefined colors via a button, then you only need to add some lines in the items and sitemap file:

add to itemsfile:

    Switch NEO_RED	"Red"	<red> {mqtt=">[mosquitto:OpenHab/RGB:command:ON:255,0,0]"}
    Switch NEO_YELLOW	"Yellow"	<yellow>	{mqtt=">[mosquitto:OpenHab/RGB:command:ON:100,96,0]"}
    Switch NEO_BLUE	"Blue"	<darkblue>{mqtt=">[mosquitto:OpenHab/RGB:command:ON:0,0,255]"}

add to the sitemap:

Switch item=NEO_RED mappings=[ON="ON"]
Switch item=NEO_YELLOW mappings=[ON="ON"]
Switch item=NEO_BLUE mappings=[ON="ON"]

As it can be a bit of a bother to find and type all the codes for the colors you may want, I added for download some 160 predefined color settings to pick and add to your sitemap and itemsfile, including some simple icons. As these items already send an R,G,B, code they do not need the rulesfile, only the colorpicker does.

How about Sliders
Perhaps you do not want to use a colorpicker but just individual sliders for Red, Green and Blue.
That is quite easy too.
add the following to your itemsfile:

Dimmer NEO_SLIDERRED "Neopixel Red [%d %%]"  <red> {mqtt=">[mosquitto:OpenHab/RGB/RED:command:*:default]"}
Dimmer NEO_SLIDERGREEN "Neopixel Green [%d %%]" <green> {mqtt=">[mosquitto:OpenHab/RGB/GREEN:command:*:default]"}
Dimmer NEO_SLIDERBLUE "Neopixel Blue [%d %%]" <blue> {mqtt=">[mosquitto:OpenHab/RGB/BLUE:command:*:default]"}

and this to your sitemap

Slider item=NEO_SLIDERRED 
Slider item=NEO_SLIDERGREEN
Slider item=NEO_SLIDERBLUE

Normally that would be enough already, but our ESP8266 program is expecting one input rather than seperate RGB inputs. That is because the colorpicker we used before sends one string of info.
We could add topics to the ESp8266 program to respond to individual RG and B values (and that is what the MQTT topics OpenHab/RGB/RED, OpenHab/RGB/GREEN, and OpenHab/RGB/Blue would be for), but it might be easier to combine those and send as one. For that we need a new rule.

add this to your rules file:

rule "Send  RGB items from slider"
when
Item NEO_SLIDERRED changed or
Item NEO_SLIDERGREEN changed or
Item NEO_SLIDERBLUE changed
then
val redValue=  Math::round(2.55* (NEO_SLIDERRED.state as DecimalType).intValue)
val greenValue=  Math::round(2.55* (NEO_SLIDERGREEN.state as DecimalType).intValue) //
val blueValue=  Math::round(2.55* (NEO_SLIDERBLUE.state as Number).intValue)
val color = redValue + "," + greenValue + "," + blueValue
	sendCommand( RGBLedColor, color)
end

While we are at it
If you want the Filename, IP number and RSSI to show up, add the following to your items file:

Number W_RSSI  "RSSI [%d dbm]" <signal>  {mqtt="<[mosquitto:home/nb/weer/RSSI:state:default]"}
String W_IP "IP [%s]" <network>   {mqtt="<[mosquitto:home/nb/weer/IP:state:default]"}
String W_version "Software versie [%s]" <version>  {mqtt="<[mosquitto:home/nb/weer/version:state:default]"}
String W_MAC "MAC [%s]" <mac> (Wweather) {mqtt="<[mosquitto:home/nb/weer/mac:state:default]"}
Number W_IP_Uptime "Uptime [%d min]" <clock> (Wweather) {mqtt="<[mosquitto:home/nb/weer/uptime:state:default]"}

and the following lines to your sitemap:

   Text item=W_RSSI
   Text item=W_IP
   Text item=W_version
   Text item=W_MAC
   Text item=W_IP_Uptime

download11
https://drive.google.com/open?id=0B9IqgvBSA4aUVzgzRE9MUUY3U2M11

Although I tried on a Wemos D1 mini, I presume this will also work perfectly on the ESP8266-01. Perhaps a great way to use those if you still have on your scrapheap as this is typically a minimal pin project.

The ESP8266 program
The Esp8266 program is rather self explanatory and going into it too deep might fall outside the openhab scope a bit, but in brief, you will find several ino files and a userconfig.h file. These all should be in the same directory and it is sufficient to open the NeopixelOpenhab_vx.ino file in your IDE. The other files will then open up too.

You need to make a few modifications in the userdata.h file.

The essential changes are your password, your SSID and the address of your MQTT server. The other options are indeed ‘optional’, can leave them as is.
the Filename is sent back to openhab as an MQTT message, so in the future you will still know what file it was you put in your ESP8266. obviously you would need to fill out the correct filename.

A handy module to control neopixels from am ESP8266-01 is described here.

Adding a popular 5Volt 4 channel relay board to a 3V3 processor (beginners)

Chinese webshops sell a 5Volt 4 channel relay board that is quite popular amongst hobbyist. Sometimes I get the question if it can be used with a 3V3 microprocessor. This ofcourse is very basic Ohms law, so just skip this article if you already know, but for those who still have questions: read on.

Well in short: any relay can be made to work with any microprocessor, but lets look at how this can be done in an efficient way.

Normally, if you have a bare 5Volt relay, it would only require a transistor or a FET to drive the relay with any voltage sufficient to open the transistor. The relay board in question though already has some electronics around it, so lets have a look at the circuit:

It is quite clear that this is not the standard one transistor relay board: the Transistor driving the relay in itself is driven by an optocoupler, that also inverts the signal: It is a LOW on the INx input that will  bring the optocoupler to open, thus feeding the base of the transistor, that will subsequently open and activate the relay. The circuit also shows that the optocoupler can be fed from the same  voltage source as the  relay, or from a different voltage source.

First question we have to ask ourselves: is a 3v3 circuit enough to drive the board?
Well, suppose we feed the board entirely with 5Volt. If we then would connect a 3V3 processor pin such as from a raspberry or ESP8266 or  a modern Arduino, a LOW would indeed activate the relay, as described above, but what happens if we do a HIGH?
Well, with a HIGH there would be a voltage of (5-3.3=) 1.7 volt over the series resistor, the optocoupler and the LED. Given the fact that the  forward voltage of the  optocoupler is about 1.5 Volt and the forward voltage over the red LED is on average 2.2 Volt, that basically absorbs the 1.7 Volt making it safe to say there will be no current flowing through the optocoupler when the IO pin is made HIGH (3V3).
Factually, even if the ‘HIGH’  would only be 2.5 Volt, chances are slim that there would be any current flowing through the optocoupler.

Now ofcourse there are people who shrug at the idea of  having any 5Volt source connected to their 3V3 pins, so what happens if we  take away the Voltage jumper, feed the relay with 5Volt and the optocoupler with 3V3.

Well, suppose we again make the IO pin LOW, then there will be 3V3 over the optocoupler, the LED and the resistor.
The LED and the optocoupler will  have a voltage drop of 1.5+2.2=3.7 Volts. Ergo, there will not be any current flowing through the optocoupler and the relay will not be activated.

Therefore: yes, the relay board can be used with a 3V3 processor, but  you will have to feed the entire board with 5Volt.

But, what if I do not want the signal to be inverted, if I want a LOW to deactivate the relay and a HIGH to activate it?

Well, that is fairly easy: do that with an inverter. One can either use an inverter IC such as a 7404, 7414 or a 4069, but ofcourse then you’d have to wonder whether 3V3 would be enough input for those IC’s  (it is).
Another possibility is just a transistor with a base resistor 470-1000 Ohm (1x for every channel).

 

Using the 18 bits MCP3421 I2C ADC with Arduino.

A while ago, I published a post about expanding the ESP8266 ADC capacities with the PCF8591 8 bits I2C ADC multiplexer. 8 Bits is really enough for most work I would guess, but if you need more accuracy, say 18 bits for a  high precision Digital Voltmeter, there is the (relatively expensive) MCP3421. I say ‘relatively coz it is still cheaper (and easier to use)  than the LTC2400 (controlled by SPI). This is only a one channel chip, so if you want more channels, you would think you have to get more (which is OK as generally they are sold in webstores in a lot of say 5 or 10), but the chip has no address selection. It has a fixed address of 0x68.
If you do not like soldering though, there is also an ‘evaluation module’ available.

The MCP3421 has an in-program sample rate selection from 12-18 bits and in inbuild Programmable Gain Amplifier that can also be controlled from  your program. There is a library available, several in fact which makes using the chip very easy. If one channel is not enough, try the MCP3424 18-bit, 4-channel, multi-address ADC

JSON, MQTT, PubSub and OpenHAB

Usually I communicate between my various nodes (arduino, esp8266) with MQTT and OpenHAB being the interface. Simple, just one string command per message. Now there comes a moment that it seems better or more convenient, to send more commands in one MQTT message, and that is where JSON comes in. JSON messages are basically an organized string and MQTT is good in sending strings.
Author of the Pubsub library Nick O’Leary’s advice on sending JSON’s is as follows:

However, you need a few tricks before you can send a string variable.

I started off by using the ArduinoJson library to make my JSON’s, but I was not quite happy with that. There are various ways to do it and you end up with some sort of data/char array.

Supposedly you could send that with "client.publish(topic, (char*) payload.c_str())". But for various reasons that didnt suit me so I used another method.

As I was a bit unhappy about adding the ArduinoJson library just to make a JSON string, I thought it would be  best to simply compile the string myself and send that. I am not saying there is no better way… and if there is, please do tell, but this worked for me.

Anyway, let’s start with something simple, I have a LiPo battery feeding an ESP8266 and in openHAB I like to keep track of the voltage of the battery, but I also like to display the Percentage of the battery charged. Ofcourse I can calculate the latter in OpenHAB, but i prefer to have the ESP8266 do that.
Note: the below calculation is for a Wemos D1, with a 100k  resistor  in series with A0. Together with the  residing voltage divider it makes a 100k/(100k+220k+100k) = 1/4.2 voltage divider,  reducing a 4.2Volt voltage to 1 Volt. Therefore a reading of 1023 (=1V) on the A0 port correlates with 4.2 Volt on the LiPo battery)

voltage=analogRead(A0);// (mind you, this is 1 V max)
voltage=voltage/1023.0;// so 1V max renders "1" here
voltage=voltage*4.2;// We want a max of 4.2, so multiply
percent=100*voltage/4.2;// and calculate percentage

The JSON string I need to make, will look as follows

{"Voltage": voltage_value,"Percent": percent_value}

to insert a quote in a string you need to use the backslash as an escape character, so, we make the JSON string as follows:

String payload="{\"Voltage\":"+String(voltage)+ ",\"Percent\":"+String(percent)+"} ";

So now we have the Stringvariable “payload” that we have to send via PubSub.

There may be various ways to do that, I did it as follows:

payload.toCharArray(data, (payload.length() + 1));
client.publish("home/battery",data);

You could probably also use: client.publish("home/battery", payload.c_str());, but I didn’t*).
So, once in openHAB it is quite easy to process the the JSON, once the proper transformation Add-on is installed.

In the items file it then looks like this:

Number battery_garden "Battery Garden [%.1f V]"  (Back_Garden, batteries) {mqtt="<[mosquitto:home/battery:state:JSONPATH($.Voltage)]"}
Number battery_garden_pct "Battery Garden [%.0f %%]"  (Back_Garden, batteries) {mqtt="<[mosquitto:home/battery:state:JSONPATH($.Percent)]"}

And on screen like this:

OK, let’s try that with the reading results of a DHT11. Sure, there might be many reasons why you would want to send the humidity reading and temperature reasing as two different MQTT strings, but for arguments sake let’ s try it as a JSON.

We will first read the DHT11 sensor,then we will create a JSON that looks like {“Temperature”: 20.0, “Humidity”: 68}  with 20.0 and 68 of course just snapshot  examples. Subsequently we will create the MQTT message and display it in openHAB

float humid_coop = dht.readHumidity();
float temp_coop = dht.readTemperature();
String payload="{\"Humidity\":"+String(humid_coop)+ ",\"Temperature\":"+String(temp_coop)+"} ";
payload.toCharArray(data, (payload.length() + 1));
client.publish("home/coop", data);

and then in the itemsfile:

Number Humidity_Coop "Humidity Coop [%.0f %%]" (coop) {mqtt="<[mosquitto:home/coop:state:JSONPATH($.Humidity)]"}
and
Number Temperature_coop "Temperatuur [%.2f °C]" (coop) {mqtt="<[mosquitto:home/coop:state:JSONPATH($.Temperature)]"}

Let’s now have a look at sending more than just two data  values. Suppose you have an I/O chip (or more) that lets you read 12 channels at the same time, you could ofcourse make a JSON like this: {“channel1” : value1, “channel2″:value2,  ……..”channel12”: value12}, but that seems to send a lot of unnecessary data, so we will create the following JSON:

{"data":[value1,.............value12]}
We do that as follows

String payload="{\"data\":["+String(ana0)+","+String(ana1)+","+String(ana2)+","+String(ana3)+","+String(ana4)+","+String(ana5)+","+String(ana6)+","+String(ana7)+","+String(ana8)+","+String(ana9)+","+String(ana10)+","+String(ana11)+ "]}";
payload.toCharArray(data, (payload.length() + 1));
client.publish("home/json", data);

in the MQTT channel in the items file we will now use a slightly different JSON format. The data will now be read by index number like:

JSONPATH($.data[0])

the full itemsfile then will be

Number Moisture1 "Moisture 1 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[0])]"}
Number Moisture2 "Moisture 2 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[1])]"}
Number Moisture3 "Moisture 3 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[2])]"}
Number Moisture4 "Moisture 4 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[3])]"}
Number Moisture5 "Moisture 5 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[4])]"}
Number Moisture6 "Moisture 6 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[5])]"}
Number Moisture7 "Moisture 7 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[6])]"}
Number Moisture8 "Moisture 8 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[7])]"}
Number Moisture9 "Moisture 9 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[8])]"}
Number Moisture10 "Moisture 10 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[9])]"}
Number Moisture11 "Moisture 11 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[10])]"}
Number Moisture12 "Moisture 12 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[11])]"}

and look like:

There is nothing stopping you from including data from more than 1 sensor in a JSON and send that all in one MQTT message. This way you could for instance put all the sensor data from say one room, or the entire garden in one MQTT message and send it.
Beware though that the default packet size supported by the PubSub client is 128 bytes. You can increase this limit by editing the value of MQTT_MAX_PACKET_SIZE in PubSubClient.h.
___________________
*)There is a fork of Nick O’Leary’s PubSub library, by Imroy, that will happily send:
client.publish(topic, String (value));

Upload Data to Thingspeak through MQTT with an ESP8266

Sending  values to Thingspeak via the Thingspeak API is well known. There is another way as well: through MQTT. Thingspeak has recently (5 dec 2016) added a (one way) MQTT broker for this at mqtt.thingspeak.com:1883.

There are two topics one can use:
To upload more than 1 field in one session use:
channels/<channelID/publish/<channelAPI>

To upload an individual channel use:
channels/<channelID>/publish/fields/field1/<channelAPI> (just using field1 as example)

In the first case, the payload string is as follows:
field1=<value1>&field2=<value2>&status=MQTTPUBLISH

In the second case the payload string is just <value1>

In the program below I am using the PubSubClient from Knolleary. The “credentials.h” file is a file that defines my WiFi credentials, you can either create such a file yourself or just insert your wificredentials.

I am using an ESP8266 to make the connection but ofcourse it is also possible to use an Arduino with Ethernet connection when you make the proper changes  in this file in order to connect to Ethernet.

To avoid using again a DHT11 as an example, I show uploading variables by using micros() and a counter

#include "PubSubClient.h" //Knolleary
#include  <ESP8266WiFi.h> //ESP8266WiFi.h
#include   <credentials.h> //This is a personal file containing web credentials

const char* ssid = WAN_SSID;// this constant is defined in my credentials file
const char* password = WAN_PW;// ditto
//char* topic="channels/<channelID/publish/<channelAPI>
char* topic = "channels/123456/publish/T8I9IO457BAJE386"; 
char* server = "mqtt.thingspeak.com";

WiFiClient wifiClient;
PubSubClient client(server, 1883, wifiClient);

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
}

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

String clientName="ESP-Thingspeak";
  Serial.print("Connecting to ");
  Serial.print(server);
  Serial.print(" as ");
  Serial.println(clientName);
  
  if (client.connect((char*) clientName.c_str())) {
    Serial.println("Connected to MQTT broker");
    Serial.print("Topic is: ");
    Serial.println(topic);
    
    if (client.publish(topic, "hello from ESP8266")) {
      Serial.println("Publish ok");
    }
    else {
      Serial.println("Publish failed");
    }
  }
  else {
    Serial.println("MQTT connect failed");
    Serial.println("Will reset and try again...");
    abort();
  }
}

void loop() {
  static int counter = 0;
  String payload="field1=";
  payload+=micros();
  payload+="&field2=";
  payload+=counter;
  payload+="&status=MQTTPUBLISH";
  
  if (client.connected()){
    Serial.print("Sending payload: ");
    Serial.println(payload);
    
    if (client.publish(topic, (char*) payload.c_str())) {
      Serial.println("Publish ok");
    }
    else {
      Serial.println("Publish failed");
    }
  }
  ++counter;
  delay(20000);
}

The file is available for download here. Whether this is a better method than with the api remains to be seen.
Currently the connection time is limited because of the limited number of sockets on Thingspeak so it is ‘connect->upload->disconnect’. Thingspeak currently cannot be used as a ‘broker’. The traffic is one way only. If your client is already connected to an MQTT network on your own private or public broker, then this method cannot be used without ‘bridging’ the two ‘networks’

Adding an MCP23017 16 port IO expander to Arduino or Esp8266 or Attiny85 or……..


Update:
After I made this expander module, a ready made module
with this chip has become available. So I actually would advice anybody needing a 16 bit expander, to buy that one rather than build it. The module will cost you abt 1.50 euro, while the individual chip may set you back a euro or so.

I am not claiming that what I am describing here is earth shattering or trailblazing, because in fact it is very simple and no doubt has been done by many already. But sometimes what is simple for the one, is still a question mark for the other, so here is quick ‘how-to’ of adding 16 I/O ports to your microprocessor. This is especially handy when working with a chip like the ESP8266 that has only limited I/O
The MCP23017 is an I2C enabled 16 I/O port chip. That means that you only need 2 pins (yes with Vcc and ground it makes 4) to control the chip and the added advantage is that you can share I2C with various other devices as well.

The 16 I/O lines are divided into an 8 I/O PORT A and an 8 I/O PORT B. Both can be used as input as well as output. The chip also has 2 configurable interrupts (that I will not be using). The physical layout of the chip makes it quite easy to use it on a piece of strip board.

The circuit (at right) is rather simple. At a last moment I decided to leave out the pull up resistors so it would be more flexible to use together with other I/O devices. The 3 Address pins A0-A2 determine the I2C address that ranges from 0x20 (all pins on ground) to 0x27 (all pins on Vcc).
The chip  can take a Vcc from 2.7V to 5V and this is perfect for 3.3 Volt devices as  the modern arduino’s and the ESP8266 range of boards.

Using the chip in a program is fairly easy. There are good libraries available, but it might help if you know how to program the chip without a library.
In my case I have all  address lines tied to ground and therefore my I2C address is 0x20. Suppose I want to use all PORT A lines as outputs. I do that  as follows:

Wire.beginTransmission(0x20);
Wire.write(0x00); // IODIRA register
Wire.write(0x00); // set entire PORT A to output
Wire.endTransmission();

For PORT B that  is rather similar:

Wire.beginTransmission(0x20);
Wire.write(0x01); // IODIRB register
Wire.write(0x00); // set entire PORT B to output
Wire.endTransmission();

If we then want to send a specific value ‘X’ to that PORT A, we do that as follows

Wire.beginTransmission(0x20);
Wire.write(0x12); // address port A
Wire.write(X);  // value to send
Wire.endTransmission();

‘X’ ofcourse is a byte value that determines whether we set a specific port HIGH or LOW.
If for instance ‘X’is ‘0’ that means we write a LOW to all PORT A outputs. If it is 255 that means we write a HIGH to all PORT A outputs.
To determine what value to send, consider the 8 I/O lines of PORT A as a byte in which the individual bits determine HIGH or LOW.
So if we only want to make PORTA.0 HIGH and the rest LOW, we write a binary value of 0b00000001 =1 to the A register. If we want to make PORTA.0 and PORTA.2 HIGH and the rest LOW we write a binary value of 0b00000101 = 5.
For PORT B it is similar:

Wire.beginTransmission(0x20);
Wire.write(0x13); // address PORT B
Wire.write(X);  // value to send
Wire.endTransmission();

If we want to use PORT B (or PORT A for that matter) as input, we do that as follows:

Wire.beginTransmission(0x20);
Wire.write(0x13); // address PORT B
Wire.endTransmission();
Wire.requestFrom(0x20, 1); // request one byte of data
byte input=Wire.read(); // store incoming byte into "input"

The byte “input” will vary between 0 and 255, in which the individual bits determine the input on the corresponding IO line. So if ‘input’  reads ‘3’  which in binary is 0b00000011, that means that both IO line 0 and 1  were HIGH and the rest LOW

#include <Wire.h> // Wire.h
byte input=0;
void setup()
{
  Serial.begin(9600);
  Wire.begin(); // wake up I2C bus
  Wire.beginTransmission(0x20);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // set entire PORT A as output
  Wire.endTransmission();
}
 
void loop()
{
  // read the inputs of bank B
  Wire.beginTransmission(0x20);
  Wire.write(0x13);
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  input=Wire.read();
 
  // now send the input data to bank A
  Wire.beginTransmission(0x20);
  Wire.write(0x12); // address PORT A
  Wire.write(input);    // PORT A
  Wire.endTransmission();
  delay(100); // for debounce
}

That’s basically it if you want to do the adressing yourself. Using a library, such as the one from Adafruit, makes it much easier though as it has commands to write and read from individual IO lines. One of the example programs to read a single button, looks  for instance like this:

#include <Wire.h> // Wire.h
#include "Adafruit_MCP23017.h"

// Basic pin reading and pullup test for the MCP23017 I/O expander
// public domain!
// Connect pin #12 of the expander to Analog 5 (i2c clock)
// Connect pin #13 of the expander to Analog 4 (i2c data)
// Connect pins #15, 16 and 17 of the expander to ground (address selection)
// Connect pin #9 of the expander to 5V (power)
// Connect pin #10 of the expander to ground (common ground)
// Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low)
// Input #0 is on pin 21 so connect a button or switch from there to ground

Adafruit_MCP23017 mcp;

void setup() 
{
mcp.begin();      // use default address 0
mcp.pinMode(0, INPUT);
mcp.pullUp(0, HIGH);  // turn on a 100K pullup internally
pinMode(13, OUTPUT);  // use the p13 LED as debugging
}

void loop() {
// The LED will 'echo' the button
digitalWrite(13, mcp.digitalRead(0));
}

If you want to use more than one MCP23017 do that as follows:

#define addr1 0 //addr1 =A2 low , A1 low , A0 low =000
#define addr2 1 //addr 2 = A2 low , A1 low , A0 high =001 
setup(){
    mcp1.begin(addr1);
    mcp2.begin(addr2);
}

Mind you that “0” is in fact 0x20 and ‘1’ is in fact 0x21

If you are using the Adafruit library with the ESP8266, you will encounter a compilation error signaling it cannot find <avr/pgmspace.h>. The solution for this is easy:

Open the cpp file of the library.

replace

#include <avr/pgmspace.h>

with

#if (defined(__AVR__))
#include <avr/pgmspace.h>
#else
#include <pgmspace.h>
#endif