Aqara M1S 2022网关刷自定义固件

  AI的出现加上工作繁忙,博客从月更变成年更了,新年第一个需要记录的事是给车库的Aqara M1S 2022网关刷上自定义固件。前因是车库的外网用的是一个4G上网卡,关上车库门后,外网丢包率很高,但是Aqara这个网关有个逆天的逻辑,这种情况下一段时间后会断开外网链接,不再尝试连接米家,临时的解决方法是装了一个智能插座,每天重启2次网关,要彻底解决这个问题需要刷上自定义固件从局域网连接(经由外网隧道,虽然丢包率高,但是网确实还是通的)。

前置准备

前置知识

  • M2网关和M2 2022网关用的是两个芯片,后者根S1E用的是同一个SOC,二进制程序需要选择正确

所需工具

  • 一个U型2.0mm螺丝刀,用于网关拆机
  • USB转串口模块
  • 测试夹或焊接工具,推荐前者吧,我手残焊了1一小时
  • 良好的网络环境,需要把梯子做在路由器上,因为需要联网下载固件,当然你可以自己改脚本从本地下载

前置工作

  1. 切换到Aqara模式
  2. 连接UART口至电脑,引脚可参考下图,从按钮开始数依次为,GND(存疑),TX,RX
  1. 串口工具打开,波特率115200
  2. 连接电源地板并上电,终端有看到数据后进入下一步

刷机

  1. 不停按回车,并重新上电
  2. 观察uboot是否已经中断
  3. 查看当前bootargs,把init=/linuxrc改为init=/bin/sh
1
2
3
printenv bootargs

ubi.mtd=UBI,2048 root=/dev/mtdblock6 rootfstype=squashfs ro init=/linuxrc LX_MEM=0x3FE0000 mma_heap=mma_heap_name0,miu=0,sz=0x200000 cma=2M mmap_reserved=fb,miu=0,max_start_off=0x3300000,max_end_off=0x3600000 mtdparts=nand0:1536k@1280k(BOOT0),1536k(BOOT1),384k(ENV),128k(KEY_CUST),5m(KERNEL),5m(KERNEL_BAK),16m(rootfs),16m(rootfs_bak),1m(factory),-(UBI)
  1. 设置bootargs并启动
1
2
setenv bootargs ubi.mtd=UBI,2048 root=/dev/mtdblock6 rootfstype=squashfs ro init=/bin/sh LX_MEM=0x3FE0000 mma_heap=mma_heap_name0,miu=0,sz=0x200000 cma=2M mmap_reserved=fb,miu=0,max_start_off=0x3300000,max_end_off=0x3600000  mtdparts=nand0:1536k@1280k(BOOT0),1536k(BOOT1),384k(ENV),128k(KEY_CUST),5m(KERNEL),5m(KERNEL_BAK),16m(rootfs),16m(rootfs_bak),1m(factory),-(UBI)
run bootcmd
  1. 挂载基础分区,这些命令执行后,不会执行fw_manager.sh,后者会把UART输出给干掉,获得一个临时的shell
1
2
3
4
mount -t ramfs ramfs /var; mkdir /var/tmp
cp /etc/init.d/rcS /var/tmp/rcS
sed -i 's/fw_manager.sh -r/echo skip/g' /var/tmp/rcS
/var/tmp/rcS
  1. 联网,现在是没有网络的,找了很多办法,wifi_start.sh始终没有办法连上Wi-Fi,这里想了一个曲线救国的办法,把fw_manager.sh中屏蔽UART输出的逻辑给屏蔽掉,阅读启动脚本/linuxrc会调用/etc/init.d/rcS也就是上面改的脚本,fw_manager.sh中依次调用main()->runner()->run_prepare(),这里只需要设置两个prop就可以bypass掉屏蔽UART掉相关逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
run_prepare()
{
local check_mdnsd=`pstree | grep mdnsd`
local check_mosqu=`pstree | grep mosquitto`
local entry_facmd=`agetprop persist.sys.factory_result`
local uart_enable=`agetprop persist.app.tty_enable`
local debug_flag=`agetprop persist.app.debug_log`

if [ "$check_mdnsd" = "" ]; then mdnsd ;fi
if [ "$check_mosqu" = "" ]; then mosquitto -d ;fi

wait_property_svr_ok
check_zigbee_ota

if [ ! "$entry_facmd" = "true" ]; then
/usr/factory_test/bin/start_fac.sh
exit 0
fi

# Disable Uart.
if [ "$uart_enable" != "true" -a "$debug_flag" != "true" ] ;then
echo "enable tty"
fi
}
1
2
asetprop persist.app.tty_enable true
asetprop persist.app.persist.app.debug_log true
  1. 重启网关,应该能正常执行完初始化,并连接上Wi-Fi,同时串口也得到了保留
  2. 下载curl,这里需要用S1E的二进制程序
1
cd /tmp && wget -O /tmp/curl "http://master.dl.sourceforge.net/project/aqarahub/binutils/curl?viasf=1" && chmod a+x /tmp/curl
  1. 刷自定义固件,我这里中间内核报错了,看着像OOM了,没管,最后刷机成功了
1
2
/tmp/curl -s -k -L -o /tmp/m1s22_update.sh https://raw.githubusercontent.com/niceboygithub/AqaraCameraHubfw/main/modified/M1S22/m1s22_update.sh
chmod a+x /tmp/m1s22_update.sh && /tmp/m1s22_update.sh
  1. 重启后telnet应该自动打开,可以去Home Assistant的Aqara Gateway集成上添加网关了

参考文献