找回密码
 立即注册

微信扫码登录

搜索
楼主: relliky

[经验分享] 米家无线八键旋钮:接入,自动化编写和维护

  [复制链接]

2

主题

48

回帖

3225

积分

论坛元老

积分
3225
金钱
3175
HASS币
0
发表于 2025-7-28 21:27:43 | 显示全部楼层
米家无线八键旋钮我先从手机的米家APP加入,接着在HA xiaomi gateway 3整合中devices.py写入相对应的设备码,然后HA装置里面就出现了 Eight scene knob switch
但我有发现日志里面的 Action 常常变成不可用,不知道这样的情况是不是正常

刚刚试过几种组合发现事件监听都没有发现点击按键的事件产生
1.
  triggers:
  - device_id: ce981b637f330808aeaf1248aeddef48
    domain: xiaomi_gateway3
    type: action
    metadata: {}
    trigger: device
    state: button_1_single

2.
  triggers:
  - trigger: state
    entity_id:
    - sensor.4f17e2b6c6ef_action
    to: button_1_single
  conditions: []

3. 前辈您的版本HA重启之后报错,自动化被停用
  triggers:
  - device_id: ce981b637f330808aeaf1248aeddef48
    domain: xiaomi_gateway3
    type: action
    metadata: {}
    trigger: device
    state:
    - knob_clockwise_after_toggling_button_1
    - knob_clockwise_after_toggling_button_1_and_knob   
  conditions: []

已经试过两三组不同的八键旋钮但情况都一样,目前我已经不知道从哪边下手了,再恳请出手相救一下
回复

使用道具 举报

2

主题

48

回帖

3225

积分

论坛元老

积分
3225
金钱
3175
HASS币
0
发表于 2025-7-29 12:48:51 | 显示全部楼层
本帖最后由 goodheartman 于 2025-7-29 15:35 编辑

我来自问自答了,发现以 MIOT 的方式是无法将设备信息送到 xiaomi gateway 3,也导致没有办法触发条件进行后面的动作

于是参考了这一篇 https://bbs.hassbian.com/thread-25809-1-1.html

1. 将MIOT协议改成 Mibeacon并改写 devices.py里面相对应的内容,

{
    # https://github.com/AlexxIT/XiaomiGateway3/pull/1303
    17825: ["Unknown", "Eight scene knob switch", "cxw.remote.ble006"],
    "spec": [
        # mibeacon2 spec
        BLEByteConv("battery", "sensor", mi=23555),  # uint8
        BaseConv("action", "sensor"), # uint8
        MapConv("action", mi=22028, map={"01": BUTTON_1_SINGLE, "02": BUTTON_2_SINGLE, "03": BUTTON_3_SINGLE, "04": BUTTON_4_SINGLE, "05": "button_5_single", "06": "button_6_single", "07": "button_7_single", "08": "button_8_single"}),
        MapConv("action", mi=22029, map={"01": BUTTON_1_DOUBLE, "02": BUTTON_2_DOUBLE, "03": BUTTON_3_DOUBLE, "04": BUTTON_4_DOUBLE, "05": "button_5_double", "06": "button_6_double", "07": "button_7_double", "08": "button_8_double"}),
        MapConv("action", mi=22030, map={"01": BUTTON_1_HOLD, "02": BUTTON_2_HOLD, "03": BUTTON_3_HOLD, "04": BUTTON_4_HOLD, "05": "button_5_hold", "06": "button_6_hold", "07": "button_7_hold", "08": "button_8_hold"}),
        BLENegativeConv("rotate", "sensor", mi=22052),
        MapConv("action", mi=22052, map={"-0b": "knob_anticlockwise_after_toggling_button_1", 
                                         "-0c": "knob_anticlockwise_after_toggling_button_2", 
                                         "-0d": "knob_anticlockwise_after_toggling_button_3",
                                         "-0e": "knob_anticlockwise_after_toggling_button_4", 
                                         "-0f": "knob_anticlockwise_after_toggling_button_5", 
                                         "-10": "knob_anticlockwise_after_toggling_button_6",
                                         "-11": "knob_anticlockwise_after_toggling_button_7", 
                                         "-12": "knob_anticlockwise_after_toggling_button_8", 
                                         "0b": "knob_clockwise_after_toggling_button_1", 
                                         "0c": "knob_clockwise_after_toggling_button_2", 
                                         "0d": "knob_clockwise_after_toggling_button_3",
                                         "0e": "knob_clockwise_after_toggling_button_4", 
                                         "0f": "knob_clockwise_after_toggling_button_5", 
                                         "10": "knob_clockwise_after_toggling_button_6",
                                         "11": "knob_clockwise_after_toggling_button_7", 
                                         "12": "knob_clockwise_after_toggling_button_8", 
                                         "-16": "knob_anticlockwise_after_toggling_button_1_and_knob", 
                                         "-17": "knob_anticlockwise_after_toggling_button_2_and_knob", 
                                         "-18": "knob_anticlockwise_after_toggling_button_3_and_knob",
                                         "-19": "knob_anticlockwise_after_toggling_button_4_and_knob", 
                                         "-20": "knob_anticlockwise_after_toggling_button_5_and_knob", 
                                         "-21": "knob_anticlockwise_after_toggling_button_6_and_knob",
                                         "-22": "knob_anticlockwise_after_toggling_button_7_and_knob", 
                                         "-23": "knob_anticlockwise_after_toggling_button_8_and_knob", 
                                         "16": "knob_clockwise_after_toggling_button_1_and_knob", 
                                         "17": "knob_clockwise_after_toggling_button_2_and_knob", 
                                         "18": "knob_clockwise_after_toggling_button_3_and_knob",
                                         "19": "knob_clockwise_after_toggling_button_4_and_knob", 
                                         "20": "knob_clockwise_after_toggling_button_5_and_knob", 
                                         "21": "knob_clockwise_after_toggling_button_6_and_knob",
                                         "22": "knob_clockwise_after_toggling_button_7_and_knob", 
                                         "23": "knob_clockwise_after_toggling_button_8_and_knob",}),

        # The knob in this device can be tuned clockwise and anti-clockwise. It can also be pressed. 
        # The device does not report how much the knob is turned and only report one knob event per second.
        # However, the device remembers the previous state and report the previous state along with the knob event.
        # Such complex events are designed to map different clockwise/anti-clockwise knob events to each button, so users do not need to create dedicated state machine to track it.
        # e.g. a usecase is that button 1 controls the ceiling light and knob for its brightness. Button 2 controls lamps and knob for their brightness.
        #      When the knob is pressed, the knob events controls the temperature of these lights instead.
        # The toggling knob state will get reset after you press a different button
        # e.g. 1) press button_1 and turn knob -> knob_anti_clockwise_after_pressing_button_1
        #      2) press the knob and turn knob -> knob_anti_clockwise_after_toggling_knob_and_pressing_button_1
        #      3) press button_2 and turn knob -> knob_anti_clockwise_after_pressing_button_2
        # Therefore, if you only uses clockwise and anti-clockwise events on its own, you need to merge these events into two triggers in your automation.

    ],
    # "ttl": "6h"  # battery every 6 hours
},



2. mibeacon.py 加入 BLENegativeConv,加上了处理负数

class BLENegativeConv(BaseConv):
    def decode(self, device: "XDevice", payload: dict, data: str):
        value = int(data[:2], 16)
        if value > 0x7F: # 处理int8的16进制负数
            value = -(0xFF - value + 1)
        payload[self.attr] = value


现在Action已经可以接收到按键跟旋钮相对应的信息,Rotate也会出现对应的数字, Battery 部分除了零火版会出现255%之外其他都可以显示

回复

使用道具 举报

0

主题

18

回帖

55

积分

注册会员

积分
55
金钱
37
HASS币
0
发表于 2025-7-29 14:05:58 | 显示全部楼层
这个厉害了,用起来很方便
回复

使用道具 举报

33

主题

1113

回帖

5472

积分

论坛元老

积分
5472
金钱
4311
HASS币
90
 楼主| 发表于 2025-7-29 16:11:45 | 显示全部楼层
goodheartman 发表于 2025-7-29 12:48
我来自问自答了,发现以 MIOT 的方式是无法将设备信息送到 xiaomi gateway 3,也导致没有办法触发条件进行 ...

恭喜,可能我的xiaomi gateway3 集成版本有点老,当时弄的时候不需要这样处理
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

2

主题

48

回帖

3225

积分

论坛元老

积分
3225
金钱
3175
HASS币
0
发表于 2025-7-29 17:52:37 | 显示全部楼层
本帖最后由 goodheartman 于 2025-7-29 19:32 编辑
relliky 发表于 2025-7-29 16:11
恭喜,可能我的xiaomi gateway3 集成版本有点老,当时弄的时候不需要这样处理 ...

没有前辈以及大家的基础,也不可能有我目前的结果出来
后来的思路是把 MIOT 代码 (mi="5.e.1012.p.1") 转换成 mibeacon格式 (mi=22028)
map部分数字从十进位的个位数字转成十六进位的两位数字并加上引号(1 -> "01")

不过可否请再帮我看看一下,目前按照先前您提示的自动化只能顺时针增加亮度但是逆时针就不会减低亮度,我怀疑是负值转换的时候出了问题,导致转换后数值无法对应到旋钮的动作

负值转换代码引用自 @invincible 前辈 [技术探讨] 【求助】【已解决】关于gateway3添加新旋钮设备
class BLENegativeConv(BaseConv):
    def decode(self, device: "XDevice", payload: dict, data: str):
        value = int(data[:2], 16)
        if value > 0x7F: # 处理int8的16进制负数
            value = -(0xFF - value + 1)
        payload[self.attr] = value


自动化
- id: '2222222222'
  alias: Test light 2
  description: ''
  triggers:
  - device_id: ce981b637f330808aeaf1248aeddef48
    domain: xiaomi_gateway3
    type: action
    metadata: {}
    trigger: device
    state:
    - knob_clockwise_after_toggling_button_1
    - knob_clockwise_after_toggling_button_1_and_knob   
  conditions: []
  actions:
  - action: light.turn_on
    data:
      brightness_step_pct: 25  
    target:
        device_id: 739b355d2f34c68335d44769a51a5ff1        
  mode: single


回复

使用道具 举报

33

主题

1113

回帖

5472

积分

论坛元老

积分
5472
金钱
4311
HASS币
90
 楼主| 发表于 2025-7-29 20:15:42 | 显示全部楼层
本帖最后由 relliky 于 2025-7-29 20:20 编辑
goodheartman 发表于 2025-7-29 17:52
没有前辈以及大家的基础,也不可能有我目前的结果出来
后来的思路是把 MIOT 代码 (mi="5.e.1012.p.1") 转 ...

看样子你的版本没有把sint8和str类型的hex8直接做转换。

与其花时间研究这个,干嘛不直接把源代码给改了?试试这个?

如果还不行,你可以自己写测试文件的慢慢差错。不需要用实物按钮测试,AlexxIT自己也写了很多测试案例的。在这里找一个测试案例抄抄改改,跑一下就好了 https://github.com/AlexxIT/Xiaom ... ts/test_conv_ble.py



{
    # https://github.com/AlexxIT/XiaomiGateway3/pull/1303
    17825: ["Unknown", "Eight scene knob switch", "cxw.remote.ble006"],
    "spec": [
        # mibeacon2 spec
        BLEByteConv("battery", "sensor", mi=23555),  # uint8
        BaseConv("action", "sensor"), # uint8
        MapConv("action", mi=22028, map={"01": BUTTON_1_SINGLE, "02": BUTTON_2_SINGLE, "03": BUTTON_3_SINGLE, "04": BUTTON_4_SINGLE, "05": "button_5_single", "06": "button_6_single", "07": "button_7_single", "08": "button_8_single"}),
        MapConv("action", mi=22029, map={"01": BUTTON_1_DOUBLE, "02": BUTTON_2_DOUBLE, "03": BUTTON_3_DOUBLE, "04": BUTTON_4_DOUBLE, "05": "button_5_double", "06": "button_6_double", "07": "button_7_double", "08": "button_8_double"}),
        MapConv("action", mi=22030, map={"01": BUTTON_1_HOLD, "02": BUTTON_2_HOLD, "03": BUTTON_3_HOLD, "04": BUTTON_4_HOLD, "05": "button_5_hold", "06": "button_6_hold", "07": "button_7_hold", "08": "button_8_hold"}),
        BLENegativeConv("rotate", "sensor", mi=22052),
        MapConv("action", mi=22052, map={"f5": "knob_anticlockwise_after_toggling_button_1", 
                                         "f4": "knob_anticlockwise_after_toggling_button_2", 
                                         "f3": "knob_anticlockwise_after_toggling_button_3",
                                         "f2": "knob_anticlockwise_after_toggling_button_4", 
                                         "f1": "knob_anticlockwise_after_toggling_button_5", 
                                         "f0": "knob_anticlockwise_after_toggling_button_6",
                                         "ef": "knob_anticlockwise_after_toggling_button_7", 
                                         "ee": "knob_anticlockwise_after_toggling_button_8", 
                                         "0b": "knob_clockwise_after_toggling_button_1", 
                                         "0c": "knob_clockwise_after_toggling_button_2", 
                                         "0d": "knob_clockwise_after_toggling_button_3",
                                         "0e": "knob_clockwise_after_toggling_button_4", 
                                         "0f": "knob_clockwise_after_toggling_button_5", 
                                         "10": "knob_clockwise_after_toggling_button_6",
                                         "11": "knob_clockwise_after_toggling_button_7", 
                                         "12": "knob_clockwise_after_toggling_button_8", 
                                         "eb": "knob_anticlockwise_after_toggling_button_1_and_knob", 
                                         "ea": "knob_anticlockwise_after_toggling_button_2_and_knob", 
                                         "e9": "knob_anticlockwise_after_toggling_button_3_and_knob",
                                         "e8": "knob_anticlockwise_after_toggling_button_4_and_knob", 
                                         "e7": "knob_anticlockwise_after_toggling_button_5_and_knob", 
                                         "e6": "knob_anticlockwise_after_toggling_button_6_and_knob",
                                         "e5": "knob_anticlockwise_after_toggling_button_7_and_knob", 
                                         "e4": "knob_anticlockwise_after_toggling_button_8_and_knob", 
                                         "16": "knob_clockwise_after_toggling_button_1_and_knob", 
                                         "17": "knob_clockwise_after_toggling_button_2_and_knob", 
                                         "18": "knob_clockwise_after_toggling_button_3_and_knob",
                                         "19": "knob_clockwise_after_toggling_button_4_and_knob", 
                                         "20": "knob_clockwise_after_toggling_button_5_and_knob", 
                                         "21": "knob_clockwise_after_toggling_button_6_and_knob",
                                         "22": "knob_clockwise_after_toggling_button_7_and_knob", 
                                         "23": "knob_clockwise_after_toggling_button_8_and_knob",}),

        # The knob in this device can be tuned clockwise and anti-clockwise. It can also be pressed. 
        # The device does not report how much the knob is turned and only report one knob event per second.
        # However, the device remembers the previous state and report the previous state along with the knob event.
        # Such complex events are designed to map different clockwise/anti-clockwise knob events to each button, so users do not need to create dedicated state machine to track it.
        # e.g. a usecase is that button 1 controls the ceiling light and knob for its brightness. Button 2 controls lamps and knob for their brightness.
        #      When the knob is pressed, the knob events controls the temperature of these lights instead.
        # The toggling knob state will get reset after you press a different button
        # e.g. 1) press button_1 and turn knob -> knob_anti_clockwise_after_pressing_button_1
        #      2) press the knob and turn knob -> knob_anti_clockwise_after_toggling_knob_and_pressing_button_1
        #      3) press button_2 and turn knob -> knob_anti_clockwise_after_pressing_button_2
        # Therefore, if you only uses clockwise and anti-clockwise events on its own, you need to merge these events into two triggers in your automation.

    ],
    # "ttl": "6h"  # battery every 6 hours
},





我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

2

主题

48

回帖

3225

积分

论坛元老

积分
3225
金钱
3175
HASS币
0
发表于 2025-7-29 20:37:48 | 显示全部楼层
本帖最后由 goodheartman 于 2025-7-29 21:24 编辑
relliky 发表于 2025-7-29 20:15
看样子你的版本没有把sint8和str类型的hex8直接做转换。

与其花时间研究这个,干嘛不直接把源代码给改了 ...

前辈不愧是高手一下就抓出我的毛病来,我刚刚也透过log档把每个负值的数值抓出来,跟您写的代码一模一样

谢谢前辈的提点逆时钟旋钮事件已经顺利触发,结果是自动化部分没有写好

现在开始研究蓝图如何写,会再继续研究前辈的自动化跟蓝图写法
回复

使用道具 举报

33

主题

1113

回帖

5472

积分

论坛元老

积分
5472
金钱
4311
HASS币
90
 楼主| 发表于 2025-7-30 01:46:05 | 显示全部楼层
goodheartman 发表于 2025-7-29 20:37
前辈不愧是高手一下就抓出我的毛病来,我刚刚也透过log档把每个负值的数值抓出来,跟您写的代码一模一样

...

HA就是个好玩的无底洞,总有新东西可以研究

十进制和十六进制换算以后不会的话,可以试试用windows或者mac自带的计算器,

选择程序员模式,
调成BYTE模式,就是1字节(8比特)显示
在DEC(十进制)里面输入负数,比如0-12=-12
它在HEX(十六进制)里面就会显示它用8个比特表示的十六进制的数值了。这里是F4


屏幕截图 2025-07-29 183921.png


我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian ( 晋ICP备17001384号-1 )

GMT+8, 2025-8-11 12:27 , Processed in 0.748714 second(s), 14 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表