ESP8266 (Arduino) Wireless Temperature Sensor

I’ve finally got round to creating a new Arduino “sketch” for my ESP8266 Wireless Temperature Sensor.

The setup is slightly different to before, so here’s a quick breakdown:

  • I’m using a version of a nodemcu board for now. It just makes developing a bit easier as I can just plug it into my computer via usb, and not worry about serial converters.
  • I’m still using the DS1631 I2C temperature. There don’t seem to be many people using this, I’m liking it (it’s easy enough to setup, has good resolution, and has good accuracy compared to some others).
  • I’m using the DS1631 Arduino library available here: https://github.com/millerlp/DS1631
  • I’m using MQTT to send the temperature to my MQTT broker (on a Raspberry Pi).
  • I’m using the Pubsubclient Arduino library to setup MQTT on the board.
  • Once a minute, the system will read the temperature from the DS1631 and send it via MQTT to the Raspberry Pi.

Circuit

As I’m looking at adding more to this circuit later on, I currently don’t have a useful circuit diagram . I will put one up soon.

A few things to note:

  • During programming and testing, the board is powered via USB from the PC. As the nodemcu board has a built-in regulator, this just makes things a bit easier.
  • However, quiet a bit of heat is generated from the regulator, messing with the temperature sensing.
  • Therefore during “normal” operation, the board is powered from 3.3v supply (delivered by a switching regulator, a good distance from the board).
  • The circuit is currently VERY messy and needs improving before I create an kind of PCB.

You can see the nice and messy circuit below.

20160220_161446.jpg

Code

I’m currently coding this product using the Arduino IDE as I was starting to struggle with the ESP8266 SDK. Although I’m not a fan of the Arduino IDE, I have found it easier for coding, etc. so I’ll see how well it works.

The code can be found below, at the project home https://github.com/nerobot/Home-Automation

/*
  DS1631_MQTT_Temperature_Sensor_0.1
  20 Feb 16
  First full attempt at using the Arduino IDE to create a MQTT DS1631 Temperature Sensor.
*/

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <Wire.h>
#include <DS1631.h>

// Update these with values suitable for your network.
const char* ssid = "SSID";
const char* password = "SSID_PASS";
const char* mqtt_server = "MQTT_SERVER";
const char* mqtt_username = "MQTT_USERNAME";
const char* mqtt_password = "MQTT_PASSWORD";
const char* mqtt_topic = "/esp8266/mainRoom/temperature/1";
const char* esp8266_client = "ESP8266_MR_1";

// Temperature Sensor
DS1631 Temp1(0);

// Ticker / Timer
Ticker flipper;
int ticker_delay = 60;

// Wifi
WiFiClient espClient;
PubSubClient client(espClient);
char msg[50];

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  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());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {     Serial.print((char)payload[i]);   }   Serial.println(); } void reconnect() {   // Loop until we're reconnected   while (!client.connected()) {     Serial.print("Attempting MQTT connection...");     // Attempt to connect     if (client.connect(esp8266_client, mqtt_username, mqtt_password)) {       Serial.println(" MQTT connected");     } else {       Serial.print("failed, rc=");       Serial.print(client.state());       Serial.println(" try again in 5 seconds");       // Wait 5 seconds before retrying       delay(5000);     }   } } void getTemp(){   Serial.println("Getting Temperature.");   uint16_t temp = Temp1.readTempOneShotInt();   uint8_t Th = temp >> 8;
  uint8_t Tl = temp & 0xFF;

  if(Th>=0x80)        //if sign bit is set, then temp is negative
    Th = Th - 256;
  temp = (uint16_t)((Th << 8) + Tl);   temp >>= 4;
  float T_dec = temp * 0.0625;

  // Display T° on "Serial Monitor"
  Serial.print("Temperature : ");
  Serial.println(T_dec);

  // Sending the unconverted temperature via MQTT
  snprintf (msg, 75, "%d", temp);
  client.publish(mqtt_topic, msg);
}

void setup() {
  Serial.begin(115200);

  // Setting up wifi
  Serial.println("Setting up wifi.");
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  // Setting up timer
  Serial.println("Setting up timer.");
  flipper.attach(ticker_delay, getTemp);

  // Setting up DS1631
  Serial.println("Setting up DS1631.");
  Wire.begin(2, 14);
  int config = Temp1.readConfig();
  Serial.print("Config settings before: ");
  Serial.println(config, BIN);

  Temp1.writeConfig(13);
  config = Temp1.readConfig();
  Serial.print("Config settings after: ");
  Serial.println(config, BIN);
}

void loop() {

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

I’ve been able to compile and upload the above to my nodemcu board and by subscribing to the MQTT topic in node-red, I can see the temperature (it just needs multiplying by 0.0625 to give the actual temperature).

So so far, so good!

Update – 21 Feb 2016

Very quick update on this project.

I’ve now created a small “Config.h” file to contain all the wifi and MQTT config, password, and username details. This should help keep the main file a bit neater (and lessen the chance of me giving away too much information by mistake 😉 )

Github project updated appropriately.

Advertisements

LED Grow System – Lettuce Experiment Week 3

Tags

, ,

Hi All,

Just a quick update for anyone interested in the progress of my DIY LED growlight experiment.

The system has been unmodified since last week. Below is a photo of the lettuce experiment after 3 weeks.

wpid-dsc_0137.jpg

I’m still quite impressed with the progress of the lettuce growth. I’ve thinned out quite a few of the lettuce and had 2 salad which they made a nice addition to. Some of the lettuce are doing really well, but one side is definitely doing better than the other. I’m sure this is due to uneven light distribution, which I’ll try and sort out over the next week or two when I update the growbox system.

Also, I wonder if hey need feeding soon as there’s not that much compost in the container.

ESP8266 Arduino IDE – Wireless Temperature Sensor

Some of you may be aware that there’s been an interesting development lately that allows you to develop, compile, and upload software for the ESP boards using the Arduino IDE.

Although I’m no great fan of the Arduino IDE, I’ve had a play around with it, and it certainly has the potential to make development much easier!

The project is in the early stages, but if development continues, there’s potential for it to make development of the ESP boards much easier. Further details can be found here: https://github.com/esp8266/Arduino

As I’m starting to struggle with the ESP SDK (I’ve managed to get some things working, but I don’t have the time to research into it as much as I’d like), I decided to see if I could convert my current wireless temperature sensor into “Arduino” code. It took a bit of work, but the code below seems to work quite well using the exact same board.

The MQTT works well (though I’ve yet to try subscribing and I’ve read there are some issues with it), and the i2c communication seems to be working fine. The code is pretty rough at this point, but I’ll tidy it up later and develop it further into my own project.

#include 
#include 
#include 
#include 

void * __dso_handle;

const char* ssid = "SSID";
const char* password = "PASSWORD";

char* topic = "TOPIC";
char* server = "MQTT SERVER";

// PIN adresses are set to GND
#define DS1631_ADDR 0x90 >> 1

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

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

String macToStr(const uint8_t* mac)
{
  String result;
  for (int i = 0; i < 6; ++i) {
    result += String(mac[i], 16);
    if (i < 5)
      result += ':';
  }
  return result;
}



// SETUP
void setup() {

  Serial.begin(9600);


  Wire.pins(2, 0);

  Wire.begin();             // join I2C bus
  Wire.pins(2, 0);


  // Stop conversion to be able to modify "Access Config" Register
  Wire.beginTransmission(DS1631_ADDR);
  Wire.write((int)(0x22)); // Stop conversion
  Wire.endTransmission();

  // Read "Access Config" regsiter
  Wire.beginTransmission(DS1631_ADDR);
  Wire.write((int)(0xAC)); // @AC : Acces Config
  Wire.endTransmission();
  Wire.requestFrom(DS1631_ADDR, 1); //Reade 1 byte
  Wire.available();
  int AC = Wire.read(); // receive a byte

  Serial.print("Acces Config (Before): "); Serial.print(AC);  Serial.println("");

  // WRITE into "Access Config" Register
  Wire.beginTransmission(DS1631_ADDR);
  Wire.write(0xAC); // @AC : Acces Config
  Wire.write(0x0C); // Continuous conversion & 12 bits resolution
  Wire.endTransmission();

  // READ "Access Config" register
  Wire.beginTransmission(DS1631_ADDR);
  Wire.write((int)(0xAC)); // @AC : Acces Config
  Wire.endTransmission();
  Wire.requestFrom(DS1631_ADDR, 1);
  Wire.available();
  AC = Wire.read();

  Serial.print("Acces Config (AFTER): "); Serial.print(AC);  Serial.println("");

  // START conversion to get T°
  Wire.beginTransmission(DS1631_ADDR);
  Wire.write((int)(0x51)); // Start Conversion
  Wire.endTransmission();



  Serial.println();
  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());

  // Generate client name based on MAC address and last 8 bits of microsecond counter

  clientName += "esp8266-";
  uint8_t mac[6];
  WiFi.macAddress(mac);
  clientName += macToStr(mac);
  clientName += "-";
  clientName += String(micros() & 0xff, 16);

  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);


  }

  else {
    Serial.println("MQTT connect failed");
    Serial.println("Will reset and try again...");
    abort();
  }

  // Setup Serial connection
  Serial.begin(9600);
  Serial.println("");
  Serial.println("-----------------------------------");
  Serial.println("DS1631 test: Temp. sensor");
  Serial.println("-----------------------------------");
  Serial.println("");
}

int itoa(int value, char *sp, int radix)
{
  char tmp[16];// be careful with the length of the buffer
  char *tp = tmp;
  int i;
  unsigned v;

  int sign = (radix == 10 && value < 0);
  if (sign)
    v = -value;
  else
    v = (unsigned)value;

  while (v || tp == tmp)
  {
    i = v % radix;
    v /= radix; // v/=radix uses less CPU clocks than v=v/radix does
    if (i < 10)       *tp++ = i + '0';     else       *tp++ = i + 'a' - 10;   }   int len = tp - tmp;   if (sign)   {     *sp++ = '-';     len++;   }   while (tp > tmp)
    *sp++ = *--tp;

  return len;
}

// Main Loop
void loop() {

  //READ T°
  Wire.beginTransmission(DS1631_ADDR);
  Wire.write((int)(0xAA)); // @AA : Temperature
  Wire.endTransmission();
  Wire.requestFrom(DS1631_ADDR, 2); // READ 2 bytes
  Wire.available(); // 1st byte
  uint8_t Th = Wire.read(); // receive a byte
  Wire.available(); // 2nd byte
  uint8_t Tl = Wire.read(); // receive a byte


  // T° processing
  //if(Th>=0x80) //if sign bit is set, then temp is negative
  // Th = Th - 256;


  uint16_t temp = (uint16_t)((Th << 8) + Tl);   temp >>= 4;

  float T_dec = temp * 0.0625;

  // Display T° on "Serial Monitor"
  Serial.print("Temperature : ");
  Serial.print(T_dec);   Serial.print(" degC / ");
  Serial.print("Th register: "); Serial.print(Th);  Serial.print(" / ");
  Serial.print("Tl register: "); Serial.print(Tl);  Serial.println("");

  if (client.connected()) {
    Serial.print("Sending payload: ");
    Serial.println(Th);

    char buf[10];
    itoa(temp, buf, 10);

    if (client.publish(topic, buf)) {
      Serial.println("Publish ok");
    }
    else {
      Serial.println("Publish failed");
    }
  }
  else {
    if (client.connect((char*) clientName.c_str())) {
      Serial.println("Connected to MQTT broker");
      Serial.print("Topic is: ");
      Serial.println(topic);
      Serial.print("Sending payload: ");
      Serial.println(Th);

      char buf[10];
      itoa(temp, buf, 10);

      if (client.publish(topic, buf)) {
        Serial.println("Publish ok");
      }
      else {
        Serial.println("Publish failed");
      }

    }

    else {
      Serial.println("MQTT connect failed");
      Serial.println("Will reset and try again...");
      abort();
    }
  }

  // Wait 1s before restart
  delay(60000);
}

I’ve had the above working for a few hours now and so far it’s all working well.

I’ve also managed to change the rx and tx pins to outputs which I’ll be experimenting with more very soon.

LED grow light trial – week 2

Tags

, ,

It’s now the end of the second week in my LED growlight trial. I’ve tried a few different boxes and positions in the house, but not much has really changed in the design. I’ve had a few issues with the temperature getting too high (about 27c) when the box is covered to stop light leaking out, so I’m currently keeping it uncovered. I’m waiting for a heatsink to arrive and when it does I’ll install the leds on a piece of metal and hopefully the heatsink will help reduce the overall temperature.

Below is a photo taken a week after the last one.

image

As you can see they are coming along really well. They will need thinning out soon and probably feeding, but for now they seem quite happy.

I’ll keep uploading their progress every week and if the trial is a success I’ll do some more development on it.

LED grow-light trial

Tags

,

Something slightly different today.

Since I now live in a TINY flat with no garden, I’m unable to grow any veg outside (and there’s a really long waiting list for local allotments). So I’ve decided to start growing as much veg indoors as possible. However, being the way I am, I’m trying to put as much DIY engineering into it as possible 😀

Rather than just start by growing stuff on a windowsill – which I’ll be doing later on – I’ve decided to create a small LED system to test out growing stuff inside using LEDs.

Grow Lights

I decided on LEDs rather than other growlight systems simply because I can buy high power LEDs very cheap online, and because they allow me to work with low voltages, making things a lot safer (particularly for when the cat decides to jump up on worktops when we aren’t looking!). Also it allows me to incorporate it into my current HA system without having to worry about switching mains voltage (well for now at least).

My current system uses 12 3W LEDs in a 3×4 array as can be seen below.

DSC_000001 2

The LEDs cost about £4 for 10 and I bought 10 red and 10 blue. Initially, a ratio of 1:1 was used, meaning I have 6 blue LEDs and 6 red LEDs. This worked fine for a while, but I seemed to blow up 2 red LEDs, so I just replaced them with blue LEDs as they were closer to me at the time. So now there’s 4 red and 8 blue LEDs in a 3×4 array.

The boards either side of the LEDs are current controlling buck converter. The blue LEDs are placed into an array with 2 lots of 3 LEDs in series placed in parallel. Not too happy with this setup as I think this caused my red LEDs to blow (when once of the LED leads came loose, too much current went to the other LEDs causing one to blow!).

I’m going to replace that once I obtain a 19v laptop power supply and can have all the LEDs – of the same colour – being powered in series. But that’s for another post…

The buck converters are setup to limit the current at 600mA, instead of the 700mA stated by the seller to try and keep heat down for now. I’m obtaining a thick piece of aluminium which will be better at dissipating the heat, so once that arrives I’ll try and up the current and see if it can still dissipate the heat.

Setup

As this is an initial experiment and I’m trying to keep the costs down as much as possible, I’m trying to use as much from around the house as possible.

Below you can see the VERY basic setup that I have at the moment.

DSC_000001

As I said, it’s VERY basic!

I simply switch the lights on and off using the wall switch, but soon I’ll incorporate it into my HA system and control the lights via a wireless relay.

Openhab

I have however, created a simple Openhab page to allow me to easily control the growlights via my HA system. As can be seen below, I – will be able to – control when the growlights come on or off and then forget about it.

Screenshot_2015-03-27-11-07-15

However, you can see a temperature chart at the bottom. This was just a small test for me to see if my lettuce would be getting too hot under the lights. For this I just used the wireless temperature sensor that I had in my bedroom and placed it in the growbox. As can be seen, the temperature goes to about 25C when the lights are on and drops to about 20 when the lights are off. For me this seems fine – please let me know if you think these values are too high.

1 week progress

I’ve had the system up and running for about a week now. I’m growing a packet of mixed lettuce as a “cut and come again” method.

DSC_000001 3 DSC_000001 1

Above you can see the lettuce progress after 1 week. They have started to grow their first true leaves and they aren’t that “leggy” yet. At this stage on a windowsill, I would expected them to be more leggy than this. The seedlings under the blue LEDs seem much happier than those under the red LEDs. I’ll see if that continues.

So far I’m quite happy with the setup and I’ll keep you updated on the progress of the growbox and the lettuce.

HA: Python VS Node-Red?

So I’ve been playing more with node-red and seeing how is compares to Python when being used for my HA system.

As I mentioned before, I’ve started to get frustrated with writing rules in Openhab, so was looking at using Openhab as the front-end and using something like Python as the decision making back end. I initially played with node-red but could really get it to work because I could only get it to work on the current message and couldn’t do something things like compare the current temperature to the variable desired temperature.

However, after doing a bit more searching, it turns out that it’s easy enough to store global variables! So by storing the different temperatures as global variables, it became trivial to compare them.

Using this I was able to switch the “boiler” on and off with great ease.

So I’m going to play around with node-red a bit more, but so far it seems to be a bit easier than the Python code (which started to get messy very quickly).

Openhab, Python, and MQTT

Lately I’ve started to get annoyed with Openhab’s rules and the way it deals with items and numbers, such as having to do things like the following, just to convert the temperature from the ESP board.


var newTemp1 = LivingRoomTemp0.state as DecimalType
postUpdate(LivingRoomTemp1, (LivingRoomTemp0.state as DecimalType) * 0.0625)

Therefore I’ve been looking at different options. For now I’m going to continue to use Openhab as the gui for my home automation system (as I’ve yet to find something that’s easier to use that still has similar interface), but I’m looking at different backends.

I’ve looked at node-red but couldn’t really figure out how to do quite simple things like compare if the current temperature is higher than my set temperature, so that’s out of the question for now.

I also looked at node.js, but not really in the mood to learn a whole new language!

So I looked at Python. I’ve done a bit of python in the past, and looking at other examples, it seemed like it might be a good way to go.

There’s also a really good Python library for MQTT called paho, which seems quite easy to use for what I’m wanting to do right now.

So here’s my current setup that I’m experimenting with:

  • Send all data from the ESP boards via MQTT (no change there)
  • The ESP temperature values are received via Python (not Openhab!) and converted to their correct value by * 0.0625
  • This new value is then sent via MQTT, which is picked up by Openhab

So far this seems to work much better!

I’ve also created a simple thermostat test where I’ve created a simple button which represents the boiler and have set the desired temperature in Openhab. This desired temperature is sent to Python via mqtt which then calculates if the boiler needs to be switched on or off. The value for the boiler (“ON” or “OFF”) is then sent out via mqtt.

The above seems to be working well, so I’m going to experiment more with this setup and then at it to my github project folder.

Wireless Thermometer Update

Tags

, , , ,

Just a quick update on the progress of the wireless temperature sensor using the DS1631, ESP8266 board, and Openhab.

Hardware

Firstly, I’ve updated the circuit diagram because there were a few obvious mistakes. The updated circuit diagram can be seen below (and in the github project folder).Circuit diagram 0.2

It’s a bit messy, but I hope to clean it up soon.

In order to do some better testing, I’ve created a simple PCB that is small and doesn’t require breadboards to be placed throughout the house. Since I wanted them quick (i.e. I didn’t want to wait over a month for boards to be manufactured in China…), and I don’t have any PCB fab facilities, I used this guy to mill 2 single sided PCB for me. Unfortunately, I designed the PCB with holes that are just a bit to small. As a result, I can’t get my reset button in, but I was able to force the rest of the components through the holes (just). The board layout is shown below.

PCB design 0.2

The two red lines are actually small wires as I couldn’t find a way to design the whole board with just tracks on the bottom (remembering that the PCB was being milled, so I couldn’t make the tracks and gaps too small). In all I was quite happy with the board and it appears to be working well. REMEMBER: If you’re going to use the board layout, make the holes bigger!

Soon I hope to make a double sided PCB with silkscreen, etc. but for now this works well.

Software

There’s not much change to the ESP code. I’ve added a small conditional statement that makes sure the device doesn’t send any numbers if the temperature is over 100C because I was having issues with high temperatures being sent out when the board first switches on (I think this is due to initialising the DS1631 board on boot up).

In order to test the DS1631 boards I’ve made (one on PCB and the other on breadboard) I decided to physically put the side by side and see how close – or otherwise – the temperatures were. Below is the temperature chart over a period of 4 hours.

Temperature variations

As you can see, the two are very similar with a max difference of about 0.4C, which I can cope with easily! Interestingly, the green line is the PCB board and appears to be more responsive to changes in temperature over the red line which was on the breadboard. That might change once the PCB is placed inside some kind of box and mount it on the wall.

Both the Openhab config files and the ESP code have been updated onto the Github project folder.

Coming up

I’m in the process of designing a small double sided PCB for the ESP temperature sensor that will be very small. I will also put the current temperature sensors in different rooms in my house.

I’m also looking at ways to actually turn the heater on and off. I initially thought that my current thermostat was RF controlled, but after taking the front off, it’s clear that it simply has a relay that opens and closes a 240v circuit which I presume goes directly to the boiler.

Therefore I’m going to have to break into the circuit and insert my own relay.

Wireless DS1631 Temperature Monitor

In the previous post I used the LM75 temperature sensing IC, but I wasn’t happy with the resolution or accuracy of the device (+- 2C). Therefore I started searching for alternative ICs and came across the TMP112. However, that was FAR TOO SMALL and I couldn’t even solder it onto a breakout board and couldn’t find a breakout board small enough to solder it on to. I then found the DS1631 chip, which is a uSOP package which I have no issue soldering on to breakout boards.

The DS1631 also works off I2C, but has an accuracy of about 0.5C and a resolution of 0.0625C which is much better than the LM75. It cost about £3.50 so it’s not too expensive either.

I’m still using Openhab and the ESP8266 wifi board, but the code is slightly different for each, though I’ll explain the differences later.

Hardware

The circuit for the board is very similar to the previous blog, but I’ve now created a small EagleCAD circuit diagram to make things a bit easier to follow (and potentially create boards from).

Below if the circuit diagram for the boards. Hopefully I’ve not make some silly mistake this time, but please let me know if I have! I’ve left out the USB-serial board, but it should be easy enough to connect RX to TX and TX to RX between the ESP board and the serial board.

DS1613 ESP8266 Circuit Diagram

DS1613 ESP8266 Circuit Diagram

I’ve yet to create a PCB or proto-board of the circuit, so at the moment the circuit is on a breadboard. I hope to create a simple proto-board of the circuit soon.

Software

At the moment I simply have one board in my living room, but I hope to have one in each room so I can – hopefully – control the temperature in each room. The software should be easy enough to adjust for multiple sensors and I hope to do that soon.

I’ve created a github project where all the code and circuit diagrams can be found here. I intend to add thermostat control to the project soon, hence the name of the github project.

ESP code

Again, the code for the ESP board is pretty similar to the previous entry. However, because I’m using the DS1631 IC rather than the LM75 IC, there’s a few small changes to the blink_cb function (I really need to change the name of that function as I just stole it from the blink example and forgot to change it’s name!) as shown below.


LOCAL void ICACHE_FLASH_ATTR blink_cb(uint32_t *args)
{
	MQTT_Client* client = (MQTT_Client*)args;
	INFO("Publishing\r\n");


	uint8_t ack = 0;

	i2c_start();
	i2c_writeByte(ADDRESS_W); //write address 0x40
	ack = i2c_check_ack();
	if (!ack){
		INFO("\r\nNot acknowledging 3\r\n");
		return;
	}
	i2c_writeByte(0xAA);
	ack = i2c_check_ack();
	if (!ack){
		INFO("\r\nSecond Ack failed\r\n");
		return;
	}

	i2c_start();
	i2c_writeByte(ADDRESS);
	ack = i2c_check_ack();
	if (!ack){
		INFO("Didn't get temp\r\n");
		return;
	}
	uint8_t T = i2c_readByte();
	i2c_send_ack(1);
	uint8_t T2 = i2c_readByte();
	i2c_stop();

	char buf[10];
	uint16_t temp = (uint16_t)((T << 8) + T2); 	temp >>= 4;
	uint8_t size = itoa(temp, buf, 10);

	if (temp < 1600)
		MQTT_Publish(client, "/LivingRoom/Temp/1", buf, size, 0, 1);
	INFO("%d %d\r\n", T, T2);
}

Also, because the DS1631 needs to have temperature sensing initiated I’ve added a small function called initI2C which is called at the start of the program.


void initI2C(){
	i2c_init();
	INFO("\r\nStarting I2C\r\n");
	i2c_start();
	i2c_writeByte(ADDRESS_W);
	uint8_t ack = 0;
	ack = i2c_check_ack();
	if (!ack){
		INFO("\r\nNot acknowledging 1\r\n");
		return;
	}
	i2c_writeByte(0x51);
	if (!ack){
		INFO("\r\nNot acknowledging 2\r\n");
		return;
	}
	i2c_stop();
}

The full code can be found at the above mentioned github project page under the folder ESP-TemperatureSensor. Although I’ve not done any extensive testing, the code does seem to work well and I’ve yet to have any stability issues. However, I will try and do more testing soon.

OpenHab

The Openhab code is very similar to the previous one, with two major exceptions:

  • I’m using rrd4j persistence instead of sql
  • I have to do a small calculation when the temperature changes, because the temperature the ESP board sends over isn’t actually correct

I’m using rrd4j rather than sql to try and keep the overheads on the Raspbery Pi to a minimum. I might change over to mysql in the near future, but for now the rrd4j seems to be fine for what I need.

I have to do the calculation in Openhab because number sent over by the ESP board hasn’t been divided by 0.0625 because I’ve yet to find a suitable function to convert a float to a string that works on the ESP board. But this is a simple enough route, so I’m not too bothered by it.

All the Openhab files can be found in the github project folder Openhab.

Temperature Chart

As everyone likes graphs and charts, here a screenshot showing the temperature of my living room since it booted up (which was less than 24 hours, but it gives you an idea). As you can see, my house doesn’t really get that cold at night despite it being bloody freezing outside 😀

Openhab temperature graph

Openhab temperature graph

Coming Up

For my next update, I hope to have a wireless temperature sensing board in each room of my house to see how the temperature varies in each.

ESP8266 Thermometer

In my last entry, I showed how to use OpenHab to control a LED connected to an ESP8266 board. From my limited testing, that seemed to go well, but of course is of limited use by itself.

Now I’m working on using the ESP board as a thermometer demo with the following features:

  • Connect the ESP board to a LM75 temperature sensor IC via i2c
  • Once a minute, measure the temperature and send the value via MQTT
  • Using OpenHab, show and plot the temperature over time

Temperature Sensor

For this project I’m currently using the LM75 ic simply because I had one around the house. However, the accuracy isn’t that great at 2C, so I’ve ordered some TMP112 temperature sensing ICs as they have an accuracy of about 0.3C, which will be much better. But for now the LM75 will do for prototyping.

Of course you could use any i2c chip, or in fact any temperature sensing ic, as long as you are willing to change the code enough.

As mentioned above, the ic has an accuracy of 2C and a resolution of 0.5C. Although the accuracy isn’t great, the resolution is fine as you’re not really going to be controlling the temperature of your house by 0.1C!

I’ve left the settings to default. The ic sends the temperature via two bytes. The first byte contains the non-decimal place number with the MSB containing the sign and the second byte contains the decimal place, with the MSB being 1 for 0.5 and 0 for 0.0. Simple!

MQTT

For MQTT, I’m using the esp_mqtt software available at https://github.com/tuanpmt/esp_mqtt. Make sure you obtain the latest version (newer than 02/02/2015) as the older versions had problems with queues which seems to be fixed now.

Eclipse IDE

For development of the ESP code, I use the Windows Eclipse IDE. Details of installation can be found here http://www.esp8266.com/viewtopic.php?f=9&t=820

Once you have the IDE installed, follow the instructions on how to create new projects and install the extra files required for the MQTT example.

Hardware

As I’m using the ESP-01 module, I only have 2 GPIO pins available: GPIO-0 and GPIO-2. Below is a circuit diagram that I’m currently using. As you can see, it’s all just on breadboard for now, and there’s a switch to choose whether GPIO-0 (not the diagram below shows GPIO-2 instead, which was a mistake) is connected to ground of to SCL (which is used to put the ESP into either programming or functional mode), and a small button used for resetting the module.

I’ve left out most of the pins for the ESP board, but the pin diagram can be easily found elsewhere.

Esp_lm75 circuit_0

ESP Code

Below is the code in my user_main.c file.

#include "ets_sys.h"
#include "driver/uart.h"
#include "driver/i2c.h"
#include "osapi.h"
#include "mqtt.h"
#include "wifi.h"
#include "config.h"
#include "debug.h"
#include "gpio.h"
#include "user_interface.h"
#include "mem.h"

MQTT_Client mqttClient;

LOCAL os_timer_t blink_timer;
#define DELAY 60000
volatile uint8_t temp = 0;
// see eagle_soc.h for these definitions
#define LED_GPIO 2
#define LED_GPIO_MUX PERIPHS_IO_MUX_GPIO2_U
#define LED_GPIO_FUNC FUNC_GPIO2

void initLM75(){
	i2c_init();
}

char* itoa(int value, char* result, int base) {
		// check that the base if valid
		if (base < 2 || base > 36) { *result = ''; return result; }

		char* ptr = result, *ptr1 = result, tmp_char;
		int tmp_value;

		do {
			tmp_value = value;
			value /= base;
			*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
		} while ( value );

		// Apply negative sign
		if (tmp_value < 0) *ptr++ = '-';
		*ptr-- = '';
		while(ptr1 < ptr) {
			tmp_char = *ptr;
			*ptr--= *ptr1;
			*ptr1++ = tmp_char;
		}
		return result;
	}

#define ADDRESS 0b10010001
#define ADDRESS_W 0b10010000
LOCAL void ICACHE_FLASH_ATTR blink_cb(uint32_t *arg)
{
	if (1){
		// Getting temperature
		INFO("\r\nStarting I2C\r\n");
		i2c_start();
		i2c_writeByte(ADDRESS_W); //write address 0x40
		uint8_t ack = 0;
		ack = i2c_check_ack();
		if (!ack){
			INFO("\r\nNot acknowledging\r\n");
			return;
		}
		i2c_writeByte(0x00);
		ack = i2c_check_ack();
		if (!ack){
			INFO("\r\nSecond Ack failed\r\n");
			return;
		}

		i2c_start();
		i2c_writeByte(ADDRESS);
		ack = i2c_check_ack();
		if (!ack){
			INFO("Didn't get temp\r\n");
			return;
		}
		uint8_t T = i2c_readByte();
		i2c_send_ack(1);
		uint8_t T2 = i2c_readByte() & 0bx10000000;
		i2c_stop();

		if (T == 0)
			return;


		char *tempStr = "123.0";
		temp = T;
		itoa(temp, tempStr, 10);
		MQTT_Client* client = (MQTT_Client*)arg;
		if (temp < 10){
			tempStr[1] = '.';
			if (T2)
				tempStr[2] = '5';
			else
				tempStr[2] = '0';
			MQTT_Publish(client, "/LivingRoom/Temp/1", tempStr, 3, 0, 1);
		}
		else if (temp < 100){
			tempStr[2] = '.';
			if (T2)
				tempStr[3] = '5';
			else
				tempStr[3] = '0';
			MQTT_Publish(client, "/LivingRoom/Temp/1", tempStr, 4, 0, 1);
		}
		else{
			tempStr[3] = '.';
			if (T2)
				tempStr[4] = '5';
			else
				tempStr[4] = '0';
			MQTT_Publish(client, "/LivingRoom/Temp/1", tempStr, 5, 0, 1);
		}
		temp++;
		INFO("Temp: %s\r\n", tempStr);
	}
}

void wifiConnectCb(uint8_t status)
{
	if(status == STATION_GOT_IP){
		MQTT_Connect(&mqttClient);
	} else {
		MQTT_Disconnect(&mqttClient);
	}
}
void mqttConnectedCb(uint32_t *args)
{
	MQTT_Client* client = (MQTT_Client*)args;
	INFO("MQTT: Connected\r\n");
}

void mqttDisconnectedCb(uint32_t *args)
{
	MQTT_Client* client = (MQTT_Client*)args;
	INFO("MQTT: Disconnected\r\n");
}

void mqttPublishedCb(uint32_t *args)
{
	MQTT_Client* client = (MQTT_Client*)args;
	INFO("MQTT: Published\r\n");
}

void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
{
	char *topicBuf = (char*)os_zalloc(topic_len+1),
			*dataBuf = (char*)os_zalloc(data_len+1);

	MQTT_Client* client = (MQTT_Client*)args;

	os_memcpy(topicBuf, topic, topic_len);
	topicBuf[topic_len] = 0;

	os_memcpy(dataBuf, data, data_len);
	dataBuf[data_len] = 0;

	INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf);

	/*if (!strcoll(topicBuf, "/LivingRoom/LED/1")){
		if (!strcoll(dataBuf, "1")){
			INFO("LED Switching On\r\n");
			GPIO_OUTPUT_SET(LED_GPIO, 1);
		}
		else{
			INFO("LED Switching Off\r\n");
			GPIO_OUTPUT_SET(LED_GPIO, 0);
		}
	}*/
	os_free(topicBuf);
	os_free(dataBuf);
}


void user_init(void)
{
	uart_init(BIT_RATE_115200, BIT_RATE_115200);
	os_delay_us(1000000);

	CFG_Load();
	//PIN_FUNC_SELECT(LED_GPIO_MUX, LED_GPIO_FUNC);

	MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security);
	//MQTT_InitConnection(&mqttClient, "192.168.11.122", 1880, 0);

	MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);
	//MQTT_InitClient(&mqttClient, "client_id", "user", "pass", 120, 1);

	MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
	MQTT_OnConnected(&mqttClient, mqttConnectedCb);
	MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
	MQTT_OnPublished(&mqttClient, mqttPublishedCb);
	MQTT_OnData(&mqttClient, mqttDataCb);

	WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb);

	INFO("\r\nSystem started ...\r\n");

	// Setting up the timer
	os_timer_disarm(&blink_timer);
	//// os_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *parg)
	os_timer_setfn(&blink_timer, (os_timer_func_t *)blink_cb, &mqttClient);
	//// void os_timer_arm(ETSTimer *ptimer,uint32_t milliseconds, bool repeat_flag)
	os_timer_arm(&blink_timer, DELAY, 1);

	initLM75();
}

The code is very similar to the example MQTT program, with a few additions:

  • A 1 minute interrupt timer is setup;
  • During the timer interrupt, the temperature is obtained from the LM75 and sent via MQTT to the broker;
  • I’ve added a simple ITOA function call that I found somewhere online (sorry forgot where), as I couldn’t send a number otherwise.

I had some issues sending numbers between MQTT and OpenHab. For OpenHab, I seemed to need to send the number as a string, hence the ITOA function. However, the MQTT publish function needs to know the length of the string it’s sending. Now it would have been easy to simply create the biggest char array, fill it with characters via ITOA, and send the whole thing, with blank characters at the end. However, this caused too many problems with OpenHab not recognising it as a number (despite the fact that other MQTT subscribers could see the number fine!).

So I have to make sure I was sending the right number of characters for the size of the number – including the decimal place – which is why I’ve got the following section in the timer interrupt (which looks very ugly!)

		if (temp < 10){
			tempStr[1] = '.';
			if (T2)
				tempStr[2] = '5';
			else
				tempStr[2] = '0';
			MQTT_Publish(client, "/LivingRoom/Temp/1", tempStr, 3, 0, 1);
		}
		else if (temp < 100){
			tempStr[2] = '.';
			if (T2)
				tempStr[3] = '5';
			else
				tempStr[3] = '0';
			MQTT_Publish(client, "/LivingRoom/Temp/1", tempStr, 4, 0, 1);
		}
		else{
			tempStr[3] = '.';
			if (T2)
				tempStr[4] = '5';
			else
				tempStr[4] = '0';
			MQTT_Publish(client, "/LivingRoom/Temp/1", tempStr, 5, 0, 1);
		}

I’m sure there’s a better way to do this, but it works for now.

OpenHab Code

It has taken me a VERY long time to figure out how to use OpenHab so even the most basic things. There really needs to be a good tutorial online on how to do basic stuff. Most of the tutorials I found went too deep too quick!

Since I want OpenHab to get the temperature via MQTT, and display the temperature along with a graph of the temperature, I need the following files (in the configurations folder): items/temp.itemspersistance/mysql.persit, and sitemaps/default.sitemap

You can name the files whatever you want as long as they are in the correct folders and have the correct suffix.

Below are the contents of the files.

test.items:

Number LivingRoomTemp <temperature> {mqtt="<[localbroker:/LivingRoom/Temp/1:state:default"}
Number TempChartPeriod
mysql.persist:
Strategies {  
	everyMinute: "0 * * * * ?"
    default = everyChange  
}  
  
Items {  
	LivingRoomTemp : strategy = everyMinute
}
default.sitemap:
sitemap TestSiteMap label="Temperature Test"
{
	Frame label="Temperatures"{
		Text item=LivingRoomTemp label="Living Room Temperature: [%.1f]"
		Switch item=TempChartPeriod label="Period" mappings=[0=Hour, 1=Day, 2=Week]
		Chart item=LivingRoomTemp period=h refresh=1000 service="mysql" visibility=[TempChartPeriod==0]
		Chart item=LivingRoomTemp period=d refresh=1000 service="mysql" visibility=[TempChartPeriod==1, TempChartPeriod=="Uninitialized"]
		Chart item=LivingRoomTemp period=W refresh=1000 service="mysql" visibility=[TempChartPeriod==2]
	}
}

This presumes that you have mysql setup as a database for OpenHab. There’s a very good tutorial here on how to setup mysql for OpenHab.

The above should be enough get temperature via MQTT and display is using OpenHab. I did add a little bit extra which allows me to choose the time period that’s being displayed on the chart.

Working

I’ve been running the setup now for about 3 days and I’ve not had any noticeable bugs or problems so far.

The screenshot below shows the OpenHab interface on my phone. As you can see, the temperature is showing well, and the graph shows about 3 days worth of data.

Screenshot_2015-02-05-16-20-18

So far I’m pretty happy with the setup and I’m going to look at making a few PCBs so I can put a few of these around the flat and monitor – and later control – the temperature in every room.