最近开始有一些安防监控方面的需求。看了一圈市场上现有的产品有三个顾虑，第一是它们的数据都要从互联网上走一圈，不是很放心；第二这种云存储/识别等服务需要月费；第三除了昂贵的专业产品，一般的民用摄像头很少有提供开放的接口，不方便进一步处理。所以决定自己从头做一个。因为手头正好有ESP32-Cam这个片子，感觉非常适合，所以花了一两天时间撸了一个版本，分享一下经验和踩到的坑。

最终的成品是这样的：

![Final product](https://yage.ai/images/esp32_cam_case.jpg)

Micro-USB口供电，有图形化Web界面，可以在电脑和手机上访问串流，支持[基于深度学习的物体检测和报警](/raspberry-pi-object-detection.html)。同时和[Alexa可以联动](/smart-home-air-quality.html)。比如可以跟Alexa说，"turn on camera one"，手机就会收到一个推送，上面是这个相机的画面，点进去可以跳转到图形化界面里面去看实时场景。

![Notification](https://yage.ai/images/esp32_cam_notification.jpg)

下面我们主要从三个方面简单介绍一下这个系统搭建的技术细节。其中所有代码都开源到了[github](https://github.com/grapeot/alexa-esp32-cam)上。

## v0: 基于ESP32-Cam的监控相机

首先介绍一下ESP68266, ESP32, ESP32-Cam这几个片子。
ESP8266是一个类似Arduino升级版的单片机（也许可以这么叫？）。
它的CPU，内存，存储空间都比Arduino强很多，带Wifi，而且开发板也很便宜，贸易战前只要不到2美元。
可以用Arduino IDE或者Visual Studio开发调试，用Arduino C或者MicroPython。
这里走个题，我觉得ESP8266其实也是[树莓派的直接竞争对手](/smart-home-air-quality.html)。
你看网上那些树莓派的使用示例，很多是用GPIO口拿来读传感器的。
毕竟现在家里都有老电脑，如果只是拿来当个媒体服务器啊啥的，直接用老电脑一分钱都不花没有购买树莓派的动力。
但读传感器这种事情ESP8266也可以干，带Wifi也很方便，稳定性更好，买一个树莓派的钱能买20个，它不香吗？

扯远了。ESP32是ESP8266这个经典片子的升级版，主要是CPU升成双核，加了一些内置传感器（霍尔效应磁场传感器，电容触摸传感器），加了BLE蓝牙。
价格贵了1美元。
开发方法不变。
然后ESP32-Cam是在上面加了一个烂怂相机模块OV2460，最大分辨率1600x1200，1/4寸的底。
板子连相机大概4美元可以买到。

![The camera module](https://yage.ai/images/esp32_cam_module.JPG)

其实这个板子就提供了监控相机的主要功能。
我们只要解决供电就好了。
找一个micro USB的breakout板子，把VCC用杜邦线接到5V，地线接地线就搞定了。
然后板子自己带了示例程序，会加入家里的无线网络，并启动一个Web服务器。
这样用浏览器访问这个网站就可以控制片子预览拍照和视频串流了。
打印一个壳子以后和充电宝连起来，在电脑端写一个程序每过10秒钟读取一次图像，进行神经网络处理和存储，一个简单的监控相机就做出来了。

![Surveillance set up](https://yage.ai/images/esp32_cam_mounted.jpg)

## v1: 改善速度和自动曝光

![Photos](https://yage.ai/images/esp32_cam_squirrel.jpg)

上面是这样的v0猴版相机的样子和拍出来的照片。
在坚持拍摄一个上午以后就被松鼠啃了。。
我还测试了一下续航时间。
72Wh的充电宝可以撑大约72小时（每10秒钟做一个Web请求拿照片，偶尔连上去看串流）。
这么看功率还是蛮大的，大约要1W。
还是需要一个有线的供电比较好，充电宝也许可以用来做临时的延时摄影等等。

除了功率以外，这个监控相机还有一个问题是速度。
即使分辨率这么低，串流的时候还是一卡一卡的。
这个原因主要是它的天线是在PCB板上的，增益很低。
ESP32-Cam其实也允许加装外置天线。
只要把一个地方的焊锡除掉让它断路，然后焊上另一个地方即可。
弄了一个外置天线以后，信号好了很多，视频串流也可以到6fps左右，够用了。

![External antenna](https://yage.ai/images/esp32_cam_external_antenna.jpg)

这里还有一个比较有意思的项目是[ESP32 NAT Router](https://github.com/martin-ger/esp32_nat_router)，可以把ESP32变成一个简单的路由器。
我用振旺的盒子拍深空有段时间了，什么都好，就是Wifi信号比较弱。
用ESP32和外置天线做了一个小路由以后，接收距离增加了，网速也变快了，感觉是个低成本改善信号的好方法。

这样我们就有了一个在白天堪用的监控相机。
但我发现它到夜里会严重欠曝，原因是它的自动曝光的算法非常保守。
这个也可以用一些简单的算法加以解决。
一种方法是根据当前照片的直方图手动指定下一张照片的相关参数。
这个在github里面的代码中有所实现。
另一种方法是拍几张照片，然后在电脑上进行叠加拉伸。
这个还在进一步的实验中。

## v2: 和Alexa和Apple Watch的集成

v1虽然已经是一个比较实用的监控相机了，但用起来还是不够爽。
比如很多时候我只想瞄一眼画面，看看有没有松鼠，或者有没有人。
这种时候要掏出手机，打开浏览器，打开收藏夹，点进网页，单击拍照，就还是很麻烦。
有没有可能我们直接跟Alexa说：把这个相机的画面推送到我的Apple Watch上面呢？
这样就人性化了很多。

调研之后我发现了[这个repo](https://github.com/igorantolic/esp32-alexa-wemo-emulator)，可以把ESP32模拟成一个Wemo的智能插座。
这样Alexa就可以搜索到，并且可以通过语音控制了。
在集成这个库的时候，我遇到了两个问题，首先这个模拟需要有自己独立的消息泵来响应Alexa的各种请求。
这个消息泵和我们前面的Web服务器是冲突的。
如果直接把两个消息泵分别执行的话，一个都跑不起来。
好消息是，ESP32有一个双核处理器（主频80MHz 23333），所以我们可以用ESP的API把Alexa的库放到0号核上面执行，相机的库放到1号核上面执行。
这样就实现了两个消息泵独立并发的执行。
但光这样还是不够的，因为Wemo需要占用80端口，这和Web服务器又冲突了。
所以还需要更改Web服务器的C代码和HTML代码。
这里一个有意思的地方是，这个Web服务器里面的静态内容都是gzip以后，直接把二进制写死在C语言里面的。
想想的确有道理，这样一方面可以节约单片机上宝贵的存储空间，一方面可以直接在http头里面指定，我们输出的是gzip内容，从而提升响应速度。
所以我们还需要解压，拿到HTML，更改，压缩，然后写程序生成C代码放进去。
相关的代码也放在github上了。

第二个问题是，这个Wemo智能插座是有开和关两种状态的。
比如我说Alexa打开XX相机，如果它本身就处于开的状态的话，就不会调用相关函数，不会做任何事情。
难道我还要硬记某个开关原来是开还是关吗？
那也太麻烦了。
所以这里我又深入模拟Wemo开关的库，更改了相关代码，加入了一个相关接口来直接操纵开关的内部状态。
这样我们就可以实现打开开关以后自动关上这个功能，所以以后只要说Alexa打开XX相机就行了。
易用性得到了很大的提升。

解决了语音控制的问题，第二步就是和Apple Watch集成起来了。
这里我用的是IFTTT这个服务。
它也是个老牌的[智能家居的服务](/adding-a-delay-to-ifttt-recipes.html)了，提供WebHook功能，也就是如果某个URL被访问的话，就可以做一些动作，比如在手机上弹个提醒之类。
这个提醒是可以有一些更多的数据的，比如提供一个缩略图，可以点进一个链接等等。
所以我们就是在这个Wemo插座打开的回调函数里面向IFTTT发送一个请求就好，然后手机和Apple Watch就会弹出通知和缩略图了。

解决了这些问题以后，我一下从aliexpress上面买了10个ESP32-Cam，下面就是真的部署在房子周围了。
现在主要的工作是，测试供电，做一个类似保安监控室那样的集成网页，提升神经网络检测的吞吐量，还有进一步优化夜间的画质。
通过这样的方法，踩了很多坑，终于做了一个不经过互联网，可以拿到视频帧进行进一步处理，也很便宜的系统了。
希望可以做成一个实用的家防系统吧。

<script async data-uid="49b08a3e73" src="https://yage-ai.kit.com/49b08a3e73/index.js"></script>
