For the last few weeks, I’ve been reading up on the ESP8266 wifi board as a potential component in my – to be developed – home automation system. Unfortunately, I’ve been unable to really do anything over the last month or two, but I have been able to read a lot of the developments on the ESP forum – http://www.esp8266.com/ – and this guys blog.
For those who don’t know, the ESP8266 is a series of boards with built in wifi access and their own MCU, and on of the main reasons many people are into them is because they are so cheap for a wifi board. For example, the ESP-01 board which I have can be bought from China for as little as £2 (and less), which is great compared to the price of the current Arduino compatible boards. They are also wildly available from a certain online auction site.
They are also really small, allowing for them to be hidden away in small devices around the home.
Since I noticed them a few months ago, there’s been a ton of development work done with them and there is now a Windows Eclipse based IDE that can be used to develop firmware to flash directly onto the board. Using this, potentially there is no need for a separate Arduino / AVR / PIC board and there are some version of the boards that have quite a few GPIO pins available (the ESP-01 only has two that I can find).
Some people have been working on porting Lua interpreters, others flashing web-servers directly to the boards, and many other things that can be found on the above link.
However, what I’m interested in is using the device as a MQTT client to send and receive data around my HA system. Over on the ESP forum, Tuanpm has been working on code to allow us to use the ESP boards as an MQTT client. The forum post is here and the wiki here. I’ll leave you to read over that if you’re interested.
LED Control
As a first test, I wanted to see if I could control a LED using MQTT.
For this, I setup Mosquitto on a Raspberry Pi, flashed adapted MQTT firmware to my ESP board, connected an LED to GPIO-2 pin, and used MyMQTT on my phone to test publishing topics.
The code is pretty much exactly the same as the in the example code from GitHub, but I changed a few small things.
- In the function mqttConnectCb(), I changed the subscription to /LivingRoom/LED/1 and removed the publishing calls
- I added PIN_FUNC_SELECT(LED_GPIO_MUX, LED_GPIO_FUNC);
to the user_init function to set GPIO-2 to output - Add the following to the beginning the user_main.c file (though I’m not actually sure what they do yet)#include <gpio.h>// 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 - Finally, added the following to the mqttDataCb functionif (!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);
}
}
The last piece of code simply turns the LED on or off depending on the content of topic /LivingRoom/LED/1
Now, by publishing either a “0” or a “1” to /LivingRoom/LED/1 I can switch the LED on and off!
MQTT Retain
One one of the things I would be looking at doing, it powering the ESP via a battery. However, the problem with that is that when the ESP board is powered down – to save battery – it won’t be subscribed to any topics, so receive the data.
The way around this issue which I’ve tried and appears to be working is to use retention in the publication. For example by tying in mosquitto_pub -r -t /LivingRoom/LED/1 -m “1” from my RasPi, I’m able to power off the ESP board, make the above call, power the ESP device on some time in the future, and once the device is booted up correctly, the LED will switch on. Great!
Coming up
My next step is to use the ESP MQTT code and turn an LED on or off using OpenHab.
James said:
Hi, nice writeup…..
Did you make all your setting changes in user_main, including the first two points?
Thanks.
nerobot said:
Hi,
If you’re asking about the changes the “LED Control” section of the blog, then yes, they are all done within the user_main.c file.
James said:
Thanks for the reply.
I’ve got it working as far as receiving the MQTT command, either 1 or 0 and it is also coming up on the serial monitor, however nothing is happening.
I presume I should see the output of INFO(“LED Switching On\r\n”); in the serial too if successful?
I do’t suppose your full code is available anywhere is it?
nerobot said:
Hi,
Yeah I believe you should see “LED Switching On” on the serial.
I’ve copied the complete user_main.c below if that helps. If not, I’ll look at at putting the project folder on github or something similar. Let me know how you get on.
#include “ets_sys.h”
#include “driver/uart.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”
#include
#include
#include
#include
#include
#include
// 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
MQTT_Client mqttClient;
void wifiConnectCb(uint8_t status)
{
if(status == STATION_GOT_IP){
MQTT_Connect(&mqttClient);
}
}
void mqttConnectedCb(uint32_t *args)
{
MQTT_Client* client = (MQTT_Client*)args;
INFO(“MQTT: Connected\r\n”);
MQTT_Subscribe(client, “/LivingRoom/LED/1”, 1); // Make sure this is the MQTT topic you are publishing to!
}
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.0.7”, 1883, SEC_NONSSL);
MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);
//MQTT_InitClient(&mqttClient, “client_id”, “”, “”, 120, 1);
MQTT_InitLWT(&mqttClient, “/lwt”, “offline”, 0, 1);
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”);
}
James said:
Perfect thanks….. You have saved my sanity!!
When I cut and past the code across the first time the ” had turned into . and I’d missed one.
Thanks
nerobot said:
Glad you got it working. I’ll be looking at improving the code soon so I can connect it to a relay to control my heating. Let me know if you find ways to improve the code.
James said:
I changed it a little to control two relays, with on and off. I can share if you like? As for major improvements, I’m not much of a programmer and don’t understand some of the lines.
I was also going to investigate if it was possible to control a dimmer (got to build one first though) or if I’d need to stick with the Arduino for that.
Either way, these are great little things even if they can only switch a few relays or act as switches themselves.
Cheers.
Phuong said:
Hi James, can you share your full code with 2 relays. Thanks and wait for your reply.