From 726446fe6eb1b12ca2fbd2ebbd3e519452e15077 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Wed, 18 May 2022 19:26:59 +0200 Subject: add support for reading the work period from the sensor --- README.md | 15 +++++++++------ init.lua | 18 ++++++++++++------ sds011.lua | 31 +++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index b38159c..1f3c839 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,14 @@ port = softuart.setup(9600, 2, 1) port:on("data", 10, uart_callback) function uart_callback(data) - local pm25i, pm25d, pm10i, pm10d = sds011.parse_frame(data) - if pm25i ~= nil then - -- pm25i/pm10i contain the integer part (i.e., PM2.5 / PM10 value in µg/m³) - -- pm25d/pm10d contain the decimal/fractional part (i.e., PM2.5 / PM10 fraction in .1 µg/m³, range 0 .. 9) - else - -- invalid checksum or non-data frame (i.e., acknowledgment of a write command) + if sds011.parse_frame(data) then + -- PM values or work period have been updated + if sds011.pm2_5i ~= nil then + -- pm2_5i/pm10i contain the integer part (i.e., PM2.5 / PM10 value in µg/m³) + -- pm2_5d/pm10d contain the decimal/fractional part (i.e., PM2.5 / PM10 fraction in .1 µg/m³, range 0 .. 9) + else + -- sds011.work_period has been updated after using sds011.set_work_period + end end end ``` @@ -68,6 +70,7 @@ Currently, the following commands are supported * sleep == true: put sensor into sleep mode. The fan is turned off, no further measurements are performed * sleep == false: wake up sensor. * `port:write(sds011.set_work_period(period))` + * period == nil: request current work period; does not change it * period == 0: continuous operation (about one measurement per second) * 0 < *period* ≤ 30: about one measurement every *period* minutes; fan turned off in-between diff --git a/init.lua b/init.lua index 51aeafc..6dc32d0 100644 --- a/init.lua +++ b/init.lua @@ -25,12 +25,13 @@ end function setup_client() print("Connected") gpio.write(ledpin, 1) + port = softuart.setup(9600, 2, 1) + port:on("data", 10, uart_callback) publishing_mqtt = true mqttclient:publish(mqtt_prefix .. "/state", "online", 0, 1, function(client) publishing_mqtt = false + port:write(sds011.set_work_period(nil)) end) - port = softuart.setup(9600, 2, 1) - port:on("data", 10, uart_callback) end function connect_mqtt() @@ -55,8 +56,7 @@ function connect_wifi() end function uart_callback(data) - local pm25i, pm25f, pm10i, pm10f = sds011.parse_frame(data) - if pm25i == nil then + if not sds011.parse_frame(data) then print("Invalid or data-less SDS011 frame") return end @@ -64,8 +64,14 @@ function uart_callback(data) if sds011.work_period > 0 then work_period = string.format("%d min", sds011.work_period) end - local json_str = string.format('{"pm2_5_ugm3": %d.%d, "pm10_ugm3": %d.%d, "rssi_dbm": %d, "period": "%s"}', pm25i, pm25f, pm10i, pm10f, wifi.sta.getrssi(), work_period) - local influx_str = string.format("pm2_5_ugm3=%d.%d,pm10_ugm3=%d.%d", pm25i, pm25f, pm10i, pm10f) + + local json_str = string.format('{"rssi_dbm":%d,"period":"%s"', wifi.sta.getrssi(), work_period) + if sds011.pm2_5i ~= nil then + json_str = string.format('%s,"pm2_5_ugm3":%d.%d,"pm10_ugm3":%d.%d', json_str, sds011.pm2_5i, sds011.pm2_5f, sds011.pm10i, sds011.pm10f) + local influx_str = string.format("pm2_5_ugm3=%d.%d,pm10_ugm3=%d.%d", sds011.pm2_5i, sds011.pm2_5f, sds011.pm10i, sds011.pm10f) + end + json_str = json_str .. '}' + if not publishing_mqtt then watchdog:start(true) publishing_mqtt = true diff --git a/sds011.lua b/sds011.lua index dc0004f..98f5b09 100644 --- a/sds011.lua +++ b/sds011.lua @@ -55,23 +55,38 @@ end function sds011.set_work_period(period) -- period == 0 : continuous operation, about one measurement per second -- period > 0 : about one measurement every minutes, fan is turned off in-between - if period < 0 or period > 30 then + if period ~= nil and (period < 0 or period > 30) then return end - sds011.work_period = period - local cmd = string.char(c_head, c_id, c_workperiod, c_write, period) + local op = c_write + if period == nil then + op = c_read + period = 0 + end + local cmd = string.char(c_head, c_id, c_workperiod, op, period) cmd = cmd .. string.char(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) return sds011.finish_cmd(cmd) end function sds011.parse_frame(data) local header, command, pm25l, pm25h, pm10l, pm10h, id1, id2, sum, tail = struct.unpack("BBBBBBBBBB", data) - if header ~= c_head or command ~= 0xc0 or (pm25l + pm25h + pm10l + pm10h + id1 + id2) % 256 ~= sum or tail ~= c_tail then - return nil + if header ~= c_head or (pm25l + pm25h + pm10l + pm10h + id1 + id2) % 256 ~= sum or tail ~= c_tail then + return false + end + if command == 0xc0 then + local pm25 = pm25h * 256 + pm25l + local pm10 = pm10h * 256 + pm10l + sds011.pm2_5i = pm25 / 10 + sds011.pm2_5f = pm25 % 10 + sds011.pm10i = pm10 / 10 + sds011.pm10f = pm10 % 10 + return true + end + if command == 0xc5 then + sds011.work_period = pm10l + return true end - pm25 = pm25h * 256 + pm25l - pm10 = pm10h * 256 + pm10l - return pm25 / 10, pm25 % 10, pm10 / 10, pm10 % 10 + return false end return sds011 -- cgit v1.2.3