domingo, 22 de março de 2015

Registro de temperaturas via Web com a utilização do módulo ESP8266

No final de 2014 diversos módulos com o chip ESP8266 apareceram no mercado como uma alternativa de baixo custo (menos de US$ 3) para projetos de "Internet das Coisas" ou IoT.
O módulo é realmente fantástico, com um microcontrolador rápido, 512 KB de flash, 256 KB de eeprom (uma 25Q4-1BT) várias GPIOs, timers, UART e o mais impressionante: Wi-FI !
Neste pouco tempo de vida, vários projetos apareceram e um igualmente incrível é o NodeMCU . Ele substitui o firmware original, onde a programação é feita por comandos AT, (que muito útil quando o módulo é usado em conjunto com um outro processador como o Arduino), por um firmware com um interpretador da linguagem LUA.
Este firmware permite a programação direta nele ou que o programa seja gravado na eeprom, evitando assim a necessidade de gravação da Flash para cada novo programa.
Eu adquiri os módulos ESP8266-7, com antena cerâmica,  no Aliexpress, por US$2,80, apesar de existirem outros modelos já com pinos para conectores.

Para o funcionamento correto do módulo, os pinos GPIO2, Reset e CH_PD  devem ser ligados ao VCC de 3,3 V por meio de resistores de 4,7K e o GPIO15 para Ground. Para que o modo "sono profundo" ou deepsleep também funcione dentro dos programas, um jumper adicional entre o GPIO16 e o Reset (que já tem o resistor)  tem de ser instalado.

A programação do novo firmware NodeMCU é feita via serial, por um adaptador USB->TTL do tipo FT-232 ou SILABS CP-2102, também facilmente encontrável no Aliexpress.com ou no DX.com.
Para se entrar no modo de upgrade de flash o pino GPIO0 deve ser ligado ao Ground. Para uso normal, o GPIO0 deve ser deixado em aberto.

Para se gravar o novo Firmware, há um aplicativo NodeMCU-Flasher. Após a gravação (e o jumper do GPIO0 retirado) se conectando um programa terminal como o Putty na interface COM onde está o conversor USB-Serial, deve se ter acesso ao modo de programação Lua.

Para a programação em Lua, uma boa opção é o LuaUploader, que utiliza a interface serial para upload dos programas escritos na própria IDE, mas antes desconecte o Putty da serial. Se um programa for gravado no módulo com o nome "init.lua" ele sempre será executado automaticamente quando o módulo for ligado.

Nos exemplo abaixo, composto de dois programas que foram gravados no ESP8266, a temperatura é lida de um chip DS18B20 pelo módulo (via protocolo Onewire). O DS18B20 foi ligado diretamente ao módulo com os dois pinos das extremidades no Ground e o do centro na GPIO5.
A tempratura é lida a cada 5 minutos e enviada para o site Thingspeak.com, que recebe o dado e o apresenta em forma de gráfico. Após a transmissão, o módulo entra em "sono profundo"com um consumo de apenas 0,4 mA, o que possibilita uma longa duração da bateria de lítio.

Programa init.lua

print("Setting up WIFI...")
wifi.setmode(wifi.STATION)
--modify according your wireless router settings
wifi.sta.config("SSID","PASSWORD")
wifi.sta.connect()
tmr.alarm(2, 1000, 1, function()
  if wifi.sta.getip()== nil then
    print("IP unavaiable, Waiting...")
  else
    tmr.stop(2)
  print("Config done, IP is "..wifi.sta.getip())
  end
end)
print("*** You've got 3 sec to stop timer 0 ***")
tmr.alarm(0, 3000, 0, function()
  dofile("onewire-things-ds18b20.lua")
end)
tmr.alarm(1, 10000, 0, function()
  print("timer1 trigger dsleep")
  node.dsleep(300*1000*1000)
end)

Programa onewire-things-ds18b20.lua

--'
-- 18b20 one wire example for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- Vowstar <vowstar@nodemcu.com>
--'
pin = 2
ow.setup(pin)
count = 0
repeat
  count = count + 1
  addr = ow.reset_search(pin)
  addr = ow.search(pin)
  tmr.wdclr()
until((addr ~= nil) or (count > 100))
if (addr == nil) then
  print("No more addresses.")
else
  print(addr:byte(1,8))
  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
--        repeat
          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)
          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
             t = (data:byte(1) + data:byte(2) * 256) * 625
             t1 = t / 10000
             t2 = t % 10000
             if wifi.sta.getip()~= nil then
                print("Temperature= "..t1.." Centigrade")
                conn=net.createConnection(net.TCP, 0)
                conn:on("receive", function(conn, payload) print(payload) end )
                conn:connect(80,"184.106.153.149")
                conn:send("GET /update?key=newkeyfromthingspeak&field1="..t1.." HTTP/1.1\r\n")
                conn:send("Host: api.thingspeak.com\r\n")
                conn:send("Accept: */*\r\n")
                conn:send("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n")
                conn:send("\r\n")
             end
          end                   
          tmr.wdclr()
--        until false
    else
      print("Device family is not recognized.")
    end
  else
    print("CRC is not valid!")
  end

end

Um exemplo de registro de temperatura pode ser visto aqui.