Room temperature control system – P(ID) and PWM

Now autumn is setting in, I’ve started doing some work on my control algorithms for my home temperature control system.

I had been using a simple On-Off (“bang-bang”) control system, but as expected, I was getting quite large temperature overshoots above the desired temperatures. In some cases, I was getting an overshoot of about 2C, which at times made things quite uncomfortable.

Since I had already done quite a bit of work on temperature control in other systems, I decided to improve on the system using a control methodology that has worked well for me in the past: PID control.

PID controller

For those that don’t know what PIC control is, there’s plenty of tutorials and examples on the internet, but a simple explanation is that is uses Proportional, Integral, Derivative errors between the desired state (temperature) and the actual state (temperature) to decide the input of the system. For my controller, the input is the amount of time the boiler is on for (I’m using PWM and will explain that more later), so the higher the number (the greater the errors), the greater the time the boiler is one for.

  • Proportional – the output is proportional to the error. For this controller, if the temperature error is higher, the boiler is switched on for longer.
  • Integral –  the output is proportional to the integral of the error. If the temperature stays too low for a long period, the integral of the error will go up, so the boiler will start to stay on for longer. This helps get rid of steady state errors.
  • Derivative – the output is proportional to the slope of the error. So if the error is getting small too fast (i.e. the temperature is rising too quickly) the boiler will switch on less. This will help reduce overshoot and to compensate for the time-delay, which can cause big issues in temperature control systems (when rooms can still get hot after the temperature source has been switched off).

For now, I’m only using P, effectively keeping D and I at zero (though in practice, I’m simply not calculating them to make life easy in the short term while I play with the system).

So, for my system, the output of the controller is simply

output = (desired temperature – actual temperature) * P

For now, I’ve got P = 100, D = 0, I = 0

PWM controller

However, my boiler doesn’t understand any of the numbers given by the PID controller above, instead only understanding ON or OFF. The control to the boiler simply consists of a esp8266 board controlling a mechanical relay, which then replaces the thermostat controller on the combi-boiler. In other words, I can only switch my heater on or off.

Therefore I’m using PWM (pulse width modulation) to convert the PID’s output into the on-off control that can be understood by the heater.

Again, I won’t go into too much detail into PWM controllers as there are better tutorials out there than I could write. When my PID controller gives out 100, the PWM system will have the heater on at 100% and when it’s at 0, the heater will be at 0. Anything else is simply a percentage between 0% and 100%.

For those interested, I chose a PRF (pulse repetition frequency) of 10 minutes and a period of 1 minute. Therefore, a PID out of 13% and 18% would have the heater stay on for 2 minutes, while a PID output of 2% would have the heater on for 1 minute. I’m sure I’ve done something wrong here and 13% should keep the boiler on for 1 minute (not 2 minutes), but it’s okay for now.

Results

I’ve only had the new system up and running for about a week, but so far it seems to work well. I now only have an overshoot of about 0.2C compared to about 2C. The system seems quick enough and I’ve yet to notice any major problems with it.

Below you can see an example screen shot of the last 24 hours showing the desired temperature along with the actual temperature. This is only the temperature in my living room, which is currently the only room to contain a temperature sensor (though that will change soon enough). The bottom graph shows when the boiler is on or off (1 being on, 0 being off).

wp-1476883910397.png

All the controlling is done through node-red and the user-interface is done via node-red-dashboard. If anyone would like more details on the node-red flows, feel free to ask.

Where next?

One thing I want to play with next is figuring out the best PRF value. I would like something smaller than 10 minutes, but I’m not sure how well the heater would cope with constantly being switched on and off. If anyone has any ideas or thoughts, I’d be happy to hear them.

I’m also going to look at introducing the D part of the PID controller to try and control any potential overshoots caused by big temperature changes.

 

Updated OLED Code

Tags

,

I’ve been trying to improve the look of the display, but I seem to be coming up to number of issues with the ESP_SSD1306.h library, mainly:

  • There’s no easy way to center or change the left / right justification of the text.
  • I can’t seem to get the width of a string.
  • It seems quite slow (though this could just be the way I’m using it…).

Therefore I decided to have another look at the esp8266-oled-ssd1306.h library which I did look at a while ago, but I found the example quite long and difficult to follow.

Well it turns out that the library itself is actually quite easy to use. I’m not sure why they have only make 1 very large example that makes it look much more difficult than it needs to be. I have no need of frames, transitions, etc. However, after playing around with it, I seem to have been able to overcome the issues I was having with the ESP_SSD1306.h library:

  • I can center text with ease. I can also change the left / right justification of text with a single line of text.
  • Getting the width of a string is really easy (only take 1 function to get the width and height of a given string).
  • It does seem quicker than what I was using before (but again, this could be a trick as I’ve not tried to actually measure anything).

I’ve not updated my code to use this other library and everything seems to be going well. I think I’ll keep using it in the future for this project.

You can see the updated display below.

img_20160401_164304.jpg

Image of latest display design

ESP8266 Thermostat -First ESP-12E Circuit

Since I’ve now got the back-none of the software created, I’m now in the process of designing and building the circuit that will be used in the final system.

Things are still currently on breadboard, but surprisingly the circuit seems to be working well!

The circuit comes from Kolban’s Book on the ESP8266 and ESP32 which gives a good circuit for programming the ESP-12E board (and ESP-1). I’m using the Arduino IDE to build and flash the “sketch” and so far it seems to be working well. The book is certainly worth a read and it has made me want to start programming using the Eclipse SDK, but maybe another day.

I’ve had to adapt the circuit for the I2C chips and the rotary encoder. The circuit diagram can be seen below, but I’ve also uploaded the EagleCAD schematic to my Github project page if anyone want to use it. There’s no PCB layout at the moment as I’m still working on improving the circuit on the breadboard.

Full Circuit Diagram

Circuit diagram for wireless temperature sensor

This all appears to be working on my breadboard, but I wish the ESP-12E was much more breadboard friendly than it is! Given all the messy wires from the board, I’m amazed that I actually managed to get it working for about a week without any issues…

img_20160401_151140.jpg

Breadboard circuit.

Anyway, above you can see my messy breadboard circuit. As you can see the ESP-12E really isn’t breadboard friendly…

I was tempted to go veroboard next, but I think I’ll go straight to making a single sided, milled PCB. So need to get started on creating a few more Eagle library components as I still can’t find one for the OLED module!

Wemos D1 Mini Boiler Switch

As well as recording the current temperature, one of the more important abilities of any thermostat system is the ability to turn the turn the boiler on and off as required.

Now I’ve played with a few “off the shelf” thermostats and really didn’t like any of them!

Therefore the obvious thing to do is create my own 🙂

I tried a few times to get my current SSR to turn my boiler on / off, but I wasn’t getting anywhere with it. It turns out that’s because I was using a zero-cross sensing SSR, which just wouldn’t work.

Therefore I looked into buying another SSR to test on my system.

Wemos D1 Mini

And then I came across the Wemos D1 Mini. This is a nice little ESP-8266EX unit, built into a stackable system. It’s much smaller than the NodeMCU boards, but still contains everything to program the board via microUSB (so no serial adapters, etc.)

miniYou can see the board above, and more details can be found here: http://www.wemos.cc/Products/d1_mini.html The board is available for just under £3, which is nice and cheap for me.

Wemos D1 Mini Relay Shield

However, what I liked about this board, was that I could buy a Relay Shield to sit on top of the ESP board.

relay

You can see the board above, and more details can be found here: http://www.wemos.cc/Products/relay_shield.html

Combined together, you have a MQTT based 240v relay switch for £4.18

There might be cheaper options out there, but I do like the the look of this one. It’s easy to build, cheap enough, and stackable (which I can’t see me needing any more than the relay switch at the moment).

Boiler Switch Circuit

The circuit for this is simple enough. Just plug in a microUSB to power the board and connect the relay pins to the required pins / cables on your boiler. This will of course be different for different boilers.

BE VERY CAREFUL AROUND 240 / 120V LIVE WIRES. I’M NOT RESPONSIBLE IF YOU’RE STUPID ENOUGH TO KILL YOURSELF BY NOT KNOWING WHAT YOUR DOING!!!

Without that out of the way, the code is simple enough and is available in my Github project folder, under “Boiler Switch”. This can be found here: https://github.com/nerobot/Home-Automation/tree/master/ESP8266%20boiler%20switch

ESP Temperature Sensor – “Sleeping”

I’m getting closer to creating – what is to me – a useful wall-mounted wireless temperature sensor using the ESP8266 module.

However, one thing that I didn’t want for this system is the display to be on all the time. The blue light from the OLED isn’t that nice and I don’t really need to know the temperature at every moment.

Instead, it would be good if the display only came on when someone is trying to change the display. More specifically, it would be good if the display only came on when the rotary encoder was being used and for about 60 seconds after the last turn.

So that’s what I’ve done!

FSM

I’ve updated the VERY simple FSM to include two more states and quite a few more transitions. Below is a messy diagram showing the state, the triggers, and the transitions for the new FSM. The letters in boxes correspond to the square brackets as explained in the transitions below.

FSM_26Mar16.jpg

Diagram of FSM

States

I now have two states in this FSM: waiting & sleeping

  • waiting
    • This is when the display is on.
    • The display should stay on for 60 seconds after the last change in the rotary encoder.
    • The display will show the latest temperature and the latest desired temperature. If either of these change in this state, the screen is updated.
  • sleeping
    • This is when the display is off.
    • This state will happen 60 seconds after the last change in the rotary encoder.
    • If the encoder is changed during this state, the FSM moves to waiting.
    • If the temperature or MQTT desired temperature are updated in this state, the new values are stored, but nothing is shown on the screen. The screen will remain blank.

Triggers

The triggers for the new FSM are explained below.

  • TRIGGER_TEMPERATURE_WAIT
    • Happens every 60 seconds.
    • Causes the system to get the current temperature.
  • TRIGGER_60_SECONDS
    • Happens every 60 seconds when in the waiting state.
    • Causes the device to go from waiting to sleeping.
  • TRIGGER_ENCODER_CHANGE
    • Happens when the encoder has changed.
    • Causes the system to come out of sleep mode or:
    • Causes the system to obtain a new desired temperature.
  • TRIGGER_NEW_MQTT_DESIRED_TEMP
    • Happens when a new desired temperature is sent to the device via MQTT.

Transitions

I now have a number of new transitions are shown below. The numbers in the square brackets correspond to the square numbers on the FSM diagram.

  • transition_waiting_to_sleeping [1]
    • Turns the display off
  • transition_encoder_move_from_sleeping [2]
    • Turns the display back on
  • transition_obtain_temp_display [3]
    • Obtains the new temperature and displays it
  • transition_new_desired_temp_mqtt [4]
    • Updates the new desied temperature and displays it
  • transition_obtain_temp_display [5]
    • Takes the new temperature from the encoder and displays it
  • transition_obtain_temp [6]
    • Obtains the new temperature, but doesn’t display it
  • transition_new_desired_temp_mqtt_sleeping [7]
    • Updates the new deisred temperature, but doesn’t display it.

Outcome

The code for this is still VERY messy, but as far as I can tell, it all appears to be working well. I’ve uploaded a short video to Youtube showing the device working. I’ve changed some of the times to make it easier to see (time until going to sleep is set as 10 seconds, temperature update interval set to 5 seconds).

You can see the video here Sorry for the terrible video quality…

Next Step

My next step is to start improving the circuit used. I’m going to start designing PCB that uses the ESP-12E board. That way I won’t be relying on the NodeMCU board, but this does mean that I have to design more of the circuit myself. That shouldn’t be an issue, but the ESP-12E isn’t the most breadboard friendly device!

ESP8266 Rotary Encoder

One of the things I’m currently working on is the ability to control the thermostat
“set point” both via a web-based UI and via the wall mounted thermostat itself.

The web-based UI is currently being created in Node-Red (more on that in a later entry), but the wall-mounted thermostat is currently working on an ESP8266. The idea is to have the following setup for the thermostat:

  • The boiler on / off is still controlled by Node-Red
  • The desired temperature can still be set using the web-interface from Node-Red.
  • The desired temperature can also be controlled directly from the wall-mounted thermostat.
  • The wall-mounted thermostat will contain:
    • An ESP8266 which will communicate with Node-Red via MQTT
    • A rotary encoder to control the current desired temperature
    • A OLED display to show the current and desired temperature

I already have the temperature sensor working (and being sent via MQTT to node-red), and the OLED seems to be setup and working. Therefore, I’m currently working on getting the rotary encoder working on the ESP8266.

The encoder I’m currently working on is the KY-040, which is a rotary encoder and a push button in one. This will allow me to choose the desired current temperature (and later use the push button to go through menus, etc.). They are cheap enough (about 40p each), but as I quickly found out, READY bouncy.

Hardware

At the moment, I don’t have the button connected up, but the rotary encoder pins are connected to GPIO 4 and GPIO 5. Below shows the diagram of the whole setup to date, which now includes:

  • ESP8266 nodemcu board
  • DS1631 i2c temperature sensor IC
  • 0.96″ OLED i2c display
  • KY-040 rotary encoder
Rotary Encoder Simplified Circuit Diagram

Simplified circuit diagram of system (excluding ESP setup).

I’ve left out most of the connection details for the ESP8266 as I’m using the nodemcu board which has all this setup (and I can’t actually find an EagleCad library that contains this particular board.

Simple enough and hopefully nothing too complicated. I’m sure there are ways I could clean up the circuit, but this will do for now.

Software

This one took my quite a bit longer than getting the hardware sorted out!

As this was my first attempt at using (cheap) rotary encoders, I stupidly thought that things would be quite easy to get working…

Attempt 1

My first attempt involved simply connecting one of the rotary encoders to a FALLING interrupt call, check the value of the other RE connection, decide if the rotary encoder had moved clockwise or anti-clockwise, and then print to serial within the interrupt call.

School-boy error! Don’t print to serial within interrupt calls. As should have been expected, the program crashed and reset everytime I turned the RE.

Attempt 2

So, second attempt was the same as above, but print to serial outside of the interrupt call.

This stopped the program from crashing, but as I did expect, the RE contacts were VERY bouncy, and the calculated position was all over the place! When turning clockwise, the calculated position was all over the place!

Getting better, but still no good.

Attempt 3

For the third attempt, I decided to get rid of the interrupt called, and poll the RE inputs. This allowed me to:

  • Easily introduce de-bouncing into the code.
  • Know if each input was pressed, had just been pressed, or had just been released.

The code for this was quite similar to what I had done for a previous project. In the git-hub project, the function for this is called checkButtons() I’m sure it could be refined, but for now it works.

For debouncing, I’m currently using 5ms, which seems to be working.

To check for the rotation of the RE, I used the same method as above. Meaning I’d check CLK for a fall (i.e. high to low) and check the value of the DT pin. If DT is high, then increase the position by 1 (i.e. clockwise). If DT is low, then reduce the position by 1 (i.e. anti-clockwise).

This seemed to work. When I turned the RE clockwise, I’d get a nice update in the number, but when I turned it anti-clockwise, it sometimes worked and sometimes didn’t work. Also, when I turned the RE fast, the numbers were all over the place, sometimes going back, sometimes forward. So getting better, but not quite there yet.

Also, increasing the debounce wait time didn’t seem to help, so I was starting to get a bit confused and had to do a bit more research.

Rotary Encoder LED Test

This got me thinking it would be good to test the RE more and see how it was actually working!

To do this, I connected the LEDs to the RE and rotated in both directions. What I found was that for 1 “click” in rotation, I had the following sequences:

  • Clockwise:
    • CLK {0 1 1 0}
    • DT   {1 1 0 0}
  • Anti-clockwise:
    • CLK {1 1 0 0}
    • DT   {0 1 1 0}

Now things are starting to make sense and I’m able to figure out some of my issues!

Attempt 4

So, now I know the pulse sequence for the RE, I was able to create a simple piece of code that stores the last 4 CLK and DT values, and update this each time the RE is rotated.

Then, only increase or decrease the current position after the correct set of sequences.

Upload the code and…

IT WORKS!!!

No bouncing problems. The values only go up when they should go up and only go down when they should go down. If I rotate the encoder, it sometimes doesn’t update. However, this is better than going in the wrong direction!

Progress

After working on the code a bit more, I now have a system where I can:

  • Choose the current desired temperature using the rotary encoder, in steps of 0.5C.
  • Whenever the desired temperature changes, it is sent to node-red via MQTT.
  • Whenever the desired temperature is changes in node-red, it also sends the new value to the ESP via MQTT.

This took a lot longer than it should, but it seems to be working well for now.

You can see the REALLY messy circuit below. The OLED shows the current temperature (in the larger text) and the desired temperature (in smaller text further down).

The code and circuit diagram for this should now be available on the Github project page.

img_20160320_160230.jpg

Circuit including OLED and Rotary Encoder

Next step

The next step is to add some functionality to the button on the rotary encoder. It would be good to get more details from the HA on node-red to display to the OLED (such as the current “Scene”, a menu).

ESP8266 Temperature Sensor – OLED

My new OLED screen has finally turned up, so I’ve been playing with ways of adding a the small display to my wireless temperature sensor.

For now I’ve only been working on using the display to show the current temperature, but soon I hope to add a rotary encoder that will allow me to choose the current desired temperature (in theory in each room, but that’s a way off for now).

The display is one of those cheap 128 x 64 0.96″ ones that cost about £3 each from China. They are small and cheap enough to place into each wall-mounted temperature sensor, but big enough for what I want to display.

I’ve obtained the I2C version which allows me to use the same pins as the temperature sensing IC, which will – hopefully – help simplify designing the final PCB.

Code

OLED Library

To control the display, I’m using the ESP_SSD1306 library, available here: https://github.com/somhi/ESP_SSD1306 After downloading and playing around, I was able to get the display to show the current temperature everytime it’s measured. I did however have a few problems:

  • Initially, I couldn’t get anything on to show on the display. It turns out that this was due to the “Wire.begin()” function call in the ESP_SSD1306 library. It was simply using the default I2C pins, which clearly were different on my board. Simple enough to fix, simply change the above line to “Wire.begin(2, 14)” and problem solved. It would be good to be able to choose the I2C pins in the default library, so might look into upgrading the library at some point.
  • Ticker.h library and the ESP_SSD1306 don’t seem to get on well together. I was unable to figure out why, but everytime I tried to display something on the display in the middle of the Ticker function, the device would reset. I never did find a solution to this (might look into it in the near future), so instead I got rid of the Ticker library and used something else.

Finite State Machine

I always intended to add a finite state machine in this project, but though I’d be looking into it at a later date. However, due to the problems with the Ticker library, I decided to get started with it sooner rather than later.

I’ve used FMSs before in AVR programs, but not directly in the Arduino environment, but I’m still learning the “Arduino-FSM” library, available here: https://github.com/jonblack/arduino-fsm

For now the FSM is very simple and probably a bit over-kill, but later I’ll use it to allow me to set the desired temperature via a rotary encoder, and potentially add a small menu, etc.

For now, the FSM has only 1 state, 1 transition, and 1 trigger.

  • The state is called “state_waiting”, during which nothing actually happens and the device is simply waiting for something to happen – in this case for a timer to say it’s time to obtain the current temperature.
  • The trigger is called “TEMPERATURE_TIME_TRIGGER”. It’s not very catchy, but gets the job done. This trigger happens once every minute (can be easily changed) and triggers the FSM to obtain the current temperature.
  • Finally, the transition is called “transition_getting_temperature”. This transition goes and gets the current temperature, displays it on the screen, and sends it via MQTT. This transition goes from “state_waiting” back to “state_waiting”, where the FSM waits for something new to happen.

The diagram below shows the FSM in a way that should be much easier to understand.

FSM

The code has been uploaded to the Github project here: https://github.com/nerobot/Home-Automation/tree/master/ESP8266%20temperature%20sensor It’s currently quite messy and will be cleaned up soon, but for now, it might be useful to someone.

Circuit

Below, you can see a photograph of the OLED displaying the current temperature. The circuit is currently very messy, but does the job.

img_20160228_131429.jpg

Next Steps

The next step is to add the rotary encoder. I hope to get the following done soon:

  • Use the rotary encoder to choose the current desired temperature.
  • Show the desired – along with actual – temperature on the OLED.
  • Send the chosen desired temperature to node-red using MQTT, and update the shown desired temperature from node-red (again using MQTT).

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.

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.