Skip to content

Instantly share code, notes, and snippets.

@foosel
Last active January 24, 2017 20:14
Show Gist options
  • Save foosel/f9eaf29944b4bcd78a34 to your computer and use it in GitHub Desktop.
Save foosel/f9eaf29944b4bcd78a34 to your computer and use it in GitHub Desktop.
First experiments with NodeMCU to publish the current settings of my adjustable height working desk to MQTT

First experiments with NodeMCU to publish the current settings of my adjustable height working desk to MQTT.

NodeMCU can be found here: https://github.com/nodemcu/nodemcu-firmware

Note that you'll need a current version with support for floats (which the ultrasonic sensor library utilizes), I'm using 0.9.5 2015-03-18 with float support myself.

Support for the HC-SR04 sensor in NodeMCU can be found here: https://github.com/sza2/node_hcsr04

I provided my slightly adjusted version which makes measuring a non-blocking afair, allowing for callbacks when the measurement completes.

For uploading the files to the ESP I used nodemcu-uploader. I compiled both hcsr04.lua and sensor.lua with the -c option, hence they are referenced in the source below as hcsr04.lc and sensor.lc.

For prototyping I used an ESP8266-03 Wifi Module Breakout Board by Stephan Limpkin I got myself a couple of weeks back. The HC-SR04 sensor module is connected to it like this:

  • VCC -> +5V
  • GND -> GND
  • Trig -> GPIO2
  • Echo -> GPIO0

Together with some mqttwarn magic my desk can now tweet and publish the current measurements to a Google Spreadsheet where I can plot it ;)

Tweeting desk

Plotting desk


Files found here:

  • hcsr04.lua: lib for reading measurements from HC-SR04 sensor
  • sensor.lua: my ESP8266 "firmware" for repeatedly reading the sensor data and publishing it to the mqtt broker
  • init.lua: NodeMCU startup file that starts sensor.lua once the node is online
  • desk.json.jinja2: Jinja2 template for transforming the current measurements from the desk into a json format (put it into the templates folder in your mqttwarn install dir)
  • mqttwarn.ini: excerpts from my mqttwarn configuration showing how I setup publishing to my Google Spreadsheet and my desk's twitter account

Post about this on G+

{% set data = {
"host": topic,
"timestamp": _dtiso,
"measurement": payload
}
%}
{{ data | jsonify }}
--
-- Copyright (C) 2014 Tamas Szabo <[email protected]>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Originally from https://github.com/sza2/node_hcsr04
--
-- Adjusted by Gina Häußge <[email protected]> to allow reporting of measurements
-- back via a callback function instead of blocking until measurement has finished.
hcsr04 = {};
function hcsr04.init(pin_trig, pin_echo)
local self = {}
self.time_start = 0
self.time_end = 0
self.trig = pin_trig or 4
self.echo = pin_echo or 3
self.callback = nil
self.measurement = nil
gpio.mode(self.trig, gpio.OUTPUT)
gpio.mode(self.echo, gpio.INT)
function self.echo_cb(level)
if level == 1 then
self.time_start = tmr.now()
gpio.trig(self.echo, "down")
else
self.time_end = tmr.now()
time_difference = self.time_end - self.time_start
if time_difference < 0 then
self.measurement = -1
else
self.measurement = time_difference / 5800
end
if (self.callback) then
self.callback(time_difference, self.measurement)
end
end
end
function self.measure(callback)
self.callback = callback
self.measurement = nil
gpio.trig(self.echo, "up", self.echo_cb)
gpio.write(self.trig, gpio.HIGH)
tmr.delay(100)
gpio.write(self.trig, gpio.LOW)
end
function self.measure_and_return(callback)
self.measure(callback)
tmr.delay(100000)
if self.measurement == nil then
return -1
else
return self.measurement
end
end
function self.measure_and_print(callback)
print(self.measure_and_return(callback))
end
return self
end
TIMER_WIFI_CONNECT = 1
tmr.alarm(TIMER_WIFI_CONNECT, 1000, 1, function()
if wifi.sta.status() == 5 then
tmr.stop(TIMER_WIFI_CONNECT)
dofile("sensor.lc")
end
end)
### Excerpt for sending the data to my Google Spreadsheet
[config:gss]
username = <my account>
password = <my app password>
targets = {
'desk' : [ '<spreadsheet id>', '<sheet: od6 for first one>' ]
}
[config:mqttpub]
targets = {
'desk' : [ 'home/office/desk_gina/current.json', 0, False ],
}
[home/office/desk_gina/current]
targets = mqttpub:desk
template = desk.json.jinja2
[home/office/desk_gina/current.json]
targets = gss:desk
### Excerpt for tweeting the current status
[config:twitter]
targets = {
'fooselsDesk' : ['<consumer key>',
'<consumer secret>',
'<access token key>',
'<access token secret>'
]
}
[home/office/desk_gina/status]
targets = twitter:fooselsDesk
format = Oh, @foosel is now {payload} (@ {_dthhmm})
dofile("hcsr04.lc")
BROKER = "<my broker>"
BRPORT = 1883
CLIENTID = "ESP8266-" .. node.chipid()
TOPIC = "home/office/desk_gina"
TOPIC_CURRENT = TOPIC.."/current"
TOPIC_STATUS = TOPIC.."/status"
TIMER_MQTT_CONNECT = 2
TIMER_MEASURING = 6
tablesensor = {}
function tablesensor.init(sitting_height, standing_height)
local self = {}
self.sitting_height = sitting_height
self.standing_height = standing_height
self.standing = false
self.sitting = false
self.device = hcsr04.init()
self.mqtt = mqtt.Client(CLIENTID, 120)
self.mqtt:on("connect", function(conn)
print("Connected to MQTT:" .. BROKER .. ":" .. BRPORT .." as " .. CLIENTID)
-- start measuring
print("Ready...")
tmr.alarm(TIMER_MEASURING, 5000, 1, function() self.device.measure(measurement_callback) end)
end)
self.mqtt:on("offline", function(conn)
print("Offline")
end)
function measurement_sent(measurement)
-- target hit if target - margin < measurement < target + margin
local sitting_hit = (measurement > 0) and (measurement <= self.sitting_height)
local standing_hit = (measurement >= self.standing_height)
if (sitting_hit) then
self.standing = false
if (not self.sitting) then
self.sitting = true
-- send sitting notification to mqtt broker
self.mqtt:publish(TOPIC_STATUS, "sitting", 0, 0, function(conn)
print("Reported sitting")
end)
end
else
self.sitting = false
if (standing_hit) then
if (not self.standing) then
self.standing = true
-- send standing notification to mqtt broker
self.mqtt:publish(TOPIC_STATUS, "standing", 0, 0, function(conn)
print("Reported standing")
end)
end
else
self.standing = false
end
end
end
function measurement_callback(time_spent, measurement)
-- send current measurement to mqtt broker
self.mqtt_sending = true
self.mqtt:publish(TOPIC_CURRENT, measurement, 0, 0, function(conn)
print("Sent current: "..measurement)
measurement_sent(measurement)
end)
end
function self.connect()
self.mqtt:connect(BROKER, BPORT)
end
return self
end
sensor = tablesensor.init(0.8, 0.8)
sensor.connect()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment