Monday, 5 August 2019

Mobile controlled MQTT smart plug and TV

I have recently finished a project that uses a mobile App to control the smart plug and a TV remote simulator. The project contains 3 parts: A smart plug, an IR transmitter and an Android mobile App. All of the 3 parts were created by myself.

This project is based on a previous project I did last year ( https://mculabs.blogspot.com/2018/10/a-mqtt-demo-using-esp-01-esp8266.html ) , but has benn improved a lot. The most significant change is this time a dedicated mobile App is created, so we can have a decent App that suites the needs. Then this time we have 2 devices connected to the MQTT server simultaneously, the 2 devices are subscribed to different topics on the MQTT server. Of course it is possible to combine these 2 into 1 and save a ESP-01 module.

The smart plug uses a ESP-01-RELAY module and a AC/DC

The IR transmitter circuit is simple
The smart plug seems more complicated in the picture but is actually very simple in the terms of software, the only thing it needs to do is the control of a GPIO to set it 1 or 0 according to the message of the subscription.



What is tricky is the IR transmitter, to simulate the work of a TV remote controller, the ESP8266 must generate a 38kHz carrier and then modulate it in order to send proper commands. Using software to generate a 38kHz wave is going to waste too much resources, fortunately the ESP8266 has a built-in I2S port, which can be configured to work at 38kHz, bad news is this I2S port has been removed from the official documents, I have to spend days on searching the internet and Espressif's SDKs to find a proper demo code which shows how to configure the I2S. Turns out, there is an API function named sdk_rom_i2c_writeReg_Mask() , which is dedicated to I2S configuration, but I couldn't find any documentation about it, if you knows about it, I would appreciate it very much if you can leave a comment below.

I would like to share the 38kHz carrier generation code here, if you are also doing a similar project, I hope this can help you. It is written in C++ but is easy to be understand and therefore adopt to any other languages.

//*********************************************************
//**** This code is by Jian Jiao, mculabs.blogspot.com ****
//*********************************************************
#include <espressif/esp_common.h>
#include "esp_carrier.h"

#define DR_REG_I2S_BASE     (0x60000e00)
#define I2SCONF            (DR_REG_I2S_BASE + 0x0008)

extern "C" void sdk_rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id,
        uint32_t reg_add, uint32_t Msb, uint32_t Lsb, uint32_t indata);

ESP_CARRIER_GEN::ESP_CARRIER_GEN()
{
    sdk_rom_i2c_writeReg_Mask(0x67, 4, 4, 7, 7, 1);
    // this is a undocumented API, copied from Espressif example code.
    // The supposed use for this API is to enable I2S CLK source
    // rom_i2c_writeReg_Mask( i2c_bbpll,
    //             i2c_bbpll_hostid,
    //             i2c_bbpll_en_audio_clock_out,
    //             i2c_bbpll_en_audio_clock_out_msb,
    //             i2c_bbpll_en_audio_clock_out_lsb,
    //             1);
   
    WRITE_PERI_REG(I2SCONF, (READ_PERI_REG(I2SCONF) & 0xF0000FFF) | (0x3e << 22) | (0x02 << 16) | (0x01 << 12));
    // set I2CCONF register. This set the I2S WS output frequency to 38kHz
    // bit 22~27 : I2S_BCK_DIV_NUM
    // bit 16~21 : I2S_CLKM_DIV_NUM
    // bit 12 : FIFO access mode, 1=SLC DMA, 0=software direct, default=1
   

    WRITE_PERI_REG(I2SCONF, (READ_PERI_REG(I2SCONF) & 0xFFFFFDFF) | (0x01 << 8));        // for output on I2SO_WS
    // WRITE_PERI_REG(I2SCONF, (READ_PERI_REG(I2SCONF) & 0xFFFFFDFF) | (0x02 << 8));    // for output on I2SI_WS
    // I2S rx start
}

void ESP_CARRIER_GEN::carrier_on(void)
{
    //PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_I2SI_WS);        // MTMS pin as WS output
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_I2SO_WS);        // GPIO_2 pin as WS output
}

void ESP_CARRIER_GEN::carrier_off(void)
{
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);        // GPIO_2 pin as GPIO
    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, 1 << 2);            // enable output
    GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << 2);            // output 0
}


The mobile app is written in C++ in Embarcadero's C++ Builder, I'm very glad they have made this great product available free for personal users. It saves me tremendous time to learn a new language in order to create a mobile phone App.


The UI of the App is still ugly and needs improvements, but for now I won't spend more time on it and just move on to my next project.

The ESP8266 part of the project was developed in the open source FreeRTOS SDK esp-open-rtos, and it's using FreeRTOS and C++.

Here is the demo video of this project.