LUA (ESP8266) 如何从字符串调用/输入模块命令

Posted

技术标签:

【中文标题】LUA (ESP8266) 如何从字符串调用/输入模块命令【英文标题】:LUA (ESP8266) How to call/enter a module command from a string 【发布时间】:2021-02-20 22:33:34 【问题描述】:

请原谅我,我什至不知道我问的是不是正确的术语。

那么……就这样吧。

我构建了 Nodemcu Dali 的自定义固件(来自 Hackerspace Stugart。)这包括他们所指的 dali 照明控制“风味”。我不得不修改它以使用最新的 LUA 版本。无论如何,它可以工作,并且 MODULE 内置在固件中。

从 LUA 命令行/解释器(Esplorer 界面,我可以调用模块,一切正常。

要使用您输入的模块:

dali.arc(address_Mode,0,parameter)

dali.send(Address_Mode,Command,Address,parameter)

Address_mode 可以是:dali.SLAVE , dali.GROUP

命令可以是dali.UP_200MS , dali.IMMEDIATE_OFF , dali.GO_TO_SCENE --... about 50 commands.

将亮度级别 128 发送到所有驱动程序的示例命令如下:

dali.arc(dali.BROADCAST,0,128)   -- direct arc mode ( all lights,*ignored*,50% dimmed)

我想用 MQTT 来控制这个东西。 我可以使用 MQTT 主题:

dali_topic/arc_broadcast -- for dali.arc(dali.BROADCAST,var1,var2)
dali_topic/group -- for dali.arc(dali.GROUP,var1,var2)
dali_topic/slave -- for dali.arc(dali.SLAVE,var1,var2)

我的有效负载字符串只需要 2 个变量,用逗号分隔,例如。 0,128。

我整天都可以做到这一点,但现在我想让它“变得更好”......

我希望能够发送消息“dali.BROADCAST,0,128”,然后代码应将其排序到包含元素的表中:

table[1] = dali.BROADCAST
table[2] = 0
table[3] = 128

并调用 dali.arc(table[1],table[2],table[3])

表创建工作,但我无法将 dali.BROADCAST 传递给模块/函数?称呼。首先是因为它是一个字符串,其次是因为它不能转换为数字或任何需要的替代品。

如果可以做到这一点,命令字段也可以与 MQTT 有效负载一起发送,而不需要 50 个 MQTT 主题。

我想我也可以尝试很多 if 语句或搜索查找表,但也许有一种简单的方法可以将命令字段插入到函数/模块调用中?

非常感谢任何帮助

编辑这里是一些 LUA 输出:

table ="dali.BROADCAST",0,128
dali.arc(table[1],table[2],table[3])

结果:

Lua error:  stdin:1: bad argument #1 to 'arc' (number expected, got boolean)

因为如果你print("dali.BROADCAST") 你会得到nil 不过

table[4] = dali.BROADCAST
dali.arc(table[4],table[2],table[3])

结果正常。

print( type(dali.BROADCAST ))

number

那么如何传递作为“dali.BROADCAST”接收的我的 mqtt 字符串 dali.BROADCAST 并将其转换为仅 dali.BROADCAST? 请注意,我没有发送“”,但是消息是由 MQTT 作为 CSV 字符串发送的。

来自dali模块的固件源..在模块文件夹中:dali.c

LROT_BEGIN(dali, NULL, 0)
LROT_FUNCENTRY( setup, dali_setup )
LROT_FUNCENTRY( arc, dali_arc )
LROT_FUNCENTRY( send, dali_send )
LROT_NUMENTRY( BROADCAST, BROADCAST )
LROT_NUMENTRY( SLAVE, SLAVE )
LROT_NUMENTRY( GROUP, GROUP )
LROT_NUMENTRY( IMMEDIATE_OFF, DALI_IMMEDIATE_OFF)
LROT_NUMENTRY( GO_TO_SCENE, DALI_GO_TO_SCENE)

shackspace github 链接是正确的,它只是基于 LUA1.45 或类似的低版本。我只需要修改 Modules 中的 dali.c 即可使用最新的 LUA。

固件中的相关dali文件位于 app/modules app/include app/dali 文件夹

【问题讨论】:

【参考方案1】:

编辑:考虑一下,您可能总是最终索引dali,在这种情况下,您可以直接通过像这样构造您的表来这样做:

table[1] = "arc"
table[2] = "BROADCAST"
table[3] = 0
table[4] = 128

通过这种方式,您可以通过 dali[table[2]] 访问 dali.BROADCAST,通过 dali[table[1]] 访问 dali.arc

提示:您可能仍然应该保留允许的白名单,因为有人可以发送任何字符串,并且您的程序不应该只是盲目地将 dali 表索引并返回它。


你可能想要this这样的东西

以下是相关代码:

function deepindex(tab, path)
    if type(path)~="string" then
        return nil, "path is not a string"
    end
    local index, rest = path:match("^%.?([%a%d]+)(.*)")
    if not index then
        index, rest = path:match("^%[(%d+)%](.*)")
        index = tonumber(index)
    end
    if index then
        if #rest>0 then
            if tab[index] then
                return deepindex(tab[index], rest)
            else
                return nil, "full path not present in table"
            end
        else
            return tab[index]
        end
    else
        return nil, "malformed index-path string"
    end
end

作业:此功能也适用于您不需要的数字索引[]。应该很容易将函数简化为只使用.进行字符串索引


您可以在全局环境中使用它来用单个字符串对其进行索引:

deepindex(_G, "dali.BROADCAST")
-- Which is the same as
_G.dali.BROADCAST
-- And, unless dali is a local, also
dali.BROADCAST

但请记住,这可以让您远程索引 _G 任何东西,这是一场巨大的安全噩梦。最好这样做:

local whitelist = 
whitelist.dali = dali

deepindex(whitelist, "dali.BROADCAST") -- this works
deepindex(whitelist, "some.evil.submodule") -- This does nothing

【讨论】:

不,string.find() 仅在您给它的字符串上,而不是整个_G。您使用它的唯一原因是您不知道某物存在于何处。他清楚地知道值存在的位置,因为它实际上只是dali.BROADCAST,但无论出于何种原因,dali.arc 函数都不允许从表中传递值;因此我改用dali.send() 的理由。【参考方案2】:

正在寻找包含更多详细信息的 Wiki 条目,但我没有找到。如果您碰巧知道详细说明可用 Lua 命令的文档在哪里,请在您的问题中包含一个链接。


似乎可能还有其他功能可以达到相同的结果,但我不确定它们在您的特定构建中的措辞方式。

https://github.com/shackspace/nodemcu-firmware-dali/blob/master/app/dali/dali_encode.c


print( type( dali.BROADCAST )) 时返回了什么?

我猜它可能是原始 C 用户数据,该 arc 命令的特定 case-switch,但是,我刚刚找到了一个类似的 Lua 项目,将其列为十六进制 255

https://github.com/a-lurker/Vera-Plugin-DALI-Planet/blob/master/Luup_device/L_DaliPlanet1.lua


是的,它可能只是发送十六进制数字。

https://en.wikipedia.org/wiki/Digital_Addressable_Lighting_Interface

尝试发送dali.arc( 0xFF, 0x00, 0x80 )dali.arc( 0xFE, 0x80 )

他们让它听起来像 '1111 1110' ( 0xFE ) 直接跟在亮度值之后,所以第二个命令可能会亮起。

我不确定为什么当您将代码放在表格中时,它似乎没有发送正确的代码。 您写的似乎是正确的,但它可能是单向广播,因此您不会收到任何错误消息...

如果您无法使用 arc 命令来处理表格,那么使用 dali.send() 命令可能会更好。可能只是该应用程序中的一个缺陷。如果无法解决,请向他们的 GitHub 页面提交错误报告。

【讨论】:

deli.BROADCAST 这样的常量通常是有原因的,用像0xFE 这样的幻数替换它们是非常糟糕的编程风格。 自 90 年代以来,常量一直没有改变。 幻数的问题不在于它们是否会改变。 您说的是写入 C 中的用户无法更改的值。如果你已经定义了它并且有能力随时改变它,这并不神奇。分配变量有什么帮助?只需在它旁边放两个破折号和评论。问题解决了。这比你说的更有用。在新的照明技术出现之前,重新编译到可能不会改变的新值,在 10 年内是什么?这个值几乎得到了整个星球的同意。如果它改变了,那将破坏与世界上数十亿个数字灯泡的兼容性? 您如何与wikipedia 进行讨论,因为我真的不认为辩论几十年前的编程智慧的有效性与这个问题有关。幻数通常被认为比命名常量更糟糕,我在您的示例中指出了这一点。处理它。

以上是关于LUA (ESP8266) 如何从字符串调用/输入模块命令的主要内容,如果未能解决你的问题,请参考以下文章

Lua语言(stm32+2G/4G模块)和C语言(stm32+esp8266)从字符串中提取相关数据的方法-整理

Lua语言(stm32+2G/4G模块)和C语言(stm32+esp8266)从字符串中提取相关数据的方法-整理

Lua语言(stm32+2G/4G模块)和C语言(stm32+esp8266)从字符串中提取相关数据的方法-整理

ESP8266 LUA脚本语言开发: 外设篇-GPIO输入检测

如何使用 lua 固件在 ESP8266 上运行 sqlite3?

ESP8266 NodeMCU Lua 如何清除堆?