Introduction
This is an introductory article which shows how high-power loads can be controlled easily using affordable electronics, like popular ESP8266 wireless module.
Background
The ESP8266 is a Wi-Fi module with full TCP/IP stack and microcontroller programming capability. The ESP8266 module can work either in the Access Point mode or in the client (Station) mode, or in both modes at once (mixed mode), although the latter is unstable. It also has 1MB of flash memory.
Module Block Diagram
Mode Detailed Technical Specifications
- 802.11 b / g / n wireless standards
- STA / AP modes support
- TCP / IP protocol stack, One socket
- Supports standard TCP / UDP Server and Client
- Supports serial port baud rate configuration: 1200/2400/4800/9600/19200/38400/57600/74800/115200 bps
- Supports serial data bits: 5/6/7/8 bits
- Supports serial parity: none
- Supports serial stop bits: 1/2 bit
- ESP8266 GPIO Pinout 0/2/4/5/9/10/12/13/14/15/16 / ADC / EN / * UART TX / UART RX
- WiFi operation current: continuous transmission operation: ≈70mA (200mA MAX), idle mode: <200uA
- Serial WiFi transmission rate: 110-460800bps
There are many flavours of ESP8266 module on the market. I was using ESP8266MOD, because it has plenty of GPIO wired outside of the chip, external antenna connector and rigid metal casing:
The Schematics
If you are familiar with the basics of electronics, you will find that constructing this schematic is very easy.
You will need:
- ESP8266MOD
- 3.3V Power Supply
- Fortek SSR40-DA-H Solid-state Relay
- A bunch of header connectors and resistors
- USB-UART 3,3V Level Adapter
Disclaimer: This application uses hazardous voltages from mains line. Please take care! Debug when disconnected from mains! Make sure everything is insulated well!
Preparing Development Environment
As a development kit, I have chosen Unofficial Development Kit for Espressif ESP8266.
Instructions for installing and configuring the Unofficial Development Kit for Espressif ESP8266:
- Download the Unofficial Development Kit for Espressif ESP8266 (148Mb) and install.
- Download and install the Java Runtime x86 or x64 (jre-8uXXX-windows-xxx.exe)
- Download and install Eclipse Neon x86 or Eclipse Neon x86_64 for the development of C ++. Extract the archive to the root of drive C.
- Download and install MinGW. Run mingw-get-setup.exe, the installation process to select without GUI, i.e., uncheck "... also install support for the graphical user interface".
- Download scripts to automate the installation MinGW packages.
- Run the install-mingw-package.bat file. Download pre-loaded packages for MinGW files ensures that they will be installed, sometimes the server where MinGW packages are no longer available and the required packages are not installed.
- Start the Eclipse Neon from the directory c:\eclipse\eclipse.exe
- In Eclipse, select File -> Import -> General -> Existing Project into Workspace, in the line Select root directory, select project root directory and import it.
- You will need to replace the file c:\Espressif\examples\ESP8266\common_cpp.mk with this file: common_cpp.zip. This is to ensure correct C99 builds.
Using the Code
The following code is used to start an Access Point:
void ICACHE_FLASH_ATTR WifiConnectorInit()
{
WifiEnterWorkMode();
captdnsInit();
WebInit();
}
void ICACHE_FLASH_ATTR WifiEnterWorkMode()
{
wifi_set_opmode(SOFTAP_MODE);
struct softap_config apconfig;
if(wifi_softap_get_config(&apconfig))
{
wifi_softap_dhcps_stop();
os_memset(apconfig.ssid, 0, sizeof(apconfig.ssid));
os_memset(apconfig.password, 0, sizeof(apconfig.password));
os_sprintf((char*)apconfig.ssid, "iqhub%ld", (long int)56);
apconfig.ssid_len = os_strlen((char*)apconfig.ssid);
apconfig.authmode = AUTH_OPEN;
apconfig.ssid_hidden = 0;
apconfig.channel = 9;
apconfig.max_connection = 4;
apconfig.beacon_interval = 100;
if(!wifi_softap_set_config(&apconfig))
os_printf("%s", "ESP8266 not set AP config!\r\n");
struct ip_info ipinfo;
wifi_get_ip_info(SOFTAP_IF, &ipinfo);
IP4_ADDR(&ipinfo.ip, 192, 168, 4, 1);
IP4_ADDR(&ipinfo.gw, 192, 168, 4, 1);
IP4_ADDR(&ipinfo.netmask, 255, 255, 255, 0);
wifi_set_ip_info(SOFTAP_IF, &ipinfo);
wifi_softap_dhcps_start();
}
wifi_set_broadcast_if(3);
}
For this project, our URL query set will look like this:
HttpdBuiltInUrl builtInUrls[]={
{"*", cgiRedirectApClientToHostname, "esp.nonet"},
{"/", cgiRedirect, "/index.html"},
{"/index.html", cgiIndex, NULL},
{"/onButton", cgiOnButton, "/index.html"},
{"/offButton", cgiOffButton, "/index.html"},
{NULL, NULL, NULL}
};
void ICACHE_FLASH_ATTR WebInit() {
httpdInit(builtInUrls, 80);
}
CGI scripts are programs running on web server that generates web pages dynamically due to client request.
To answer some of this client requests, we need to implement several custom CGI scripts:
static char * g_web_index = {
static char * g_web_index_formated = NULL;
typedef struct {
int arrayPos;
char buff[128];
} LongPageSendState;
bool g_ledState = false;
int ICACHE_FLASH_ATTR cgiIndex(HttpdConnData *connData) {
LongPageSendState *state= (LongPageSendState *)connData->cgiData;
int len;
if (connData->conn==NULL) {
if (state!=NULL) os_free(state);
if(g_web_index_formated) {
os_free(g_web_index_formated);
g_web_index_formated = NULL;
}
return HTTPD_CGI_DONE;
}
if (state == NULL) {
state= (LongPageSendState *)os_malloc(sizeof(LongPageSendState));
g_web_index_formated = (char *)os_malloc(sizeof(g_web_index) + 10);
connData->cgiData=state;
state->arrayPos= 0;
state->buff[0] = 0;
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/html");
httpdEndHeaders(connData);
}
os_sprintf(g_web_index_formated, g_web_index, g_ledState ? "ON" : "OFF");
len = os_strlen(g_web_index_formated) - state->arrayPos;
if (len>128) len=128;
if (len==0) {
os_free(state);
os_free(g_web_index_formated);
g_web_index_formated = NULL;
return HTTPD_CGI_DONE;
}
for(int i = 0; i < len; i++){
state->buff[i] = g_web_index_formated[i + state->arrayPos];
}
httpdSend(connData, state->buff, len);
state->arrayPos+=len;
if (len == 128) {
return HTTPD_CGI_MORE;
} else {
os_free(state);
os_free(g_web_index_formated);
g_web_index_formated = NULL;
return HTTPD_CGI_DONE;
}
}
int ICACHE_FLASH_ATTR cgiOnButton(HttpdConnData *connData){
g_ledState = true;
ioLed(1);
return cgiRedirect(connData);
}
int ICACHE_FLASH_ATTR cgiOffButton(HttpdConnData *connData){
g_ledState = false;
ioLed(0);
return cgiRedirect(connData);
}
And our web page HTML code will look like this:
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:">
<style>html { text-align: center;} </style></head>
<body><h1>ESP8266 Web Server</h1>
<p>GPIO 5 - State %s</p>
<p><a href="onButton"><button class="button">ON</button></a></p>
<p><a href="offButton"><button class="button">OFF</button></a></p>
</body></html>
Converting Web to Binary Format
To convert HTML page to C++ code, I have used a utility that receives HTML file path as command line argument.
Usage:
BinToCArray.exe index.html
And the output looks like this:
The source code of this utility is pretty simple:
int main(int argc, char** argv) {
assert(argc == 2);
char* fn = argv[1];
FILE* f = fopen(fn, "r");
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
printf("char a[%ld] = {\n", size );
unsigned long n = 0;
while (!feof(f)) {
unsigned char c;
if (fread(&c, 1, 1, f) == 0) break;
printf("0x%.2X,", (int)c);
++n;
if (n % 10 == 0) printf("\n");
}
fclose(f);
printf("};\n");
}
By doing this, we can store our web pages in ESP8266 RAM. As an alternative, I suggest you write it into the header file and include it into the module where it is used.
How to Build and Flash
- In Eclipse, select File -> Import -> General -> Existing Project into Workspace, in the line Select root directory, select project root directory and import it.
- To build project, select Project -> Build Project on Menu Bar.
- To flash the ESP8266, go to project folder on Make Target view and build "flash" target.
- You will need USB-3.3V UART adapter, there's plenty on the market available for a few bucks.
- Before flashing, make sure GPIO0 is tied to ground and reset the chip (power cycle), disconnect from ground after flashing.
How to Use
If flashed correctly, the module will bring up access point called iqhub56, connect to it using any mobile phone and open web address: http://192.168.4.1. You will see small webpage where you will be able to control pin output. Here is a small video showing how this device works:
History
- 6th August, 2018 - First version