背景
最近心血来潮买了个米家门窗传感器,打算用在浴室实现一种人来灯亮,人走灯灭的效果,但买回来后却发现实际场景比我想象中要复杂得多。为啥呢?门窗传感器最大的问题在于只能感知开/合两种状态,所以无法得知是否有人在浴室内。如果你仅靠闭门来触发关灯的话,就会有一个大问题:当你触发开门的时候灯亮了,然后你走进浴室,这时关门,pa 的一下,灯灭了。。尴尬。。
方案
如果要解决这个问题,首先想到的是再买个人体红外感应器配合来用。但一来吧,总觉得为了这一个小自动化功能买两个传感器不经济;二来红外感应器在浴室的表现并不好(覆盖角度有限制而且有些浴室设计还是分区的,加上浴室水蒸气有时会干扰红外检)因此不是个很好的方案。
但东西都买回来了,总不能丢一边吃灰吧。好在办法总比困难多。门窗传感器本身虽然不足以检测到人,但米家给我们提供了其它逻辑工具啊~
来看看这个问题,其实可以抽象成如何设计一个有限状态机(Finite Automate)以保证浴室自动化符合我们的要求的问题,其中:
要处理的浴室状态有:
- close_out: 室内无人且门属于关闭状态(此状态时灯与排气扇关闭)
- open_wait: 室内无人且门属于打开等待进入状态(此状态时灯与排气扇打开)
- close_in: 室内有人且门属于关闭状态(此状态时灯与排气扇保持打开)
- open_in: 室内有人且门属于打开状态(此状态时灯与排气扇区保持打开)
tips: 因为还要考虑人是否在内,所以要考虑的状态有四个而非简单的开和闭两个。
影响状态变换的条件有:
- open: 浴室门打开
- close: 浴室门关闭
但实际上还有个隐藏条件可以利用:
- time_elaspe: 时间流逝 ns(比如我们假定现实中 90% 的场景下人进入浴室,都会在 15s 内关上门)
如果把人工干预也算上,那还可以加上:
- manual: 检测到手动操作(例如,手动关灯)
最终设计出来的状态变换图如下
其中 close_out
即是起始状态也是最终状态。
对应状态转换表如下
open | close | time elaspe | manual | |
---|---|---|---|---|
close_out | open_wait | - | - | - |
open_wait | - | close_out | open_in | - |
close_in | close_out | - | - | close_out |
open_in | - | close_out | - | - |
横杠 - 表示该状态下不接受此输入的意思
验证
接下来我们把要处理的场景跑一遍,看上述 FA 能否满足我们的要求。
为了简化表述,我们把状态和条件均用数字代替:
- state set: close_out(1), open_wait(2), close_in(3), open_in(4)
- criteria: open(1), close(2), time_elaspe(3)
场景一:长时间事务,会关门进行(如洗澡,蹲坑)
输入:1, 2, 1, 2
状态变换过程:1->2->3->4->1
最终状态为 close_out
,可接受,符合预期
子场景 1.1:人在里边临时开门(不超时)
输入:1, 2, 1, 2
状态变换过程:1->2->3->4->1
最终状态为为 close_out
,可接受,但不符合预期(预期状态是保持 close_in
),需要将输入调整为 1, 2, 1, 2, 1, 2(也就是临时开门后再执行一次开关门,中间会经历一次灯断电,体验稍差)
状态变换过程:1->2->3->4->1->2->3,符合预期
场景二:短时间事务,不关门(如洗手,时间足以触发条件 3)
输入:1, 3, 2
状态变换过程:1->2->4->1
最终状态为 close_out
,可接受,符合预期
场景三:误操作,开门后立马关门(时间不足以触发条件 3)
输入:1, 2
状态变换过程:1->2->3
最终状态为 close_in
,非可接受状态,因此要人工介入,使得
输入变为: 1, 2, 4
状态变换过程:1->2->3->1
最终状态回到 close_out
,可接受,符合预期
总结
可以看到在场景 1.1 & 3 下若没有人工介入依然是无法很好地处理的。好在 1&2 占了我们日常场景的 90% 以上,总的来说此方案还是利大于弊。
实现
由于笔者使用的是米家 APP,因此这里仅展示基于米家『场景』模块的实现(理论上只要支持上述触发条件的平台都能实现)
这里的场景指的是米家 APP 上的『场景』模块,与我们文章上述提到的场景并非同一概念
米家场景分为自动(又称作智能)和手动两类,手类执行的场景除了手动操作外,还可以通过自动场景来触发
我们把浴室的状态与米家的场景对应起来(有些状态可能会对应多个场景),得到以下场景
close_out
- 触发条件:门窗传感器开
- 执行动作:
- 开浴室灯 & 排气扇(这块可以根据实际需求自行调整)
- 关闭智能
close_out
- 开启智能
open_wait
- 关闭智能
open_in
- 执行手动场景
open_wait.time_elaspe
tips: 其中命名
close_out
代表该米家场景打开时我们的浴室是处在状态close_out
的,一旦检测到门窗传感器打开将执行相应动作。动作 2&3 组合起来实现了状态切换的效果(关闭当前智能,打开目标状态对应的智能,也就是open_in
);动作 5 是模拟以时间条件为输入的效果,详见open_wait.time_elaspe
的配置
此外,这里还出现了一个看似没啥用的动作 关闭 open_in,将在后面作解答
open_wait.time_elaspe
- 触发条件:手动触发
- 执行动作:
- 延时 15s(时间可以自行调整成符合家庭习惯的数值)
- 开启
open_in
open_wait
- 触发条件:门窗传感器关
- 执行动作:
- 关闭智能
open_wait
- 开启智能
close_in
- 开启智能
close_in.manual
- 关闭智能
open_in
- 关闭智能
tips: 这里的状态切换是由动作 1&2&3 共同组成的,这是因为在我们的状态转换表里面
close_in
状态是可以被条件open
/manual
任其一触发转换到其它状态,所以状态close_in
其实是对应了两个米家智能,这两个智能只能是同时开启或同时关闭,才能保证自动化不会出现混乱
close_in
- 触发条件:门窗传感器开
- 执行动作:
- 关闭智能
close_in
- 关闭智能
close_in.manual
- 开启智能
open_in
- 关闭智能
close_in.manual
- 触发条件:浴室灯 or 排气扇任一关闭(这块可以根据实际需求自行调整)
- 执行动作:
- 关浴室灯 & 排气扇(这块可以根据实际需求自行调整)
- 关闭智能
close_in
- 关闭智能
close_in.manual
- 开启智能
close_out
- 关闭智能
open_in
open_in
- 触发条件:门窗传感器关
- 执行动作:
- 关浴室灯 & 排气扇(这块可以根据实际需求自行调整)
- 关闭智能
open_in
- 开启智能
close_out
最后,还记得上面提到的 关闭 open_in 这个看似没啥用的动作吗,其实不仅在 close_out
状态中,在除 open_in
外的每一个状态动作执行时都要加上这个动作。这是因为利用米家 APP 的延时模拟时间条件的输入这个是无法取消的,即是说一旦执行了 open_wait.time_elaspe
,15s 后必定会打开 open_in
场景,而这时我们的浴室可能处在任何一个状态。为了避免因此导致的混乱,我们才需要在每个状态的动作加入此动作
tips: 超时效果也可以通过门窗传感器自带的超时未关通知能力来实现,这样就相当于是可中断的,不需要上述的的补偿操作了。但有个问题是,目前我这款传感器好像只支持配置分钟时间粒度
手机截图如下
结语
以上配置对于普通用户(尤其是没有编程基础的)来说还是有些过于复杂了,建议厂家可以将状态机直接集成到门窗传感器中的,用户只要决定用或不用即可。
另外,米家平台提供的基础能力也比较有限(可能是基于易用性及安全性的考虑?),导致很多效果实现起来还是比较困难。不管怎样,希望希望米家能加入一些变量能力,可以通过动作来设置变量值,也可以根据变量值的不同来触发不同的智能,这样会有更高的可玩性。