Ostatnio uruchamialiśmy Domoticz’a – zanim przejdziemy do Z-Wave – przyjrzyjmy się fantastycznemu małemu gadżetowi – ESP8266
ESP8266 to SoC czyli System on a Chip, co w tym przypadku oznacza bardzo ciekawe rozwiązanie – CPU/RAM/FLASH z GPIO i WiFi – a więc mały bezprzewodowy mini komputer. Można o nim myśleć jako o ultra małym, bardzo energooszczędnym Pi w wersji AAA (z dość ograniczoną możliwością uruchamiania własnych programów), z własnym WLAN i minimalnie dwoma GPIO do sterowania. Tak możemy na nim uruchomić serwer WWW!
Producentem jest Espressif, a inne firmy tworzą gotowe płytki ze złączami i antenami:
Podsumujmy – mamy możliwość sterowania dwoma GPIO, łącząc się z urządzeniem po WiFi, które zużywa bardzo mało prądu. Możemy też napisać program, który cyklicznie dokonuje aktualizacji danych – ponieważ możemy nie tylko uruchomić serwer http (WWW) czy telnetu, ale także w pętli czytać z GPIO i przesyłać np: w stylu nodejs albo URL json.html dla domoticza. Ta druga opcja jest zdecydowanie bardziej stabilna i niewymagająca od ESP zbyt dużo na początek.
Zatem – mamy świetny zdalny termometr do stacji pogodowej – pod warunkiem, że są gotowe przykłady, które możemy zaadaptować.
Układ posiada UART – złącza TX,RX – które świetnie nadają się do domyślnej komunikacji przez… Raspberry Pi. Jest to najlepsza moim zdaniem konsola dla ESP8266. Ta jednak domyślnie jest okupowana przez konsolę systemową – a więc jeśli podłączymy ją do ESP to zalejemy go danymi. Należy w pliku /boot/cmdline.txt usunąć część: console=/dev/ttyAMA0,115000. Po ponownym uruchomieniu możemy ją wreszcie wykorzystać.
Będziemy potrzebować:
ESP8266 najczęściej trafia do nas z firmware reagującym na komendy AT, jeśli kiedyś rozmawialiście z modemem w latach 90-tych albo modemem GSM – wiecie o czym mówię. My jednak użyjemy firmware od NodeMCU – obsługujący LUA – bardzo prosty do nauki język programowania (a więc bardzo potężny!). W chwili pisania dostępny był: nodemcu_integer_0.9.6-dev_20150704.bin, który pobieramy wraz z narzędziem – esptool.py. Teraz przystępujemy do prawidłowego połączenia ESP8266 do Raspberry Pi:
Upewnijmy się najpierw – czy w systemie mamy bibliotekę do obsługi portu szeregowego przez pythona:
sudo apt-get install python-serial
Teraz możemy aktualizować firmware:
python esptool.py -p /dev/ttyAMA0 write_flash 0x000000 nodemcu_integer_0.9.6-dev_20150704.bin
Jeśli zapomniałeś o podłączeniu GPIO0 z ESP-01 do GND Raspberry Pi to zobaczysz:
pi@raspberrypi ~/esp8266 $ python esptool.py -p /dev/ttyAMA0 write_flash 0x000000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Traceback (most recent call last):
File "esptool.py", line 353, in
esp.connect()
File "esptool.py", line 138, in connect
raise Exception('Failed to connect')
Exception: Failed to connect
A jeśli nie to, po podłączeniu GPIO0 do masy (GND) i resecie (odłącz zasilanie ESP8266 na chwilę) aktualizacja przebiegnie poprawnie:
python esptool.py -p /dev/ttyAMA0 write_flash 0x000000 nodemcu_integer_0.9.6-dev_20150704.bin
Connecting...
Erasing flash...
Writing at 0x00005800... (5 %)
Writing at 0x00031800... (45 %)
Writing at 0x00057c00... (80 %)
Writing at 0x0006dc00... (100 %)
Leaving...
Po aktualizacji należałoby się oswoić z nową zabawką. W tym celu – dostaniemy się do niej przez konsolę. Instalujemy picocom i wydajemy:
picocom -b 9600 --omap crcrlf /dev/ttyAMA0
Jak widać powitał nas prompt „>”. Jeśli znacie LUA to można przystąpić do testów komend, albo po prostu użyć: przykładów z oficjalnej strony:
print(wifi.sta.getip())
--nil
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID","password")
print(wifi.sta.getip())
--192.168.1.12
Jak można zobaczyć, po zamianie SSID oraz password na właściwe dla Waszej sieci domowej – urządzenie połączy się z Access Point’em i pobierze adres z DHCP. Dobra nasza, to połowa sukcesu. Teraz czas na połączenie termometru Dallas DS18b20. Jest to dość ciekawe i tanie rozwiązanie pozwalające na pomiar temperatury. NodeMCU posiada doskonały przykład obsługi tego konkretnego chipu, z którego skorzystamy. Pobieramy więc następujący plik z: biblioteki modułów: ds18b20.lua.
Ponieważ jednak standardowo po jego wykonaniu (o tym za chwilę) dostajemy precyzję tylko do jednego stopnia Celsjusza – lokalizujemy linię:
t = t / 10000
i zamieniamy ją na
t = t / 100
Otrzymamy teraz precyzję do dwóch miejsc po przecinku. Gotowy plik – dla pewności – zamieszczam jego wersję po zmianach:
--------------------------------------------------------------------------------
-- DS18B20 one wire module for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- Vowstar <[email protected]>
-- 2015/02/14 sza2 <[email protected]> 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 / 100
-- 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
zachowujemy na później (za chwilę o wgrywaniu na ESP) – przechodzimy do podstawowej własności ESP8266 w wersji z LUa od NodeMCU – uruchamianiu programów po starcie SoC’a
Autostart programów na ESP8266
ESP8266 po starcie wykonuje automatycznie program w init.lua, który jest umieszczony na jego flash. Bardzo ważne jest przetestowanie programu przed zapisaniem go jako init.lua, tak aby ESP nie wpadł w pętlę. Wszyscy znamy sytuacje, gdzie jeden błąd powoduje, że pętla wykonuje się w nieskończoność. W związku z tym – nasz plik/program init.lua powinien zawierać minimalny zestaw komend – faktycznie powinien tylko pobrać adres IP przez WiFi i wykonać główny program czytający i wysysający temperaturę do domoticza. Tak więc niezłym pomysłem będzie próba połączenia z DWOMA różnymi sieciami WiFi – najpierw z pierwszą – a jeśli się nie powiedzie to z drugą. Dzięki temu mamy możliwość ustawienia sobie 'roboczej’ sieci WiFi na potrzeby debugowania lub zmiany oprogramowania w ESP. Druga ważna funkcja to pauzy. Init.lua przed pobraniem adresu powinno dawać wystarczająco dużo czasu na zmianę pliku init.lua – skasowanie go, tak aby zastąpić go nowym – jeśli nie mamy możliwości zestawienia połączenia z siecią WiFi. Zatem – tworzymy init.lua w edytorze (nano, joe – na Pi):
--init.lua
wifi.setmode (wifi.STATION)
wifi.sta.config("MOJE SSID 1","tajne_haslo_do_ssid_1")
wifi.sta.connect()
tmr.alarm(1, 6000, 1, function()
if wifi.sta.getip()== nil then
print("Brak polaczenia i IP, probuje dalej...")
wifi.sta.config("DRUGIE ZAPASOWE SSID","jeszcze_bardziej_tajne")
wifi.sta.connect()
else
tmr.stop(1)
print("Tryb pracy ESP8266: " .. wifi.getmode())
print("Adres MAC ESP8266: " .. wifi.ap.getmac())
print("Sukces, adres IP: "..wifi.sta.getip())
dofile ("domoticz.lua")
end
end)
Tak przygotowany program na początku ustawia w tryb kliencki ESP (bo ESP może być też np: Access Pointem), ustawia parametry sieci WiFi i nakazuje się połączyć. Następnie po 6000ms spradzany jest warunek czy wifi.sta.getip() zawiera cokolwiek innego niż „nil” i jeśli nie zawiera – to konfigurowana jest zapasowa sieć WiFi i co 6000ms próba jest ponawiana do skutku. Jest to też czas na skasowanie programu jeśli coś poszło nie tak. Na końcu mamy komendę dofile, której zadaniem jest uruchomienie głównego programu – domoticz.lua:
--domoticz.lua
require('ds18b20')
gpio0 =3
gpio2 =4
ds18b20.setup(gpio2)
t=ds18b20.read()
print("Surowy odczyt z ds28b20:" .. t .. " C\n")
if(t==nil) then
t=0
end
tmr.alarm(0,240000, 1, function()
t=ds18b20.read()
tpre=t/100
tsub=string.sub(t,-2)
temp=tpre .. "." .. tsub
print("Temperatura przekazywana:" .. temp .. " C\n")
conn=net.createConnection(net.TCP, 0)
conn:on("receive", function(conn, payload) print(payload) end )
conn:connect(8080,"192.168.1.15")
conn:send("GET /json.htm?type=command¶m=udevice&idx=11&nvalue=0&svalue=" .. temp .. " HTTP/1.1\r\nHost: termometr.domek\r\n".."Connection: keep-alive\r\nAccept: */*\r\n\r\n")
end)
Główny program ma za zadanie wykorzystać wcześniej załączoną bibliotekę ze strony NodeMCU (z drobną modyfikacją). Następnie ustawia PINy na ESP odpowiednio, tak aby czytać temperaturę z GPIO 2. Możemy szybko wyświetlić surowy odczyt, który będzie zawierał 4 cyfry. To jest właśnie sedno modyfikacji – nie przetestowany do końca hack, który pobiera 4 cyfry, a następnie manipulując zamianą na ciąg znaków – bierze ostanie dwie, dwie pierwsze i wstawia między nie kropkę. Tak spreparowaną zmienną wysyła używając interfejsu JSON domoticza, który występuje tutaj pod adresem 192.168.1.15 na porcie 8080 – w którym należy poprawnie podać IDX sensora temperatury jaki stworzyliśmy (Urządzenia). I to wszystko, chociaż nadal czekam na ujemną temperaturę aby móc wrócić do pomysłu odbierania precyzyjnych danych! Pozostaje więc umieszczenie trzech plików na ESP8266.
Dzięki kolejnemu programowi w Pythonie, możemy zamiast przepisywać linia po linii kod, który trzeba umieścić w pliku na ESP8266, otworzyć/zamknąć – możemy użyć luatool.py:
python luatool.py -p /dev/ttyAMA0 --src init.lua --dest init.lua
python luatool.py -p /dev/ttyAMA0 --src domoticz.lua --dest domoticz.lua
python luatool.py -p /dev/ttyAMA0 --src ds18b20.lua --dest ds18b20.lua
Jeśli wcześniej poprawnie udało się połączyć z ESP przez picocom, luatool.py powinien podać po kolei wydawane komendy, a następnie zapisać plik. Jeszcze raz przypominam, że init.lua musi być bezpieczny – jeśli ESP wpadnie w pętlę, zacznie się resetować – będzie ciężko wymazać filesystem.
Ponieważ czujnik temperatury z WiFi jest z natury urządzeniem bardzo „mobilnym” – możemy zadbać o zasilenie go z baterii, które będą ładowane przez panel fotowoltaniczny. W tym celu należy wybrać panel, baterie Li-Ion oraz najlepszą metodę ładowania i zasilania.
Po kilku próbach najlepsze okazały się następujące komponenty:
UWAGA: Pamiętaj, aby nie używać baterii 18650 poza specyfikacją – np: w niskich lub wysokich temperaturach! Baterie 18650 mogą być niebezpieczne, jeśli używane są niezgodnie z przeznaczeniem i specyfikacją.
Panel montujemy na podstawce – tutaj po prostu kawałek pleksi i umieszczamy frontem do przechodzącego przez nieboskłon słońca pod kątem 45 stopni:
Panel należy zabezpieczyć przed wilgocią – klejem:
A następnie podłączyć do gotowego układu (przez przejściówkę z załączonej wtyczki na USB:
Tutaj jak widać mamy już wersję w obudowie ESP-12E oraz płytce NodeMCU (o czym w kolejnym wpisie o ESP Easy)