afkkk 发表于 2023-7-24 18:04:10

系列教程《HA+NR流程控制》之四:在NR中使用状态机初级篇

本帖最后由 afkkk 于 2023-7-24 18:17 编辑

这是一个系列教程:

* 之一:等待无人状态持续x秒
* 之二:满足多个条件后关闭灯光
* 之三:Aqara和HA+NR通讯

去年装修后开始使用HA,经过一段时间调整,目前各项配置属于比较稳定、便捷的状态。其中使用了一些技巧很少被提及,特别是对新人来说难以找到这方面的资料。所以用《HA+NR流程控制》为标题总结分享一下。每篇帖子单独分享一个技巧。

这个系列将给读者带来的帮助:

[*]熟悉NR常用排名在10以后的节点
[*]熟悉多种不同复杂度的范式,并运用其实现更强大的智能家居控制流
[*]了解一些使用HA+NR接入/控制外围设备的例子
阅读需要具备的背景知识:

[*]运行和维护Home Assistant系统;
[*]以任何方式安装了Node-RED,并将Node-RED接入Home Assistant系统;
[*]熟悉Home Assistant中常用基本概念:如Integration, Device, Service, Entity;
[*]在Node-RED中编写过Flow,了解NR内置以及node-red-contrib-home-assistant-websocket插件中常用节点;
环境:Home Assistant 20230608.0 + Node-RED 3.0.2


-----------------------------------------------以下为正文-----------------------------------------------


从这个post开始,大概会用3-4节介绍一下在NR中使用状态机,以及为什么要使用状态机。这篇从比较简单的场景开始 -- 使用两个motion_sensor判断人的行走方向。

----------------------------------
入口                                    出口
----------------------------------
假设有上图所示的一条走廊,在走廊入口和出口处都设有人体传感器。我们知道在智能家居App中很容易设置如下Automation。
if 入口有人 then 执行操作1
if 出口有人 then 执行操作2这些App还允许你设置逻辑与和或,
if 入口有人 and 出口有人 then 执行操作1
if 入口有人 or 出口有人 then 执行操作2
在Node-RED下,是否能超越这种简单的if-else,实现更复杂的逻辑呢?例如结合两个人体传感器的数据,实现if 入口处有人 随后 出口处有人 then 表明有人从入口走向出口,执行某操作
答案是肯定的,这就是典型的使用状态机的场景。但在开始介绍状态机之前,我想先回到米家App,看看在米家App中虽然曲折但仍然可行的实现。

米家app实现双传感器联动:
1. 设置规则1:当 入口传感器有人移动 ,则 开启自动化规则2,等待15秒后,关闭自动化规则2
2. 设置规则2:当 出口传感器有人移动,则执行操作
3. 把规则1设为启用,把规则2初始设为禁用

这个规则组合能够实现超出if-else逻辑的原因是,我们配置了两条规则;并且我们把15秒内入口是否有人移动这个信息,存储在规则2是否为启用状态上了。而某条规则是否enable,也基本上是各智能家居App唯一支持使用的变量。而在Node-RED中,当然可以模拟传统的做法,这里有一个典型的例子和传统思路下的解决方案。

但这种中间变量,其实就是手写有限状态机,随着场景的复杂,手写状态机会变得非常困难 -- 难以实现和难以维护。为什么不直接使用状态机呢?好在Node-RED插件库是非常全的,我们不需要自己实现一遍,我试过几个插件,最后选择插件node-red-contrib-xstate-machine,它是对xstate的简单封装。

我们把场景转化为状态图如下:


即:1. 初始状态为无人状态
2. 当 入口传感器 事件发生时,状态机从 无人状态 进入 入口有人状态;如果在15秒内出现 出口传感器 事件,则进一步进入 入口向出口方向移动 状态,否则回到无人状态。
3. 出口传感器 事件触发的逻辑,与此同理。

NR流程图如下:

SMXState节点的配置如下:

这段配置对于没有接触过编程的朋友学习曲线会稍有点陡峭,但其实我们认真看一下会发现还是很直观:
1. machine定义了初始节点为无人状态;
2.states定义了无人状态, 入口有人状态, 出口有人状态, 入口向出口方向移动, 出口向入口方向移动,一共5种状态;
3.每种state的on指定了这个状态可以转换为什么状态;
4.after表示当前状态在没有任何其他事件影响的情况,会在15000毫秒后自动转到target的状态;在这里用来达成15秒延迟复位的效果。

更多的内容可以参考SMXState和Xstate的文档。这里先回到流程图:

1. 最左侧蓝色events: state节点监听人体传感器状态,把对应事件转化作为smxstate的输入;
2. 浅绿色smxstate节点处理所有的逻辑;
3. 黄色switch节点捕捉我们关心的结果状态,并调用最后的call-service。

这里需要特别注意的是,smxstate使用的是msg.topic而不是msg.payload作为输入。记得要正确设置smxstate的上游节点:


流程代码:
PS. 调试smxstate其实非常方便,我一般会把状态机所用到的所有state做成一列Inject节点,调试的时候挨个点击即可模拟任意人体传感器触发顺序了,如下图:


OK,这个最基本的流程就介绍到这里。
最后补充一下:前面介绍的是一个假设场景,请别太在意检测走廊进出有什么用,或者用存在传感器就能得到行走方向,也别在意万一走廊两端各有一个人这类问题。假设这个简化的场景是为了更多的朋友可以快速入门这个稍复杂的插件和技巧。

实际上状态机能适应非常复杂的场景,例如实现以下这些相当复杂的逻辑,甚至可以把这些逻辑糅合到同一个场景中:
1. 使用门窗传感器 + 人体传感器双传感器判断一个密闭空间是否有人,例如卫生间、浴室
2. 传感器自动开灯和关灯的Automation,可以被物理按键Override一段时间
3. 不同时间段,无人关灯等待时间不同
4. 某个特定传感器可以触发开灯,但周围多个传感器都能保持灯不灭
5. 离开卫生间有个必经的传感器,这个传感器被触发可以加速卫生间关灯

但,家里大部分情况其实是不需要使用状态机这么重的解决方案。大家在尝试的过程中,可以根据实际场景复杂度,来使用不同的解决方案。

下一篇,我会进一步展开smxstate的使用,介绍更复杂一点的场景。







hassfan 发表于 2023-7-24 18:56:32

学习、学习、学习

idook 发表于 2023-7-24 19:27:31

要好好研究研究

zddontheway 发表于 2023-7-24 23:25:06

学习学习

relliky 发表于 2023-7-25 07:17:02

好东西,一直在用ha自身的自动化和pyscript写状态机,因为畏惧javascript一直没有学习nr,但看完楼主的教程感觉自己可以试试了

ilongjiang 发表于 2023-7-25 23:30:28


学习、学习、学习.太牛了

ablenet 发表于 2023-8-11 15:27:36

好好学习,天天研究。。

bennie812 发表于 2023-8-20 18:26:20

厉害,需要向大佬学习

hhxxttxsok 发表于 2023-9-27 21:21:25

分享的都是经典,谢谢

ilongjiang 发表于 2023-9-29 00:50:09

大神什么时候更新。下一个教程啊。这个教程有一个地方不明白就是”smxstate使用的是msg.topic而不是msg.payload作为输入“。msg.topic没有内容啊。入口是一个人体传感器。msg.topic没有数据。msg.payload是on。这里怎么弄?
页: [1] 2
查看完整版本: 系列教程《HA+NR流程控制》之四:在NR中使用状态机初级篇