前言

家里的几扇窗户都换成了电动控制,并接入了米家和苹果HomeKit。作为一个智能家居控,怎么能止于简单的电动控制,自动化控制才是智能家居的精髓。下雨自动关窗,这是最朴素最基本的需求,但是目前却没有接入米家或HomeKit的降水传感器,都得自己手动DIY才能达到不错的效果。下面就记录一下我目前在用的两种降雨传感器

利用Aqara水浸传感器改造

Aqara水浸传感器(E1)支持同时接入米家和HomeKit,使用zigbee协议通讯,稳定可靠又省电,灵敏度也很不错。闲鱼或淘宝花1-10元买一块雨水传感器的感应板,最好是镂空的,面积大一点的灵敏度更高。将感应板的两极用长导线连接至水浸传感器的两个螺丝柱,为了更小的电阻,我直接买了十米1.5平方的护套软铜线。

将感应板想办法固定在雨水能第一时间淋到的地方,最好倾斜固定,让水珠能自然滚落,这样雨停后传感器恢复未浸水的状态更快。Aqara水浸传感器一定不要暴露放置于雨水能淋到的地方,不然几场大雨后一定会坏,虽然名叫水浸传感器,但并不防长时间水浸,另外长时间的阳光暴晒也会大大减少传感器的寿命。我的已经坏了一个第一代的了,之后换了第二代的E1版,利用长导线将传感器本体延长至安全的地方,目前已稳定时间一年有余。

只要感应板的位置放得好,实测水浸传感器对于雨滴的检测非常灵敏,只需几滴就可以立即报警。然后米家或HomeKit内置的规则就会自动执行关窗任务。

但物理传感器的弊端就是雨停后需要很长时间才能恢复未浸水的状态,自然阴干最长可能需要十几个小时。如果这之前你已经将窗户打开了的话,此时再下雨传感器是不会报警的。为了解决这个问题我又发明了第二种互联网思维的解决方法

利用彩云天气的实时降雨量API制作虚拟降水传感器

手机上安装了彩云天气的App,有提供分钟级的网格天气预报,精度1KM,其中实时降雨量来自气象局的实时雷达回波图数据,准确度非常高,未来降雨量的预报也是分钟级的,参考度也非常高。于是就想能不能手搓一个虚拟的传感器接入Homekit,每分钟调用一次彩云天气的API,如果API的结果说我的家正在下雨或10分钟后会降雨,就把传感器的状态设置为正在下雨。

添加虚拟传感器

虚拟传感器我选择在homebridge下运行HttpWebHooks,运行后可以通过简单的HTTP API来配置虚拟水浸传感器的状态,homebridge配置文件如下

{
	"platform": "HttpWebHooks",
	"webhook_port": "28888",
	"sensors": [{
		"id": "sensor1",
		"name": "Rainfall Sensor",
		"type": "leak"
	}]
}

之后只需要wget或curl简单地访问http://[homebridge_IP]:28888/?accessoryId=sensor1&value=[1 or 0]就可以设置传感器的状态,1为下雨,0为未下雨。将homebridge添加到HomeKit

调用彩云天气API

彩云有提供公开的API和文档,详见:https://open.caiyunapp.com/彩云天气_API。经测试,通用预报接口/v2.5这个接口比较适合我的用途。

以下代码运行于OpenWrt下,没有jq的话使用opkg update;opkg install jq安装

#!/bin/sh

export LOCATION=经度, 纬度
export CAIYUN_API=彩云天API KEY

PAGESOURCE=$(curl "https://api.caiyunapp.com/v2.5/$CAIYUN_API/$LOCATION/weather?lang=zh_CN&dailystart=-1&hourlysteps=1&dailysteps=3&alert=true")
REALTIME=$(echo $PAGESOURCE | jq -r '.result.realtime.precipitation.local.intensity')
FORCAST=$(echo $PAGESOURCE | jq -r '.result.minutely.precipitation_2h[10]')
NEAREST=$(echo $PAGESOURCE | jq -r '.result.realtime.precipitation.nearest.distance')

if [ `expr $REALTIME \> 0.031` -eq 1 ]
then
        echo "It's raining"
        curl "http://192.168.2.88:28888/?accessoryId=sensor1&value=1"
elif [ `expr $FORCAST \> 0.031` -eq 1 ]
then
        echo "It will rain in 10 minutes"
        curl "http://192.168.2.88:28888/?accessoryId=sensor1&value=1"
elif [ `expr $NEAREST \< 1` -eq 1 ]
then
                echo "It's raining nearby"
                curl "http://192.168.2.88:28888/?accessoryId=sensor1&value=1"
else
        echo "It's not raining! Nearest raining area is ${NEAREST}km away"
        curl "http://192.168.2.88:28888/?accessoryId=sensor1&value=0"
fi

根据彩云天气的API文档雷达降水强度(0 ~ 1)判断降水等级:0.03~0.25 小雨(雪), 0.25~0.35 中雨(雪), 0.35~0.48大雨(雪), >0.48 暴雨(雪);雷达降雨强度大于0.03才代表有降水,所以上述脚本中的判断阈值为0.031。这其中还踩了一个坑,Linux shell无法对浮点小数做大小比较,导致刚开始出现莫名其妙的结果还总找不到原因,后来用一个很偏门的expr命令实现了小数的比较。

这里除了当前的实时降雨强度外还额外判断了10分钟后的预报和最近降雨带的距离,如果10分钟后会下雨或者最近的降雨带距离小于1KM,虚拟传感器也会报警,做到万无一失

创建定时任务

创一个cronjob,每分钟运行一次上面的脚本

* * * * * /root/rainfallsensor/rainfallsensor.sh

和风天气

除了彩云天气外,和风天气也提供了分钟级降水API,而且免费提供。相较于彩云天气,和风天气的分钟级预报每五分钟才更新一次,实测准确度也不如前者,酌情加入以作辅助之用