用Node-RED编程彻底解决子擎人在传感器抽疯的毛病
一、序言
子擎人在传感器发布之后,我买了2个,在洗手间和厨房各布置了一个。
装了子擎之后,基本上人在灯亮,人走灯灭的问题都ok。不过,用了一段时间之后,发现了一个很闹心的问题,子擎的传感器会误判,明明没有人,它却判断有人,一家人在餐厅吃饭,厨房灯自己亮了,然后半天都不灭;明明大家都在各自房间看电视,洗手间灯亮了……
厨房里面误判的情况比洗手间严重得多,估计是厨房里面的热源比较丰富的缘故,炉头、油烟机、电热水壶、高压锅、电饭煲、洗碗机和热水器都是热源。
频繁的误判让我被家人嘲笑了,领导发话不解决就拆掉,这让我很没面子,智能家居居然成了智障家居。
米家APP里面,可以对子擎传感器进行高级设置,进行训练,但实际上,啥用都没有!
二、解决方案1:不需要js编程的零代码方案(满分10分,自认可以评7分)
最后,不得不把Node-RED请出来,搞了一个曲线救国的方法:每15秒检测一次房间灯亮的状态,如果是亮的,那么再检测一下有没有人在房间,没有就关掉灯。
用了这招之后,厨房和洗手间自己亮灯的情况依然存在,但是至少,最多15秒,它就自动熄灯了。有时刚被强制熄灯了,又会马上再亮,一会儿又再次强制熄灯。看着闹心但起码不用担心灯亮了一晚上不关呀。

三、解决方案2:使用js编程的终极大招(满分10分,自认可以评9分)
评论里面有位叫值友(值友1181616891)提供了他的思路,即开灯时并不靠一次“有人”的消息,而是收到第一次“有人”消息后,过500毫秒再判断一次子擎传感器的状态是否还是“有人”,这个思路其实就是单片机编程时,对按键进行去抖动的思路,即在一段时间内连续收到“有人”的消息,才认为有人,如果仅是一个短暂的“有人”消息,持续的时间长度达不到我们预设的阈值,那么我们把它当作毛刺(即,误报消息)丢弃掉。
我的代码,采取了相对保守的策略:(1)对“有人”判断进行了长达1s的去抖动(这个时长读者可以自己调整),系统必须在1s内持续接收到“有人”消息,才会执行开灯,这就基本上杜绝了因为子擎传感器误报而错误开灯的情况;(2)对“无人”判断进行了长达60s的去抖动(其实设置成5s或者10s也非常好用,我是应家人要求,设的60s),系统必须在60s内持续接收到“无人”消息,才会执行关灯,当我们坐在马桶上玩手机时,只要不保持60s静止不动,灯都不会关掉,再也不怕人明明在洗手间里面,突然灯关了,只能摸黑嘘嘘或者摸黑冲凉了!
3.1 Node-RED流程图
Node-RED流程图3.2 evnets:state节点的设置:
使用这个“events:state”节点,我们可以捕捉到子擎传感器名为“binary_sensor.xxxxx_occupancy”这个实体(它对应的值是:有人时“on”,无人时“off”)值发生翻转,并通过消息“msg.payload"把当前的值传递给下个节点。
evnets:state节点的设置3.3 function节点的代码:
// 在流程的上下文中分别存储“无人”和“有人”状态的定时器ID
const noManTimerId = flow.get('no_man_timer_id') || null;
const hasManTimerId = flow.get('has_man_timer_id') || null;
// 检查消息是否表示有人
if (msg.payload === 'on') {
// 有人,如果还没有有人的定时器正在运行,则设置一个新的1秒定时器
if (!hasManTimerId) {
const newHasManTimerId = setTimeout(function() {
// 1秒后发送消息以开灯
//node.warn('开灯');
node.send({ payload: '开灯' });
// 清除此定时器ID
flow.set('yes_man_timer_id', null);
}, 1000);
// 将新的定时器ID存储在流程的上下文中
flow.set('yes_man_timer_id', newHasManTimerId);
}
// 如果已经设置了无人的定时器,清除它
if (noManTimerId) {
clearTimeout(noManTimerId);
flow.set('no_man_timer_id', null);
}
// 不发送任何消息,直到定时器结束
return null;
} else if (msg.payload === 'off') {
// 无人,如果还没有无人的定时器正在运行,则设置一个新的60秒定时器
if (!noManTimerId) {
const newNoManTimerId = setTimeout(function() {
// 60秒后发送消息以关灯
//node.warn('关灯');
node.send({ payload: '关灯' });
// 清除此定时器ID
flow.set('no_man_timer_id', null);
}, 60000);
// 将新的定时器ID存储在流程的上下文中
flow.set('no_man_timer_id', newNoManTimerId);
}
// 如果已经设置了有人的定时器,清除它
if (hasManTimerId) {
clearTimeout(hasManTimerId);
flow.set('has_man_timer_id', null);
}
// 不发送任何消息,直到定时器结束
return null;
}
// 默认情况下返回原始消息
return msg;
3.4 switch节点的设置:
这个节点的功能很简单,根据function节点传过来的消息(“开灯” or “关灯”),分别向对应的设备(吸顶灯)发出开灯和关灯的指令。
switch节点的设置3.5 2个call service节点的设置:
下面这个是switch节点的输出1所接的设备呼叫服务的节点,即开灯:
负责执行开灯的call service节点设置下面这个是switch节点的输出2所接的设备呼叫服务的节点,即关灯:
负责执行关灯的call service节点设置四、回答评论里面值友的问题

小米的绝大多数设备(包括兼容小米智能的,例如“子擎”、“领普”传感器),都是靠这个“xiaomi Gateway 3”插件接入HA的,另外那个“xiaomi Miiot Auto”插件是个摆设,没啥用处。
五、关于小米多模网关2的固件版本
如果你手里的小米多模网关2(方的,可以插网线的这种),固件版本是1.05或者更旧的,千万保护好它,千万不要手欠点“升级固件”,把米家APP里面的“自动升级”选项去掉勾选。因为1.06或者1.07版本的固件,需要拆开外壳焊线接到笔记本电脑上进行破解才能继续用,超级超级麻烦!说了都是泪!
作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~

值友1181616891
校验提示文案
浣熊熊
校验提示文案
1024楼主好人一生平安
校验提示文案
胶己人食茶
校验提示文案
ooor
校验提示文案
王甩聪
校验提示文案
王甩聪
校验提示文案
ooor
校验提示文案
胶己人食茶
校验提示文案
值友1181616891
校验提示文案
1024楼主好人一生平安
校验提示文案
浣熊熊
校验提示文案