惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
P
Proofpoint News Feed
V
Visual Studio Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
爱范儿
爱范儿
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
GbyAI
GbyAI
博客园 - 聂微东
D
DataBreaches.Net
酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
美团技术团队
H
Help Net Security
aimingoo的专栏
aimingoo的专栏
C
Check Point Blog
U
Unit 42
博客园 - 叶小钗
有赞技术团队
有赞技术团队
M
MIT News - Artificial intelligence
MongoDB | Blog
MongoDB | Blog

竹林里有冰的博客

Nuxt SSG 博客的尾斜杠到底怎么加? | 竹林里有冰的博客 小米 Xiaomi Book Pro 14 (Ultra X7) Linux 兼容性实测 | 竹林里有冰的博客 国内(大陆)版小米 FCM 熄屏断连:Rootless 环境下的尝试与可能的解决方案 | 竹林里有冰的博客 我没法访问 dl.google.com —— 记一次 TUN 下的网络 debug | 竹林里有冰的博客 Vercel 的缓存控制,你注意过吗? | 竹林里有冰的博客 小记 —— Caddy 在 Layer 4 上的流量代理实践 | 竹林里有冰的博客 你的域名后缀拖慢你的网站速度了嘛?——再谈 DNS 冷启动 | 竹林里有冰的博客 DNS 冷启动:小型站点的“西西弗斯之石” | 竹林里有冰的博客 HTTP/2 Server Push 已事实性“死亡”,我很怀念它 | 竹林里有冰的博客 Nuxt Content v3 中数组字段的筛选困境与性能优化 | 竹林里有冰的博客 后 OCSP 时代,浏览器如何应对证书吊销新挑战 | 竹林里有冰的博客 初试 Github Action Self-hosted Runner,想说爱你不容易 | 竹林里有冰的博客 DNS 解析延迟毁了我的图床优化 | 竹林里有冰的博客 Vue Markdown 渲染优化实战(下):告别 DOM 操作,拥抱 AST 与函数式渲染 | 竹林里有冰的博客 Vue Markdown 渲染优化实战(上):从暴力刷新、分块更新到 Morphdom 的华丽变身 | 竹林里有冰的博客 node-sass 迁移至 dart-sass 踩坑实录 | 竹林里有冰的博客 前端中的量子力学——一打开 F12 就消失的 Bug | 竹林里有冰的博客 2025 年,如何为 web 页面上展示的视频选择合适的压缩算法? | 竹林里有冰的博客 el-image 和 el-table 怎么就打架了?Stacking Context 是什么? | 竹林里有冰的博客 2025年,前端如何使用 JS 将文本复制到剪切板? | 竹林里有冰的博客 ssh 拯救世界——通过 ssh 隧道在内网服务器执行 APT 更新 | 竹林里有冰的博客 Cudy TR3000 吃鹅(daed)记 | 竹林里有冰的博客 使用 Cloudflare Workers 监控 Fedora Copr 构建状态 | 竹林里有冰的博客 基于 Cloudflare Workers 实现的在线服务状态检测告警系统 | 竹林里有冰的博客 构建部署在 Cloudflare Workers 上的 TG Bot | 竹林里有冰的博客 2024年,Firefox 是唯一还在坚持执行在线的 SSL 证书吊销状态检查的主流浏览器 | 竹林里有冰的博客 小爱课程表适配不完全指北——以 ZJUT 本科正方教务系统为例 | 竹林里有冰的博客 将博客从 waline v2 更新到 waline v3 | 竹林里有冰的博客 给家里云装上 Fedora 41 KDE 后,我是如何配置的 | 竹林里有冰的博客 为 Hexo 添加 follow 认证 | 竹林里有冰的博客
通过巴法云将向日葵智能插座接入米家,实现小爱同学远程控制 ...
竹林里有冰 · 2023-11-02 · via 竹林里有冰的博客

上一篇博客中,我们介绍了如何在本地局域网中通过发送 http 请求控制向日葵智能插座 C2 的开关状态。但这还远远不够,我自己是小米生态链的忠实用户,在宿舍里也接入了四五个米家的智能设备,因此我想把这个智能插座接入米家,实现离家时一键关闭。

在阅读小米IoT开发者平台的接入文档后,我发现米家对于个人开发者并不友好,接入文档大部分要完成企业认证以后才能实现。在谷歌一番搜索过后,我发现了通过假设 Home Assistant 后通过巴法云接入米家的方案。但我眼下就这一个非米家的智能家具,暂时还不想去碰 Home Assistant 那套体系。

因此我便找上了巴法云。在巴法云的官网中提到,他们是「专注物联网设备接入&一站式解决方案」,对于个人开发者,目前平台免费使用。网站的文档虽然并不优雅美观,却透露出实用主义的气息,针对接入提供了 TCP 长连接和 MQTT 两种方案,看着就很适合实现我的需求。

在巴法云文档中的「五分钟入门」那一栏介绍了远程控制的业务逻辑:

如果单片机订阅了一个主题,手机往这个主题推送个消息指令,单片机由于订阅了这个主题,就可以收到发往这个主题的消息,就可以达到手机控制单片机的目的。

所以我需要在巴法云的控制台创建一个针对于智能插座的主题,让我局域网内的一台设备订阅这个主题。接入米家以后,米家需要控制向日葵的智能插座时就向巴法云的这个主题推送一条消息,局域网内的设备就能接收到推送消息,进而调用智能插座的 api 实现远程开关。在这里,我选择使用一台刷了 Armbian 的 N1 作为局域网内的转发器。整个控制流程看上去是下面这个样子:

控制流程图控制流程图

我并不知道 tcp 长连接的数据传输应该如何实现,但看起来 MQTT 是一个比较成熟的协议,因此我选择使用 MQTT 作为巴法云和 N1 之间的通讯协议。

在巴法云的控制台,选择 MQTT 设备云,创建一个新的主题,注意需要以 001~009 结尾,否则在米家里看不见创建的这个主题。

当主题名字后三位是001时为插座设备。

当主题名字后三位是002时为灯泡设备。

当主题名字后三位是003时为风扇设备。

当主题名字后三位是004时为传感器设备。

当主题名字后三位是005时为空调设备。

当主题名字后三位是006时为开关设备。

当主题名字后三位是009时为窗帘设备。

当主题名字为其他时,默认为普通主题节点,不会同步到米家。

创建新主题创建新主题

此时,我便可以在手机的米家中找到巴法云并接入这个插座。

米家找连接巴法云米家找连接巴法云

至此,米家那边的接入已经完成了,虽然没法在米家中找到对应设备的卡片,但是可以在小爱同学的小爱训练计划中找到对应的设备。

我们还需要让本地的 N1 盒子使用 MQTT 协议订阅巴法云的消息。

参考代码如下:

#!/usr/bin/python3

import paho.mqtt.client as mqtt
import requests

# 智能插座相关
host = ''
sn = ''
key = ''
time = ''

# 巴法云相关
client_id = ''
theme = ''

def set_adapter_status(status: bool):
    url = 'http://' + host + '/plug'
    requests.get(url, params={
        "status": 1 if status else 0,
        "sn": sn,
        "key": key,
        "_api": "set_plug_status",
        "time": time,
        "index": 0
    })

def on_connect(client, userdata, flags, rc):
    print("Connection returned with result code:" + str(rc))
    client.subscribe(theme, qos=1)

def on_message(client, userdata, msg):
    if msg.payload.decode("utf-8") == 'on':
        set_adapter_status(True)
    elif msg.payload.decode("utf-8") == 'off':
        set_adapter_status(False)

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed: " + str(mid) + " " + str(granted_qos))
    
client = mqtt.Client(client_id=client_id, clean_session=False, protocol=mqtt.MQTTv311)
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe

client.connect("bemfa.com", 9501, 60)
client.loop_forever()

参考链接#