mod_led_control: added netdev trigger, more options for timer trigger.

This commit is contained in:
gSpot
2025-08-09 18:37:11 +03:00
parent 9067d3d3ab
commit 1c02ace538
11 changed files with 466 additions and 115 deletions

View File

@@ -1,51 +1,53 @@
local unistd = require("posix.unistd")
local dirent = require("posix.dirent")
local time = require("posix.time")
local unistd = require("posix.unistd")
local Module = {
name = "mod_led_control",
runPrio = 10,
config = {},
syslog = function(level, msg) return true end,
debugOutput = function(msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
runInterval = 5,
sysLedsDir = "/sys/class/leds",
ledsPerInstance = 3,
ledAction1Default = 1, -- 1: off, 2: on, 3: blink
ledAction2Default = 1,
status = nil,
_enabled = false,
_leds = {},
_counter = 0,
name = "mod_led_control",
runPrio = 10,
config = {},
syslog = function(level, msg) return true end,
debugOutput = function(msg) return true end,
writeValue = function(filePath, str) return false end,
readValue = function(filePath) return nil end,
runInterval = 5,
sysLedsDir = "/sys/class/leds",
ledsPerInstance = 3,
ledAction1Default = 1, -- 1: off, 2: on, 3: blinking, 4: netdev
ledAction2Default = 1,
ledBlinkDelayDefault = 500,
ledNetlinkDeviceDefault = nil,
ledNetdevModeLinkDefault = "1",
ledNetdevModeRxDefault = "0",
ledNetdevModeTxDefault = "0",
status = nil,
_enabled = false,
_leds = {},
_counter = 0,
}
function Module:resetLeds()
local ok, dir = pcall(dirent.files, self.sysLedsDir)
if not ok then
return
end
for led in dir do
local brightness = string.format("%s/%s/brightness", self.sysLedsDir, led)
if unistd.access(brightness, "w") then
self.writeValue(brightness, 0)
end
end
end
function Module:setLedAttrs(t)
t.ledDir = string.format("%s/%s", self.sysLedsDir, t.ledName)
t.ledMaxBrightnessFile = string.format("%s/max_brightness", t.ledDir)
t.ledBrightnessFile = string.format("%s/brightness", t.ledDir)
t.ledMaxBrightness = self.readValue(t.ledMaxBrightnessFile) or 1
t.ledMaxBrightness = self.readValue(t.ledMaxBrightnessFile) or "1"
t.ledTriggerFile = string.format("%s/trigger", t.ledDir)
t.ledDelayOnFile = string.format("%s/delay_on", t.ledDir)
t.ledDelayOffFile = string.format("%s/delay_off", t.ledDir)
t.ledDeviceNameFile = string.format("%s/device_name", t.ledDir)
t.ledLinkFile = string.format("%s/link", t.ledDir)
t.ledRxFile = string.format("%s/rx", t.ledDir)
t.ledTxFile = string.format("%s/tx", t.ledDir)
t.ledPrevState = {
brightness = self.readValue(t.ledBrightnessFile),
trigger = self.readValue(t.ledTriggerFile),
}
if t.ledPrevState.trigger then
t.ledPrevState.trigger = t.ledPrevState.trigger:match("%[[%w%-_]+%]"):gsub("[%]%[]", "")
local val = t.ledPrevState.trigger:match("%[[%w%-_]+%]")
if val then
t.ledPrevState.trigger = val:gsub("[%]%[]", "")
end
end
end
@@ -65,10 +67,43 @@ function Module:init(t)
return
end
for i, l in ipairs(self._leds) do
if t["led" .. i .. "_name"] ~= nil then
l.ledName = t["led" .. i .. "_name"]
l.ledAction1 = tonumber(t["led" .. i .. "_action_1"]) or self.ledAction1Default
l.ledAction2 = tonumber(t["led" .. i .. "_action_2"]) or self.ledAction2Default
local led = "led" .. i
if t[led .. "_name"] ~= nil then
l.ledName = t[led .. "_name"]
l.ledAction1 = tonumber(t[led .. "_action_1"]) or self.ledAction1Default
l.ledAction2 = tonumber(t[led .. "_action_2"]) or self.ledAction2Default
l.ledBlinkOnDelay1 = tonumber(t[led .. "_blink_on_delay_1"]) or self.ledBlinkDelayDefault
l.ledBlinkOffDelay1 = tonumber(t[led .. "_blink_off_delay_1"]) or self.ledBlinkDelayDefault
l.ledBlinkOnDelay2 = tonumber(t[led .. "_blink_on_delay_2"]) or self.ledBlinkDelayDefault
l.ledBlinkOffDelay2 = tonumber(t[led .. "_blink_off_delay_2"]) or self.ledBlinkDelayDefault
l.ledNetlinkDevice1 = t[led .. "_netdev_device_1"] or self.ledNetlinkDeviceDefault
l.ledNetlinkDevice2 = t[led .. "_netdev_device_2"] or self.ledNetlinkDeviceDefault
l.ledNetdevModeLink1 = self.ledNetdevModeLinkDefault
l.ledNetdevModeTx1 = self.ledNetdevModeTxDefault
l.ledNetdevModeRx1 = self.ledNetdevModeRxDefault
l.ledNetdevModeLink2 = self.ledNetdevModeLinkDefault
l.ledNetdevModeTx2 = self.ledNetdevModeTxDefault
l.ledNetdevModeRx2 = self.ledNetdevModeRxDefault
local ndm1 = t[led .. "_netdev_mode_1"]
if ndm1 ~= nil and type(ndm1) == "table" then
local enabledFlags = {}
for _, v in ipairs(ndm1) do
enabledFlags[v] = "1"
end
l.ledNetdevModeLink1 = enabledFlags.link or "0"
l.ledNetdevModeTx1 = enabledFlags.tx or "0"
l.ledNetdevModeRx1 = enabledFlags.rx or "0"
end
local ndm2 = t[led .. "_netdev_mode_2"]
if ndm2 ~= nil and type(ndm2) == "table" then
local enabledFlags = {}
for _, v in ipairs(ndm2) do
enabledFlags[v] = "1"
end
l.ledNetdevModeLink2 = enabledFlags.link or "0"
l.ledNetdevModeTx2 = enabledFlags.tx or "0"
l.ledNetdevModeRx2 = enabledFlags.rx or "0"
end
self:setLedAttrs(l)
l.enabled = true
else
@@ -82,29 +117,119 @@ function Module:init(t)
end
end
function Module:setTriggerTimer(t)
self.writeValue(t.ledTriggerFile, "timer")
function Module:checkLedTimer(t)
return (unistd.access(t.ledDelayOnFile, "rw") and unistd.access(t.ledDelayOffFile, "rw"))
end
function Module:checkLedNetdev(t)
return (unistd.access(t.ledDeviceNameFile, "rw") and
unistd.access(t.ledLinkFile, "rw") and
unistd.access(t.ledRxFile, "rw") and
unistd.access(t.ledTxFile, "rw"))
end
function Module:setTriggerNone(t)
self.writeValue(t.ledTriggerFile, "none")
self.debugOutput(string.format(
"%s: LED TRIGGER SET: none, %s", self.name, t.ledTriggerFile))
end
function Module:setTriggerTimer(t, delayOn, delayOff)
if not delayOn then
delayOn = self.ledBlinkDelayDefault
end
if not delayOff then
delayOff = self.ledBlinkDelayDefault
end
self.writeValue(t.ledTriggerFile, "timer")
for i = 0, 10 do
if self:checkLedTimer(t) then
self.writeValue(t.ledDelayOnFile, delayOn)
self.writeValue(t.ledDelayOffFile, delayOff)
break
else
time.nanosleep({ tv_sec = 0, tv_nsec = 500000 })
end
end
self.debugOutput(string.format(
"%s: LED TRIGGER SET: timer, %s; delayOn = %s, delayOff = %s",
self.name, t.ledTriggerFile, tostring(delayOn), tostring(delayOff))
)
end
function Module:setTriggerNetdev(t, device, link, tx, rx)
if not device then
return
end
self.writeValue(t.ledTriggerFile, "netdev")
for i = 0, 10 do
if self:checkLedNetdev(t) then
self.writeValue(t.ledDeviceNameFile, device)
self.writeValue(t.ledLinkFile, link)
self.writeValue(t.ledTxFile, tx)
self.writeValue(t.ledRxFile, rx)
break
else
time.nanosleep({ tv_sec = 0, tv_nsec = 500000 })
end
end
self.debugOutput(string.format(
"%s: LED TRIGGER SET: netdev, %s; device = %s, link = %s, rx = %s, tx = %s",
self.name, t.ledTriggerFile, tostring(device), tostring(link), tostring(rx), tostring(tx))
)
end
function Module:getCurrentTrigger(t)
local trigger = self.readValue(t.ledTriggerFile)
if trigger and trigger:match("%[timer%]") then
return true
if trigger then
if trigger:match("%[timer%]") then
return "timer"
elseif trigger:match("%[netdev%]") then
return "netdev"
end
end
end
function Module:getTriggerValues(t, trigger)
local currentTrigger = self:getCurrentTrigger(t)
if trigger == currentTrigger then
if trigger == "timer" then
return {
trigger = currentTrigger,
delayOn = tonumber(self.readValue(t.ledDelayOnFile)),
delayOff = tonumber(self.readValue(t.ledDelayOffFile)),
}
elseif trigger == "netdev" then
return {
trigger = currentTrigger,
device = self.readValue(t.ledDeviceNameFile),
link = self.readValue(t.ledLinkFile),
tx = self.readValue(t.ledTxFile),
rx = self.readValue(t.ledRxFile),
}
end
end
return {}
end
function Module:on(t)
self:setTriggerNone(t)
self.writeValue(t.ledBrightnessFile, t.ledMaxBrightness)
self.debugOutput(string.format("%s: LED ON: %s", self.name, t.ledBrightnessFile))
end
function Module:off(t)
self:setTriggerNone(t)
self.writeValue(t.ledBrightnessFile, 0)
self.writeValue(t.ledBrightnessFile, "0")
self.debugOutput(string.format("%s: LED OFF: %s", self.name, t.ledBrightnessFile))
end
function Module:getCurrentState(t)
@@ -125,8 +250,21 @@ function Module:ledRunFunc(t, currentStatus)
self:on(t)
end
elseif t.ledAction1 == 3 then
if not self:getCurrentTrigger(t) then
self:setTriggerTimer(t)
local triggerValues = self:getTriggerValues(t, "timer")
if (not next(triggerValues)) or (triggerValues.delayOn ~= t.ledBlinkOnDelay1 or
triggerValues.delayOff ~= t.ledBlinkOffDelay1) then
self:setTriggerTimer(t, t.ledBlinkOnDelay1, t.ledBlinkOffDelay1)
end
elseif t.ledAction1 == 4 then
local triggerValues = self:getTriggerValues(t, "netdev")
if (not next(triggerValues)) or (triggerValues.device ~= t.ledNetlinkDevice1 or
triggerValues.link ~= t.ledNetdevModeLink1 or
triggerValues.tx ~= t.ledNetdevModeTx1 or
triggerValues.rx ~= t.ledNetdevModeRx1) then
self:setTriggerNetdev(t,
t.ledNetlinkDevice1, t.ledNetdevModeLink1,
t.ledNetdevModeTx1, t.ledNetdevModeRx1
)
end
end
else
@@ -139,8 +277,21 @@ function Module:ledRunFunc(t, currentStatus)
self:on(t)
end
elseif t.ledAction2 == 3 then
if not self:getCurrentTrigger(t) then
self:setTriggerTimer(t)
local triggerValues = self:getTriggerValues(t, "timer")
if (not next(triggerValues)) or (triggerValues.delayOn ~= t.ledBlinkOnDelay2 or
triggerValues.delayOff ~= t.ledBlinkOffDelay2) then
self:setTriggerTimer(t, t.ledBlinkOnDelay2, t.ledBlinkOffDelay2)
end
elseif t.ledAction2 == 4 then
local triggerValues = self:getTriggerValues(t, "netdev")
if (not next(triggerValues)) or (triggerValues.device ~= t.ledNetlinkDevice2 or
triggerValues.link ~= t.ledNetdevModeLink2 or
triggerValues.tx ~= t.ledNetdevModeTx2 or
triggerValues.rx ~= t.ledNetdevModeRx2) then
self:setTriggerNetdev(t,
t.ledNetlinkDevice2, t.ledNetdevModeLink2,
t.ledNetdevModeTx2, t.ledNetdevModeRx2
)
end
end
end

View File

@@ -350,12 +350,15 @@ end
function Module:httpRequest(url)
local retCode = 1, data
local iface = ""
if self.config.serviceConfig.iface then
iface = " --interface " .. self.config.serviceConfig.iface
end
local fh = io.popen(string.format(
'%s%s --connect-timeout %s %s "%s"; printf "\n$?";', self.curlExec, iface, self.timeout, self.curlParams, url), "r")
local curl = string.format(
'%s%s --connect-timeout %s %s "%s"; printf "\n$?";',
self.curlExec,
self.config.serviceConfig.iface and (" --interface " .. self.config.serviceConfig.iface) or "",
self.timeout,
self.curlParams,
url
)
local fh = io.popen(curl, "r")
if fh then
data = fh:read("*a")
fh:close()