ESP8266/templogger
ESP8266 ThingSpeak
L'ESP8266 può essere utilizzato come microcontrollore standalone con il firmware Nodemcu. Grazie ai due GPIO pins si possono collegare sensori di temperatura, led, relè o altro. In questo esempio il GPIO2 è collegato ad un sensore DS18B20 per la misurazione della temperatura e ogni 30 secondi la lettura viene inviata a ThingSpeak
Schema elettrico
Consiglio di alimentare ESP8266 attraverso un alimentatore dedicato, non utilizzare i collegamenti forniti da altro micro controllore tipo Arduino, nè quelli del convertitore USB-TTL.
Nella millefori è utile predisporre anche le uscite dei pin RX, TX, GND, GPIO2, GPIO0 in modo da avere massima flessibilità e poter facilmente collegare l'unità per la programmazione oppure per sperimentare con le uscite.
Firmware
Collegare TX del convertitore USB-TTL a RX del ESP8266 e RX del convertitore a TX del ESP8266. Nota: il convertitore deve funzionare 3,3V e non a 5V!
Scaricare l'ultima versione di Nodemcu e attraverso ESPlorer caricare i tre sketch lua
ds18b20.lua
-------------------------------------------------------------------------------- -- DS18B20 one wire module for NODEMCU -- NODEMCU TEAM -- LICENCE: http://opensource.org/licenses/MIT -- Vowstar <vowstar@nodemcu.com> -- 2015/02/14 sza2 <sza2trash@gmail.com> Fix for negative values -------------------------------------------------------------------------------- -- Set module name as parameter of require local modname = ... local M = {} _G[modname] = M -------------------------------------------------------------------------------- -- Local used variables -------------------------------------------------------------------------------- -- DS18B20 dq pin local pin = nil -- DS18B20 default pin local defaultPin = 9 -------------------------------------------------------------------------------- -- Local used modules -------------------------------------------------------------------------------- -- Table module local table = table -- String module local string = string -- One wire module local ow = ow -- Timer module local tmr = tmr -- Limited to local environment setfenv(1,M) -------------------------------------------------------------------------------- -- Implementation -------------------------------------------------------------------------------- C = 0 F = 1 K = 2 function setup(dq) pin = dq if(pin == nil) then pin = defaultPin end ow.setup(pin) end function addrs() setup(pin) tbl = {} ow.reset_search(pin) repeat addr = ow.search(pin) if(addr ~= nil) then table.insert(tbl, addr) end tmr.wdclr() until (addr == nil) ow.reset_search(pin) return tbl end function readNumber(addr, unit) result = nil setup(pin) flag = false if(addr == nil) then ow.reset_search(pin) count = 0 repeat count = count + 1 addr = ow.search(pin) tmr.wdclr() until((addr ~= nil) or (count > 100)) ow.reset_search(pin) end if(addr == nil) then return result end crc = ow.crc8(string.sub(addr,1,7)) if (crc == addr:byte(8)) then if ((addr:byte(1) == 0x10) or (addr:byte(1) == 0x28)) then -- print("Device is a DS18S20 family device.") ow.reset(pin) ow.select(pin, addr) ow.write(pin, 0x44, 1) -- tmr.delay(1000000) present = ow.reset(pin) ow.select(pin, addr) ow.write(pin,0xBE,1) -- print("P="..present) data = nil data = string.char(ow.read(pin)) for i = 1, 8 do data = data .. string.char(ow.read(pin)) end -- print(data:byte(1,9)) crc = ow.crc8(string.sub(data,1,8)) -- print("CRC="..crc) if (crc == data:byte(9)) then t = (data:byte(1) + data:byte(2) * 256) if (t > 32767) then t = t - 65536 end if(unit == nil or unit == C) then t = t * 625 elseif(unit == F) then t = t * 1125 + 320000 elseif(unit == K) then t = t * 625 + 2731500 else return nil end t = t / 10000 -- print("Temperature="..t1.."."..t2.." Centigrade") -- result = t1.."."..t2 return t end tmr.wdclr() else -- print("Device family is not recognized.") end else -- print("CRC is not valid!") end return result end function read(addr, unit) t = readNumber(addr, unit) if (t == nil) then return nil else return t end end -- Return module table return M
postThingSpeak.lua
function postThingSpeak(level) conn=net.createConnection(net.TCP, 0) conn:on("receive", function(conn, payload) if (string.find(payload, "Status: 200 OK") ~= nil) then print("Posted OK"); end end) conn:on("connection", function(connout, payloadout) print ("Posting..."); conn:send("GET /update?api_key=CHIAVE&field1=" .. level .. " HTTP/1.1\r\n" .. "Host: api.thingspeak.com\r\n" .. "Connection: close\r\n" .. "Accept: */*\r\n" .. "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n" .. "\r\n") end) conn:on("disconnection", function(connout, payloadout) connout:close(); collectgarbage(); end) conn:connect(80,'184.106.153.149') -- api.thingspeak.com 184.106.153.149 end
Sostituire CHIAVE con la chiave ottenuta dalla registrazione su Thingspeak.com
init.lua
--init.lua require("postThingSpeak") ledPin = 3 --> GPIO0 value = gpio.LOW -- Initialise the pin gpio.mode(ledPin, gpio.OUTPUT) gpio.write(ledPin, value) print("Setting up WIFI...") wifi.setmode(wifi.STATION) wifi.sta.config("ssid","pw") wifi.sta.connect() tmr.alarm(1, 30*1000, 1, function() t = require("ds18b20") tempPin = 4 --> GPIO2 t.setup(tempPin) temp = t.read() print("Temperature: "..temp.."C") print("Sending data to thingspeak.com") postThingSpeak(temp) -- Don't forget to release it after use t = nil ds18b20 = nil package.loaded["ds18b20"]=nil end)
Sostiture ssid e pw con il nome del access point e la password
ThingSpeak
https://thingspeak.com/channels/32934
Riferimenti
- http://www.instructables.com/id/Low-cost-WIFI-temperature-data-logger-based-on-ESP/?ALLSTEPS
- https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_modules/ds18b20/ds18b20.lua
ESP8266 Redis
Una variante rispetto al primo progetto presentato in questa pagina: un sensore che pubblica i dati su un server redis, è una versione base che pubblica semplicemente i dati su server, il file DS18B20.lua è lo stesso usato nella prima parte di questa pagina.
Non avendo trovato un'esempio soddisfacente nelle librerie nodemcu, ho scritto quattro righe di codice per fare dei test con un sensore portatile.
wifi.lua
Il file di connessione Wifi l'ho mantenuto separato perchè a me piace così.
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID_rete_WiFI", "password")
wifi.sta.connect()
ip = wifi.sta.getip()
print(ip)
redis.lua
La connessione a redis è molto semplice, è una semplice connessione telnet alla porta 6379. Attenzione bisogna che il server redis(magari su un raspberry) accetti connessioni dall'esterno perchè normalmente accetta solo connessioni dalla macchina su cui è in esecuzione quindi va modificato il file /etc/redis/redis.conf :
bind 127.0.0.1 indirizzo_ip_server_redis
e poi il server va restartato
/etc/init.d/redis-server restart
Attenzione: questo è solo un test, non ho settato password e tutta la parte di configurazione di sicurezza accessi è tralasciata, per un uso continuativo è utile fare un'analisi più approfondita a livello di autenticazione e controllo.
function sendtoredis(temp)
conn=net.createConnection(net.TCP, 0)
conn:on("receive", function(conn, payload)
if (string.find(payload, ":") ~= nil) then
print("Save: OK");
end
end)
conn:on("connection", function(connout, payloadout)
print ("Saving");
conn:send("rpush esp_temp " .. temp .. "\r\n")
end)
conn:on("disconnection", function(connout, payloadout)
connout:close();
collectgarbage();
end)
conn:connect(6379,'indirizzo_ip_server_redis') -- server redis
end
init.lua
Il file init lancia lo script di connessione wifi legge la temperatura dal sensore e lancia la funzione di pubblicazione su redis.
dofile("wifi.lua")
require("redis")
tmr.alarm(1, 30*1000, 1, function()
t = require("ds18b20")
tempPin = 4 --> GPIO2
t.setup(tempPin)
temp = t.read()
print("Temperature: "..temp.."C")
print("Sending data to redis server")
sendtoredis(temp)
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
end)
Utilizzo
Questo esperimento mi serve per testare un sensore di temperatura 1 wire/wifi che produce dati per il mio progetto Termostato.
Riferimenti
- Accesso a Redis via telnet Redis Protocol specification