Sunspot Home

First experiments with the ESP8266 WiFi board - notes for a bad memory

Objective
- Use these boards to create a network of "internet of things" detectors and actuators
- read greenhouse temperatures, control windows, fans, water solenoids etc

Method
- attach various sensors - publish the data - have my Openwrt Linux master router box process the data and create a website.

Links
There is a mass of confusing data - this chip is causing much excitement!

The most helpful starting point http://www.arduinesp.com/getting-started

I loaded ARDUINO ESP8266 Version 0.41 into WinXP in VMware on OSX Mavericks

My Chinese USB to TTL-RS232 was labeled CTS where the example said RST
It would not do an automatic download.
I used the manual method - but the mini switches would not connect with my pin board and needed soldered wire extensions
So blink worked in the end.

How to get data into my Openwrt box?

First attempt -

UDP client

- from http://www.esp8266.com/viewtopic.php?f=29&t=2451

with a first attempt to send data from the ESP

// Ref : http://www.esp8266.com/viewtopic.php?f=28&t=2295&p=13730#p13730

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

WiFiUDP port;

char packetBuffer[255];
unsigned int localPort = 9999;
int temperature;

void setup() {
Serial.begin(115200);
WiFi.begin("garden", "mypassword");
port.begin(localPort);

}

void loop() {

temperature = 65; \\seems to be sent as a byte


int packetSize = port.parsePacket();
// Serial.println(packetSize);
if (packetSize) {
int len = port.read(packetBuffer, 255);
if (len > 0) packetBuffer[len-1] = 0;
Serial.println(packetBuffer);
port.beginPacket(port.remoteIP(),port.remotePort());

port.write("Your UDP packet was received OK\r\n");
port.write(temperature);
port.write("\r\n");
port.endPacket();
}
delay(500);
}

In a Mac terminal

graham-iMac-4:~ graham$ nc -u 192.168.0.244 9999
hello
Your UDP packet was received OK
A

So the int sent the byte 65 ASCII coding for A

--------------------------------------------

I opened a link to Debian Linux on a Bifferboard router box on my LAN by ssh


graham-iMac-4:~ graham$ ssh root@192.168.0.9

(some code removed)

BiffDeb09:~# nc -u 192.168.0.244 9999
hello
Your UDP packet was received OK
A

So I can get data from the ESP from Debian Linux !!
- also OK on a Debian Joggler

But with Openwrt on NSLU2 busybox nc does not allow -u,
so netcat was installed on top
opkg update - then - opkg install netcat
install was OK but after
nc -u 192.168.0.244 9999
it just returns to the prompt

So I wonder if a Web server on the ESP would be better?

I could wget an ESP web page and then play with the string returned . . .

LETS TRY !!

The very basic webserver below from the examples is modified to send the variable const char* temp = "22.5";
Which I guess could come from a sensor

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

const char* ssid = "garden";
const char* password = "mypassword";

ESP8266WebServer server(80);

const int led = 2;

const char* temp = "22.5";

void handle_root() {
digitalWrite(led, 1);
// server.send(200, "text/plain", "hello from esp8266!");
server.send(200, "text/plain", temp);
delay(100);
digitalWrite(led, 0);
}

void setup(void)
{
Serial.begin(115200);
pinMode(led, OUTPUT);
digitalWrite(led, 0);

// Connect to WiFi network
WiFi.begin(ssid, password);
Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

server.on("/", handle_root);

server.on("/inline", [](){
server.send(200, "text/plain", "this works as well");
});

server.begin();
Serial.println("HTTP server started");
}

void loop(void)
{
server.handleClient();
}

The source of the web page is very minimal ! - it is

22.5

I guess wget could get that !!

Do the same but with a fixed IP address on the LAN

//HelloServerfixedIP-2

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

const char* ssid = "garden";
const char* password = "mypassword";
ESP8266WebServer server(80);

const int led = 2;
const char* temperature;

//-----------------------------------------------------FUNCTIONS
void handle_root()
{
digitalWrite(led, 1);
temperature = "22.5"; //get some data here
server.send(200, "text/plain", temperature);
delay(100);
digitalWrite(led, 0); // flash led while we build a web page
}
//-------------------------------------------------------------

//=========================================================SETUP
void setup(void)
{
Serial.begin(115200);
pinMode(led, OUTPUT);
digitalWrite(led, 0);

// Connect to WiFi network with a fixed address
WiFi.begin(ssid, password);
IPAddress ip(192, 168, 0, 101);
IPAddress gateway(192, 168, 0, 230);
IPAddress subnet(255, 255, 255, 0);
WiFi.config(ip, gateway, subnet);

Serial.println("------------------------------------------------");

// Wait for connection then print to terminal
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

server.on("/", handle_root);

server.begin();
Serial.println("HTTP server started");
}

//=============================================================LOOP
void loop(void)
{
server.handleClient();
}

 

- and the other standard example works - I added a new string

/*
* This sketch demonstrates how to set up a simple HTTP-like server.
* The server will set a GPIO pin depending on the request
* http://server_ip/gpio/0 will set the GPIO2 low,
* http://server_ip/gpio/1 will set the GPIO2 high
* server_ip is the IP address of the ESP8266 module, will be
* printed to Serial when the module is connected.
*/

#include <ESP8266WiFi.h>

const char* ssid = "garden";
const char* password = "mypassword";

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
Serial.begin(115200);
delay(10);

// prepare GPIO2
pinMode(2, OUTPUT);
digitalWrite(2, 0);

// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

// Start the server
server.begin();
Serial.println("Server started");

// Print the IP address
Serial.println(WiFi.localIP());
}

void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}

// Wait until the client sends some data
Serial.println("new client");
while(!client.available()){
delay(1);
}

// Read the first line of the request
String req = client.readStringUntil('\r');
Serial.println(req);
client.flush();

// Match the request
int val;
if (req.indexOf("/gpio/0") != -1)
val = 0;
else if (req.indexOf("/gpio/1") != -1)
val = 1;
else {
Serial.println("invalid request");
client.stop();
return;
}

// Set GPIO2 according to the request
digitalWrite(2, val);

client.flush();

// Prepare the response
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
s += (val)?"high":"low";
s += "<BR>";
String temp;
temp = "22.5";

// Send the response to the client
client.print(s);
client.print("the temperature is - ");
client.print(temp);
client.print(" degrees");
client.print("</html>");
delay(1);
Serial.println("Client disonnected");

// The client will actually be disconnected
// when the function returns and 'client' object is detroyed
}

The web page shows

GPIO is now low
the temperature is - 22.5 degrees

and the source is

<!DOCTYPE HTML>
<html>
GPIO is now low<BR>the temperature is - 22.5 degrees</html>


Now get some real data using two Onewire DS18B20 thermometers

I joined together the Onewire example based on
http://www.pjrc.com/teensy/td_libs_OneWire.html
-
and the simple web server example

Either of these work perfectly alone.
The combined program compiles OK and shows -

Sketch uses 213,096 bytes (40%) of program storage space. Maximum is 524,288 bytes.

after the combined program has run well for a while see a heap problem -

HTTP server started
No more addresses.

ROM = 28 14 73 1F 5 0 0 2D
Chip = DS18B20
Data = 1 7E 1 4B 46 7F FF 2 10 25 CRC=25
Temperature = 23.87 Celsius, string calculation for both thermometers next

temp1_as_long = 2387

temp2_as_long = 2287

temp1_as_string1 = 2387

temp2_as_string1 = 2287

HTTP server started
ROM = 28 7 3 8D 5 0 0 A4
Chip = DS18B20
Data = 1 6E 1 4B 46 7F FF 2 10 71 CRC=71
Temperature = 22.87 Celsius, string calculation for both thermometers next

temp1_aNo heap available, failed to malloc 192
No heap available, failed to malloc 192
No heap available, failed to malloc 192


The combined program -

#include <OneWire.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire ds(2); // on pin 2 (a 4.7K resistor is necessary)

long celsius_x_100 ;
long celsius1_x_100 ; //multiply float like 12.34 to get long 1234 - then convert to string
long celsius2_x_100 ;
long celsius1 ;
long celsius2 ;
String string_to_send;
String temp1_as_string;
String temp2_as_string;
const char* ssid = "garden";
const char* password = "uu8diode";
ESP8266WebServer server(80);
//-----------------------------------------------------------------------SETUP START
void setup(void) {
Serial.begin(9600);
// Connect to fixed address WiFi network
WiFi.begin(ssid, password);
IPAddress ip(192, 168, 0, 101);
IPAddress gateway(192, 168, 0, 230);
IPAddress subnet(255, 255, 255, 0);
WiFi.config(ip, gateway, subnet);

Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// connected
}

//------------------------------------------------------------------------LOOP START
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;

if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}

Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}

if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();

// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}

ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end

delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad

Serial.print(" Data = ");
Serial.print(present, HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();

// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

if (addr[7] == 0x2D) celsius1_x_100 = celsius * 100;
if (addr[7] == 0xA4) celsius2_x_100 = celsius * 100;

Serial.println(" string calculation for both thermometers next");
Serial.println("");
Serial.print("temp1_as_long = ");
Serial.println(celsius1_x_100);
Serial.println("");
Serial.print("temp2_as_long = ");
Serial.println(celsius2_x_100);
Serial.println("");
temp1_as_string = String(celsius1_x_100);
temp2_as_string = String(celsius2_x_100);

Serial.println("");
Serial.print("temp1_as_string1 = ");
Serial.println(temp1_as_string);
Serial.println("");
Serial.print("temp2_as_string1 = ");
Serial.println(temp2_as_string);
Serial.println("");
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// create the web page
server.on("/", handle_root);
server.begin();
Serial.println("HTTP server started");

server.handleClient();
delay (1000);

}
//------------------------------------------------------------------------------------LOOP END

//------------------------------------------------------------------------------------FUNCTIONS
void handle_root()
{
string_to_send = temp1_as_string + " " + temp2_as_string;
server.send(200, "text/plain", string_to_send);
delay(100);
}
//---------------------------------------------------------------------
//function to extract decimal part of float
long getDecimal(float val)
{
int intPart = int(val);
long decPart = 1000*(val-intPart); //I am multiplying by 1000 assuming that the foat values will have a maximum of 3 decimal places
//Change to match the number of decimal places you need
if(decPart>0)return(decPart); //return the decimal part of float number if it is available
else if(decPart<0)return((-1)*decPart); //if negative, multiply by -1
else if(decPart=0)return(00); //return 0 if decimal part of float number is not available
}

Why ??


Testing Lua - nodeMCU - DHT22 humidity and temperature

Buy this book!! http://randomnerdtutorials.com/ - a great basic introduction !!
- with some clever web page ideas as well.

The following works with DHT22 (seems to keep running OK)

- but my DHT11 sensors (on small boards from eBay)
gave crazy temperatures - I will test them on an Arduino ASAP

See the book! then these worked for me -

dht.lua - load first

-- ***************************************************************************
-- for communication of DHT sensor only
-- DHT module for ESP8266 with nodeMCU floating point
-- Written by Javier Yanez
-- but based on a script of Pigs Fly from ESP8266.com forum
-- MIT license, http://opensource.org/licenses/MIT
-- ***************************************************************************

local moduleName = ...
local M = {}
_G[moduleName] = M

local humidity
local temperature

function M.read(pin)
local checksum
local checksumTest
humidity = 0
temperature = 0
checksum = 0

-- Use Markus Gritsch trick to speed up read/write on GPIO
local gpio_read = gpio.read

local bitStream = {}
for j = 1, 40, 1 do
bitStream[j] = 0
end
local bitlength = 0

-- Step 1: send out start signal to DHT22
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
tmr.delay(100)
gpio.write(pin, gpio.LOW)
tmr.delay(20000)
gpio.write(pin, gpio.HIGH)
gpio.mode(pin, gpio.INPUT)

-- Step 2: DHT22 send response signal
-- bus will always let up eventually, don't bother with timeout
while (gpio_read(pin) == 0 ) do end
local c=0
while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
-- bus will always let up eventually, don't bother with timeout
while (gpio_read(pin) == 0 ) do end
c=0
while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end

-- Step 3: DHT22 send data
for j = 1, 40, 1 do
while (gpio_read(pin) == 1 and bitlength < 10 ) do
bitlength = bitlength + 1
end
bitStream[j] = bitlength
bitlength = 0
-- bus will always let up eventually, don't bother with timeout
while (gpio_read(pin) == 0) do end
end
hum=" "
tem=" "
chk=" "
--DHT data acquired, process.
for i = 1, 16, 1 do
hum=hum.." "..tostring(bitStream[i])
tem=tem.." "..tostring(bitStream[i+16])
if (bitStream[i] > 3) then
humidity = humidity + 2 ^ (16 - i)
end
if (bitStream[i + 16] > 3) then
temperature = temperature + 2 ^ (16 - i)
end
end
for i = 1, 8, 1 do
chk=chk.." "..tostring(bitStream[i+32])
if (bitStream[i + 32] > 3) then
checksum = checksum + 2 ^ (8 - i)
end
end
checksumTest = (bit.band(humidity, 0xFF) + bit.rshift(humidity, 8) + bit.band(temperature, 0xFF) + bit.rshift(temperature, 8))
checksumTest = bit.band(checksumTest, 0xFF)

if temperature > 0x8000 then
-- convert to negative format
temperature = -(temperature - 0x8000)
end

-- conditions compatible con float point and integer
if (checksumTest - checksum >= 1) or (checksum - checksumTest >= 1) then
humidity = nil
end
--print("checksum ", checksum)
--print("checksumTest ", checksumTest)
--print("humidity - timing of bits ",hum)
--print("temperat - timing of bits ",tem)
--print("checksum - timing of bits ",chk)
end

function M.getTemperature()
return temperature
end

function M.getHumidity()
return humidity
end

return M

init.lua

wifi.setmode(wifi.STATION)
wifi.sta.config("garden","mypassword") - - - - - - -- - - - - - -<<<<<<<<<<< NB!
--wifi.sta.connect()
wifi.sta.setip({ip="192.168.0.102",netmask="255.255.255.0",gateway="192.168.0.230"})
--print("ESP8266 mode is: " .. wifi.getmode())
--print("The module MAC address is: " .. wifi.ap.getmac())
--print("Config done, IP is "..wifi.sta.getip())

tmr.delay(5000)

sensorType="dht22" -- set sensor type dht11 or dht22
pin = 4 -- data pin, GPIO2
humi=0
temp=0
fare=0
bimb=1
--load DHT module for read sensor
function ReadDHT11()
dht=require("dht")
dht.read(pin)
chck=1
h=dht.getHumidity()
t=dht.getTemperature()
if h==nil then h=0 chck=0 end
if sensorType=="dht11"then
humi=h/256
temp=t/256
else
humi=h/10
temp=t/10
end
fare=(temp*9/5+32)
print("Humidity: "..humi.."%")
print("Temperature: "..temp.." deg C")
print("Temperature: "..fare.." deg F")
-- release module
dht=nil
package.loaded["dht"]=nil
end
ReadDHT11()

tmr.alarm(1,5000, 1, function() ReadDHT11() bimb=bimb+1 if bimb==5 then bimb=0 wifi.sta.connect() print("Reconnect")end end)

srv=net.createServer(net.TCP) srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
--print(payload) -- for debugging only
--generates HTML web site
conn:send('HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nCache-Control: private, no-store\r\n\r\n\
<!DOCTYPE HTML>\
<html><head><meta name="viewport" content="width=device-width, initial-scale=1"></head>\
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">\
<meta http-equiv="refresh" content="6">\
</head><div class="container">\
<h1>Sensor Data</h1></br><div class="row">\
<div class="col-md-4"><div class="panel panel-primary"><div class="panel-heading"><h3 class="panel-title">Humidity</h3>\
</div><div class="panel-body">\
<div class="form-group form-group-lg"><input type="text" class="form-control" value="'..humi..' %">\
</div></div></div></div>\
<div class="col-md-4"><div class="panel panel-info"><div class="panel-heading"><h3 class="panel-title">Temperature</h3>\
</div><div class="panel-body">\
<div class="form-group form-group-lg"><input type="text" class="form-control" value="'..temp..' deg C">\
<input type="text" class="form-control" value="'..fare..' deg F">\
</div></div></div></div></div></div></html>')
conn:on("sent",function(conn) conn:close() end)
end)
end)

 

Please email me if you want to swap notes

SUNSPOT HOME