ESP8266 temperature logging to MQTT device. master
authorPat Thoyts <patthoyts@users.sourceforge.net>
Mon, 9 Jan 2017 22:17:58 +0000 (22:17 +0000)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Mon, 9 Jan 2017 22:17:58 +0000 (22:17 +0000)
Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
application.lua [new file with mode: 0644]
config.lua.example [new file with mode: 0644]
ds18b20.lua [new file with mode: 0644]
esp01_sensor.pdf [new file with mode: 0644]
init.lua [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..07da015
--- /dev/null
@@ -0,0 +1,4 @@
+/config.lua
+/ESPlorer.Log
+/ESPlorer.Log.lck
+
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..ff12389
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+MQTT Temperature Sensor
+-----------------------
+
+Publish temperature over MQTT every 10 minutes
+
+Timer 4 reads the temperature every second and other
+timers cause the last temperature reading to be published at intervals
+over mqtt as defined in the config.lua file. We are sending to the local
+server each minute and to a public one every 10 minutes.
+
+
+The circuit board is an MP1584 based step-down board to provide 3V3 power
+and two DS18B20 sensors hooked onto GPIO0 (aka pin 3 in nodemcu).
+Also added 4K7 pullups to RST and EN and the 1-wire data line and
+connected the ESP8266 serial lines to a molex RA header.
+
+Setup
+-----
+
+Copy 'config.lua.example' to 'config.lua' and modify to suit your setup.
+Upload to the ESP8266 device using luaload or esplorer etc.
+
diff --git a/application.lua b/application.lua
new file mode 100644 (file)
index 0000000..36df79a
--- /dev/null
@@ -0,0 +1,90 @@
+require('ds18b20')
+require('mqtt')
+require('gpio')
+
+dofile('config.lua')
+
+function mqtt_build_message()
+    local r = {}
+    for id,t in pairs(ds18b20.values) do
+        local t1 = t / 10000
+        local t2 = (t >= 0 and t % 10000) or (10000 - t % 10000)
+        table.insert(r, string.format("{\"id\":\"%s\",\"temp\":%d.%04d}", id, t1, t2))
+    end
+    return "[" .. table.concat(r, ",") .. "]"
+end
+
+function mqtt_publish(m, prefix)
+   local topic = prefix .. '/' .. node.chipid()
+   m:publish(topic .. '/temperature', mqtt_build_message(), 0, 0, nil)
+end
+
+function mqtt_create_client(server, prefix, timerid, interval)
+   local m = mqtt.Client(node.chipid(), 60, MQTT_USERNAME, MQTT_PASSWORD, 0)
+   m:lwt(prefix .. '/' .. node.chipid() .. '/error', 'disconnected', 0, 0)
+   m:on("connect", function(client)
+           mqtt_publish(client, prefix)
+           -- max time is 6870947 (1:54:30.947)
+           tmr.alarm(timerid, interval, 1, function() mqtt_publish(client, prefix) end)
+   end)
+   m:on("offline", function(client)
+           tmr.stop(timerid)
+           m:connect(server, MQTT_PORT, 0, 1)
+   end)
+   m:connect(server, MQTT_PORT, 0, 1)
+   return m
+end
+
+function mqtt_start()
+   local clients = {}
+   ds18b20.update()
+   tmr.alarm(SENSOR_TIMER, SENSOR_INTERVAL * 1000, tmr.ALARM_AUTO, ds18b20.update)
+   for index,broker in ipairs(MQTT_BROKERS) do
+      local interval = broker.interval * 1000
+      local m = mqtt_create_client(broker.host, broker.prefix, broker.timer, interval)
+      table.insert(clients, m)
+   end
+   return clients
+end
+
+function mqtt_stop()
+   print("mqtt_stop")
+   for index,broker in ipairs(MQTT_BROKERS) do
+      tmr.stop(broker.timer)
+      tmr.unregister(broker.timer)
+   end
+   for index,client in ipairs(clients) do
+      if pcall(client.close) then
+         print("closed client")
+      else
+         print("failed to close client")
+      end
+   end
+   tmr.stop(SENSOR_TIMER)
+   tmr.unregister(SENSOR_TIMER)
+end
+
+LED_STATE = 1
+
+function blink()
+   if LED_STATE == 1 then
+      LED_STATE = 0
+   else
+      LED_STATE = 1
+   end
+   gpio.write(LED_PIN, LED_STATE)
+end
+
+function blink_start()
+   gpio.mode(LED_PIN, gpio.OUTPUT)
+   tmr.alarm(LED_TIMER, LED_INTERVAL, tmr.ALARM_AUTO, blink)
+end
+
+function blink_stop()
+   tmr.stop(LED_TIMER)
+   tmr.unregister(LED_TIMER)
+end
+
+ds18b20.init(SENSOR_PIN)
+blink_start()
+clients = mqtt_start()
diff --git a/config.lua.example b/config.lua.example
new file mode 100644 (file)
index 0000000..c8069cc
--- /dev/null
@@ -0,0 +1,26 @@
+-- WiFi network to join and the PSK password
+
+SSID='WIFI_SSID_HERE'
+PASSWORD='WIFI_PASSWORD'
+
+SENSOR_PIN = 3
+SENSOR_TIMER = 2
+SENSOR_INTERVAL = 10 -- seconds
+
+LED_PIN = 4
+LED_TIMER = 5
+LED_INTERVAL = 1000
+
+-- Username and password to use for MQTT
+MQTT_PORT = 1883
+MQTT_USERNAME=''
+MQTT_PASSWORD=''
+
+-- MQTT brokers and prefixes
+--
+-- a list of MQTT brokers to publish too with a custom prefix for
+-- each broker. Use a separate timer id for each broker.
+MQTT_BROKERS = {
+   -- iot.eclipse.org
+   { host='198.41.30.241', prefix='mqtt_sensor_demo/nodemcu', timer=4, interval=600 }
+}
diff --git a/ds18b20.lua b/ds18b20.lua
new file mode 100644 (file)
index 0000000..208ec9b
--- /dev/null
@@ -0,0 +1,80 @@
+local modname = ...\r
+local M = {} -- public interface\r
+_G[modname] = M\r
+\r
+require('bit')\r
+require('ow')\r
+\r
+M.CONVERT = 0x44\r
+M.READ_SCRATCHPAD = 0xBE\r
+\r
+local function hexstring(...)\r
+    local len = select('#', ...)\r
+    local r = {}\r
+    for n = 1, len do r[n] = string.format("%02x", select(n,...)) end\r
+    return table.concat(r, ':')\r
+end\r
+\r
+local function find_devices(pin)\r
+    ow.setup(pin)\r
+    ow.reset_search(pin)\r
+    local devices = {}\r
+    repeat\r
+        local addr = ow.search(pin)\r
+        if addr ~= nil then table.insert(devices, addr) end\r
+        tmr.wdclr()\r
+    until addr == nil\r
+    return devices\r
+end\r
+\r
+function M.init(pin)\r
+    M.pin = pin\r
+    M.timerid = 1\r
+    M.delay = 800\r
+    M.pending = 0\r
+    M.values = {}\r
+    M.sensors = find_devices(pin)\r
+end\r
+\r
+function M.read_sensors()\r
+    local pin = M.pin\r
+    for i,addr in ipairs(M.sensors) do\r
+        local id = hexstring(addr:byte(1,8))\r
+        ow.reset(pin)\r
+        ow.select(pin,addr)\r
+        ow.write(pin,M.READ_SCRATCHPAD,1)\r
+        local data = nil\r
+        data = string.char(ow.read(pin))\r
+        for i = 1, 8 do\r
+            data = data .. string.char(ow.read(pin))\r
+        end\r
+        local crc = ow.crc8(string.sub(data,1,8))\r
+        if (crc == data:byte(9)) then\r
+            local t = data:byte(1) + data:byte(2) * 256\r
+            if (t > 32768) then\r
+                -- convert unsigned to signed twos complement.\r
+                t = (bit.bxor(t, 0xffff) + 1) * -1\r
+            end\r
+            t = t * 625\r
+            print(id, t)\r
+            M.values[id] = t\r
+        else\r
+            print(id, "bad crc")\r
+        end\r
+        M.pending = M.pending - 1\r
+    end\r
+end\r
+\r
+function M.update()\r
+    local t = 0\r
+    M.pending = 0\r
+    for i,addr in ipairs(M.sensors) do\r
+        ow.reset(M.pin)\r
+        ow.select(M.pin, addr)\r
+        ow.write(M.pin, M.CONVERT, 1)\r
+        M.pending = M.pending + 1\r
+    end\r
+    tmr.alarm(M.timerid, M.delay, tmr.ALARM_SINGLE, M.read_sensors)\r
+end\r
+\r
+return M\r
diff --git a/esp01_sensor.pdf b/esp01_sensor.pdf
new file mode 100644 (file)
index 0000000..73705b8
Binary files /dev/null and b/esp01_sensor.pdf differ
diff --git a/init.lua b/init.lua
new file mode 100644 (file)
index 0000000..bfe3ec3
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,37 @@
+require('tmr')
+require('wifi')
+require('file')
+
+-- load credentials, 'SSID' and 'PASSWORD' declared and initialize in there
+dofile("config.lua")
+
+function startup()
+   if file.exists("application.lua") then
+      -- the actual application is stored in 'application.lua'
+      print("Running application.lua")
+      dofile("application.lua")
+   else
+      print('warning: missing file "application.lua"')
+   end
+end
+
+function abort()
+   tmr.stop(1)
+end
+
+print("Connecting to WiFi access point...")
+wifi.setmode(wifi.STATION)
+print('MAC: ' .. wifi.sta.getmac())
+wifi.sta.config(SSID, PASSWORD)
+-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default
+tmr.alarm(1, 1000, tmr.ALARM_AUTO, function()
+    if wifi.sta.getip() == nil then
+        print("Waiting for IP address...")
+    else
+        tmr.stop(1)
+        print("WiFi connection established, IP address: " .. wifi.sta.getip())
+        print("You have 5 seconds to abort (abort())")
+        print("Waiting...")
+        tmr.alarm(1, 5000, tmr.ALARM_SINGLE, startup)
+    end
+end)