Skip to content

Commit

Permalink
Merge pull request #25 from fikin/dev
Browse files Browse the repository at this point in the history
fixing closing of the socket session for telnet.
  • Loading branch information
fikin committed Sep 21, 2023
2 parents 4154be3 + 0d072b3 commit cb17a26
Show file tree
Hide file tree
Showing 15 changed files with 258 additions and 72 deletions.
1 change: 1 addition & 0 deletions build.config
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ spiffs-1mboundary=true
lua=53
lua-init=require('init')

lua-modules=adc-ntc
lua-modules=bootprotect
lua-modules=bootstrap
lua-modules=device-settings
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/lua/testInit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ local function assertTelnet()
local skt = nodemcu.net_tpc_connect_to_listener(23, "0.0.0.0")
assertSktReceived(skt, "Enter username:")
assertSktSendReceived(skt, "dummy", "Enter username:")
assertSktSendReceived(skt, "telnet", "Enter password:")
assertSktSendReceived(skt, "admin", "Enter password:")
assertSktSendReceived(skt, "dummy", "Enter username:")
assertSktSendReceived(skt, "telnet", "Enter password:")
assertSktSendReceived(skt, "admin", "Enter password:")
assertSktSendReceived(skt, "admin", "") -- this is now deviating from actual device, as node.output() is not properly captured in mock setup
assertSktSendReceived(skt, "return 'abc'", "abc\n")
end
Expand Down
8 changes: 8 additions & 0 deletions lua_modules/adc-ntc/fs/fs-adc-ntc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Rntc": 50000,
"R1": 330000,
"VCC": 5,
"A": 1.129148e-3,
"B": 2.34125e-4,
"C": 8.76741e-8
}
69 changes: 69 additions & 0 deletions lua_modules/adc-ntc/lua/adc-ntc.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
--[[
ADC reader for NTC connected to ADC input.
R1 is connected to VCC and Rntc.
]]
local modname = ...

local adc = require("adc")

---@class adcNtc_cfg
---@field Rntc integer NTC resistance in Kohm
---@field R1 integer resistor 1 in Kohm
---@field VCC integer VCC in V
---@field A number Steinhart-Hart model coefficient
---@field B number Steinhart-Hart model coefficient
---@field C number Steinhart-Hart model coefficient

---table with "adc" key and temperature in C.
---this is temp-sensor interface req.
---@alias adc_temp {[string]:number}

---@type adcNtc_cfg
local cfg = require("device-settings")(modname)

---natural logarithm approximation
---@param x number
---@return number
function ln(x) --natural logarithm function for x>0 real values
local y = (x - 1) / (x + 1)
local sum = 1
local val = 1
if (x == nil) then
return 0
end
-- we are using limited iterations to acquire reliable accuracy.
-- here its upto 10000 and increased by 2
for i = 3, 10000, 2 do
val = val * (y * y)
sum = sum + (val / i)
end
return 2 * y * sum
end

---@param cnt integer how to many readinds to average
---@return number average value
local function readAvg(cnt)
local t = 0
for i = 1, cnt, 1 do
t = t + adc.read(0)
end
return t / cnt
end

---@param onReadCb fun(adc_temp) callback when temps have been read
local function main(onReadCb)
package.loaded[modname] = nil

local dAdcValue = readAvg(10)
local dVout = (dAdcValue * cfg.VCC) / 1023
local dRth = (cfg.VCC * cfg.R1 / dVout) - cfg.R1
-- Temperature in kelvin
local t = (1 / (cfg.A + (cfg.B * ln(dRth)) + (cfg.C * (ln(dRth)) ^ 3)))
-- Temperature in degree celsius
t = t - 273.15

onReadCb({ adc = t })
end

return main
31 changes: 24 additions & 7 deletions lua_modules/bootstrap/fs/bootstrap-sw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,32 @@

local fs = require("factory-settings")

--fs("wifi-sta"):set("config.ssid","<SSID>"):set("config.pwd","<PWD>"):set("hostname","<HOSTNAME>"):done()
-- TODO : typically one wants to update these ones as part
-- of device inital boostrap.
-- Or use web-portal to update it later on too.
-- By default hostname is based on chipID
local hostname = "nodemcu" .. require("node").chipid()
local staSsid = hostname
local staPwd = "1234567890"
local apSsid = hostname .. "_ap"
local apPwd = "1234567890"

-- minimal set of modules on
-- fs("init-seq"):set("bootsequence",{ "bootstrap", "user-settings", "log-start", "wifi-apply-config", "wifi-mgr", "http-srv", "telnet" }):done()
local mac = require("wifi").ap.getmac()
fs("wifi-sta"):set("config.ssid", staSsid):set("config.pwd", staPwd):set("hostname", hostname):set("mac", mac):done()
fs("wifi-ap"):set("config.ssid", apSsid):set("config.pwd", apPwd):set("mac", mac):done()

-- likely same credentials for admin services
-- fs("telnet"):set("usr", "<ADMIN>"):set("pwd", "<APWD>"):done()
-- fs("web-portal"):set("usr", "<ADMIN>"):set("pwd", "<APWD>"):done()
-- fs("web-ota"):set("usr", "<ADMIN>"):set("pwd", "<APWD>"):done()
-- TODO likely update these too
local adminUsr = "admin"
local adminPwd = "admin"
fs("telnet"):set("usr", adminUsr):set("pwd", adminPwd):done()
fs("web-portal"):set("usr", adminUsr):set("pwd", adminPwd):done()
fs("web-ota"):set("usr", adminUsr):set("pwd", adminPwd):done()

-- minimal HomeAssistant modules and credentials
--fs("web-ha"):set("entities", { "system-hass" }):set("credentials.usr", "<HAUSER>"):set("credentials.pwd", "<HAPWD>"):done()
-- fs("web-ha"):set("entities", { "system-hass" }):set("credentials.usr", "<HAUSER>"):set("credentials.pwd", "<HAPWD>"):done()

-- minimal set of modules on.
-- restart at the end since the boot sequence is modified.
-- fs("init-seq"):set("bootsequence",{ "bootstrap", "user-settings", "log-start", "wifi-apply-config", "wifi-mgr", "http-srv", "telnet" }):done()
-- node.restart()
35 changes: 20 additions & 15 deletions lua_modules/bootstrap/lua/bootstrap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,32 @@ local modname = ...

local file, log = require("file"), require("log")

local fName = "bootstrap-sw.lc"
local fName = "bootstrap-sw"
local fNameErr = "bootstrap-sw.PANIC.txt"

local function main()
package.loaded[modname] = nil

if file.exists(fName) then
log.info("running %s", fName)

local ok, err = pcall(require, "bootstrap-sw")

file.remove(fName)

if not ok then
log.error("bootstrap failed : %s : %s", fName, err)
file.remove(fNameErr)
file.putcontents(fNameErr, err)
for _, ext in ipairs({".lc", ".lua"}) do
local f = fName .. ext
if file.exists(f) then
log.info("running %s", f)

local ok, err = pcall(require, "bootstrap-sw")

file.remove(f)

if not ok then
log.error("bootstrap failed : %s : %s", f, err)
file.remove(fNameErr)
file.putcontents(fNameErr, err)
end

collectgarbage()
collectgarbage()

return
end

collectgarbage()
collectgarbage()
end
end

Expand Down
15 changes: 3 additions & 12 deletions lua_modules/device-settings/lua/user-settings.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
--[[
Add here device settings which you want to apply programmatically at boot time.
Add here device settings which you want to
apply programmatically at boot time each time.
Use builder:set("field path", value) to set a value.
Expand All @@ -14,23 +15,13 @@
]]
local modname = ...

local fs = require("factory-settings")

---place to provide with device specific hardcoded device settings.
---feel free to modify the settings here, boot sequence will ensure
---the data is properly handled in device settings.
local function main()
package.loaded[modname] = nil

-- typically set hostname is based on chipID
-- until user overwrites it via web-portal for example

-- Superseeded by boostrap-sw module !!!
-- local hostname = "nodemcu" .. require("node").chipid()
-- local mac = require("wifi").ap.getmac()
-- fs("wifi-sta"):default("hostname", hostname):default("mac", mac):done()
-- fs("wifi-ap"):default("config.ssid", hostname .. "_ap"):default("mac", mac):done()

-- local fs = require("factory-settings")

-- TODO add here your other hardcoded settings if you want to
end
Expand Down
3 changes: 3 additions & 0 deletions lua_modules/ds18b20/fs/fs-ds18b20.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"pin": 5
}
51 changes: 35 additions & 16 deletions lua_modules/ds18b20/lua/ds18b20.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,34 @@ local READ_SCRATCHPAD = 0xBE
local READ_POWERSUPPLY = 0xB4
local MODE = 1

---@class ds18b20_sensor_cfg
---@field pin integer

---@type ds18b20_sensor_cfg
local cfg = require("device-settings")(modname)

---table with sensor addresses and temperature in C.
---this is temp-sensor interface req.
---@alias ds18b20_temps {[string]:number}

---converts ow sensor addr to string representation
---@class ds18b20_struct
---@field pin integer
---@field cb function(ds18b20_temps)
---@field discoveredAddrs string[]
---@field validAddrs table

---@type ds18b20_struct
local callState = {
pin = cfg.pin,
---@type function(ds18b20_temps)
cb = nil,
---@type string[]
discoveredAddrs = nil,
---@type table
validAddrs = nil,
}

---converts ow sensor addr to string representation
---@param addr string
---@return string
local function addrToStr(addr)
Expand Down Expand Up @@ -167,7 +191,7 @@ local function readRawTemps(pin, addrs)
end

---read temps after conversion
---@param o ds18b20_struct*
---@param o ds18b20_struct
local function readTempsAfterConversions(o)
local rawTemps = readRawTemps(o.pin, o.validAddrs)
local temps = decodeTemps(rawTemps)
Expand All @@ -176,7 +200,7 @@ local function readTempsAfterConversions(o)
end

---suspend the thread until node.taks revives it back.
---@param o ds18b20_struct*
---@param o ds18b20_struct
---@param delay? integer
local function wait(o, delay)
local f = function() readTempsAfterConversions(o) end
Expand All @@ -187,7 +211,7 @@ local function wait(o, delay)
end
end

---@param o ds18b20_struct*
---@param o ds18b20_struct
local function readT(o)
ow.setup(o.pin)
o.discoveredAddrs = readAddrs(o.pin)
Expand All @@ -199,19 +223,14 @@ end
---read DS18B20 sensor temperature over OW and returns its temperature.
---throws error in case there was a problem with reading the data.
---internally it uses coroutine to suspend execution call when time delay is needed.
---@param pin integer
---@param onReadCb fun(ds18b20_temps) callback when temps have been read
local function main(pin, onReadCb)
---@class ds18b20_struct*
local o = {
pin = pin,
cb = onReadCb,
---@type string[]
discoveredAddrs = nil,
---@type table
validAddrs = nil,
}
readT(o)
---@return ds18b20_struct one can use it to troubleshoot ow addresses
local function main(onReadCb)
package.loaded[modname] = nil

callState.cb = onReadCb
readT(callState)
return callState
end

return main
5 changes: 4 additions & 1 deletion lua_modules/telnet/lua/telnet.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ local function readAndSendOnceFact(tbl)
return function(skt)
local rec = tbl.pipe:read(1400)
if rec and #rec > 0 then
skt:send(rec)
if not pcall(function() skt:send(rec) end) then
pcall(function() skt:close() end)
onDisconnect()
end
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion lua_modules/temp-sensor/fs/fs-temp-sensor.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"periodMs": 19000,
"pin": 5
"filterSize": 20,
"moduleName": "ds18b20"
}
20 changes: 12 additions & 8 deletions lua_modules/temp-sensor/lua/temp-sensor-control.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,26 @@ local state = getState()
---@param temp table as provided by ds18b20
local function updateTempState(temp)
local log = require("log")
local moreThanOne = false
local addrsCnt = 0
for addr, temp in pairs(temp) do
if moreThanOne then
log.info("temp sensor %s (%f°C) is ignored, only one sensor over i2c bus is supported", addr, temp)
if addrsCnt > 1 then
log.info("temp sensor %s (%f°C) is ignored, only one sensor is supported", addr, temp)
else
state.data.native_value = temp
log.info("temp of sensor %s is %f°C", addr, temp)
-- pass new value over avg filter logic
state.data.native_value = (state.data.native_value * (state.filterSize - 1) + temp) / state.filterSize
log.info("temp of sensor %s is : %f°C : new reading is %f°C", addr, state.data.native_value, temp)
end
moreThanOne = true
addrsCnt = addrsCnt + 1
end
if addrsCnt == 0 then
log.error("no temp sensor readings provided : %s", log.json, temp)
end
end

---call thermostat's control loop
local function applyControlLoop()
local ds18b20 = require("ds18b20")
ds18b20(state.pin, updateTempState)
local m = require(state.moduleName)
m(updateTempState)
end

local function main()
Expand Down
3 changes: 2 additions & 1 deletion lua_modules/temp-sensor/lua/temp-sensor-start.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ local log = require("log")

---@class temp_sensor_cfg
---@field periodMs integer
---@field pin integer
---@field filterSize integer
---@field moduleName string
---@field data temp_sensor_cfg_data

---@return temp_sensor_cfg
Expand Down

0 comments on commit cb17a26

Please sign in to comment.