之前的博客文章 <如何在 Home Assistant 上实现防止猫咪出逃的自动化> 提到了用 Aqura 空调伴侣和门磁来做传感器控制报警。最近打算再深入看下其中的原理。
通过局域网抓取报文发现(图中的报文是双份的原因:我在无线 AP 处抓包,AP从无线侧收到空调伴侣的报文,然后再转发到有线侧,因此所有的组播报文在同一时间为两份),Aqura 的空调伴侣添加了门磁之后,在门开启和关闭的时候,空调伴侣会发送相应的组播报文。
于是用 python 写了一个接收组播报文的一个小程序
import socket
import struct
multi_cast_group = '224.0.0.50' # 播组
server_address = ('', 9898) # 播组端口
# Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind to the server address
sock.bind(server_address)
# Tell the operating system to add the socket to the multi_cast group on all interfaces.
group = socket.inet_aton(multi_cast_group)
m_req = struct.pack('4sL', group, socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, m_req)
# Receive/respond loop
while True:
data, address = sock.recvfrom(65535) # socket的recvfrom()会返回数据以及相应的地址
print('Server received from {}:{}'.format(address, data.decode('utf-8')))
收到的报文打印如下(heartbeat 为心跳报文):
Server received from ('192.168.33.225', 4321):{"cmd":"heartbeat","model":"acpartner.v3","sid":"04cf8ca2b371","token":"iQKPcpSfluF5V6UU","params":[{"ip":"192.168.33.225"}]}
Server received from ('192.168.33.225', 4321):{"cmd":"report","model":"sensor_magnet.aq2","sid":"158d000445872e","params":[{"window_status":"open"}]}
Server received from ('192.168.33.225', 4321):{"cmd":"heartbeat","model":"acpartner.v3","sid":"04cf8ca2b371","token":"QGCd6BdvS4dVSQSg","params":[{"ip":"192.168.33.225"}]}
Server received from ('192.168.33.225', 4321):{"cmd":"report","model":"sensor_magnet.aq2","sid":"158d000445872e","params":[{"window_status":"close"}]}
Server received from ('192.168.33.225', 4321):{"cmd":"heartbeat","model":"acpartner.v3","sid":"04cf8ca2b371","token":"2xyqtf3ryLgf3MYY","params":[{"ip":"192.168.33.225"}]}
但我在实际测试过程中发现,一次开关门,程序经常只打印 open 或者 close,很少出现同时打印 open 和 close。想了半天,应该是我的计算机用 WiFi 接入的。改用有线接入,丢包的现象不再出现。