Termometr z wifi

Mam już drukarkę 3d. Pora jej użyć w praktycznym zastosowaniu – zbudować kompletne urządzenie z porządną obudową. Skoro już ma być solidnie i elegancko, to będzie także płytka drukowana i żadnego kleju na gorąco. A wszystko przygotuję od podstaw, razem z projektami i oprogramowaniem dla ESP8266.

Termometr Wifi

Na początek założenia – urządzenie ma być małe, ale nie musi być miniaturowe. Ma mieć możliwość podłączenia kilku termometrów do magistrali one-wire, ale ze względów praktycznych musi być możliwość podłączenia wszystkich przewodów do urządzenia, żeby uniknąć łączenia przewodów na zewnątrz. Oczywiście zaletą magistrali jest to, że wiele czujników można umieszczać na jednym kablu, natomiast w praktycznych zastosowaniach, np. przy monitoringu temperatur w kotłowni, dobrze jest jak wszystkie przewody wychodzą z jednego miejsca i nie są łączone dalej. Dla maksymalnej prostoty i uniknięcia instalacji kilku gniazd i wtyczek, termometry będą podłączane przez złącza goldpin wewnątrz obudowy.

Podłączony termometr wifi

Jednostką sterującą będzie ESP8266, a konkretnie jego mała odmiana ESP8266-01, która posiada wyprowadzenia w rastrze 2,54mm i dysponuje 2 wyjściami GPIO. Do urządzenia będzie można podłączać termometry Dallas DS18B20, które pracują na magistrali one-wire. Układ zostanie zaprogramowany w języku LUA dzięki NodeMCU. Zasilany będzie z zewnętrznego zasilacza, którego napięcie będzie stabilizowane do 3,3V wewnątrz urządzenia. Podczas projektowania warto wykorzystać doświadczenia z wcześniejszego projektu.

Elektronika

Trzeba zająć się projektem urządzenia od strony elektronicznej. Schemat jest bardzo prosty i zakłada użycie:

  • gniazda zasilania dla wtyku okrągłego 5,5mm x 2,5mm
  • stabilizatora LD33V (L1117)
  • kondensatorów potrzebnych dla stabilizatora – 100nf i 10μF
  • gniazda goldpin 4×2 dla wetknięcia ESP8266-1
  • rezystora dla połączenia linii danych z zasilaniem (4700Ω według specyfikacji lub 1000Ω w moim przypadku)
  • pięciu złącz goldpin 3×1 dla podłączenia termometrów

Schemat termometru wifi na ESP8266

Schemat został przygotowany w programie Eagle, który umożliwia także przygotowanie projektu płytki drukowanej. Do schematu powstała płytka drukowana o wymiarach 3cm x 5cm.

termometr-esp8266-plytka-z-gndWarto zauważyć, że pole masy jest nieciągłe, więc lutując trzeba połączyć dwa pola przewodem (są potrzebne otwory w płytce). Na płytce znajdują się otwory do mocowania, natomiast zakładam, że będzie ona trzymana przez obudowę lub przykręcona jednym wkrętem (przez otwór w obudowie stabilizatora).

Płytka drukowana internetowego termometru

Płytkę można trawić samemu, ale można też zamówić ją u jednego z usługodawców. Lutowanie kilku elementów nie powinno dla nikogo stanowić problemu.

Obudowa

Aby zaprojektować obudowę, nauczyłem się podstaw obsługi programu OpenSCAD. Wybrałem go, bo jest bezpłatny, a projektowanie przypomina programowanie w specjalnym języku opisującym obiekty trójwymiarowe. Dla mnie jest to bardzo przyjazne, precyzyjne i daje duże możliwości. W programie tym zapisuje się obiekty w formacie .scad, jednak do zewnętrznego użycia eksportuje się je do formatu .stl, który jest szeroko używany przez programy do druku 3d.

Projekt obudowy w OpenSCAD

Mając plik STL wygenerowany, dobrze jest go przepuścić przez jedno z narzędzi sprawdzających i naprawiających błędy (np. przenikanie się modelu czy tzw. wodoszczelność). Można to zrobić online. W rezultacie otrzymujemy plik stl, który już bez obaw można zaimportować do programu do obsługi druku (np. Repetier Host) czy wprost do slicera (np. Slic3r). W rezultacie otrzymujemy plik z gcode, czyli poleceń zrozumiałych dla drukarki 3d. Możemy go wgrać na kartę SD dla drukarki lub uruchomić drukowanie przez USB.

Repetier Host - pudełko ESP8266

Po uruchomieniu wydruku pozostaje czekać. A potem wydrukować jeszcze górną część. Wydruk z filamentu PET-G wychodzi zawsze jak trzeba i bardzo dobrze wygląda. Mi szczególnie podoba się efekt przezroczystości.

druk-obudowy-3d

Płytka wchodzi do obudowy ciasno, dzięki czemu jest stabilna, nawet bez przykręcania.

Wnętrze urządzenia

Oprogramowanie

Skoro sprzęt jest już gotowy pozostaje napisać oprogramowanie. Sam sposób wgrania programu oraz język programowania, były już opisywane na blogu. Nieco natomiast zmienił się sam projekt NodeMCU i teraz nie ma już gotowych obrazów do pobrania, w miejscu, gdzie utrzymywany jest projekt. Docelowe binaria można albo wygenerować samemu, albo użyć narzędzia do przygotowywania obrazów online. Jest to bardzo dobre podejście, bo można wybrać tylko te moduły, które są potrzebne i nie przejmować się brakiem pamięci RAM na pisane programy. Dla potrzeb internetowego termometru wybrałem kompilację z modułami bit, enduser_setup, file, gpio, net, node, ow, tmr, uart, wifi. Dostałem dwa linki do ściągnięcia, z których wybrałem wersję float. Po wgraniu firmware można przygotować program. Zaczynamy od init.lua:

wifi.setmode(wifi.STATION)
wifi.sta.config("siecwifi","tajnehaslo")
node.compile('ds18b20.lua')
node.compile('test.lua')
dofile('test.lc')

Ten plik definiuje tryb pracy wifi i dane dostępowe do sieci. Następne dwie linijki są nowością (w stosunku do ostatnich moich opisów) i odpowiadają za kompilację plików ze źródłami programów. Język Lua jest interpretowany i nie trzeba tego robić, natomiast pozwala to zaoszczędzić sporo pamięci RAM przy wykonywaniu programu. Ostatnia linijka wywołuje program zapisany w pliku test.lc, skompilowanym z test.lua. Będzie on odpowiadał za pracę urządzenia – sprawdzanie temperatur, wysyłanie ich do serwera oraz ewentualne restarty przy nieudanych próbach połączenia lub malejącej dostępnej pamięci.

Plik ds18b20.lua jest okrojoną przeze mnie wersją biblioteki do obsługi termometrów, w czasach gdy zajętość pamięci była jeszcze dużym problemem:

local modname = ...
local M = {}
_G[modname] = M
local pin = nil
local table = table
local string = string
local ow = ow
local tmr = tmr
setfenv(1,M)


function setup(dq)
 pin=dq
 ow.setup(dq)
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
 ow.reset(pin)
 ow.select(pin, addr)
 ow.write(pin, 0x44, 1)
 present = ow.reset(pin)
 ow.select(pin, addr)
 ow.write(pin,0xBE,1)
 data = nil
 data = string.char(ow.read(pin))
 for i = 1, 8 do
 data = data .. string.char(ow.read(pin))
 end
 crc = ow.crc8(string.sub(data,1,8))
 if (crc == data:byte(9)) then
 if(unit == nil or unit == C) then
 t = (data:byte(1) + data:byte(2) * 256) * 625
 else
 return nil
 end
 t = t / 10000
 return t
 end
 tmr.wdclr()
 else
 end
 else
 end
 return result
end
function read(addr, unit)
 t = readNumber(addr, unit)
 if (t == nil) then
 return nil
 else
 return t
 end
end
return M

Pozostał jeszcze główny program – test.lua:

vds = require("ds18b20")

gpio0 = 3
gpio2 = 4

local timeout=60000
local tmrtimeout=6

local lasttemp = -100
local lasthum = -100

local numreq=0;
local connwait=false;
local numerr=0;

local temps={}

local httpsend=function(txt)
 if connwait == true then
 numerr=numerr+1
 else
 connwait=true
 tmr.alarm(tmrtimeout, timeout, 0, function() conn:close() connwait=false numerr=numerr+1 end)
 conn=net.createConnection(net.TCP, 0) 
 conn:on("receive", function(conn, pl) print(pl) print("receive\n") end)
 conn:on("sent", function(conn) print("sent\n") numreq=numreq+1 end)
 conn:on("connection", function(conn) print("connection\n") conn:send("GET /skrypty/esp.php?i="..node.chipid().."&h="..node.heap().."&rq="..numreq..txt.." HTTP/1.0\nHost: www.luksoft.org\n\n") end)
 conn:on("disconnection", function(conn) print("disconnection\n") conn:close() tmr.stop(tmrtimeout) connwait=false end)
 conn:connect(80,"www.mojserwer.org")
 end
end

local checknode=function()
 print("checknode() "..node.heap().."\n")
 if numerr>20 then node.restart() end 
 if node.heap()<1000 then node.restart() end
end

local discoverds=function()
 print("discoverds() ")
 addrs = vds.addrs()
 for i,id in ipairs(addrs) do
 print("*")
 if temps[id]==nil then temps[id]=-100 end
 end
 print("\n")
end

local actnum=1

local readnexttemp=function()
 print("readnexttemp()\n")
 local acttemp
 if addrs~=nil then
 acttemp=vds.read(addrs[actnum],nil)
 if(acttemp==nil) then acttemp=-100 end
 if(acttemp>-40 and acttemp<85) then temps[addrs[actnum]]=acttemp end
 actnum=actnum+1
 if actnum>table.getn(addrs) then actnum=1 end
 end
end

local checkds=function()
 print("checkds()\n")
 local u="0"
 if(addrs~=nil and table.getn(addrs)>0) then
 u=string.format("%i", table.getn(addrs))
 for i,id in ipairs(addrs) do
 if temps[id]~=nil then
 u=string.format("%s,%02X%02X%02X%02X%02X%02X%02X%02X,%.2f", u, id:byte(1),id:byte(2),id:byte(3),id:byte(4),id:byte(5),id:byte(6),id:byte(7),id:byte(8),temps[id])
 end
 end
 end
 tmr.alarm(5, 50, 0, function() httpsend(string.format("&ds=%s", u)) end)
end

vds.setup(gpio2)
discoverds()

tmr.alarm(0, 30000, 1, checkds)
tmr.alarm(1, 90000, 1, checknode)
tmr.alarm(2, 3600000, 1, discoverds)
tmr.alarm(3, 5000, 1, readnexttemp)

Ostatnie 4 linie odpowiadają za ustawienie cyklicznego wywoływania funkcji:

  1. checkds – formatującej odpowiedź z tablicy temperatur i wywołującej połączenie z serwerem www
  2. checknode – sprawdzającej czy nie warto zrestartować układu
  3. discoverds – sprawdzającej czy przypadkiem nowe termometry nie zostały podłączone
  4. readnextemp – odczytującej temperaturę z kolejnego termometru DS18B20

Zapytanie GET do serwra wysyłane jest w formacie:

/esp.php?i=<identyfikator_esp>&h=<ilość_wolnej_pamięci>&rq=<numer_wywołania_od_restartu>&ds=<liczba_termometrów>,<numer_seryjny_termometru1>,<temperatura_z_termometru1>,<numer_seryjny_termometru2>,<temperatura_z_termometru2>,…

np.

/esp.php?i=10310057&h=27448&rq=152&ds=2,2814B86704000060,27.50,283240BF040000E1,27.63

To co zrobi serwer www z tą informacją to już inna sprawa. Może zapisać do bazy i wygenerować wykresy albo ostrzec kogoś, że za bardzo rośnie temperatura, albo włączyć ogrzewanie, albo… zależy do czego ma służyć to urządzenie. U mnie zwykle służą do monitoringu temperatur – rysowania wykresów i ewentualnie ostrzegania o nieprawidłowościach. Jest też elementem systemu nawadniania ogródka.

Przy domach z piecami węglowymi bardzo przydaje się do analizy pracy kotłów i zaworów czwórdrogowych. Widać wszystko jak na dłoni. Mi przykładowo pozwoliło od razu zauważyć awarię zaworu zwrotnego w obwodzie cyrkulacji ciepłej wody użytkowej (i ciągłą cyrkulację grawitacyjną). Bez tego pewnie zastanawiałbym się, czemu kocioł pali tak dużo węgla. Przykładowy wykres z pracy kotła na ekogroszek latem:

Wykres temperatur kotła na węgiel

Zastosowań urządzenia może być wiele. Można je też udoskonalać. Przykładowo do obudowy można dołożyć uchwyty do powieszenia na ścianę, gdyby miało być zainstalowane np. w kotłowni na stałe. Do kotłowni zrezygnowałbym też z otworu wentylacyjnego w obudowie, żeby zmniejszyć przenikanie pyłu węglowego.

Prototyp tego urządzenia działa u mnie już ponad rok (a pewnie znacznie dłużej) bez żadnych problemów czy potrzeby ręcznego restartowania.

Zainteresowanym mogę udostępnić wszystkie pliki konieczne do samodzielnego wykonania termometru według powyższego projektu.

Warto zaznaczyć, że wszystkie użyte programy są multiplatformowe. Ja używałem ich pod Ubuntu, natomiast nic nie stoi na przeszkodzie, żeby projekty wykonać w środowisku Windows.

Ten wpis został opublikowany w kategorii Inteligentny Dom i oznaczony tagami , , , , , , , , , , , . Dodaj zakładkę do bezpośredniego odnośnika.

0 odpowiedzi na Termometr z wifi

  1. GD pisze:

    Brawo kolego.

  2. Mikołaj Lasociński pisze:

    Swietna sprawa, co jest centrala?
    Mozesz udostepnic projekt z Eagla?

  3. TadzikJ pisze:

    Witam.
    Mógłbym prosić o kod programu zarówno w php jak i lua
    Pozdrawiam. Tadzik

  4. jendrush pisze:

    Do projektowania 3D dla początkujących fajny jest jeszcze DesignSpark Mechanical. Jest darmowy do zastosowań niekomercyjnych i projektuje się w nim bardzo prosto.

    • jendrush pisze:

      Dodam jeszcze, że podobny i także darmowy jest także Fusion 360. Jest w sumie o tyle lepszy, że jest to pełna wersja płatnego programu. DesignSpark Mechanical to taka trochę okrojona wersja SpaceClaim.

  5. Janusz pisze:

    Ciekawy projekt bo obsługuje kilka czujników na jednym porcie. Ostatnio zainteresowałem się projektem Supla, ciągle rozwijany, ale brakuje mu właśnie kilku czujników na jednym module ESP8266. Może autor artykułu ogarnie temat dodania kilku czujników w Supli, ciekawie by to wyglądało ponieważ wszystko można odczytywać na aplikacji pod systemem Android.

  6. ziyo98 pisze:

    Witam,
    @Techniczny, czy byłaby szansa na otrzymanie kompletu plików? z góry dzięki.

  7. LUCENT pisze:

    Cześć. Mam jedno pytanko. Dlaczego zasilanie 5V stabilizowane do 3.3 zamiast poprstu podpiąć USB?

  8. LUCENT pisze:

    A jakbyśmy chcieli podlączyć LCD to 3.3V wystarczy?

  9. mag pisze:

    Witam.
    Robię bardzo podobny projekt oparty o ESP8266 12E.
    Sprawdzałem go wysyłając dane na thingspeak.com i dane są tam zbierane czyli wysyłanie wydaje się działać prawidłowo.
    Chcę tak jak w tym przykładzie informacje wysyłać na mojej stronce ale nie działa mi ani metoda GET ani POST (oczywiście w odpowiedniej składni).
    Kod wyświetlania danych na stronie jest poprawny, bo go sprawdziłem.
    Ale nie dochodzą żadne dane z ESP na moją stronkę.
    W ESPlorerze dostję komunikat zwrotny:

    HTTP/1.1 404 Not Found
    Date: Tue, 28 Nov 2017 22:45:13 GMT
    Server: Apache
    Content-Length: 328
    Content-Type: text/html; charset=iso-8859-1

    I jeszcze kilka linijek.

    Podaję różne ścieżki dostępu i nic.
    Zmieniam porty na serwer i też nic.

    Próby prowadzę już z od jakiegoś czasu.
    Net przekopałem i nie udało mi się znaleźć pomocy.

    Może ktoś ma pomysł co mogę jeszcze zrobić lub sprawdzić?

    • techniczny pisze:

      Jesteś na dobrej drodze. 404 to odpowiedź z serwera mówiąca, że taki dokument nie istnieje. Sprawdź w logach serwera do czego się odwołujesz, to będzie wiadomo co robisz źle.

      Pamiętaj też, że dla wirtualnych hostów bazujących na nazwie, musisz podać nazwę hosta w nagłówkach zapytania http. Może to jest problem?

      • mag pisze:

        Dzięki za szybką odpowiedź.
        Co do loga to nie bardzo wiem czego w nim szukać a jest on duży.
        Host nie jest wirtualny.
        Mam jeszcze pytanie związane z serwerem.
        Stronę powiedzmy aaa.pl mam na serwerze powiedzmy 100.100.100.100
        Czy aby mój program zaczął wysyłać info na stronkę aaa.pl/esp8266.php to muszę zrobić tak:
        conn:send(„GET /esp8266.php?temp=”..cels..” HTTP/1.1\r\n”)
        conn:send(„Host: aaa.pl”)
        conn:connect(80,”100.100.100.100″)
        czy
        conn:send(„GET /esp8266.php?temp=”..cels..” HTTP/1.1\r\n”)
        conn:send(„Host: aaa.pl”)
        conn:connect(80,”aaa.pl”)
        ?

      • mag pisze:

        Problem rozwiązany.
        Miałem szkolny błąd.
        Może komuś się przyda.
        Po adresie hosta powinno być: \r\n
        Jak poniżej:
        conn:send(„Host: http://www.stronka.pl\r\n”)

  10. Piotr Żurawski pisze:

    Witam
    Czy mógłbym prosić o udostępnienie plików do wykonania termometru według powyższego projektu.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *