2024年9月

更新

今天我更新了一下Xiaomi Miot Auto发现多了一个可选项,

禁用米家APP通知消息实体 这个虚拟传感器以前就有 但我没有使用过
禁用米家场景历史实体 这个是新增加的 正好两个一起研究一下

v0.7.14 的更新,add scene history sensor (#1361)
https://github.com/al-one/hass-xiaomi-miot/releases/tag/v0.7.14

打印一下传感器信息:

sensor.mi_345123456_message

Array (
    [entity_id] => sensor.mi_345123456_message
    [state] => 摄像机: 用户345123456于23:42在带屏音箱上观看摄像机 储藏室直播视频.
    [attributes] => Array
        (
            [entity_class] => MihomeMessageSensor
            [filter_homes] => Array
                (
                )

            [exclude_types] => Array
                (
                    [0] => 13
                )

            [msg_id] => 17344867324567850112
            [is_new] => 1
            [type] => 6
            [title] => 用户345123456于23:42在带屏音箱上观看摄像机直播视频.
            [content] => 摄像机
            [user_id] => 345123456
            [ctime] => 1703173364
            [timestamp] => 2023-12-21T15:42:44+00:00
            [model] => isa.camera.hlc6
            [device_id] => 345123456
            [home_name] => 大楼
            [room_name] => 一楼
            [event] => stream
            [event_data] => 
            [prev_message] => 小米智能摄像机: 用户345123456于23:09在带屏音箱上观看小米智能摄像机直播视频.
            [icon] => mdi:message
            [friendly_name] => Xiaomi 345123456 message
        )

    [last_changed] => 2023-12-21 23:42:56
    [last_updated] => 2023-12-21 23:42:56
    [context] => Array
        (
            [id] => 01HJ6ASDFARTEGWT083FPEH
            [parent_id] => 
            [user_id] => 
        )
)

sensor.mi_666666666_66660166660575_scene_history

Array (
    [entity_id] => sensor.mi_345123456_884885886887_scene_history
    [state] => 旅行
    [attributes] => Array
        (
            [entity_class] => MihomeSceneHistorySensor
            [from] => user
            [name] => 旅行
            [ts] => 1703173662
            [timestamp] => 2023-12-21T15:47:42+00:00
            [scene_id] => 1731231401335251234
            [targets] => Array
                (
                    [0] => Array
                        (
                            [at] => phone
                            [error] => 0
                            [note] => 
                            [origCode] => 0
                            [origErr] => 
                            [t] => 1
                        )

                )

            [prev_value] => 有人移动-米家智能充电台灯开灯并设置灯光
            [prev_scene_id] => 1721231066712417412
            [icon] => mdi:message
            [friendly_name] => Xiaomi 345123456_884885886887 Scene History
        )

    [last_changed] => 2023-12-21 23:47:57
    [last_updated] => 2023-12-21 23:47:57
    [context] => Array
        (
            [id] => 01HJ6XXXXXXXXXXJQKQM2DFM5Q
            [parent_id] => 
            [user_id] => 
        )
)

作用

一个是记录米家的通知消息,一个是记录米家的场景消息,通过这两个虚拟传感器,就可以捕捉到米家智能化都做了些什么。但home assistant是通过轮询来工作的,所以消息不是实时的。

但是不管怎么说,这都为米家 & home assistant 通讯提供了另一条途径。

问题

  • 这两个传感器都只保留最后两条消息,(当然可以通过读取日志获取更多的历史消息)
  • 读取的消息不是实时的,轮训的周期应该是30秒,当然可以自定义
  • 每次读取最后一条消息,如果瞬间触发了5个场景事件,生成5条消息,那么除了最后一条,其余4条就都被MISS了,

使用

未完....

Home Assistant

Home Assistant是一个IoT设备的集中管理平台,他可以解决各家产品相互不兼容的问题。

我用的最多的设备是米家,其次是易微联,还有少量的其他品牌的产品,另外还有一些自己DIY的设备,比如WLED,ESP8266的继电器等等。

这些品牌都互不兼容,或者蹩脚兼容。好在这些品牌几乎都能被Home Assistant所支持,或者说大家都符合相关IoT标准。

丢弃米家接口

我一直都是通过对https://api.io.mi.com/app接口进行抓包,而后将数据rc4加解密,直接对米家APP的接口进行读写操作。这套流程很麻烦,涉及到抓包,签名,授权,数据加解密等各个环节。

[抓包米家app文章] 米家"智能"设备折腾 模拟米家协议

麻烦是麻烦些,因为是直接操作的米家APP接口,好处是相当稳定。随着手机抓包的越来越难,加之有个别新的设备抓包数据莫名其妙的无法解密,比如最新的人体传感器2S,所以我决定弃用解密米家APP的方案。

即使数据可以解密,这个方法也不是长久之计,说不定哪天一更新就不能用了,所以我决定扔掉用了几年的米家接口。

请勿索要米家APP接口协议,因为这涉及加解密,其实GITHUB上有,我就是参考的别人的代码,也可已参考上文完整的思路已经给出了

Home Assistant REST API

REST API是Home Assistant另外一个非常大的特点,别的品牌也有开放接口给开发者的,但是这些接口更多的是给产品、给厂商,并不是给普通用户的。

Home Assistant的API是面向用户的,你只需要会一点点基础编程就可以使用,最少也就3-4行代码就可以解决问题了。

比如,要把灯打开:

// php
$token = "xxxxxxxxxx"; // token
$id = "xxxxxxxxxx"; // 设备id
$url = "http://192.168.1.15:8123/api/services/light/turn_on"; // hass 服务器地址
$opts = ["http" => ["method" => "POST", "content" => json_encode(['entity_id' => $id], 320), "header" => "Authorization: Bearer {$token}"]];
file_get_contents($url, false, stream_context_create($opts));

加上一个cron就可以做一些自定义的控制了。

Home Assistant REST API 官方文档:

HA的API几乎可以做所有的操作,官方文档有详细实例。
https://developers.home-assistant.io/docs/api/rest/

开启Home Assistant接口功能

API功能是Home Assistant系统默认就带的,只需在菜单administrator中开启高级模式,再在长期访问令牌中添加一个TOKEN就可以了。

注意生成了TOKEN要及时复制保存,关闭了alert就再也看不到了。

除了灯和开关 为什么找不到其他的控制方法?

灯和开关都可以找到demo,一搜一大堆。除了这两个方法之外就几乎再也找不别的方法实例了,github和官方文档都没有,难道所有人只操作灯和开关?

官方文档services方法这样写:

Returns an array of service objects. Each object contains the domain and which services it contains.

看了几遍我都没有明白,直到我把自己的services全部打印出来,里面把所有的域名,方法,属性全部列了出来。
只要按照里面的数据,构建自己的请求就可以了。

我做了4个方法:

  • light 控制灯
  • switch 控制开关
  • cover 控制电机(窗帘等)
  • text 控制小爱语音

如果有小爱,是有一个偷懒的办法的,只要一个text就够了,所有的操作都让小爱去干就可以了,比如关闭4个灯:
light(灯0, off),light(灯1, off),light(灯2, off),light(灯3, off)

text(小爱同学,关闭所有的灯。)

Xiaomi Miot Auto

Xiaomi Miot Auto是一个非常不错的集成,支持米家几乎所有的非触发型设备,

安装 Xiaomi Miot Auto For HomeAssistant

文档 github

https://github.com/al-one/hass-xiaomi-miot/blob/master/README_zh.md
  • 进入容器

    docker exec -it HASS bash
  • 安装

    wget -O - https://get.hacs.vip | DOMAIN=xiaomi_miot bash -
  • 配置

    配置 > 设备与服务 > 添加集成
    添加 Xiaomi-Miot-Auto
    Add devices using Mi Account (账号集成) > 云端模式

本地模式还是云端模式

开始我是使用的是作者推荐的自动模式,自动模式的意思支持本地模式的设备本地化,不支持本地模式的设备走云端模式,也就是说大部分设备是本地化运行的。

但我发现本地模式有个致命的问题,当网络重启(DHCP),设备新获取到的IP地址与设备添加时的IP地址不一致时,设备就掉线了。尝试重载设备等方法均无效。到现在我也不知道如何解决这个问题。

而后我只能尝试云端模式。经过长时间的运行,发现云端模式非常稳定。所以只要家庭网络稳定,云端模式是非常不错的选择。

可以部署到公网?

我猜想:如果只走云端控制设备,把HASS部署在公网服务器上也是一样的,还更稳定。外网操作HASS的问题也就存在了。硬件设备也不需要了,功耗问题也不存在了。
回头试试,验证一下。

Home Assistant

logo

Docker 下 Home Assistant 安装

docker run -d --restart=always --name=HASS -p 8123:8123 -v /root/hass/config:/config homeassistant/home-assistant

1.nginx 反向代理

由前端的 https 反向代理到后端的 http

location / {
    set $site "http://192.168.1.101:8080";
    proxy_pass $site;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

2.nginx 永久链接 rewrite

/article-{cid}.html

我更喜欢article-999.html这样的url结构,slug看起来有点乱,slug对于现代搜索引擎来说也并无太大的优势。
page和category数量很少,就沿用slug了。

rewrite 规则:

location /blog/ {
    if (!-e $request_filename) {
        rewrite ^(.*)$ /blog/index.php$1 last;
    }
}

article这个规则我是配置在后端的http server,后端我用的是bt面板。
rewrite规则很简单,bt后台已经内置了typecho的配置。

3.nginx禁止sqlite文件被下载

我用的是sqlite数据库,sqlite的库文件.db是可以被直接下载的,虽然文件名很难被猜到,但如果报错了就有可能直接打印出.db文件的路径。
禁止db被下载,在后端nginx上设置.db 404就行了。

location ~ (.db)$ {
    return 404;
}

其实被下载了也无所谓,db中的内容几乎都是可以被浏览到的,除非有非公开文章。

4.IP白名单

不知道typecho的安全性如何,特别是admin目录,准备给admin目录加一个ip白名功能,只允许我所在城市的ip登陆后台。

nginx的ip白名单无法限制到地理区域,所以只能用php写一个api获取ip地理区域白名单功能。

临时用最简单的先对付一下,只允许服务器和本机,将就用以后再说。
/admin/common.php 文件开头加一行

// ban ip 简单ip白名单
if (!in_array($_SERVER['HTTP_X_REAL_IP'], [dns_get_record("home.dns.com")[0]['ip'], "192.168.1.21"])) {
    exit(http_response_code(403));
}

5.页面细节修改

注释掉由 Typecho 强力驱动,所有博客都是强力驱动的,所以去掉。

字太小了,默认是87.5%,修改style.css文件,body font-size都改为95%,前台后台都改。

其他,比较多,记不住了。

6.升级了怎么办

我修改了很多细节,有修改的模版,有修改的程序源代码,特别是修改了很多后台部分,模版可能升级了还能兼容,直接修改代码的部分升级就很麻烦了。
修改的多,我自己都不记得修改了那些地方了。

7.测试一下emoji,

😊😂🌃

8.添加List页面

读一下数据库,生成一个分类文章list。
把数据读出来,拼接好html代码,直接修改contents表中对于cid行的text字段。
https://www.goao.net/blog/list.html

TEST ARTICLE

博客用的是 typecho 系统,PHP语言,数据库支持mysql,sqlite,挺不错的一个开源博客系统(github)。

typecho原生支持markdown,正是我需要的。

比wordpress简洁易用;
比blogger易控;
比Hexo、Hugo这类静态的更方便。

总的来说,就是简单,够用,聚焦内容。

在移动互联网这个新时代下,又回到了博客这个旧时代的产物上。