
完美无止境。 似乎一切正常,较小的错误等已修复。
现在,我将首先向您介绍自上一篇文章以来我一直遇到的问题,其次是有关有助于该项目当前状态的解决方案。
→ 关于以前版本的文章
名称
bobaos
-npm模块,用于使用UART与BAOS 83x交互。 返回原始数据。 在下面列出的所有其他模块中使用。
bdsd.sock
用于处理KNX对象的脚本。 存储数据点列表,在发送/接收时转换值。 从DPT1到true / false,从DPT9到float。 还监听Unix套接字以接收来自其他进程的请求。
bobaos.pub
是使用bobaos.pub
进行进程间通信的新版本。
KNX /
-组地址(a)对应(或不对应)的ETS中配置的BAOS 83x模块的通信对象。 在当前版本的铁中,最大数量为1000。
挑战赛
主要任务与以前的版本相同。 到串行端口只有一个连接。 KNX有很多脚本。 除此之外,我还想实现进程间通信。 即 这样,不仅一个bdsd.sock
进程可以bdsd.sock
套接字,而且每个正在运行的脚本都可以发送和接收请求。
主意
我想到了一个想法,就是在Unix套接字之上的node.js上创建自己的消息代理,客户端将根据其中编写的代码连接,订阅主题以及接收/发送消息。 我知道已经有现成的解决方案,只是懒惰者最近才听说过,他们研究了这些解决方案,但是做出我自己的决定的想法是强迫性的。
结果,该服务被启动。
编写了一个向主题发送消息的记录器。 订户可以接收并且可以自由地做任何事情,或者说是规定的事情。 方便-可以在一个控制台输出中查看来自多个来源的日志。
我在npm中编写并发布了bobaos.pub软件包,该软件包与bdsd.sock不同,不再创建套接字文件,而是连接到代理。 乍一看,一切都会按预期进行。
问题
然后,我运行了一个脚本,该脚本会在一夜之间定期向KNX总线发送请求。 早上醒来时,通过LED指示灯的闪烁表示发送/发送数据,我意识到有些问题。 邮件未按时到达。 我发现自写消息代理几乎占用了所有可用的512MB RAM(来自BeagleBoard Black)。 与nodejs的进一步合作证实了内存是js脚本的弱点。
解决方案
结果,决定从通用Unix套接字切换到Redis(顺便说一句,他也知道如何使用它们)。 也许值得整理一下内存,查找泄漏,但是我想运行得更快。
bobaos表示FT1.2中具有消息包装功能的UART通信,我们具有同步通信。 即 <..--..>
。 负责通信的bobaos模块将所有请求存储在阵列中,依次将其拉出,将其发送到UART,并使用传入的响应来允许负责此请求的诺言。
您可以这样:服务侦听redis PUB / SUB通道,接受请求,并将其发送到KNX。 在这种情况下,请求队列上的负载由js bobaos
模块bobaos
。 为了实现,您需要编写一个订阅频道的简单模块,并使用JSON.parse()
方法转换消息。 此外,该模块可以在其他脚本中使用。
我最终redis
另一个选择redis
:在redis
之上使用现有的任务管理器。 在bee-queue
上有几种选择。
→ 引擎盖下
它描述了bee-queue
工作方式。 如果为其他编程语言实现此库,则可以通过这种方式为bobaos
创建客户端库。
在第二个版本中,所有请求都存储在redis
列表中,依次拉出并发送到串行端口。
此外,下面是对先前版本的重写,但是我已经将所有数据存储在redis
数据库中的数据点上。 我遇到的唯一不便是所有请求都是异步的,因此获取值数组已经比仅访问数组要难一些。
进行了次要优化。
如果以前有单独的方法getValue/getValues/readValue/readValues/setValue/setValues
,现在getValue/readValue/setValues
既可以接受单个值也可以接受数组。
先前版本中的getValue([id1, id2, ...])
方法getValue([id1, id2, ...])
向每个数据点的串行端口发送了一个请求。 但是,有机会发送多个值的请求。 限制-响应大小必须等于BufferSize
,最大-250个字节; 也不可能超出对象数量;对于当前版本的BAOS 83x模块-1000。
值的长度也是已知的,标题也是如此。 此外,具有while和await周期=)的相当简单的算法
- 对数组进行排序,删除重复的元素(如果有)。 我们得到一个
idUniq
数组。 - 我们开始循环
i < idUniq.length
,在其中执行以下操作:
a) start: idUniq[i]
,因为它考虑了我们可以获得的最大值数量。 例如,如果所有对象的类型均为DPT1 / DPT5(1个字节),那么我们可以得到48个值。只有一句话:例如,如果我们配置了对象#E [1、2、3、10 #[1, 2, 3, 10, 20]
,然后在查询GetDatapointValue.Req(1, 30)
,即使对于不存在的数据点[4, 5, 6, ..., 30]
,响应也将返回零个单字节值。
b)计数在一个新的周期j < i + max
(其中max
为50,或者,如果接近1000,则最大值1000 - id + 1
,对于990,它将为11,对于999-2)进行,如果在计数过程中我们满足来自原始查询的数组元素,然后将索引i
分配给变量i
。
c)如果在周期j
计算出的长度超过最大缓冲区长度,则我们形成查询卡元素{start: start, number: number}
,将其放入单独的数组中,增加变量i
(或将索引分配给数组中找到的idUniq
),中断循环j
,两个循环都重新启动。
因此,我们对bobaos
提出了一些要求。 例如,如果您发送getValue([1, 2, 3, 40, 48, 49, 50, 100, 998, 999, 1000])
请求getValue([1, 2, 3, 40, 48, 49, 50, 100, 998, 999, 1000])
,则对于特殊情况,请求可以如下所示:
{start: 1, number: 48}, // 1, 2, 3, 40, 48 {start: 49, number: 48}, // 49, 50 {start: 100, number: 48}, // 100 {start: 998, number: 3} // 998, 999, 1000
可以采取不同的方法:
{start: 1, number: 48}, // 1, 2, 3, 40, 48 {start: 49, number: 2}, // 49, 50 {start: 100, number: 1}, // 100 {start: 998, number: 3} // 998, 999, 1000
将有尽可能多的请求,更少的数据。 但是我停在第一个选项上,因为获得的值分别存储在redis
数据库中,所以可以使用getStoredValue
方法获得它们,我尝试使用的方法要比通过串行端口发送数据的getValue
多得多。
将为ping/get sdk state/reset
服务方法创建一个单独的队列。 因此,如果串行端口上的通信出现问题(帧计数器误入歧途,等等),并且在某些任务上执行停止,则可以在另一个队列中发送reset
请求,然后重新启动sdk
。
客户端-bobaos.sub
要在用户脚本中控制KNX数据点,可以使用bobaos.sub
模块。
以下示例涵盖了模块的所有功能:
const BobaosSub = require("bobaos.sub"); // : // redis: url // request_channel: "bobaos_req" , // service_channel: "bobaos_service" , // broadcast_channel: "bobaos_bcast" let my = BobaosSub(); my.on("connect", _ => { console.log("connected to ipc, still not subscribed to channels"); }); my.on("ready", async _ => { try { console.log("hello, friend"); console.log("ping:", await my.ping()); console.log("get sdk state:", await my.getSdkState()); console.log("get value:", await my.getValue([1, 107, 106])); console.log("get stored value:", await my.getValue([1, 107, 106])); console.log("get server item:", await my.getServerItem([1, 2, 3])); console.log("set value:", await my.setValue({id: 103, value: 0})); console.log("read value:", await my.readValue([1, 103, 104, 105])); console.log("get programming mode:", await my.getProgrammingMode()); console.log("set programming mode:", await my.setProgrammingMode(true)); console.log("get parameter byte", await my.getParameterByte([1, 2, 3, 4])); console.log("reset", await my.reset()); } catch(e) { console.log("err", e.message); } }); my.on("datapoint value", payload => { // , payload , // Array.isArray(payload) console.log("broadcasted datapoint value: ", payload); }); my.on("server item", payload => { // , payload , // Array.isArray(payload) console.log("broadcasted server item: ", payload); }); my.on("sdk state", payload => { console.log("broadcasted sdk state: ", payload); });
命令行界面已被重写。 关于如何实现它,以下文章:
→ 在NodeJS上编写CLI
团队变得越来越短,越来越清晰,功能越来越强大。
bobaos> progmode ? BAOS module in programming mode: false bobaos> progmode 1 BAOS module in programming mode: true bobaos> progmode false BAOS module in programming mode: false bobaos> description 1 2 3 #1: length = 2, dpt = dpt9, prio: low, flags: [C-WTU] #2: length = 1, dpt = dpt1, prio: low, flags: [C-WT-] #3: length = 1, dpt = dpt1, prio: low, flags: [C-WT-] bobaos> set 2: 0 20:27:06:239, id: 2, value: false, raw: [AA==] bobaos> set [2: 0, 3: false] 20:28:48:586, id: 2, value: false, raw: [AA==] 20:28:48:592, id: 3, value: false, raw: [AA==]
后记
结果是一个稳定的工作系统。 Redis
作为后端运行稳定。 在开发过程中,包装了许多锥体。 但是学习过程有时是不可避免的。 根据我的经验,我注意到nodejs
进程会消耗大量RAM(开始时为20 MB),并且可能会泄漏。 对于家庭自动化,这是至关重要的-因为脚本必须持续工作,并且如果脚本随着时间增长越来越多,那么在某个时候它可能会占用所有空间。 因此,您必须仔细编写脚本,了解垃圾收集器的工作方式,并使所有内容都受到控制。
可以在此处找到更新文档。
在下一篇文章中,我将讨论如何使用redis
和bee-queue
提供软件附件服务。
UPD: bobaoskit-附件,dnssd和WebSocket
我会很高兴收到任何反馈。