Showing posts with label ESP-01. Show all posts
Showing posts with label ESP-01. Show all posts

Saturday, August 27, 2016

A good book about ESP8266

One thing that I did in the last two months was to collaborate with Packt Publishing to be technical supervisor for a book about the ESP8266.

Book is written by Marco Schwartz and can be purchased from Amazon.

The summary of the book is in the following pictures.









Friday, August 5, 2016

Mqtt broker on ESP8266 #4


[Later edit]. On iotcentral.eu you will find instructions on how to install the ESP8266 MQTT broker on your EPS8266 and how to use the MQTT service provided by iotcentral.eu


I have more progress in ESP8266 as MQTT broker.


What I have for now on this ESP8266 module:



  • MQTT broker functionality
  • Bridging data to/from and another MQTT broker ( usually a cloud MQTT instance)
  • websockets connectivity ( I can now connect with my Homy application directly to the ESP8266 acting as an MQTT broker)
  • OTA (Over The Air) updates. Every time I have a new software update the ESP8266 is updating itself so, I can say that I have continuous integration (CI) and continuous deployment(CD). Also all the modules are activated over the air.
With all those function in place I still have 34kb of heap available for other features and yes is running on an ESP with a minimum 1Mb of memory. ESP8285 is a good candidate for running the broker.

Is working also on and old ESP-01 with 512kb but without OTA functionality.

Previous posts on the same subject:


IoT with ESP8266: Mqtt broker on ESP8266 #1


Tuesday, May 31, 2016

Keep your house cool with ESP8266 #1.




Since the summer is near, yesterday were like 30 degrees Celsius, nothing is more comforting then coming home and have a nice temperature inside. 

But how to do that ? You can program your air conditioning AC to do that (if it has this function) but how about the days when you are not know at what time you will be home ?

It will be a lot of money that will be spend on electricity for nothing.

What if you will be able to control from your smart phone when to start the AC, what temperature to maintain, in which intervals everything with a cost of 5USD ?

Again for this project I am using the Witty module but  ESP-01 can do it  if you have one that you are not using it.


Witty module with IR LED and IR receiver


The schematics is very simple, below is one with 2 IR LEDs but you can use only one. An old remote control can be a good source of IR LED.



If you don't have R1 of 1K you can replace it with 680. The VCC I've used is 5V ( available on Witty module.

Parts list:
Witty ESP8266 module
Resistors - with 7USD you can buy 1400 pcs with all values (1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82, 100, 120, 150, 180, 220, 270, 330, 390, 470, 560, 680, 820, 1K, 1.2K, 1.5K, 1.8K, 2.2K, 2.7K, 3.3K, 3.9K, 4.7K, 5.6K, 6.8K, 8.2K, 10K, 12K, 15K, 18K, 22K, 27K, 33K, 39K, 47K, 56K, 68K, 82K, 100K, 120K, 150K, 180K, 220K, 270K, 330K, 390K, 470K, 560K, 680K, 820K, 1M)
Transistor   2N2222 
IR LED or you can recover one from an old remote control

For capturing the signals from a remote control you can use:
IR Sensor module

For other project involving IR and ESP you can buy a remote control. and you will receive also an IR sensor and and IR LED.


Enough with the hardware, now lets go on the software.

Off course that my AC ( GREE model ) is not working with any standard protocol NEC, SONY, PANASONIC, LG, RC5, RC6 so a lot of work need to be done to make it work.


First  capturing the IR code sent by my AC remote using the IRremoteESP8266 library showed that it has an NEC encoding and 73 bytes. Playing the recorded 73 bytes with the 

void IRsend::sendRaw(unsigned int buf[], int len, int hz)

function didn't work. The IRremoteES8266 library has a standard buffer in IRremoteESP8266.h of 100 bytes.

#define RAWBUF 100 // Length of raw duration buffer


What if my data is bigger then that ? I've changed the value up to 512 bytes, but nothing,the AC was not responding to the raw data.

Ok then, may be the library is not recording the complete data sent be my remote, so a different approach was need it.


Let's record the data using the ISR.

1. Attaching the interrupt RX_PIN on function rxData with CHANGE ( both direction UP/DOWN)

attachInterrupt(RX_PIN, rxData, CHANGE);

2.Write the rxData function to record the time-stamp for any CHANGE in rx signal in a buffer.

void rxData()
{
buff[x] = micros();
x++;
}

3. After 3 seconds dump the data recorded in the buff[] decreasing the two consecutive values. At the end will have just the time difference between any consecutive CHANGE in signals.




Wow ! The length of data is bigger now (139 vs 73 bytes)



unsigned int buff[73] = {9000,4500, 650,1650, 650,600, 650,600, 650,1700, 650,600, 650,600, 650,600, 650,600, 650,1700, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,600, 650,1650, 650,1650, 650,600, 650,600, 650,600, 650,600, 650,600, 650,1650, 650,600, 650,1700, 650,600, 650,600, 650,1700, 650,600, 650};


versus

unsigned int buff[139] = {9050,4500, 800,1600, 750,550, 700,550, 700,1600, 750,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,1600, 750,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,1600, 750,1600, 750,550, 700,550, 700,550, 700,550, 700,550, 700,1600, 750,550, 700,1600, 750,550, 700,550, 700,1600, 750,550, 700,19950, 750,500, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,1600, 750,550, 700,550, 750,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,550, 700,1550, 800,550, 750,500, 700,1600, 750};


EUREKA ! sending the new captured data start the AC !!!

Now lets see what is different between those two data sets. In the middle of the 139 buffer I can see that there is a big value of 19950 (in usec => 19.95 ms) and the data after, looks almost the same for each command. That's the catch!!!

Full data received will be like this:



Timing[139]: 
     +9050, -4450     + 800, -1600     + 700, - 550     + 700, - 550
     + 700, - 550     + 700, - 550     + 700, - 550     + 700, -1650
     + 800, - 500     + 700, -1650     + 800, - 500     + 700, -1650
     + 800, - 500     + 700, - 550     + 700, - 550     + 700, - 550
     + 700, - 550     + 700, - 550     + 700, - 550     + 700, - 550
     + 700, - 600     + 750, - 500     + 700, -1650     + 800, -1550
     + 800, - 500     + 700, - 550     + 700, - 550     + 750, - 500
     + 700, - 550     + 700, -1650     + 800, - 500     + 700, -1650
     + 800, - 500     + 700, - 550     + 700, -1650     + 800, - 500
     + 700, -19900    + 800, -1600     + 800, - 500     + 700, - 550
     + 700, - 550     + 700, -1650     + 800, - 500     + 700, - 550
     + 700, - 550     + 700, - 550     + 700, - 550     + 700, - 550
     + 700, - 550     + 700, - 550     + 700, -1650     + 800, - 500
     + 700, - 550     + 700, - 550     + 700, - 550     + 700, - 550
     + 700, - 550     + 700, - 550     + 700, - 550     + 700, - 550
     + 700, - 550     + 700, - 550     + 700, - 550     + 700, - 550
     + 700, - 550     + 700, -1650     + 800, -1550     + 800, - 500
     + 700, - 550     + 700

Where 9050 (9ms )and 4450 (4,5ms) are the header. After removing the header you see a
lot of +value and -value. Observing them can jump to the conclusion that after removing all the +values the rest will be 0 (~700+/-200) and 1 (~1600+/-200). Counting the number of bits from the beginning and from the end will result in 32 + 3 + 32 where the middle 3 bits are just before the -19000 (19ms) value and are always 010(b).

Header: 9000
Header space: 4500

Logic "0" 0: 600
Logic "0" 1" 600 ====> +700 -550 is coresponding a "0" logic

Logic "1" 0: 600
Logic "1" 1: 1650 ====>+700 -1690 is coresponding an "1" logic

Now looks like the protocol is 35 bits followed by 32 bits. So for turning on the AC with value of 20 degrees will have 0x9220060A 101(b) 0x8804004.

I see that the last digit (4) from 0x8804004 is changing based on the temperature and the command (on/off) so, can be a kind of CRC.

Other codes (until the 19950) decoded as NEC protocol.

Temp / Data
16 0x9000060A;
17 0x9080060A;
18 0x9040060A;
19 0x90C0060A;
20 0x9020060A;
21 0x90A0060A;
22 0x9060060A;
23 0x90E0060A;
24 0x9010060A;
25 0x9090060A;
26 0x9050060A;
27 0x90D0060A;
28 0x9030060A;
29 0x90B0060A;
30 0x9070060A;



Changing third byte is changing the temperature. Other bytes are for cool/dry/heat/fan/auto for fan power or swing option etc.

Now I need to add the regular MQTT and WiFi code like in this post, change the mobile app to accommodate the new module and I will be able to set up the temperature in my house from my mobile.

Unfortunately there is no feedback to check that the ON command was received by your AC device, but an accelerometer can be attached to sense the vibrations of your AC ( in this case the unit need to be put on top of your AC) or a temperature sensor can be place in front of your AC and monitor air temperature provided by your AC unit.



If you have more AC units in your house you can build more modules and add more sensors to them (temperature, vibration to check that the unit is working etc).




Monday, October 19, 2015

Update: Android application to control my ESP devices around the home

I've updated the Homy application that controls my ESP8266 based devices around the house.

So more Smart Plugs has been added, more irrigation controllers (for testing),  temperature and humidity sensors.

At the begging each node is starting as AP with it own embedded web server. I can connect to it
with a browser to it and setup the WiFi network and password ( I am planning to do this also from Homy application). After that node gets rebooted and became part of the network.

At statup Homy connects to the cloud broker ( which is connected to my local one) and request an
update from all devices. In this way knows how many of them are and what types they are, what cron settings thay have and what IP, software version they have etc.



Next to do on devices is OTA.
Next device to build is a chrono thermostat device. It will be able to control a heater based on its predefined cron program and aggregated temperature from sensors. Off course  I will be able to control it from the Homy application around the world.




Monday, April 20, 2015

First IoT device - Plug

Because was raining outside and I couldn't work in the backyard, I've made rapidly an IoT plug with ESP8266 .

Donor for the case was a timer plug that was in the house. After I've removed its content, I've added my stuff.

IoT plug
Inside the case I have:

  • power supply (220V-3v3 1A)
  • 5V relay ( is working fine on 3.3 V)
  • ESP-01 covered in blue tape 
And the final IoT plug:

IoT final plug



The ESP-01 is accepting JSON over MQTT from my mosquitto broker. 

To control the plug from my phone, I've created an android application that connects over
websockets to mosquitto broker and is sending commands. 

Plug is sending status every 15 seconds to its subscribers and a status after every command its receiving.

Cool.....now I can turn on or off  my  lamp with my IoT device. 

For Android application I've used for rapid development a template, but I am planning to build a totally new application that will discover the IoT devices and add them automatically to the control screen.



IoT Plug application
EDIT: The Android application is different now. See this post.

And a video:











Friday, March 20, 2015

Publish data from your ESP8266 to thingspeak.com

On this posts ( post#1, post#2) I've presented how to create a channel, fields, API KEYS on thingspeak.com

Now will publish some data from ESP8266 to thingspeak.com. Can be any kind of data, from
temperature, humidity, voltage you name it. As long as it has a value, can be published.

Add following  lines after the include statements. (Can use the blinky code as skeleton).

#include "espconn.h" 
LOCAL struct espconn *pCon = NULL;
LOCAL my_count = 0;
LOCAL your_value = 33;




Add the following code in the user_init() function.

const char ssid[32] = "my_home_ssid";
const char password[32] = "my_home_password";

struct station_config stationConf;

wifi_set_opmode( STATION_MODE );
os_memcpy(&stationConf.ssid, ssid, 32);
os_memcpy(&stationConf.password, password, 32);
wifi_station_set_config(&stationConf); 
wifi_station_connect();
//connect to the previous pCon created structure
int ret = 0;
ret = espconn_connect(pCon);

if(ret == 0) 
      INFO("espconn_connect OK!\r\n");
else
{
      //INFO("espconn_connect FAILED!\r\n");  
      char *fail;
      os_sprintf(fail, "%d \r\n", ret);
      //INFO(fail);
      //clean up allocated memory
      if(pCon->proto.tcp)
          os_free(pCon->proto.tcp);
      os_free(pCon);
      pCon = NULL;


Add this code in a timer function like in this example:

pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
if (pCon == NULL)
{
        os_printf("pCon ALLOCATION FAIL\r\n");
        return;
}

pCon->type = ESPCONN_TCP;
pCon->state = ESPCONN_NONE;
    
pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
pCon->proto.tcp->local_port = espconn_port();
//set up the server remote port
pCon->proto.tcp->remote_port = 80;

//set up the remote IP
uint32_t ip = ipaddr_addr("184.106.153.149"); //IP address for thingspeak.com
os_memcpy(pCon->proto.tcp->remote_ip, &ip, 4);

//set up the local IP
struct ip_info ipconfig;
wifi_get_ip_info(STATION_IF, &ipconfig);
os_memcpy(pCon->proto.tcp->local_ip, &ipconfig.ip, 4);

//register publish_thingspeak_connect_cb that will be called when the
//connection with the thingspeak is done. In this call back function
// will actualy do the data sending
espconn_regist_connectcb(pCon, publish_thingspeak_connect_cb);



where the callback function is:


static void ICACHE_FLASH_ATTR publish_thingspeak_connect_cb(void *arg)
{
  //INFO("========>publish_thingspeak_connect_cb\r\n");
  my_count++;

  struct espconn *pespconn = (struct espconn *)arg;

  char payload[128];

  char field1[10];
  char field2[10];

  os_sprintf(field1, "%d", your_value);
  os_sprintf(field2, "%d", my_count);

  os_sprintf(payload, "GET /update?  api_key=YOUR_THINGSPEAK_API_KEY&field1=%s&field2=%s\r\n", field1, field2);

  espconn_sent(pespconn, payload, strlen(payload));
  
}

and need to be added before the user_main function.

Change my_count and your_value with your data. 

Notes:

1. The time between to posts on thingspeak.com must be greater then 15 seconds.
2. Up to 8 fields can be used to post data on thingspeak.com





Thursday, March 19, 2015

Example: Blink a LED

Like in the Arduino case one of the first thinks to try it is to blink an LED.

The following link contains the code for blink an LED.

Materials:

  • ESP-01 - or other version 
  • LED 
  • SERIAL to USB

If you have my setup described here 

1. put the the archive into this directory

/opt/Espressif/ESP8266_SDK   

2. untar the file

tar -xvf blinky.tar

3. enter in the app directory

cd blinky

4. compile the code

make clean ; make.

5. Upload the resulting files ( from the firmware directory) to your ESP after this steps

5.1 Unplug the VCC power pin
5.2 Connect the GPIO0 pin to ground
5.3.Use the command to write the firmware

./burnESP


Anatomy of the code

 The main application file is the user_main.c file located in 
/opt/Espressif/ESP8266_SDK/blinky/user

The file content is:


#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "user_config.h"

#define user_procTaskPrio        0
#define user_procTaskQueueLen    1
os_event_t    user_procTaskQueue[user_procTaskQueueLen];
static void user_procTask(os_event_t *events);

static volatile os_timer_t some_timer;


void some_timerfunc(void *arg)
{
    //Do blinky stuff
    if (GPIO_REG_READ(GPIO_OUT_ADDRESS) & BIT2)
    {
        //Set GPIO2 to LOW - TURN OFF the LED
        gpio_output_set(0, BIT2, BIT2, 0);
    }
    else
    {
        //Set GPIO2 to HIGH - TURN ON the LED
        gpio_output_set(BIT2, 0, BIT2, 0);
    }
}

//Do nothing function
static void ICACHE_FLASH_ATTR  user_procTask(os_event_t *events)
{
    os_delay_us(10);
}

//Init function 
void ICACHE_FLASH_ATTR user_init()
{
    // Initialize the GPIO subsystem.
    gpio_init();

    //Set GPIO2 to output mode
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);

    //Set GPIO2 low
    gpio_output_set(0, BIT2, BIT2, 0);

    //Disarm timer
    os_timer_disarm(&some_timer);

    //Setup timer
    os_timer_setfn(&some_timer, (os_timer_func_t *)some_timerfunc, NULL);

    //Arm the timer, &some_timer is the pointer 1000 is the fire time in ms
    //0 for once and 1 for repeating timer
    os_timer_arm(&some_timer, 1000, 1);
    
    //Start os task
    system_os_task(user_procTask, user_procTaskPrio,user_procTaskQueue, user_procTaskQueueLen);
}


and is pretty much self explanatory.

1. Include the necessary headers. See that user_config.h is empty so if you can use this app as a skeleton for your future applications. 

2. In user_init() function the GPIO is initialized, GPIO2 is set up as an output pin and is set
to 0 (LOW, GND).

3. A timer is defined (some_timer) and initialized and the  callback function is set to be called every 1000ms (1sec) interval. 

4. Callback function some_timerfunc is doing all the stuff, if the LED is ON turn it to OFF,
otherwise turn the LED ON.


If you want to add extra functionality check this post for how to have arduino like functions
to manipulate your GPIO. 

Happy codding !!! 

Thursday, March 12, 2015

Arduino function for ESP8266

        If programming the GPIO is hard for you as a beginner but you are familiar with Arduino functions, the following functions can be used as have the same name as in the Arduino IDE.

First define some data in an .h file.

#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x1
#define OUTPUT 0x0
                                                   /*   GPIO | SDK board    |       */
                                                   /*   --------------------|       */
int gpio_pin_register[16] = {PERIPHS_IO_MUX_GPIO0_U,    // 0  gpio 0        | 
                             PERIPHS_IO_MUX_U0TXD_U,    // 1  gpio 1        | 
                             PERIPHS_IO_MUX_GPIO2_U,    // 2  gpio 2        | 
                             PERIPHS_IO_MUX_U0RXD_U,    // 3                |
                             PERIPHS_IO_MUX_GPIO4_U,    // 4  gpio 4        | 
                             PERIPHS_IO_MUX_GPIO5_U,    // 5  gpio 5 buzzer | 
                             PERIPHS_IO_MUX_SD_CLK_U,   // 6                |
                             PERIPHS_IO_MUX_SD_DATA0_U, // 7                |
                             PERIPHS_IO_MUX_SD_DATA1_U, // 8                |
                             PERIPHS_IO_MUX_SD_DATA2_U, // 9  gpio 9        | 
                             PERIPHS_IO_MUX_SD_DATA3_U, // 10 gpio 10       | 
                             PERIPHS_IO_MUX_SD_CMD_U,   // 11               |
                             PERIPHS_IO_MUX_MTDI_U,     // 12 gpio12  blue  | 
                             PERIPHS_IO_MUX_MTCK_U,     // 13 gpio13  green | 
                             PERIPHS_IO_MUX_MTMS_U,     // 14 gpio14  white | 
                             PERIPHS_IO_MUX_MTDO_U};    // 15 gpio15  red   | 
                             

#define GPIO_PIN_ADDR(i)    (GPIO_PIN0_ADDRESS + i*4)


Now the Arduino like functions can be added:

/********************************************************************
* FunctionName: pinMode
* Description : set up a pin mode.
* Parameters  : pin: pin mumber
*             : mode 0 for OUTPUT or 1 for INPUT
*             : pullup 0 for pullup DISABLED and 1 for pullup ENABLED
*             : pulldown not yet supported
* Returns     : None                                                     
*********************************************************************/

void ICACHE_FLASH_ATTR pinMode(uint8_t pin, uint8_t mode, uint8_t pullup) {
    if ((0x1 << pin) & 0b110101) {
        PIN_FUNC_SELECT(gpio_pin_register[pin], 0); //0,2,4,5
    } else {
        PIN_FUNC_SELECT(gpio_pin_register[pin], 3);
    }
    PIN_PULLDWN_DIS(gpio_pin_register[pin]);
    if(pullup)
      PIN_PULLUP_EN(gpio_pin_register[pin]);
    else  
      PIN_PULLUP_DIS(gpio_pin_register[pin]);
    if (mode) {
        GPIO_REG_WRITE(GPIO_ENABLE_W1TC_ADDRESS, 1<<pin); // GPIO input
    } else {
        GPIO_REG_WRITE(GPIO_ENABLE_W1TS_ADDRESS, 1<<pin); // GPIO output
    }
}


Example:
pinMode(0, OUTPUT, 0); //is setting the GPIO 0 as an OUTPUT with pullup disabled

If you want to control also the pulldown add an extra parameter and call the 
PIN_PULLDWN_DIS(gpio_pin_register[pin])for disable and PIN_PULLDWN_EN(gpio_pin_register[pin])for pulldown enable.


Next function are the well known Arduino function for read and write:

/********************************************************************
* FunctionName: digitalWrite
* Description : use to set up HIGH or LOW on a GPIO pin
* Parameters  : pin: pin mumber
*             : state HIGH or LOW
* Returns     : None                                                     
*********************************************************************/

void ICACHE_FLASH_ATTR 
digitalWrite(uint8_t pin, uint8_t state) {
    if (state) {
        GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1<<pin); // set GPIO pin high
    } else {
        GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1<<pin); // set GPIO pin low
    }
}
/********************************************************************
* FunctionName: digitalRead
* Description : use to set up HIGH or LOW on a GPIO pin
* Parameters  : pin: pin mumber
* Returns     : 1 if pin is HIGH or 0 if pin is LOW                                                     
*********************************************************************/

int ICACHE_FLASH_ATTR 
digitalRead(uint8_t pin) {
    return (GPIO_REG_READ(GPIO_OUT_ADDRESS)>>pin) & 1;
}



Example:

digitalWrite(0, HIGH); //set HIGH the GPIO 0 pin

int gpio_state = digitalRead(0); will return 1 if the GPIO 0 pin's is HIGH or 0 if is LOW

If you save your .h file in the include directory, just use #include "your_file_name.h" in your user_main.c.


For controlling GPIO16 see this post.