Android app for remote control

 

This app can be used together with Arduino, ESP8266, Raspberry pi and many other modules where you require to send/receive data via WiFi.  By pressing an on or off button on the main screen the app will send the data specified in the settings tab to your module. Your Arduino, ESP8266, Raspberry pi can use this data to enable or disable any device like (home) lamps, televisions, modems, camera’s etc.

In the settings tab you can set up a destination IP address and port number to send data after you pressed a button on the main screen. In the settings tab you can predefine the transmitting data corrosponding to a button. After pressing the button the predefined data will be send to your module and can be handled there to activate led’s, lamps, televisions, fan’s or anything your project requires.

If the module sends the same data back to this app the app will detect this and change the status on the mainscreen. This is to make sure your module has a way to confirm the required action is done completely by the module.

The Android remote buttons app can be downloaded here.

The Atmega328 code

The software is a simplefied version of the software in my last blog. The last software “web server” was a bit more complicated, because a browser sends around 500 byters on average and thats a lot for this microcontroller. The Android app only sends around 50 bytes, depending what text you predefine. In the last blog I tried to keep the buffer small and therefor I had to programm some bufferoverflow corrections and thats not needed for this project. Besides that, a web page had to be send by the microcontroller to the web browser and that also takes a lot of bytes. With the Android app we only have to send about 50 bytes, again depending on the predefined text.

The working is simple. The ESP8266 waits for an incoming TCP/IP message send by the Android app. The ESP8266 passes this message to the microcontroller. The microcontroller checks if the incoming message match with some predefined values. If not it discarge the message. If it matches a led will be triggered and a message will appear on the lcd. After that the received message will be send back to the ESP8862 via the UART and the ESP8266 will convert it to TCP/IP and sends it back to the Android app. This whole loop just continues for ever. Download the full code for the microcontroller here and see the main changes compared to the framework below.

Application1.c

/*
 * application1.c
 *
 * Created: 8-2-2018 15:07:22
 * Author: HdH
 * Description: webserver controlling 4 outputs.
 */

#define F_CPU 16000000UL // 16 MHz clock speed for delay.h
#define PIN_LED1 10
#define PIN_LED2 9
#define PIN_LED3 6
#define PIN_LED4 8

#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "gpiolib.h"
#include "i2cdisplay.h"
#include "esp8266.h"



/****************************************************************************
	Bit and byte definitions
****************************************************************************/


extern int alarmCode;


void Application1(void){

uint8_t p;

	p = readInComing(0, NULL); // Checking incoming uart data
	switch (p){
	
		case BTN1RCVDON:
			writeI2cDisplayLine("Button1 on pressed",0,1);
			writePin(PIN_LED1, HIGH);
			esp8266_send(BTN1ONTEXT);
			resetIncoming();
			break;
		case BTN1RCVDOFF:
			writeI2cDisplayLine("Button1 off pressed",0,1);
			writePin(PIN_LED1, LOW);
			esp8266_send(BTN1OFFTEXT);
			resetIncoming();
			break;
		case BTN2RCVDON:
			writeI2cDisplayLine("Button2 on pressed",0,1);
			writePin(PIN_LED2, HIGH);
			esp8266_send(BTN2ONTEXT);
			resetIncoming();
			break;
		case BTN2RCVDOFF:
			writeI2cDisplayLine("Button2 off pressed",0,1);
			writePin(PIN_LED2, LOW);
			esp8266_send(BTN2OFFTEXT);
			resetIncoming();
			break;
		case BTN3RCVDON:
			writeI2cDisplayLine("Button3 on pressed",0,1);
			writePin(PIN_LED3, HIGH);
			esp8266_send(BTN3ONTEXT);
			resetIncoming();
			break;
		case BTN3RCVDOFF:
			writeI2cDisplayLine("Button3 off pressed",0,1);
			writePin(PIN_LED3, LOW);
			esp8266_send(BTN3OFFTEXT);
			resetIncoming();
			break;
		case BTN4RCVDON:
			writeI2cDisplayLine("Button4 on pressed",0,1);
			writePin(PIN_LED4, HIGH);
			esp8266_send(BTN4ONTEXT);
			resetIncoming();
			break;
		case BTN4RCVDOFF:
			writeI2cDisplayLine("Button4 off pressed",0,1);
			writePin(PIN_LED4, LOW);
			esp8266_send(BTN4OFFTEXT);
			resetIncoming();
			break;
			
		default:
			break;
	}
}

Esp8266.h

/*
 * esp8266.h
 *
 * Created: 8-2-2018 21:08:06
 *  Author: acer
 */ 


#ifndef ESP8266_H_
#define ESP8266_H_

//#define GETRECEIVED 1
#define USERDEFINEDRECEIVED 2
#define BTN1RCVDON 3
#define BTN1RCVDOFF 4
#define BTN2RCVDON 5
#define BTN2RCVDOFF 6
#define BTN3RCVDON 7
#define BTN3RCVDOFF 8
#define BTN4RCVDON 9
#define BTN4RCVDOFF 10
#define NOTHINGSET 11

#define BTN1ONTEXT "lamp on"
#define BTN1OFFTEXT "lamp off"
#define BTN2ONTEXT "tv on"
#define BTN2OFFTEXT "tv off"
#define BTN3ONTEXT "cam on"
#define BTN3OFFTEXT "cam off"
#define BTN4ONTEXT "fan on"
#define BTN4OFFTEXT "fan off"

void esp8266_init(void);
bool esp8266_send(const char* text1);
uint8_t readInComing(int timeout, const char* text1);
void resetIncoming(void);
uint8_t checkIncomingFlag(void);
char* getIP(void);

extern unsigned long int msCounter;
struct RcvFlag rcvFlag1;

struct RcvFlag {
	bool userDefinedReceived;
	bool btn1RcvdOn;
	bool btn1RcvdOff;
	bool btn2RcvdOn;
	bool btn2RcvdOff;
	bool btn3RcvdOn;
	bool btn3RcvdOff;
	bool btn4RcvdOn;
	bool btn4RcvdOff;
};


#endif /* ESP8266_H_ */

Esp8266.c

/*
 * esp8266.c
 *
 * Created: 8-2-2018 21:07:55
 *  Author: acer
 */ 

#define F_CPU 16000000UL // 16 MHz clock speed

#include <avr/io.h>
#include <util/delay.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include "timer4clocklib.h"
#include "i2cdisplay.h"
#include "uart.h"
#include "esp8266.h"



/****************************************************************************
	esp8266_init(), initialize the esp8266
****************************************************************************/
void esp8266_init(){
	
	uint8_t p;
	
	// Check the status of the ESP8266 if not ok reset
	_delay_ms(500);
	serialWrite("AT", CRLF);
	p = readInComing(1000, "OK\r\n");
	if (p != 2){
		writeI2cDisplayLine("Reset needed!", 0, 1);
		_delay_ms(4000);
		serialWrite("AT+RST", CRLF);
		p = readInComing(3000, "OK\r\n");
		if (p == 2){
			writeI2cDisplayLine("Reset done OK!", 0, 1);
			_delay_ms(1000);
		}
	}
	else{
		writeI2cDisplayLine("ESP8266 conn. OK", 0, 1);
		_delay_ms(1000);
	}
	
	// reset all flags generated by incoming data from the ESP8266 and empty the buffer.
	resetIncoming();
	
	
	// configure the server and activate the server on the ESP8266
	serialWrite("AT+CIPMUX=1", CRLF);
	p = readInComing(1000, "OK\r\n");
	if (p == 2){
		resetIncoming();
		writeI2cDisplayLine("AT+CIPMUX=1 set", 0, 1);
		_delay_ms(1000);
		serialWrite("AT+CIPSERVER=1,80", CRLF); //\r\n
		p = readInComing(1000, "OK\r\n");
		if (p == 2){
			resetIncoming();
			writeI2cDisplayLine("AT+CIPSERVER set", 0, 1);
		}
	}
	
	// init is done so clean up all flags again.
	resetIncoming();
}

/****************************************************************************
	esp8266_send, send uart data to the esp8266
****************************************************************************/
bool esp8266_send(const char* text1){
	
	int p;
	int textLength;
	char buf1[50] = {'\0'};
	char itoaBuf[3];


	if (text1 != NULL){
		strcpy(buf1, (char *) text1);
		textLength = strlen(buf1);
	}
	else{
		textLength = 0;
	}
	
	// the esp8266 requires the amount of bytes that will be send in chars.
	itoa(textLength+2, itoaBuf ,10);
	serialWrite("AT+CIPSEND=0,", NO_EOL);
	serialWrite(itoaBuf, CRLF);
	
	// the data is send wait on the esp8266 for a confirmation
	resetIncoming();
	p = readInComing(1000, "OK\r\n");
	if (p == 2){
		resetIncoming();
		writeI2cDisplayLine(buf1,0,2);
		serialWrite(buf1, CRLF);
		p = readInComing(500, "SEND OK\r\n");
		if (p == 2){
			resetIncoming();
			return true;
		}
		else{
			return false;
		}
	}
	else{
		return false;
	}
		
}

/****************************************************************************
	checkInComing, check/read data received by the esp8266
****************************************************************************/
uint8_t readInComing(int timeOut, const char* text1){ // ipv int
	
	char buf1[30] = {'\0'};
	uint8_t flag;
	
	uint8_t p; //unsigned char p;
	
	uint8_t lengthUsrDef;
	uint8_t lengthBtn1On, lengthBtn1Off, lengthBtn2On, lengthBtn2Off, lengthBtn3On, lengthBtn3Off, lengthBtn4On, lengthBtn4Off;
	
	uint8_t posUsrDef = 0;
	uint8_t posBtn1On = 0;
	uint8_t posBtn1Off = 0;
	uint8_t posBtn2On = 0;
	uint8_t posBtn2Off = 0;
	uint8_t posBtn3On = 0;
	uint8_t posBtn3Off = 0;
	uint8_t posBtn4On = 0;
	uint8_t posBtn4Off = 0;
	
	lengthBtn1On = strlen(BTN1ONTEXT);
	lengthBtn1Off = strlen(BTN1OFFTEXT);
	lengthBtn2On = strlen(BTN2ONTEXT);
	lengthBtn2Off = strlen(BTN2OFFTEXT);
	lengthBtn3On = strlen(BTN3ONTEXT);
	lengthBtn3Off = strlen(BTN3OFFTEXT);
	lengthBtn4On = strlen(BTN4ONTEXT);
	lengthBtn4Off = strlen(BTN4OFFTEXT);
	
	
	if (text1 != NULL){
		strcpy(buf1, (char *) text1);
		lengthUsrDef = strlen(buf1);
	}
	else{
		lengthUsrDef = 0;
	}
	
	flag = checkIncomingFlag();			
	if (flag != NOTHINGSET){
		return flag;
	}

	
	if(timeOut != 0){ // user gives predefined time
		unsigned long stop = msCounter + timeOut;
		do{
			p = getChar();
			while (p != 0x0){
				
				posUsrDef = (p == buf1[posUsrDef]) ? posUsrDef + 1 : 0;
				if (lengthUsrDef > 0 && posUsrDef == lengthUsrDef){ // user defined
					rcvFlag1.userDefinedReceived = true;
					return USERDEFINEDRECEIVED;
				}
				p = getChar();
			}
		}while (msCounter < stop); } else if(timeOut == 0){ // if no time out set, used in the app to continuously check for incoming data p = getChar(); while (p != 0){ posUsrDef = (p == buf1[posUsrDef]) ? posUsrDef + 1 : 0; posBtn1On = (p == BTN1ONTEXT[posBtn1On]) ? posBtn1On + 1 : 0; posBtn1Off = (p == BTN1OFFTEXT[posBtn1Off]) ? posBtn1Off + 1 : 0; posBtn2On = (p == BTN2ONTEXT[posBtn2On]) ? posBtn2On + 1 : 0; posBtn2Off = (p == BTN2OFFTEXT[posBtn2Off]) ? posBtn2Off + 1 : 0; posBtn3On = (p == BTN3ONTEXT[posBtn3On]) ? posBtn3On + 1 : 0; posBtn3Off = (p == BTN3OFFTEXT[posBtn3Off]) ? posBtn3Off + 1 : 0; posBtn4On = (p == BTN4ONTEXT[posBtn4On]) ? posBtn4On + 1 : 0; posBtn4Off = (p == BTN4OFFTEXT[posBtn4Off]) ? posBtn4Off + 1 : 0; if (lengthUsrDef > 0 && posUsrDef == lengthUsrDef){ // user defined
				rcvFlag1.userDefinedReceived = true;
				return USERDEFINEDRECEIVED;
			}
			if (lengthBtn1On > 0 && posBtn1On == lengthBtn1On){ // button 1 on
				rcvFlag1.btn1RcvdOn = true;
				return BTN1RCVDON;
			}
			if (lengthBtn1Off > 0 && posBtn1Off == lengthBtn1Off){ // button 1 off
				rcvFlag1.btn1RcvdOff = true;
				return BTN1RCVDOFF;
			}
			if (lengthBtn2On > 0 && posBtn2On == lengthBtn2On){ // button 2 on
				rcvFlag1.btn2RcvdOn = true;
				return BTN2RCVDON;
			}
			if (lengthBtn2Off > 0 && posBtn2Off == lengthBtn2Off){ // button 2 off
				rcvFlag1.btn2RcvdOff = true;
				return BTN2RCVDOFF;
			}
			if (lengthBtn3On > 0 && posBtn3On == lengthBtn3On){ // button 3 on
				rcvFlag1.btn3RcvdOn = true;
				return BTN3RCVDON;
			}
			if (lengthBtn3Off > 0 && posBtn3Off == lengthBtn3Off){ // button 3 off
				rcvFlag1.btn3RcvdOff = true;
				return BTN3RCVDOFF;
			}
			if (lengthBtn4On > 0 && posBtn4On == lengthBtn4On){ // button 4 on
				rcvFlag1.btn4RcvdOn = true;
				return BTN4RCVDON;
			}
			if (lengthBtn4Off > 0 && posBtn4Off == lengthBtn4Off){ // button 4 off
				rcvFlag1.btn4RcvdOff = true;
				return BTN4RCVDOFF;
			}
			
			p = getChar();
		}
	}
		
	return NOTHINGSET;
}

/****************************************************************************
	checkIncomingFlag, check the current status of what message is received at last
****************************************************************************/
uint8_t checkIncomingFlag(){
	

	if(rcvFlag1.userDefinedReceived == true){
		return USERDEFINEDRECEIVED;
	}
	
	else if(rcvFlag1.btn1RcvdOn == true){
		return BTN1RCVDON;
	}
	
	else if(rcvFlag1.btn1RcvdOff == true){
		return BTN1RCVDOFF;
	}
	
	else if(rcvFlag1.btn2RcvdOn == true){
		return BTN2RCVDON;
	}
	
	else if(rcvFlag1.btn2RcvdOff == true){
		return BTN2RCVDOFF;
	}
	
	else if(rcvFlag1.btn3RcvdOn == true){
		return BTN3RCVDON;
	}
	
	else if(rcvFlag1.btn3RcvdOff == true){
		return BTN3RCVDOFF;
	}
	
	else if(rcvFlag1.btn4RcvdOn == true){
		return BTN4RCVDON;
	}
	
	else if(rcvFlag1.btn4RcvdOff == true){
		return BTN4RCVDOFF;
	}
	else{
		return NOTHINGSET;
	}
}

/****************************************************************************
	resetIncoming, reset all flags to prepare for the next expected data from the esp8266
****************************************************************************/

void resetIncoming(){
	
	rcvFlag1.userDefinedReceived  = false;
	rcvFlag1.btn1RcvdOn = false;
	rcvFlag1.btn1RcvdOff = false;
	rcvFlag1.btn2RcvdOn = false;
	rcvFlag1.btn2RcvdOff = false;
	rcvFlag1.btn3RcvdOn = false;
	rcvFlag1.btn3RcvdOff = false;
	rcvFlag1.btn4RcvdOn = false;
	rcvFlag1.btn4RcvdOff = false;
}


/****************************************************************************
	getIP, just to know the IP as i forgot to make it static instead of dhcp...
****************************************************************************/

char* getIP(){
	
	uint8_t p;
	int posIpReceived = 0;
	char matchStaip[] = "STAIP,\"";
	int ipCharsCounter = 0;
	int staIpLength = strlen(matchStaip);
	static char tempBuffer[16];
	bool matched = false;
	
	serialWrite("AT+CIFSR", CRLF);
	_delay_ms(200); // wait for all the data from this cmd
	p = getChar();
	while (p != 0x0){
		
		if(p == matchStaip[posIpReceived]){
			posIpReceived++;
		}
		else{
			posIpReceived = 0;
		}
		
		if (staIpLength > 0 && posIpReceived == staIpLength){ // STAIP received
			matched = true;
		}
		
		if(matched == true){
			tempBuffer[ipCharsCounter] = p;
			ipCharsCounter++;
			if (ipCharsCounter > 16){
				ipCharsCounter = 0;
				matched = false;
				return tempBuffer;
			}
			
		}
		p = getChar();
	}
	
	return NULL;
	
}

Uart.h

/*
 * uart.h
 *
 * Created: 8-12-2017 13:36:22
 *  Author: acer
 */


#ifndef UART_H_
#define UART_H_

/****************************************************************************
	Bit and byte definitions
****************************************************************************/
#define CLOCKSPEED_CPU   16000000
#define BAUD    57600
#define BRC     ((CLOCKSPEED_CPU/16/BAUD) - 1)
#define TX_BUFFER_SIZE  40
#define RX_BUFFER_SIZE  200 // it's a bit big because of the CIFSR cmd returns a lot of bytes used in getIp()
#define CR 1
#define LF 2
#define CRLF 3
#define NO_EOL 4



/****************************************************************************
	Function definitions
****************************************************************************/

void UART_Init();
void serialWrite(char c[], uint8_t eol);
void UART_Transmit(unsigned char data );
char getChar(void);


#endif /* UART_H_ */

Uart.c

/*
 * uart.c
 *
 * Created: 8-12-2017 13:36:09
 *  Author: acer
 */ 

#define F_CPU 16000000UL // 16 MHz clock speed


#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdbool.h>
#include "uart.h"


/****************************************************************************
	Bit and byte definitions
****************************************************************************/
char rxBuffer[RX_BUFFER_SIZE];
uint8_t rxWritePos = 0;
uint8_t rxReadPos = 0;


/****************************************************************************
	USART_Init, see important info below
****************************************************************************/
void UART_Init(){

	UBRR0H = (unsigned char)(BRC >> 8); //baud rate register set to 9600 BAUD
	UBRR0L = (unsigned char) BRC;

	UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1 << RXCIE0);
	UCSR0C = (1 << UCSZ01) | (3<<UCSZ00);
}


/****************************************************************************
	serialWrite, send data with optional crlf
****************************************************************************/
void serialWrite(char c[], uint8_t eol)
{
	int i;
	
	for(i = 0; i < strlen(c); i++)// put the string you want to write in a buffer. { UART_Transmit(c[i]); //put the char's one by one in the buffer } if (eol == CR){ UART_Transmit(0xd); //CR \r } else if (eol == LF){ UART_Transmit(0xa); //LF \n } else if (eol == CRLF){ UART_Transmit(0xd); //CR \r UART_Transmit(0xa); //LF \n } else if (eol == NO_EOL){ return; } } /**************************************************************************** ISR(USART_RX_vect), Fills up a buffer. ****************************************************************************/ ISR(USART_RX_vect) { rxBuffer[rxWritePos] = UDR0;// rxWritePos++; if(rxWritePos >= RX_BUFFER_SIZE)
	{
		rxWritePos = 0;
	}

}

/****************************************************************************
	USART_Transmit, 
****************************************************************************/
void UART_Transmit(unsigned char data ){
	
	while( !( UCSR0A & (1<<UDRE0)) ); // Wait for empty transmit buffer UDR0 = data; // Put data into buffer, sends the data } /**************************************************************************** getChar, ****************************************************************************/ char getChar(void) { char ret = '\0'; _delay_us(500); // to prevent reading faster then the bytes are coming in if(rxReadPos != rxWritePos) { ret = rxBuffer[rxReadPos]; rxReadPos++; if(rxReadPos >= RX_BUFFER_SIZE)//
		{
			rxReadPos = 0;
		}
	}
	
	return ret;
}

 

Thanks for reading!

Programming an IoT webserver

 

In this project I build a webserver with the ESP8266 as the interface between the TCP/IP protocol and the Atmega328 microcontroller. The interesting part is that both parts are very cheap and that makes it a practical way to connect home devices to the internet. It’s a bit basic now with only a few buttons to turn 4 led’s on or off via a webpage, but the led’s can be replaced with relay’s and a proper current driver for the relays. Then it will be possible to control all your home equipment remotely from any location in the world with an internet connection.

The hardware setup

In the schematic I removed the connection details of the lcd display to get the schematic on 1 page. In this blog you can find these connections. Keep in mind that the logic level converter and ESP8266 requires 3.3V instead of 5V.

Schematic esp8266 with the Atmega328p

 

The software

I preconfigured the esp8266 in my last blog with the settings that will not change like the ssid and WiFi password and the baudrate. All other settings are set in the esp8266_init() function in the esp8266 library. This library also contains a function to send data to the esp. The esp requires a noticiation of the amount of bytes that are going to be send and after an ok is received by the microcontroller the bytes can be send so just sending with the uart send function doesn’t work.

The basic working of the program is text getting send to the esp by an internet browser. The microcontroller reads it and checks it against some predefined text. If it matches then the display will show this and a GPIO gets turned on or off.

Because I only have 2Kb of data memory and a basic page with 8 buttons takes a lot of bytes, i used the PROGMEM macro to save the page in the program memory, because i have enough free space there.

The incoming UART data gets automatically saved via interrupts. To save some space I used a smaller buffer then the actual bytes that get send by an web browser. For this project only the first ca. 50 bytes send by the browser are interesting, because these bytes tells which button is pressed. So the rest of the bytes will not be used and a buffer overflow var is set. After the incoming message is handelled the buffer overflow can be reset by the flushBuffer function.

Download the full code here or have a look below.

esp8266.h

/*
 * esp8266.h
 *
 * Created: 8-2-2018 21:08:06
 *  Author: acer
 */ 


#ifndef ESP8266_H_
#define ESP8266_H_

#define GETRECEIVED 1
#define USERDEFINEDRECEIVED 2
#define BTN1RCVDON 3
#define BTN1RCVDOFF 4
#define BTN2RCVDON 5
#define BTN2RCVDOFF 6
#define BTN3RCVDON 7
#define BTN3RCVDOFF 8
#define BTN4RCVDON 9
#define BTN4RCVDOFF 10
#define NOTHINGSET 11



void esp8266_init(void);
bool esp8266_send(const char* text1);
uint8_t readInComing(int timeout, const char* text1);
void resetIncoming(void);
uint8_t checkIncomingFlag(void);
char* getIP(void);

extern unsigned long int msCounter;
struct RcvFlag rcvFlag1;

struct RcvFlag {
	bool getReceived;
	bool userDefinedReceived;
	bool btn1RcvdOn;
	bool btn1RcvdOff;
	bool btn2RcvdOn;
	bool btn2RcvdOff;
	bool btn3RcvdOn;
	bool btn3RcvdOff;
	bool btn4RcvdOn;
	bool btn4RcvdOff;
};


#endif /* ESP8266_H_ */

esp8266.c

/*
 * esp8266.c
 *
 * Created: 8-2-2018 21:07:55
 *  Author: acer
 */ 

#define F_CPU 16000000UL // 16 MHz clock speed

#include <avr/io.h>
#include <util/delay.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include "timer4clocklib.h"
#include "i2cdisplay.h"
#include "uart.h"
#include "esp8266.h"

/****************************************************************************
	Bit and byte definitions
****************************************************************************/

char getReceived[] = "GET / HTTP/1.1";
char btn1RcvdOn[] = "GET /?p1=on HTTP/1.1";
char btn1RcvdOff[] = "GET /?p1=off HTTP/1.1";
char btn2RcvdOn[] = "GET /?p2=on HTTP/1.1";
char btn2RcvdOff[] = "GET /?p2=off HTTP/1.1";
char btn3RcvdOn[] = "GET /?p3=on HTTP/1.1";
char btn3RcvdOff[] = "GET /?p3=off HTTP/1.1";
char btn4RcvdOn[] = "GET /?p4=on HTTP/1.1";
char btn4RcvdOff[] = "GET /?p4=off HTTP/1.1";

/****************************************************************************
	esp8266_init(), initialize the esp8266
****************************************************************************/
void esp8266_init(){
	
	uint8_t p;
	
	// Check the status of the ESP8266 if not ok reset
	_delay_ms(500);
	serialWrite("AT", CRLF);
	p = readInComing(1000, "OK\r\n");
	if (p != 2){
		writeI2cDisplayLine("Reset needed!", 0, 1);
		_delay_ms(1000);
		serialWrite("AT+RST", CRLF);
		p = readInComing(2000, "OK\r\n");
		if (p == 2){
			writeI2cDisplayLine("Reset done OK!", 0, 1);
			_delay_ms(1000);
		}
	}
	else{
		writeI2cDisplayLine("ESP8266 conn. OK", 0, 1);
		_delay_ms(1000);
	}
	
	// reset all flags generated by incoming data from the ESP8266 and empty the buffer.
	resetIncoming();
	flushBuffer();
	
	// configure the server and activate the server on the ESP8266
	serialWrite("AT+CIPMUX=1", CRLF);
	p = readInComing(1000, "OK\r\n");
	if (p == 2){
		resetIncoming();
		flushBuffer();
		writeI2cDisplayLine("AT+CIPMUX=1 set", 0, 1);
		_delay_ms(1000);
		serialWrite("AT+CIPSERVER=1,80", CRLF); //\r\n
		p = readInComing(1000, "OK\r\n");
		if (p == 2){
			resetIncoming();
			writeI2cDisplayLine("AT+CIPSERVER set", 0, 1);
			//_delay_ms(1000);
		}
	}
	
	// init is done so clean up all flags again.
	resetIncoming();
}

/****************************************************************************
	esp8266_send, send uart data to the esp8266
****************************************************************************/
bool esp8266_send(const char* text1){
	
	int p;
	int textLength;
	char buf1[700] = {'\0'};
	char itoaBuf[3];

	// the PROGMEM memory for saving the data memory usage.
	if (text1 != NULL){
		strcpy_P(buf1, (char *) text1);
		textLength = strlen(buf1);
	}
	else{
		textLength = 0;
	}
	
	// the esp8266 requires the amount of bytes that will be send in chars.
	itoa(textLength+2, itoaBuf ,10);
	serialWrite("AT+CIPSEND=0,", NO_EOL);
	serialWrite(itoaBuf, CRLF);
	
	// the data is send wait on the esp8266 for a confirmation
	p = readInComing(1000, "OK\r\n");
	if (p == 2){
		resetIncoming();
		flushBuffer();
		serialWrite(buf1, CRLF);
		p = readInComing(500, "SEND OK\r\n");
		if (p == 2){
			resetIncoming();
			flushBuffer();
			return true;
		}
		else{
			return false;
		}
	}
	else{
		return false;
	}
		
}

/****************************************************************************
	checkInComing, check/read data received by the esp8266
****************************************************************************/
uint8_t readInComing(int timeOut, const char* text1){ // ipv int
	
	char buf1[30] = {'\0'};
	uint8_t flag;
	
	uint8_t p; //unsigned char p;
	
	uint8_t lengthGetRcvd;
	uint8_t lengthUsrDef;
	uint8_t lengthBtn1On, lengthBtn1Off, lengthBtn2On, lengthBtn2Off, lengthBtn3On, lengthBtn3Off, lengthBtn4On, lengthBtn4Off;
	
	
	uint8_t posGetRcvd = 0;
	uint8_t posUsrDef = 0;
	uint8_t posBtn1On = 0;
	uint8_t posBtn1Off = 0;
	uint8_t posBtn2On = 0;
	uint8_t posBtn2Off = 0;
	uint8_t posBtn3On = 0;
	uint8_t posBtn3Off = 0;
	uint8_t posBtn4On = 0;
	uint8_t posBtn4Off = 0;
	
	lengthGetRcvd = strlen(getReceived);
	lengthBtn1On = strlen(btn1RcvdOn);
	lengthBtn1Off = strlen(btn1RcvdOff);
	lengthBtn2On = strlen(btn2RcvdOn);
	lengthBtn2Off = strlen(btn2RcvdOff);
	lengthBtn3On = strlen(btn3RcvdOn);
	lengthBtn3Off = strlen(btn3RcvdOff);
	lengthBtn4On = strlen(btn4RcvdOn);
	lengthBtn4Off = strlen(btn4RcvdOff);
	
	
	
	if (text1 != NULL){
		strcpy(buf1, (char *) text1);
		lengthUsrDef = strlen(buf1);
	}
	else{
		lengthUsrDef = 0;
	}
	
	flag = checkIncomingFlag();			
	if (flag != NOTHINGSET){
		return flag;
	}

	
	if(timeOut != 0){ // user gives predefined time
		unsigned long stop = msCounter + timeOut;
		do{
			p = getChar();
			while (p != 0x0){
				
				posUsrDef = (p == buf1[posUsrDef]) ? posUsrDef + 1 : 0;
				if (lengthUsrDef > 0 && posUsrDef == lengthUsrDef){ // user defined
					rcvFlag1.userDefinedReceived = true;
					return USERDEFINEDRECEIVED;
				}
				p = getChar();
			}
		}while (msCounter < stop); } else if(timeOut == 0){ // if no time out set, used in the app to continuously check for incoming data p = getChar(); while (p != 0){ //writeI2cDisplay(p, DATAREGISTER); posGetRcvd = (p == getReceived[posGetRcvd]) ? posGetRcvd + 1 : 0; posUsrDef = (p == buf1[posUsrDef]) ? posUsrDef + 1 : 0; posBtn1On = (p == btn1RcvdOn[posBtn1On]) ? posBtn1On + 1 : 0; posBtn1Off = (p == btn1RcvdOff[posBtn1Off]) ? posBtn1Off + 1 : 0; posBtn2On = (p == btn2RcvdOn[posBtn2On]) ? posBtn2On + 1 : 0; posBtn2Off = (p == btn2RcvdOff[posBtn2Off]) ? posBtn2Off + 1 : 0; posBtn3On = (p == btn3RcvdOn[posBtn3On]) ? posBtn3On + 1 : 0; posBtn3Off = (p == btn3RcvdOff[posBtn3Off]) ? posBtn3Off + 1 : 0; posBtn4On = (p == btn4RcvdOn[posBtn4On]) ? posBtn4On + 1 : 0; posBtn4Off = (p == btn4RcvdOff[posBtn4Off]) ? posBtn4Off + 1 : 0; if (lengthGetRcvd > 0 && posGetRcvd == lengthGetRcvd){ // "GET / HTTP/1.1"
				rcvFlag1.getReceived = true;
				return 1;
			}
			if (lengthUsrDef > 0 && posUsrDef == lengthUsrDef){ // user defined
				rcvFlag1.userDefinedReceived = true;
				return 2;
			}
			if (lengthBtn1On > 0 && posBtn1On == lengthBtn1On){ // button 1 on
				rcvFlag1.btn1RcvdOn = true;
				return 3;
			}
			if (lengthBtn1Off > 0 && posBtn1Off == lengthBtn1Off){ // button 1 off
				rcvFlag1.btn1RcvdOff = true;
				return 4;
			}
			if (lengthBtn2On > 0 && posBtn2On == lengthBtn2On){ // button 2 on
				rcvFlag1.btn2RcvdOn = true;
				return 5;
			}
			if (lengthBtn2Off > 0 && posBtn2Off == lengthBtn2Off){ // button 2 off
				rcvFlag1.btn2RcvdOff = true;
				return 6;
			}
			if (lengthBtn3On > 0 && posBtn3On == lengthBtn3On){ // button 3 on
				rcvFlag1.btn3RcvdOn = true;
				return 7;
			}
			if (lengthBtn3Off > 0 && posBtn3Off == lengthBtn3Off){ // button 3 off
				rcvFlag1.btn3RcvdOff = true;
				return 8;
			}
			if (lengthBtn4On > 0 && posBtn4On == lengthBtn4On){ // button 4 on
				rcvFlag1.btn4RcvdOn = true;
				return 9;
			}
			if (lengthBtn4Off > 0 && posBtn4Off == lengthBtn4Off){ // button 4 off
				rcvFlag1.btn4RcvdOff = true;
				return 10;
			}
			
			p = getChar();
		}
	}
		
	return NOTHINGSET;
}

/****************************************************************************
	checkIncomingFlag, check the current status of what message is received at last
****************************************************************************/
uint8_t checkIncomingFlag(){
	
	
	if(rcvFlag1.getReceived == true){
		return GETRECEIVED;
	}
	else if(rcvFlag1.userDefinedReceived == true){
		return USERDEFINEDRECEIVED;
	}
	
	else if(rcvFlag1.btn1RcvdOn == true){
		return BTN1RCVDON;
	}
	
	else if(rcvFlag1.btn1RcvdOff == true){
		return BTN1RCVDOFF;
	}
	
	else if(rcvFlag1.btn2RcvdOn == true){
		return BTN2RCVDON;
	}
	
	else if(rcvFlag1.btn2RcvdOff == true){
		return BTN2RCVDOFF;
	}
	
	else if(rcvFlag1.btn3RcvdOn == true){
		return BTN3RCVDON;
	}
	
	else if(rcvFlag1.btn3RcvdOff == true){
		return BTN3RCVDOFF;
	}
	
	else if(rcvFlag1.btn4RcvdOn == true){
		return BTN4RCVDON;
	}
	
	else if(rcvFlag1.btn4RcvdOff == true){
		return BTN4RCVDOFF;
	}
	else{
		return NOTHINGSET;
	}
}

/****************************************************************************
	resetIncoming, reset all flags to prepare for the next expected data from the esp8266
****************************************************************************/

void resetIncoming(){
	
	
	rcvFlag1.getReceived = false;
	rcvFlag1.userDefinedReceived  = false;
	rcvFlag1.btn1RcvdOn = false;
	rcvFlag1.btn1RcvdOff = false;
	rcvFlag1.btn2RcvdOn = false;
	rcvFlag1.btn2RcvdOff = false;
	rcvFlag1.btn3RcvdOn = false;
	rcvFlag1.btn3RcvdOff = false;
	rcvFlag1.btn4RcvdOn = false;
	rcvFlag1.btn4RcvdOff = false;
}


/****************************************************************************
	getIP, just to know the IP as i forgot to make it static instead of dhcp...
****************************************************************************/

char* getIP(){
	
	uint8_t p;
	int posIpReceived = 0;
	char matchStaip[] = "STAIP,\"";
	int ipCharsCounter = 0;
	int staIpLength = strlen(matchStaip);
	static char tempBuffer[16];
	bool matched = false;
	
	serialWrite("AT+CIFSR", CRLF);
	_delay_ms(200); // wait for all the data from this cmd
	p = getChar();
	while (p != 0x0){
		
		if(p == matchStaip[posIpReceived]){
			posIpReceived++;
		}
		else{
			posIpReceived = 0;
		}
		
		if (staIpLength > 0 && posIpReceived == staIpLength){ // STAIP received
			matched = true;
		}
		
		if(matched == true){
			tempBuffer[ipCharsCounter] = p;
			ipCharsCounter++;
			if (ipCharsCounter > 16){
				ipCharsCounter = 0;
				matched = false;
				flushBuffer();
				return tempBuffer;
			}
			
		}
		p = getChar();
	}
	
	return NULL;
	
}

application1.c

/*
 * application1.c
 *
 * Created: 8-2-2018 15:07:22
 * Author: HdH
 * Description: webserver controlling 4 outputs.
 */

#define F_CPU 16000000UL // 16 MHz clock speed for delay.h
#define PIN_LED1 10
#define PIN_LED2 9
#define PIN_LED3 6
#define PIN_LED4 8

#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "gpiolib.h"
#include "i2cdisplay.h"
#include "uart.h"
#include "esp8266.h"


void sendPage(void);

/****************************************************************************
	Bit and byte definitions
****************************************************************************/

const char htmlHeader[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Location: /buttons.html\r\nContent-Type: text/html\r\n";
const char htmlPart1[] PROGMEM = "<!DOCTYPE HTML><html><head><title>hdh</title></head><body>

<form method=\"GET\" >
"
"

 GPIO1 <input type=\"submit\" name=\"p1\" value=\"on\"><input type=\"submit\" name=\"p1\" value=\"off\">

"
"

 GPIO2 <input type=\"submit\" name=\"p2\" value=\"on\"><input type=\"submit\" name=\"p2\" value=\"off\">

"
"

 GPIO3 <input type=\"submit\" name=\"p3\" value=\"on\"><input type=\"submit\" name=\"p3\" value=\"off\">

"
"

 GPIO4 <input type=\"submit\" name=\"p4\" value=\"on\"><input type=\"submit\" name=\"p4\" value=\"off\">

"
"</form>


</body></html>\r\n";


extern int alarmCode;


void Application1(void){

uint8_t p;

	p = readInComing(0, NULL); // Checking incoming uart data
	switch (p){
		
		case GETRECEIVED:
			writeI2cDisplayLine("Get received",0,1);
			sendPage();
			break;
		case BTN1RCVDON:
			writeI2cDisplayLine("Button1 on pressed",0,1);
			writePin(PIN_LED1, HIGH);
			sendPage();
			break;
		case BTN1RCVDOFF:
			writeI2cDisplayLine("Button1 off pressed",0,1);
			writePin(PIN_LED1, LOW);
			sendPage();
			break;
		case BTN2RCVDON:
			writeI2cDisplayLine("Button2 on pressed",0,1);
			writePin(PIN_LED2, HIGH);
			sendPage();
			break;
		case BTN2RCVDOFF:
			writeI2cDisplayLine("Button2 off pressed",0,1);
			writePin(PIN_LED2, LOW);
			sendPage();
			break;
		case BTN3RCVDON:
			writeI2cDisplayLine("Button3 on pressed",0,1);
			writePin(PIN_LED3, HIGH);
			sendPage();
			break;
		case BTN3RCVDOFF:
			writeI2cDisplayLine("Button3 off pressed",0,1);
			writePin(PIN_LED3, LOW);
			sendPage();
			break;
		case BTN4RCVDON:
			writeI2cDisplayLine("Button4 on pressed",0,1);
			writePin(PIN_LED4, HIGH);
			sendPage();
			break;
		case BTN4RCVDOFF:
			writeI2cDisplayLine("Button4 off pressed",0,1);
			writePin(PIN_LED4, LOW);
			sendPage();
			break;
			
		default:
			break;
	}
}

void sendPage(){

	flushBuffer();
	resetIncoming();
	
	esp8266_send(htmlHeader);
	esp8266_send(htmlPart1);
	
	serialWrite("AT+CIPCLOSE=5", CRLF);
	
}

uart.h

/*
 * uart.h
 *
 * Created: 8-12-2017 13:36:22
 *  Author: acer
 */


#ifndef UART_H_
#define UART_H_

/****************************************************************************
	Bit and byte definitions
****************************************************************************/
#define CLOCKSPEED_CPU   16000000
#define BAUD    57600
#define BRC     ((CLOCKSPEED_CPU/16/BAUD) - 1)
#define TX_BUFFER_SIZE  40
#define RX_BUFFER_SIZE  300
#define CR 1
#define LF 2
#define CRLF 3
#define NO_EOL 4



/****************************************************************************
	Function definitions
****************************************************************************/

void UART_Init();
void serialWrite(char c[], uint8_t eol);
void UART_Transmit(unsigned char data );
uint8_t getChar(void);
void flushBuffer(void);


#endif /* UART_H_ */

uart.c

/*
 * uart.c
 *
 * Created: 8-12-2017 13:36:09
 *  Author: acer
 */ 

#define F_CPU 16000000UL // 16 MHz clock speed


#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdbool.h>
#include "uart.h"


/****************************************************************************
	Bit and byte definitions
****************************************************************************/
char rxBuffer[RX_BUFFER_SIZE];
uint8_t rxWritePos = 0;
uint8_t rxReadPos = 0;
bool bufferOverFlow = false;
long bufferOverFlowWaitTime;


/****************************************************************************
	USART_Init, see important info below
****************************************************************************/
void UART_Init(){

	UBRR0H = (unsigned char)(BRC >> 8); //baud rate register set to 9600 BAUD
	UBRR0L = (unsigned char) BRC;

	UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1 << RXCIE0);
	UCSR0C = (1 << UCSZ01) | (3<<UCSZ00);
}


/****************************************************************************
	serialWrite, send data with optional crlf
****************************************************************************/
void serialWrite(char c[], uint8_t eol)
{
	int i; //was uint8
	
	//_delay_us(100);
	for(i = 0; i < strlen(c); i++)// put the string you want to write in a buffer. { UART_Transmit(c[i]); //put the char's one by one in the buffer } if (eol == CR){ UART_Transmit(0xd); //CR \r } else if (eol == LF){ UART_Transmit(0xa); //LF \n } else if (eol == CRLF){ UART_Transmit(0xd); //CR \r UART_Transmit(0xa); //LF \n } else if (eol == NO_EOL){ return; } } /**************************************************************************** ISR(USART_RX_vect), Fills up a buffer, to keep the buffer not to big I used a buffer overflow var in case the buffer exceeds. Internet explorer sends almost 500 bytes. the buffer overflow gets a reset by the flushbuffer function. ****************************************************************************/ ISR(USART_RX_vect) { if(rxWritePos >= RX_BUFFER_SIZE - 1){
		bufferOverFlow = true;
	}
	if (bufferOverFlow == false){
		rxBuffer[rxWritePos+1] = 0x0;
		rxBuffer[rxWritePos] = UDR0;//
		rxWritePos++;
	}
}

/****************************************************************************
	USART_Transmit, 
****************************************************************************/
void UART_Transmit(unsigned char data ){
	
	while( !( UCSR0A & (1<<UDRE0)) ); // Wait for empty transmit buffer
	UDR0 = data; // Put data into buffer, sends the data
}


/****************************************************************************
	getChar, 
****************************************************************************/


uint8_t getChar(void)
{
	uint8_t ret = 0x0;  // '\0';
	
	_delay_us(500); // to prevent reading faster then the bytes are coming in
	if(rxWritePos != 0){
		ret = rxBuffer[rxReadPos];
		rxReadPos++;
		if(ret == 0){ // last byte read, start from the beginning
			flushBuffer();
		}
	}
	return ret;
}


void flushBuffer(void){
	
	for(int i=0; i<RX_BUFFER_SIZE; i++){
		rxBuffer[i] = 0;
	}
	rxWritePos = 0;
	rxReadPos = 0;
	bufferOverFlow = false;
}

 

Even a simple webpage uses relatively a lot of memory when using a microcontroller. To get a better user interface I will make an android application to control the microcontroller instead of a web browser in a later blog. So stay tuned and thanks for reading!

 

ESP8266 IoT programming

ESP8266 WiFi module

The ESP8266 WiFi module converts TCP/IP data to UART. This comes in handy if you want to connect a microcontroller to the internet. This module only costs a few euro’s and has a lot of functionallity. If you are interested in this module then i hope this blog will be usefull and will save you some time setting up the module. I’m planning to create an Android application for my phone to control different devices like lamps, computer, media set, etc, in my house. To get to this I already created a lot of software for the microcontroller (see my other blogs) so now it’s time to explore the ESP8266 and get this module working.

The ESP8266 hardware

There are a few things to keep in mind when you connect the ESP8266 to your computer.

  1. The module needs a lot of current specially when booting up. Use a power supply that can deliver at least 400mA. Symptoms of to less current is a blinking blue led, but you are able to communicate with the module or the unit keeps rebooting.
  2. The ESP8266 requires 3.3V for the rx and tx lines and your computer with rs232 uses about 12V for rx and tx. So make sure you level to the correct voltage, see example below. If you use more then 3.3V on the module it will burn!
  3. The module needs a 3.3V power supply and the microcontroller (Atmegaa328) needs 5V. A voltage regulator is needed at least for the 3.3V power supply and must be able to deliver at least 400mA.
ESP8266 setup
ESP8266 connected to a computer schematic

 

Above is the schematic how to connect the ESP8266 to a computer. Left is the module itself. To get the 3.3V power for the unit I used this  voltage regulator. It can provide 800mA with cooling. In this project no cooling is needed, because the module consumes less then 400mA.  The middle module is a level converter to convert from 3.3V to 5V and vice versa. It is needed for the Atmega328 microcontroller, but for testing and configuring the module on a computer only it is not needed yet and can be by-passed. For later testing it is nice to connect the microcontroller and a computer at the same time to see what is going on, but feel free to leave the logic level converter out for now and connect the ESP8266 directly to the rs232 logic converter. As I don’t have an rs232 port on my laptop I used an USB to rs232 converter.

Communicating with the ESP8266

The ESP8266 comes with different default baudrate settings. The best way to figure out what is the correct baudrate is trying them all… I used TeraTerm client to control and test the module and in my case the baudrate is default 115200 bps. The port number can be found at the device settings so in my case it’s com9.

Select the correct com port.

 

The module requires an “enter” after each AT command. This can be set in the terminal setup by changing the transmit new-line to CR+LF.

Tera term settings
Tera term port settings.

 

There is a complete list with commands for the module available here. For now I will connect the unit to my home WiFi modem and save the settings. After this it will always connect automatically and I don’t have to program the microcontroller to this. Another thing todo is to configure the module as a server and specify a port to listen to, but this will be done my the micrcontroller too so it’s only for testing now.

Commands to set up a permanent WiFi connection

 

AT+GMR – show the current firmware version. Just to check if the communication is working.
AT+CWMODE=3 – set’s the module to “SoftAP+Station mode”.
AT-CWLAP – gives a list with WiFi AP’s in the neighbourhood. I blacked it out a bit for security reasons.
AT+CWJAP_DEF=”TP-LINK_A6A8″,”password” – connects the module to the WiFi and saves the settings in the flash memory.

If a different baud rate is required then use the command “AT+UART_DEF=115200,8,1,0,0” to make it definite and get it saved in the flash memory.

The following configures the module as a server, all though this will be done by the micro controller later on.

Setting up the server.

 

AT-CIPMUX=1 – Enables multiple connections instead of just 1 connection at a time with the module.
AT+CIPSERVER=1,80 – The ‘1’ creates a server and listens to port 80.
AT+CIFSR – shows the ip the module received.

Open a browser and connect to the correct ip (in my case 192.168.0.101)  The module received the text send by the browser so the module works fine.  In the next blog I will connect the esp8266 to a microcontroller and make it possible to control devices via the web browser. Thanks for reading!