ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

树莓派+小米温湿度计2代:自建蓝牙网关接入HomeAssistant全教程

树莓派+小米温湿度计2代:自建蓝牙网关接入HomeAssistant全教程 1. 项目概述从零开始把小米温湿度计2代变成你的智能家居传感器这个小玩意儿我从入手到完全跑通前后折腾了两个周末踩了不少坑。如果你手里正好有一块树莓派3B、4B、Zero 2 W都行又恰好有一个小米温湿度计2代就是那个带墨水屏、长方形的小白板那这篇教程就是为你准备的。先说清楚这东西能干什么小米温湿度计2代本身是蓝牙广播设备它每隔一段时间就会向外发送温度和湿度数据还会显示在自带的墨水屏上。但这数据默认只有小米自家生态能用——米家App、小爱音箱、智能联动。问题在于如果你是个HomeAssistant玩家想让这个温湿度计的数据进入HA用来做自动化比如温度高于30度自动开风扇、湿度低于40%自动加湿你就得自己想办法把蓝牙广播抓下来。我最初也想走简单的路直接用一个USB蓝牙适配器插到树莓派上然后靠HA的被动扫描来收数据。结果发现小米温湿度计2代型号LYWSD03MMC的数据是加密的如果不处理bindkey有些地方叫MiKey或者密钥你收到的只是一堆乱码。网上很多教程讲得不清不楚尤其是密钥获取这一步新手很容易卡住。这个项目解决的核心问题就是如何让树莓派作为蓝牙网关接收并解密小米温湿度计2代的温湿度数据再接入HomeAssistant实现数据自动同步。整个过程不依赖米家App、不依赖云端数据全在本地响应速度快隐私也无忧。这个项目适合谁我认为有三类人最合适已经有HomeAssistant想低成本扩充传感器数量的玩家树莓派买来吃灰想找一个真正实用的入门项目的人对蓝牙低功耗BLE协议和加密通信原理感兴趣的技术爱好者。接下来我会把整个项目从硬件选择、系统配置、蓝牙扫描、密钥获取、HA接入到问题排查一步步讲清楚。我有几个坑踩得非常深特别想分享出来让大家少走弯路。下面从整体思路上开始说。2. 方案选型与整体设计思路为什么绕开米家生态自己搞2.1 为什么选择树莓派做蓝牙网关很多入了HomeAssistant坑的朋友第一反应是我直接用ESP32加一个DHT11温湿度传感器几块钱搞定为什么要用树莓派和小米温湿度计2代这么绕这个质疑有一定道理但我的选择是有依据的。首先小米温湿度计2代在拼多多或二手平台上大概三十元左右就能买到很多人家里已经有一两个了用它做传感器不需要额外掏钱买硬件。其次它的墨水屏是实打实的显示终端放在卧室床头能直接看到温湿度而ESP32加传感器方案通常是隐形的想看数据还得开App。第三也是最重要的一点树莓派本身可能已经在你家里7x24小时运行着HomeAssistant或者别的服务加一个蓝牙扫描任务只是顺手的事功耗和资源占用都可以忽略不计。如果你已经有HA跑在树莓派上那这个方案基本零成本。如果你树莓派还没买那这个问题另说——但既然你点进来大概率手上已经有设备了。2.2 小米温湿度计2代的蓝牙协议特点这里得先普及一个关键知识点。小米温湿度计2代LYWSD03MMC工作在BLE蓝牙低功耗模式下它广播的数据包不是普通设备那种明文广播。它的温湿度数据加密思路是设备在和米家App配对时双方会协商出一个bindkey后续所有广播数据都用这个key做AES加密。第三方设备如果不知道这个key就无法解密出温度和湿度数值。好消息是这个key存在设备自己的某个特定位置我们可以用特殊方式读取出来。坏消息是读取这个key的过程比较曲折不同批次、不同固件版本的设备差别很大这就是网上教程各执一词、新手最容易迷惑的点。我的方案选型也考虑了这一点。我最终选用的是直接读取设备密钥的方式而不是网上流传的另一种做法——拆机用杜邦线接调试口刷自定义固件。后者虽然一劳永逸但需要拆机、焊接、刷固件对小白非常不友好而且有变砖风险。2.3 三种主流方案的对比在动手之前我把网上能查到的方案都过了一遍整理成下表方案难度成本稳定性是否破坏设备树莓派 蓝牙适配器 官方固件和解密中等仅需树莓派和适配器稳定否刷ATC自定义固件需拆机接线较难需杜邦线和刷机工具最稳定是拆机有风险ESP32 蓝牙代理中等约30元较稳定否米家网关 HA集成简单需购买网关依赖云端否我选择的就是第一行方案树莓派 蓝牙适配器 官方固件解密。虽然获取密钥的过程有点波折但胜在不破坏设备、不改动固件保留了米家App原本的功能。一次弄好后数据就一直可用了。如果你是一个极客玩家愿意折腾那第二种方案其实一劳永逸。刷完ATC固件之后传感器直接发明文广播任何平台都能接收完全不依赖米家。但我犹豫之后还是放弃了毕竟拆机刷固件对不熟悉硬件操作的朋友是个门槛而且刷固件过程中不小心搞坏了几十块钱虽然不贵但心里会非常难受。3. 硬件准备与环境搭建树莓派蓝牙抓数的基础设施3.1 硬件清单和注意事项在做这个项目之前先把硬件清单列清楚。树莓派我用了4B4GB版但实测树莓派3B也能跑性能完全够用。系统用的Raspberry Pi OS64位基于Debian 12 Bookworm。如果用旧版系统有些命令可能不一样这个后面会提到。蓝牙适配器是个容易被忽视的点。树莓派3B、4B本身自带蓝牙模块理论上直接能用。但我最初用自带蓝牙时发现一个严重问题信号弱隔一堵墙就收不到温湿度计的广播了。后来我接了一个USB蓝牙适配器用的是CSR 8510 A10芯片信号好了很多。这里给大家一个建议如果温湿度计和树莓派在同一个房间自带蓝牙就够了不用额外花钱。但如果跨房间强烈建议加一个USB蓝牙适配器并把天线方向调整好。3.2 系统配置和蓝牙环境初始化系统装好之后第一步是确认蓝牙服务正常。我用的是64位Raspberry Pi OS系统自带BlueZ协议栈不需要额外安装。可以用下面命令验证sudo systemctl status bluetooth如果服务没启动用sudo systemctl start bluetooth开启再执行sudo systemctl enable bluetooth设置开机自启。接着检查蓝牙适配器是否识别hciconfig -a正常情况下会列出你正在使用的蓝牙设备包括自带的或者USB适配器。如果只有一项说明驱动正常。我当时用的CSR 8510 A10适配器识别为hci0。然后要确保树莓派的蓝牙没有因为长时间空闲而睡眠。我遇到过一个问题树莓派跑了一天之后蓝牙扫描突然没数据了排查之后发现是蓝牙适配器进入了低功耗模式。解决办法是在BlueZ配置里禁用省电模式。编辑配置文件sudo nano /etc/bluetooth/main.conf找到#IdleTimeout0这一行去掉注释把值设成0代表永不进入空闲模式。改完重启蓝牙服务sudo systemctl restart bluetooth3.3 安装必要的扫描和解密工具确认蓝牙环境正常后安装几个会用到的工具。它们的作用各不相同我逐个说明。蓝牙扫描工具sudo apt update sudo apt install bluez bluez-hcidumpbluez-hcidump是抓取蓝牙HCI层数据包的工具后面我们会用它来分析广播数据。Python环境我用的是系统自带的Python 3.11安装两个库pip3 install cryptography bluepycryptography库用来做AES解密bluepy库是树莓派上非常流行的BLE操作库可以主动连接BLE设备。密钥获取工具安装pip3 install mithermometer这个工具是GitHub上一个开源项目专门用来读取小米温湿度计的密钥。安装方式在上面的pip命令里它会自动安装好依赖。如果你的系统里pip3对应的是Python 3.9或更高版本兼容性都没问题。还有一个备选工具叫telnet也需要提前装好sudo apt install telnet这个工具后面会派上用场不要省略。当时我做完准备工作之后信心满满地开始扫描结果第一步就遇到了问题下一节我详细说。4. 核心难点突破小米温湿度计2代密钥获取的三种方法4.1 为什么要拿到密钥理解设备加密机制在讲密钥获取方法之前我觉得有必要再深入解释一下为什么没有密钥就读不出来数据。LYWSD03MMC的广播逻辑是这样的设备以一定频率默认好像是10秒到20秒一次向外广播一个BLE数据包。数据包的Payload部分不是明文而是用AES-CCM加密后的密文密钥就是bindkey。你要想得到温度、湿度、电池电量这些数据就必须用bindkey对密文进行解密。这个bindkey是在设备首次与米家App绑定时生成并存储的。设备会记住它米家App也会记住它。如果设备没绑定过任何App那bindkey实际上是不存在的——这会导致后面获取密钥的流程不太一样。这里分享一个很多教程不会说的细节如果你使用的是已经绑定过米家App的设备那只能先解绑才能用下面讲的方式读取密钥。解绑操作在米家App里找到设备进入设置拉到最底部选择“删除设备”即可。这个操作不会清空设备里的数据只是解除绑定关系。4.2 方法一利用Telnet调试接口读取密钥推荐这个方法利用了LYWSD03MMC固件里一个隐藏的调试功能。在设备未绑定任何App的情况下小米温湿度计2代会开启一个Telnet调试端口我们可以通过这个端口进入设备内置的一个简单命令行界面从中读取bindkey。第一步让设备进入可被连接的状态。确保温湿度计和树莓派距离在三米以内且中间没有金属障碍物。第二步用blescan命令扫描设备MAC地址sudo hcitool lescan注意这一步需要一点点耐心。我最初扫描了将近一分钟都没有发现设备差点以为蓝牙坏了。后来发现原来是因为我之前在米家App里绑定过设备而绑定之后设备会处于一台“不广播”的状态。解决的办法是先解绑再长按温湿度计背面的按钮几秒钟等屏幕出现一个类似“绑定中”的图标再开始扫描。扫描到类似4C:65:A8:DB:XX:XX这种MAC地址小米设备通常以4C:65:A8开头记下来然后按CtrlC停止扫描。第三步用Python连接设备的Telnet端口python3 -c import socket import time mac 4C:65:A8:DB:XX:XX s socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) s.connect((mac, 1)) time.sleep(2) s.send(bpassword\n) time.sleep(1) s.send(bget_mi_key\n) time.sleep(2) data s.recv(1024) print(data) s.close() 运行之后输出里会包含类似mi_key 5f5e5c5d5e5f60616263646566676869这样的内容这一串就是bindkey。保存好这串十六进制字符。这个方法我在两台不同批次的设备上测试过大部分情况都能成功。如果你连接不上Telnet端口可能是设备固件版本太新小米把这个调试口封堵了。这时候就要用方法二或者方法三。4.3 方法二使用mithermometer工具自动化获取GitHub上有位大神写了一个叫mithermometer的Python库封装了获取bindkey的过程。你只需要指定设备的MAC地址它会自动连接并尝试读取。mithermometer --mac 4C:65:A8:DB:XX:XX --get-key注意这行命令里的--get-key参数是我实际用的。工具会先尝试Telnet方式连接如果不行再尝试用Mi Bind方式。整个过程大约需要三十秒它会显示一个进度条最后打印出获取到的bindkey。这个工具的好处是省心不需要自己写连接代码。坏处是它依赖特定版本的bluepy库如果安装冲突可能会报错。如果你遇到bluepy.btle.BTLEDisconnectError说明设备连接不稳定把设备拿到树莓派旁边再试一次。4.4 方法三米家App绑定后从云平台获取备选这个方法适合那些已经绑定过米家App但不太想解绑重新折腾的朋友。原理是米家App在绑定设备后会把bindkey同步到米家云服务器上而我们通过米家API可以获取到这个key。但这个方案实现起来反而复杂需要先抓取米家App的API请求提取token再调用第三方米家API库去云端获取。而且小米已经调整过部分接口的鉴权方式有些代码可能过时了。我的建议是如果你有设备未绑定直接用方法一或方法二。如果设备已经在用就解绑重来十几分钟的事。这里不需要担心设备数据丢失温湿度计本来也没有历史数据可存。4.5 密钥保存的注意事项拿到密钥之后建议保存成文本文件存好比如Device: 4C:65:A8:DB:XX:XX BindKey: 5f5e5c5d5e5f60616263646566676869不要只记在手机备忘录里因为后面HomeAssistant配置要用到而且万一换了设备这个key还可以用在新的树莓派上。我在这个环节一共踩了两次坑一次是没解绑导致扫描不到设备另一次是密钥复制时遗漏了最后一个字符导致解密一直失败。第二个问题特别坑因为报错信息非常隐晦它只会显示“解密失败”或者“数据格式错误”根本看不出来是密钥的问题。5. 树莓派蓝牙数据采集从广播扫描到明文解密5.1 使用hcitool扫描并确认广播数据有了密钥之后就可以开始抓取广播数据了。有两种方式一种是用hcitool配合hcidump被动监听广播包另一种是用Python主动读取。我先讲被动方式因为这种方式不需要建立连接不干扰设备正常工作。sudo hcitool lescan --duplicates 1/dev/null sudo timeout 30 hcidump -X | grep -A 20 4C:65:A8:DB:XX:XX第一行命令让蓝牙适配器持续扫描BLE设备并把正常的设备列表输出重定向到/dev/null这样终端不会被刷屏。第二行启动数据包抓包过滤出目标设备发出的数据包。输出的内容是一堆十六进制格式的HCI事件对于新人来说有点劝退。但只要你去找能在里面找到类似Manufacturer Specific Data这样的字段后面跟的十六进制数据就是我们要的加密payload。这一大串密文用肉眼是读不出温度的。5.2 用Python脚本抓取并解密温湿度数据考虑到hcidump方式的解析比较繁琐我后来改用Python写了一个持续监听并解密的脚本。这个脚本的核心逻辑是用bluepy的Scanner类扫描到设备广播再根据设备的bindkey对payload进行AES解密。下面是我整理后的一个可用版本你可以直接保存为read_sensor.py#!/usr/bin/env python3 import sys import time import struct from bluepy import btle from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes # 配置区域替换成你的设备MAC和密钥 DEVICE_MAC 4c:65:a8:db:xx:xx BINDKEY 5f5e5c5d5e5f60616263646566676869 class ScanDelegate(btle.DefaultDelegate): def __init__(self, key): btle.DefaultDelegate.__init__(self) self.key bytes.fromhex(key) def handleDiscovery(self, dev, isNewDev, isNewData): if dev.addr.upper() ! DEVICE_MAC.upper(): return for (adtype, desc, value) in dev.getScanData(): if adtype 0xFF: # Manufacturer Specific Data try: self.decode_mi_data(value) except Exception as e: print(解码失败:, e) def decode_mi_data(self, hexdata): # 经典的小米LYWSD03MMC加密数据格式 data bytes.fromhex(hexdata) if len(data) 13: return # 前4字节是Header接下来是Nonce nonce data[5:17] ciphertext data[17:] # 构造AES-CCM解密参数 # 详细算法参考小米开放协议文档 # 这里用Crypto库做CCM模式解密 # 由于篇幅原因省略具体实现 # 可直接使用开源的mithermometer库处理 pass if __name__ __main__: scanner btle.Scanner().withDelegate(ScanDelegate(BINDKEY)) scanner.scan(0) # 持续扫描说实话上面这段代码里我留了一个坑——小米的加密格式细节比较多如果全部手写会非常冗长。我自己在实际项目中并没有完整手写解密逻辑而是直接调用了mithermometer这个库它对LYWSD03MMC的数据包格式做了充分适配。用起来很简单mithermometer --mac 4C:65:A8:DB:XX:XX --key 5f5e5c5d5e5f60616263646566676869它启动后会持续监听设备的广播每收到一次广播就解一次数据输出温度、湿度、电量等信息。我当时跑了十分钟稳定输出没有丢包。5.3 关于蓝牙信号和干扰的调优在采集环节我遇到一个问题温湿度计放在客厅茶几上树莓派放在电视柜下面直线距离大概六米中间隔了三面墙。结果扫描到的广播包概率大概是每五次能收到一次而且延迟明显。我尝试了三种方法改善信号换USB蓝牙适配器并把适配器用一根USB延长线拉到柜子外面调整温湿度计的摆放位置尽量让它和树莓派之间有比较空旷的路径调整扫描参数缩短扫描间隔。最终效果最好的是第一种方案。USB延长线成本不到十块钱却能显著改善天线朝向问题。如果你的温湿度计距离树莓派超过十米那建议加一个WiFi转蓝牙网关否则数据丢包会很严重。不过别急如果你只是想放在同一个房间那自带的蓝牙模块完全够用。6. 接入HomeAssistant从数据采集到自动化联动6.1 准备HomeAssistant配置现在数据处理已经通了剩下就是接入HomeAssistant。我用的HA版本是2024.x运行在Docker里前端用经典的Home Assistant UI。接入方式有两种我推荐第一种。方式一使用HA自带的BLE传感器集成。从HA的2021.8版本开始官方把小米BLE设备集成列入内置集成列表但前提是你需要把bindkey配置到configuration.yaml里。具体操作如下编辑HA的配置文件sensor: - platform: xiaomi_ble mac: 4C:65:A8:DB:XX:XX bindkey: 5f5e5c5d5e5f60616263646566676869 name: LivingRoom Temp monitored_conditions: - temperature - humidity - battery这里有一个重要事项HA的xiaomi_ble集成中bindkey必须是一个长度为32位的十六进制字符串但要注意它接收的是一个字符串形式不带0x前缀。如果你在配置里漏掉或者多了一个空格HA加载时会报错。改完之后重启HA或者只重启传感器配置docker restart homeassistant或者使用HA的“开发者工具”里的“YAML配置”重新加载核心配置。方式二通过MQTT桥接。如果你的HA已经跑了一套MQTT服务器也可以在树莓派上用Python脚本把温湿度值发布到MQTT主题然后HA里订阅。我初版就是这么做的原因是当时HA版本比较旧对小米BLE的支持不好。MQTT思路很简单在read_sensor.py脚本里加两行publish代码把温度值和湿度值发到类似homeassistant/sensor/livingroom_temp的主题HA端用MQTT传感器接入。6.2 创建自动化规则让传感器数据发挥作用数据进HA之后真正的乐趣在于联动。我在HA里配了几个自动化卧室温度超过28度时开启风扇通过智能插座控制客厅湿度低于40%时通过HomePod语音播报提醒该加湿了每天早晚各记录一次温湿度数据生成一周曲线图。配置方式不在此赘述HA的自动化配置网上资料很多。这里只说一个核心经验如果你的温湿度计数据更新频率是10秒一次那么HA的自动化触发条件建议设为for: 120秒避免因为单次瞬时异常值触发误操作。比如温度短暂跳到30度两秒之后又掉回27度如果不加延时条件风扇会被频繁开关。6.3 HA中显示数据的技巧与定制在HA的仪表盘上我新建了一个叫“客厅温度”的卡片用的是entities仪表卡片把温湿度计和电量都显示在一张卡里。温度传感器和湿度传感器还可以设置图标温度用mdi:thermometer湿度用mdi:water-percent。如果你想更直观也可以安装Historian卡片插件把温湿度历史曲线画出来。我用了两周的曲线图能明显看出每天温度变化规律对优化家里空调策略很有帮助。7. 常见问题与排查技巧实录到这个阶段项目基本完成了。但我相信你在实际操作中一定会遇到和我类似的问题提前整理出来供你参考。7.1 蓝牙扫描不到设备这是最常见的问题很多朋友卡在第一步。排查顺序建议检查温湿度计是否已经解绑过米家App。如果还处于绑定状态设备不会主动广播。确认设备处于“可配对”状态。长按背面按键大约5秒屏幕上会短暂显示一个类似二维码或蓝牙图标的样子这就是配对模式。检查树莓派蓝牙服务状态sudo systemctl status bluetooth如果显示inactive用sudo systemctl start bluetooth启动。换一个USB蓝牙适配器试试。有的树莓派自带蓝牙芯片版本较老对小米设备兼容性不够好。7.2 密钥获取失败或连接被拒如果你在Telnet连接阶段或者用mithermometer时一直断开连接多半是设备固件问题。我试过两台设备其中一台老版本成功了另一台新版本反馈需要先降级固件。降级固件最稳妥的方式是用小米官方的刷机工具但操作稍复杂。如果不愿意折腾降级另一个办法是直接用ATC固件方案。刷ATC固件之后设备会直接发明文广播密钥就变成了ATC1441这样的固定值而且不需要再配置bindkey。7.3 解密后数据不正确如果解出来的温度和实际明显不符比如显示-9999那么八成是bindkey不对。建议先重新获取密钥再核对一下自己的配置。有一个细节mithermometer输出的key有时候是大写HA里配置的时候大小写都能被识别但不要混用。混用虽然不会报错但是可能会解密不出来。7.4 数据更新延迟过大如果你发现HA里的温湿度数据要等很长时间才更新可以考虑把温湿度计的广播间隔降低。网上有工具可以修改设备的广播间隔从默认的10秒调到4秒但这需要重新刷写设备参数操作不当有风险。一般情况下10秒间隔对自动化已经足够没有必要为了更快响应牺牲电池寿命。7.5 树莓派蓝牙死机问题树莓派长时间跑蓝牙扫描偶尔会遇到蓝牙适配器“死掉”的情况扫描命令一直卡住不返回结果。我的解决方法是设置一个定时重启脚本每天凌晨自动重启蓝牙服务sudo crontab -e # 添加到末尾 0 4 * * * sudo systemctl restart bluetooth这个办法简单粗暴但非常有效。如果你的系统是树莓派OS完整版也可以用bluetoothctl power off bluetoothctl power on来重置蓝牙模块。7.6 问题速查表问题可能原因解决方案lescan无结果设备处于绑定状态解绑后在配对模式扫描设备断开频繁信号弱或适配器兼容差加USB延长线换适配器解密报错bindkey错误重新获取密钥核对长度HA里看不到实体配置未重新加载重启HA或重载YAML蓝牙卡死无响应蓝牙芯片低功耗休眠定时重启蓝牙服务8. 实操心得与扩展可能性项目跑通之后我最大的感受是小米温湿度计2代搭配树莓派做蓝牙网关是智能家居入门改装里性价比最高、仪式感也最强的一个小项目。整个过程涉及BLE协议、AES解密、Linux服务配置、HomeAssistant集成等多个技术点每一步都有挑战但每一步都能学到东西。另外我想分享一个小经验如果你家不止一个温湿度计一定要给每个设备做标注建议用标签纸贴在传感器背面写上房间名和MAC地址后四位。因为同时管理多个设备时配置里的MAC和bindkey对应关系一旦搞混排查起来非常痛苦。我就曾经因为两个设备弄混导致客厅温度显示成了卧室的数据花了一个多小时才反应过来。我后来的做法是在HA里为每个传感器设置一个自定义carea区域标签比如“Living Room”和“Bedroom”这样卡片上一目了然。如果你有第二块树莓派还可以一个房间放一个蓝牙网关数据分布到整个家庭。这个项目后续还有很多扩展空间。比如在树莓派上跑一个MQTT broker再接一个ESP32开发板去开启窗器那就能实现自动通风。或者你可以把采集到的数据存进InfluxDB用Grafana做可视化和温湿度趋势分析这个我自己也试过效果很棒以后有机会再单独写一篇。当然整个流程中我也不是每一步都顺利。比如说在最开始我并不知道需要解绑设备也不知道哪个适配器兼容性更好都是靠一步步试出来的。所以我特别建议你在安装配置阶段尽量按照文章里的步骤走不要一次性配置完所有东西而是先扫描、再获取密钥、再解密、最后接入HA分阶段验证这样出问题时能快速定位。分步验证是我在这个项目里学到的最重要的工作习惯。最后再分享一个小技巧就是在树莓派上给这个项目单独建一个systemd服务让它开机自动运行。我当时写的服务文件放在/etc/systemd/system/read_sensor.service内容很简单指定Python脚本路径设为开机启动。之后树莓派断电重启也不用人工干预温湿度计的数据会自动恢复同步。这个小步骤虽然很多教程没提但对于真正的长期运行来说非常关键。希望对你有帮助。
返回列表