使用 ESP32 将单元门门禁接入智能家居
前言
在很久以前,小区单元门门禁卡是可以复制到手环上的,回家开门不需要从口袋里掏掏掏就能解锁单元门。但好景不长,小区换了门禁系统,门禁卡再也没法复制到手环上了,再加上家门是密码锁,平常出门根本不会带钥匙,要我随身带一张门禁卡可真是要了老命,所以我急需一个新的方案来方便我回家。
既然门禁卡加密了,那我们当然应该想着把门禁卡加密给破解了,但是想要破解门禁卡还是有点难度的,一方面我对 RFID 卡片破解的知识还停留在 16 年,而且手头也没有合适的工具,所以我不打算从卡片破解入手。
既然没法破解门禁卡,那还有什么方法能方便快捷地解锁单元门呢?一般来说,解锁单元门有两条途径,一是在楼下刷卡,二是在楼下按门铃,楼上点击解锁。既然我没法破解门禁卡,那我就从第二种解锁途径入手,在楼下按门铃,然后用一个 IoT 设备在楼上点击解锁按钮。我正好会一些!那就开干吧!
先放张门铃的照片,可以看到它的构成非常简单,左边一个听筒以及检测听筒是否挂在墙上的开关,右边一个解锁按钮,门铃响后按下去就可以解锁单元门。
门神 MVP v1.0
我们先来写一下 BRD:
👆 这人一看就是上班上癫了
- 我才不要随身带什么他妈的门禁卡
- 我拎着一堆东西回家的时候别让我再去口袋里掏半天东西
根据 BRD 再来写一下 RPD:
- 不带门禁卡了,但手机肯定得带身上,那可以在楼下先按门铃,然后手机控制楼上的 IoT 设备点击解锁
- 自动识别门铃声,然后自动点击开门(
研发说难搞,先不做)
分析门铃电路
好,让我们把门铃拆开,看看它里面的电路长什么样。我们先看正面,从上到下,从左往右分析
- 首先可以看到一个蓝色的东西,它是一个开关,当听筒挂上去的时候会把这个开关按下去,就像图中那团纸做的一样
- 然后是一颗二级管(被那团纸挡住了),不知道是干啥用的
- 接着是一个 4pin 插座,引出来的线接到了听筒上
- 最右上角是一个铁片和铁棒,这就是开门按钮,按下去就会让铁片和铁棒接触(真简陋啊)
- 中间下方是一个 5pin 插座,从墙里出来的线就接在了这个插座上
正面没有电路,我们把电路板拆下来看看背面:
- 可以看到左边凸出来那坨就是解锁按钮,把眼睛瞪大,发现当解锁按钮按下时,会将 5pin 插座中的红线和蓝线短接在一起
就这么简单,我们只需要让 IoT 设备替这个按钮把红线和蓝线短接在一起就能实现解锁单元门了。
设计电路
既然我们只需要简单将两条线短接,那可以随便找颗光耦充当开关,不过得保证红线和蓝线的电位差总是正的或总是负的,因为光耦约等于一个发光二级管加一个光电二级管,发光二级管照射光电二级管使之导通,既然是二级管,那意味着不能反向导通(按小学二年级的说法)。
所以我用万用表确认了一下红线和蓝线的电位,确定红线电位比蓝线高,而且是固定的 12V,然后我直接去淘宝上随便买了点 PC817C 光耦,根据数据手册,它的 VCEO最大耐压 80V,没有问题。
电路也没啥好设计的,光耦 1 号引脚接 ESP32 的 GPIO 口,2 号引脚接 ESP32 的地,3 号引脚接红线,4 号引脚接蓝线,再接两颗限流电阻。
当我按照这个原理图接上后,发现并没有像预期的那样解锁,经测量发现在光耦导通时,V_EXT 和 GND_EXT 间电位差还有几伏,根本达不到短接红线和蓝线的效果。既然如此,那我直接把限流电阻删了(好孩子别学我这样不经计算就乱搞),发现还是不行,然后我就粗暴地多并联了一颗光耦上去(我嘞个去),发现能解锁了。
至于 ESP32 的供电嘛……直接拉了根线给开发版提供 5V 输入,我太菜了不会做低功耗的电源板 :P
编写 ESPHome 配置
弄完了硬件来弄软件,咱也没搞过什么正经的嵌入式开发,怎么快怎么来,直接拿 ESPHome 来实现我们想要的功能,也方便接入 Home Assistant。
OK,我们将程序刷入 ESP32,刷写过程不是重点,此处略,将线连接好,上电!
现在我就可以在 Home Assistant 上按下解锁按钮了,回家按门铃,然后手机上点一下解锁,单元门就开了~
门神 v2.0
虽然门神 v1.0 实现了我出门不想带卡的需求,但是解锁单元门还是比较复杂的,如果手上拿着一堆东西,按完门铃还要把手机掏出来也挺操蛋的。
开脑洞环节:
- 既然按完门铃要在一定时间内在手机上点击解锁,那可以写一个自动化,开启自动化后每 5 秒按一下解锁按钮,连续按个几分钟。
- 在人进入地理围栏后,自动运行上面的自动化,可以不掏手机。
- 或者想办法监听门铃声,有人按门铃时就自动按解锁按钮。
1 和 2 都不是很好,因为按下解锁按钮时门铃会发出“嘟”的一声,连续响个几分钟还是挺吵的,但由于不能在楼下按门铃时都解锁,把听筒摘掉让门铃不要响也不合适。
所以得想办法检测楼下按门铃。我最初的想法是给 ESP32 加一个麦克风,检测是否有声音。但这不好,我在旁边叫一声、关门嘭的一声它也会认为有人按了门铃。那我们还可以从门铃的铃声信号线入手,这条信号线一定是模拟信号,我们已经看过电路板了,这上面一点数字芯片都没有。那我们要怎么从信号线上检测铃声呢?我想过使用某某芯片将模拟信号转为数字信号,不需要编码成什么音频格式,只需要检测出信号线当前电平高低即可,然后在电平变化时认为检测到了铃声。不过这样又引入了某某芯片,还得上网买,买回来也不知道能不能行,因为我不知道铃声信号线上模拟信号的电压区间,没有示波器来验证。没想出什么好办法,就一直搁置了许久。
后来我突然想到,不是不知道模拟信号电压区间吗,那我直接拿两颗电阻分压个 5% 出来,然后拿 ESP32 的 ADC 去读分压电阻上的电压不就不怕烧芯片了嘛。而且门铃铃声也挺长的,在这快两秒的时间内读到一个高电平的概率还是挺高的。说干就干。
分析门铃电路
接下来我们把门铃再次拆开分析电路,这次得找出哪条线是铃声信号线。
注意一个细节:听筒挂上时,门铃声会非常大,隔着卧室门都能听见的那种;而拿起听筒时,只有听筒里传出声音,正常打电话的那种音量。但在电路板上我们没法找到扬声器,最后发现大声的门铃声也是从听筒里发出的。所以我猜测有这几种可能:
- 电路板上设计了什么拿起听筒时减小电压的电路
- 楼下送上来的铃声信号线不止一条,一条是拿起听筒时的小声信号,一条是挂上听筒时的大声门铃
- 信号的正半周幅值很大,能让听筒大声发出铃声,同时信号的负半周很小,拿起听筒时使用二级管去掉正半周的信号,只留下负半周小声的信号。
接着我们从听筒开关入手,也就是正面那个蓝色的开关,首先得弄明白它的开关逻辑,直接用万用表的通断档去测量各个引脚的通断,最后测出下图所示的逻辑:
- 听筒挂上时,红线接通
- 拿起听筒时,黄线接通
可以得出结论,这是一个双刀双掷开关。既然是双刀,那合理推测,其中一路是控制听筒的,另一路是控制话筒的。再仔细看看电路板,会发现右边中间的这个引脚是悬空的,由此推断右边这路是控制话筒的,拿起听筒时才接通话筒,挂上听筒时回路断开,保证家里的声音不会传给楼下。同时电路板丝印也能佐证这个猜想,A 代表 Amplifier 扬声器,M 代表 Mic 麦克风。看下图,话筒信号从黄线进入开关,再从橙线进入话筒,最后从红线回到墙壁线路里。
接下来关注左边这一路,我们只看挂上听筒时的回路,挂上听筒时,门铃声从紫色进入,经过开关由蓝色进入扬声器,最后经黑色回到墙壁线路里。
最后,图中蓝色线和黑色线之间还连接着一个二级管,判断为保护二级管,防止紫色、黑色间电压过高烧坏听筒。
这下可以确认铃声信号来自紫色线路了,接下来就开始设计电路吧。
设计电路
我们保留 v1.0 的光耦电路,新增一个电压检测电路。
由于 ESP32 的 ADC 最大支持电压为 3.3V,由于不知道铃声信号最大电压能达到多少,先选用 1MΩ 和 22Ω 两颗电阻进行分压,用 ESP32 读 22Ω 电阻上的电压,那么理论上读到的电压应该是铃声信号的 0.002%,有点保守了 hhh。
然后我们编写 ESPHome 配置,将检测到的电压实时打印出来
惊奇地发现,采样到的电压居然也超过了 2V,我估计是没有共地导致的。不过已经能识别出门铃是否在响了,就先不管这些细节了。直接把电路板焊好,开始写 ESPHome 配置。
编写 ESPHome 配置
刚刚我们采样到了铃声信号的电压,但没有将这个信息暴露给 Home Assistant,还需要定义一个二元传感器:
既然已经能检测门铃是否在响了,那就做绝一点,尽可能在门铃响后最短的时间内把单元门解锁了。为了减少从楼下门铃允许解锁到按下解锁按钮的延迟,先来测试一下解锁按钮能支持多高的点击频率,修改 ESPHome 开门按钮的行为,在 Home Assistant 发出一次按下按钮的指令后,ESPHome 会导通光耦 50ms,然后关断光耦 50ms,如此重复 10 次:
将程序刷入 ESP32,去 Home Assistant 中发出解锁指令,门铃中传出了快速的 10 下解锁声!那看来这个频率好使,期望延迟为 50ms。为了提高解锁成功率,我们把重复次数调为 50 次,大致持续 5 秒。
配置 Home Assistant 自动化
首先配置自动化的触发条件,刚刚新增的二元传感器,当它变为已触发时,执行自动化。
然后配置执行的动作,首先向 ESP32 发出解锁指令,然后等待 8 秒,因为按下解锁按钮时门铃也会响,需要防止解锁声触发新的解锁动作。
同时需要设置自动化执行模式为单点,在上一次解锁未完成的情况下不响应新的铃声,也是为了防止解锁声触发新的解锁动作。
经测试,在楼下按门铃后 1 秒才允许解锁,而从按门铃到发出解锁指令延迟大约只有 500ms,基本达到了最佳解锁速度,在楼下按门铃,手移动到门把时正好能够解锁。
后续优化
虽然门神 v2.0 已经让我很满意了,但还是有一些小缺陷待修复。
首先是安全风险,现在无论任何人在任何时间按门铃,都会解锁单元门。这可以通过联动 Home Assistant 的地理围栏进行优化,在人员进入围栏后的一段时间内才允许自动解锁。
其次是电路的共地问题,现在门铃的地和 ESPHome 的地没有连接在一起,可能会有一些问题。