硬核“破解”小区门禁,让 Gemini 给我开门呼梯!—— Leexxx 门禁接入 Home Assistant 折腾手记
更新日期:
前言:一个不安分的“智能家居”灵魂
作为一个智能家居爱好者,我一直致力于将家中万物都接入 Home Assistant 的统一管理之下。从灯光、窗帘到各种传感器,一切都安排得明明白白。但唯独有一个东西,像一座孤岛,顽固地游离在我的智能网络之外——小区门禁和电梯系统。
我们小区的这套“leexxx”(立x)门禁系统,像当前市面上的许多楼宇门禁系统一样,突出一个“封闭”。既没有开放的 API(例如完全SIP协议),也不支持米家等任何主流生态,而是实现了一套自己的基于UDP的私有通讯协议,难以直接通过抓包分析(看到网上说一些包可以重放)。每次有朋友来访,我都没法远程开门;智能门锁检测到我回家了,电梯却不能自动下来迎接。这种“不够智能”的感觉,对于一个爱折腾的 Geek 来说,简直是“是可忍孰不可忍”!
于是,一个大胆的想法在我脑中萌生:能不能把它“破解”了,强行接入我的 HA 系统?
幸运的是,万能的 GitHub 给了我一线曙光。我无意间搜索到了两个同名的开源项目:leexxx_code
和 leelen-controller
。虽然看起来年代久远,但代码中透露出的协议细节,让我看到了希望。于是,我火速 clone 下来,一场硬核的“破解”之旅就此展开!
技术探索:在 UDP 的世界里“捕风捉影”
协议分析与网络拓扑
通过研读参考项目的源码(一个是 C++ Qt 实现(像是门禁机固件代码),一个是 Python 实现),我逐渐摸清了这套系统的底细。它完全基于 UDP 协议进行通信,设备之间通过特定的广播和单播包来交互。
为了能和门禁系统“对话”,我设计了如下的网络拓扑。简单来说,就是让我家的网络和门禁系统处于同一个局域网下:
当然这里一定要注意许多门禁系统的网线实际包含了非标POE的18v供电,需要分离1236四根芯(这四根传数据其他4578是+18v供电的)来接入交换机,不要直接接入交换机容易烧网口!!!
1 | +----------------------+ +----------------------+ +----------------------+ |
我用一个刷了 OpenWrt 的路由器充当交换机,将门禁网线、入户网线,以及 Home Assistant 主机的一个专用网口都接在上面。然后给 HA 主机的这个网口配置一个和门禁设备同网段的静态 IP(比如 172.168.2.201
)。这样一来,我的 HA 主机就成了一个能同时访问内外网的“中间人”,具备了监听和发送门禁网络数据包的能力。
抓包!发包!验证!
网络联通后,就到了最激动人心的环节。我直接在 OpenWrt 路由器上使用 tcpdump
工具,像一个侦探一样,监听着门禁网络中的一举一动。每当有人刷卡、开门、呼叫电梯,我都能看到对应的 UDP 数据包在屏幕上飞速滚过。
结合着参考代码中对协议结构的定义,我逐渐破译了这些数据包的“语言”。比如,哪个字段代表源地址,哪个字段代表目标地址,哪个字节是开门指令,哪个字节又是呼梯指令……
为了验证我的猜想,我开始尝试伪造数据包。将抓到的合法数据包进行修改,然后通过 Python 脚本重新发送出去。当看到单元门“咔哒”一声应声而开,电梯的楼层显示屏亮起时,那种兴奋感,相信每个爱折腾的人都懂!
我的核心武器:control.py
在反复的抓包和验证之后,我将所有的逻辑都沉淀到了一个核心脚本中——control.py
。它就是我接入 HA 和 AI 的终极武器。这个脚本主要提供了三个命令行功能:
discovery
: 发现设备 IP。call_elevator
: 呼叫电梯。open_door
: 打开门禁。
下面是它的命令行参数用法:
1 | usage: control.py [-h] [--local_username LOCAL_USERNAME] [--udp_port UDP_PORT] [--local_ip_for_discovery LOCAL_IP_FOR_DISCOVERY] [--cache-file CACHE_FILE] {discovery,call_elevator,open_door} ... |
这个脚本最核心的亮点,是我设计的一套“带缓存的乐观执行”机制。因为门禁设备的 IP 偶尔会变动,如果写死 IP 会很不稳定。我的 send_leelen_command_with_cache
函数是这样工作的:
- 乐观尝试:执行命令时,首先从一个 JSON 缓存文件里读取目标设备(比如2栋地库门)上次的 IP 地址,然后乐观地把命令发过去。
- 事后验证:命令发出后,脚本会立刻
ping
一下刚才的 IP。 - 验证成功:如果
ping
通了,说明 IP 没变,缓存有效,任务顺利完成! - 验证失败:如果
ping
不通,说明 IP 可能变了。此时脚本会自动触发“设备发现”流程,通过 UDP 广播去寻找目标设备的新 IP。 - 更新缓存并重试:找到新 IP 后,立即更新本地的 JSON 缓存文件,并用新的 IP 重新发送一次命令。
这套机制,让整个系统在实际使用中非常稳定可靠。即使偶尔设备 IP 变动,系统也能自我修复,无需人工干预。
接入 Home Assistant:打通“任督二脉”
有了 control.py
这个利器,接入 Home Assistant 就变得水到渠成了。我使用了 HA 的 command_line
集成,将开门和呼梯的命令封装成了两个 switch
开关。
现在,我不仅可以在 HA 的界面上一键远程开门,更实现了我最初的梦想:开门自动呼梯!通过将我的智能门锁(Aqara N100)的“室内开锁后上提把手锁门”事件作为触发器,设置一个自动化,一旦我出门锁门,HA 就会立即执行呼叫电梯的命令。从此告别在电梯口的焦急等待,体验感直接拉满!
AI 赋能:让 Gemini 成为我的“门童”
在成功接入 HA 之后,我又突发奇想:既然我已经写了那么多 MCP 服务器,为什么不把这个也封装一下,让 AI 大模型来直接控制呢?
说干就干!我很快就写好了一个 leelen-mcp-server
。现在,我可以像和真人助理对话一样,对我的 Gemini 说:“帮我把12栋的电梯叫到5楼”,或者“打开3栋的地库门”。AI 助手会立即理解我的意图,调用对应的工具,并通过 control.py
脚本向门禁系统发送指令。有碟中谍007那味了哈哈哈。
这种通过自然语言与物理世界直接交互的感觉,实在是太奇妙了!
法律与安全风险提示
写在最后,也是最重要的。这次“折腾”纯粹是出于个人技术探索和提升生活便利性的目的。需要强调的是,对小区门禁等公共设施进行任何形式的修改或接入,都可能涉及法律、法规和安全风险。
不同地区的物业管理规定各不相同,在进行类似尝试前,请务必了解并遵守当地的法律法规和物业要求。同时,任何对安防系统的改动都必须将安全性放在首位,确保不会产生新的安全漏洞。
出于这些考虑,本项目的相关代码将不会开源,这篇博文也仅作为一次技术思路的分享,单次尝试,实际无意长期接入控制门禁电梯系统。请大家务必在法律和安全的框架内进行探索。
这篇文章当然也是在我的好伙伴 Gemini 的帮助下完成的,哈哈哈!