本帖最后由 thisisanid 于 2021-5-31 21:52 编辑
前言
最近帮家里的灯换了至拓的LED驱动器+网关,搭配了之前板上有人发过的教程,成功接入了HA
教程位址:https://bbs.hassbian.com/thread-8126-1-1.html
这个接入我个人觉得还有些不完美的地方,主要是:
1. 必须要用雷士云的MQTT服务器更新状态,延迟比较大
2. 控制要另外发http post,除了灯本身的configure,还要多写rest_command以及很多automation才能兜出完整可控的灯
所以又自己捣鼓了一阵子,成功达成了利用本地MQTT接入ha,以及纯mqtt灯的configuration接入。
废话就不多说,咱们直接开始:
前置作业
首先先把灯以及小网关都设定好,App为可以正常控制灯的状态
然后照着另一篇教程的作者的方法,抓出网关的UUID
利用本地MQTT服务器取代雷士云服务器
说明一下大致上的概念,基本上这里要做的事情很简单,就是欺骗小网关把雷士云的服务器换成我们自己的服务器,
不过由于网关应该是在固件里面直接写死了雷士云的MQTT服务器IP,所以单纯的DNS替换是没办法达成的,必须要直接在路由器上作手脚。
必要条件:
1. 可以自定义使用者账号的本地MQTT服务器 (我是用hassio官方插件的Mosquitto broker)
2. 可以自定义NAT转发规则的路由器以及网路环境 (这里用Mikrotik的RouterOS做示范)
取得雷士云IP位址:
利用nslookup或是ping之类的工具来查询雷士云的IP位址
我这边解析出来的结果是120.25.222.238
设定NAT转发规则:
然后去路由器上设定NAT的转发规则
> /ip firewall nat print
1 ;;; xlinyun: redirect
chain=dstnat action=dst-nat to-addresses=<本地MQTT服务器位址> to-ports=1883 protocol=tcp src-address=<小网关位址> dst-address=<雷士云位址> in-interface-list=LAN dst-port=1883
log=no log-prefix=""
2 ;;; xlinyun: masquerade
chain=srcnat action=masquerade protocol=tcp dst-address=<本地MQTT服务器位址> out-interface-list=LAN dst-port=1883 log=no log-prefix=""
第一条规则是把所有从小网关发出来而且目标为雷士云MQTT的所有封包都转到本地MQTT服务器
第二条规则则是告诉从本地MQTT服务器返回的封包原路回到小网关
建立小网关使用者:
在Mosquitto插件的设定页面加入一组账号密码DL_Light:dl_123456
这组账号是我用抓包工具从最新固件的命令里面解析出来的,未来升级固件会不会变就不知道了
logins:
- username: DL_Light
password: dl_123456
完成以上步骤之后重启小网关,小网关应该就会直接连线到本地的MQTT服务器了
接下来我们就可以直接从本地MQTT服务器来对小网关作互动或是读取状态了
利用MQTT接入至拓无极调光LED灯
这里要做的主要是利用UUID/userin这个MQTT Topic来取代另一个教程的HTTP POST法,
由于我们已经成功将MQTT本地化了,就不需要另外直接对小网关发命令
命令格式:
Topic:
<小网关UUID>/userin
Content:
{
"mode": 15,
"rgb": {
"cwhite": <亮度值: 整数, 有效范围1-255, 0为关灯状态>,
"wwhite": <色温值: 整数, 有效范围1-100, 0为关灯状态>,
"red": <LED编号: 整数>,
"blue": 0,
"green":<命令种类: 整数, 0:关灯, 1:开灯, 4:调整亮度色温>
}
}
基本上跟HTTP POST的命令内容相同
接入Home Assistant:
到hass的configuration照着以下设定加入一个MQTT灯即可
light:
- platform: mqtt
schema: template
name: My GTOP Light
state_topic: <小网关UUID>/out
state_template: >
{% if (value_json.light.l0.cw != 0) or (value_json.light.l0.ww != 0) %}
on
{% else %}
off
{% endif %}
command_topic: <小网关UUID>/userin
command_on_template: >
{% set command = 1 %}
{% if brightness is defined %}
{% set command = 4 %}
{% elif state_attr('light.my_gtop_light', 'brightness') != None %}
{% set brightness = state_attr('light.my_gtop_light', 'brightness') %}
{% else %}
{% set brightness = 255 %}
{% endif %}
{% if color_temp is defined %}
{% set command = 4 %}
{% set color_temp = ((color_temp - 153) / 347 * 100) | int %}
{% elif state_attr('light.my_gtop_light', 'color_temp') != None %}
{% set color_temp = ((state_attr('light.my_gtop_light', 'color_temp') - 153) / 347 * 100) | int %}
{% else %}
{% set color_temp = 100 %}
{% endif %}
{"mode":15,"rgb":{"cwhite":{{ brightness }},"wwhite":{{ color_temp }},"red":0,"blue":0,"green":{{ command }}}}
command_off_template: >
{"mode":15,"rgb":{"cwhite":0,"wwhite":0,"red":0,"blue":0,"green":0}}
brightness_template: >
{{ value_json.light.l0.cw}}
color_temp_template: >
{{ (value_json.light.l0.ww / 100 * 347 + 153) | int }}
max_mireds: 500
min_mireds: 153
unique_id: my_gtop_light
为何不使用white_value而要使用color_temp接入
因为template格式的MQTT灯会利用有设定的template种类来自动判断灯所支持的调整种类(明暗、彩光、色温等等),
如果使用white_value的话会被hass判断为有彩光功能的灯,而多了一个可以设定颜色的UI区块,但实际上是没有的。
为何不直接将max_mireds(最大色温)与min_mireds(最小色温)设定为100与1
因为Homelkit会参考这两个值来决定这个灯可以调整的色温,100色温大约是浅蓝白,1是全白,UI会看起来很奇怪
所以这边会将0-100的数字转换为较常见的153-500来做色温设定
已知问题
Home Assistant重启之后灯会变成关上的状态
因为小网关发送状态MQTT的时候没有加上retain flag,所以一旦home assistant重启之后就不会知道灯的状态了
可以用Node-Red之类的工具设定一个自动化,收到没有retain的状态就重新发一个一样的带retain的状态到同一个topic应该就可以解决
或是利用小网关的UDP广播状态,直接转成mqtt到状态topic也行(我还没找到做法)
总结
之前在论坛上获得了不少帮助,这次自己捣鼓出了一点心得来跟大家分享一下。
也非常感谢写了另一篇教程的作者提供了命令格式的细节以及思路。
|