UNO R4 Wi-Fi 接入 Home Assistant

项目介绍

本项目是Funpack第五期板卡三的任务1实现.
任务目标是让UNO R4 Wi-Fi通过网络连接到智能云端, 并模拟成一个可以控制的灯, 通过远程控制调整自带的LED矩阵点亮范围.

实现思路

将UNO R4作为灯装置接入IOT平台, 随后在IOT平台上下发命令来操作UNO R4, 调整这个”灯”的亮度.
这里我选择的是可以部署在内网环境下的Home Assistant.

UNO R4通过MQTT服务器与Home Assistant进行通信. MQTT服务器选择EMQX开源版.

结构图

服务器部署

本项目需要有一台服务器,并且在服务器上部署Home Assistant和EMQX两个服务.
本节简单介绍下两个服务的部署方式.

Home Assistant

Home Assistant官网上有较为详细的多种安装方式介绍.这里我选择的是使用Docker进行安装,可以忽略很多具体环境差异,只需要输入命令便可将Home Assistant跑起来.
具体介绍位于
Install Home Assistant Container

1
2
3
4
5
6
7
8
9
docker run -d \
--name homeassistant \
--privileged \
--restart=unless-stopped \
-e TZ=MY_TIME_ZONE \
-v /PATH_TO_YOUR_CONFIG:/config \
-v /run/dbus:/run/dbus:ro \
--network=host \
ghcr.io/home-assistant/home-assistant:stable

命令执行完毕,打开使用服务器IP配合默认端口号8123->http://:8123即可进入主面板.

EMQX

EMQX同样可以使用Docker进行安装部署, 页面通过 Docker 运行 EMQX详细介绍了所需的命令.

运行以下命令获取 Docker 镜像:

1
docker pull emqx/emqx:5.8.1

运行以下命令启动 Docker 容器。

1
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.8.1

HomeAssistant对接到EMQX

进入HomeAssistant主页后点击右下角设置,选择设备与服务, 搜索MQTT

安装MQTT插件

安装好MQTT插件后,进入插件面板点击添加条目填写上一步配置的EMQX信息即可.

代码编写

注册到Home Assistant

publish 指定格式的payload到topic
其中topic格式为homeassistant/设备类型/自定义名称/config,根据格式要求.
得到主题应当为homeassistant/light/fun_matrix/config.
payload内容是一个描述设备的json字符串, 如下代码所示.

  • 其中name是设备名称;
  • device_class要和注册topic中设备类型对应;
  • command_topic代表设备的开关状态;
  • brightness_command_topic灯的亮度控制;
  • unique_id装置唯一ID;
  • device设备描述;
  • schema代表当前为json格式;
  • brightness代表本装置支持亮度控制;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    void registerToHomeAssistantServer() {
    const char* topic = "homeassistant/light/fun_matrix/config";
    std::string message = R"({
    "name": "led",
    "device_class": "light",
    "command_topic": "fun_matrix/light/state",
    "brightness_command_topic": "fun_matrix/light/brightness/set",
    "unique_id": "fun_matrix",
    "device": {
    "identifiers": "fun_matrix",
    "name": "UnoR4WiFi"
    },
    "schema": "json",
    "brightness": true
    }
    )";
    bool retained = false;
    int qos = 1;
    bool dup = false;
    mqttClient.beginMessage(topic, message.length(), retained, qos, dup);
    mqttClient.print(message.c_str());
    mqttClient.endMessage();
    }

响应HomeAssistant命令

根据注册时候payload中brightness_command_topic和command_topic, 来响应具体的动作即可.
其中command_topic固定传递ON和OFF字符串, brightness_command_topic传递亮度值0-255.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void onMqttMessage(int messageSize) {
String topic = mqttClient.messageTopic();
Serial.println(topic);
String payload;
while (mqttClient.available()) {
payload = mqttClient.readString();
Serial.println(payload);
}

if (topic.endsWith("state")) {
Serial.print("brightness_state_topic");
bool enable = payload.equals("ON");
if (lightIsOn != enable) {
lightIsOn = enable;
if (lightIsOn) {
showFrame(level);
} else {
showFrame(0);
return;
}
}
}
if (topic.endsWith("set")) {
Serial.print("brightness_command_topic");
level = payload.toInt() / 25;
Serial.println(level);
showFrame(level);
return;
}
}

功能展示

在网页上设置亮度, 均能够在设备上得到实时的响应.
不同的亮度,亮起的区域.

Friday Ink 今天是周五吗

今天是周五吗

GitHub项目地址
立创开源广场

Part Ⅰ

封面
这是一个拖了很久的项目, 有很多废案. 隔一段时间想起来有这回事情,于是缝缝补补, 推倒很多次.

MCU从最开始使用的是ESP32, 也用过ESP32C3, 最后使用是CH582F.

起初他有很多功能,比如移植了一个lua解析器, 这样就可以动态的加载lua脚本, 以显示不同的内容.

也引入过FreeType, 用来解析.ttf字体, 以具有显示不同尺寸文字的效果.

旧版本渲染图

尽管废案的完成度已经相当高了.但是实测续航表现十分糟糕. 一想到他要充电就让我感到无奈.

终于有一天看到了CH582F这款芯片. 唤起了重新实现Friday Ink的念头.

查了一些资料后, 那一刻我觉得这就是我要找的芯片. QFN28封装, 纽扣电池就能驱动, 二话不说斥巨资12元买入开发板着手开发.

Part Ⅱ

固件最开始是使用C开发的, 而且完成度也是很高, 只差休眠和蓝牙部分了. 结果这时候莫名其妙的加了一个Rust嵌入式的群, 群里面有个佬又正好做了CH582F的Rust适配.
于是决定试试Rust来开发.
显示部分直接用了bindgen把u8g2绑过来, bind就完事.
休眠部分, ch58x-hal没有封装, 所以这次只能手搓寄存器, 于是对着官方的休眠代码, 人肉翻译了起来. 好在最后能工作(当然能工作, 毕竟我只是翻译了一下)

Friday Ink的功能十分简单.

只要启动时候检测一下有没有按下按钮,按下就显示一张图片, 然后扫描周边的蓝牙广播,扫描到符合时间协议的就设置本地RTC然后重启.
如果没有按下按钮就检测今天是不是星期五, 执行刷屏, 然后设备休眠. 直到第二天00:00唤醒.

Part Ⅲ

用纽扣电池作为输入,然后接上合宙的电流表, 110小时后统计信息如下:

耗电信息

改装米家1代屏幕挂灯,接入HomeKit

前言

我住的屋子床头没有插座也没有控制房间顶灯的开关,假如熄灯睡觉的话会让房间陷入一片漆黑.
所以很长一段时间里我都把米家屏幕挂灯的控制器放在床头,用于临时照明.

这就引发了另外一个问题,每次回家开电脑打开屏幕挂灯,我都得走到床头找到控制器开启屏幕挂灯.
在经历了多次麻烦后,我决定把这个屏幕挂灯接入HomeKit. 这样就可以用语音或者手机控制了.

资料搜集

在阅读了这篇拆解报告:MJ米家显示器挂灯MJGJD01YL后, 需要做的工作就很明确了.
大致分为以下几个步骤

  • 阅读手册,找到控制引脚
  • 拆除芯片,替换成ESP32
  • 编写代码,接入HomeKit

阅读手册,找到控制引脚

看完拆解报告后,得知亮度由TLSR8368和SY7301A芯片控制实现, 两款芯片的资料很容易在Google上搜索到.

基本上可以确定是由TLSR8368发送PWM信号给SY7301A进行调光.

TLSR8368一共就16个引脚, 对照手册配合示波器挨个测量控制引脚测出PWM引脚是由#3,#5产生, 还有一个引脚#8用于使能SY7301A芯片.

measurePins

测量出引脚如下

拆除芯片,替换成ESP32

到了这一步需要选择合适尺寸的芯片,然后重新绘制一块板子寄生在原始位置即可.

拆除原来的TLSR8368以后,留下的空间还算宽敞.
选用尺寸较小的ESP32-C3(对应的型号名称是ESP8685), 封装为QFN28 4x4mm

Lamp++ Top View

这里右半部分的TypeC和LDO部分将会在在烧录后折断, 后续固件可以通过4P 2mm间距探针或者OTA进行更新.

附上一张初版焊接后的图片, 初版为之前没有预留可折断TypeC部分的版本.

Preview

编写代码,接入HomeKit

得益于HomeSpan这个库,需要编写的代码很简单.

目前实现了白色LED的调光, 由于我损坏了暖黄色LED控制引脚的阻焊,所以没有对齐控制,待后续购入新的屏幕挂灯补充这部分功能.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <Arduino.h>

#include "HomeSpan.h"
#include "extras/PwmPin.h" // library of various PWM functions

////////////////////////////////////

struct FadingLED : Service::LightBulb {
LedPin *ledPin; // reference to Led Pin
SpanCharacteristic *power; // reference to the On Characteristic
SpanCharacteristic *level; // reference to the Brightness Characteristic
SpanCharacteristic *colorTemperature; // reference to the Color Temperature

FadingLED(int _ledPin) : Service::LightBulb() {
power = new Characteristic::On();
level = new Characteristic::Brightness(0);
colorTemperature = new Characteristic::ColorTemperature(200, true);
ledPin = new LedPin(_ledPin);
}

boolean update() {
Serial.printf("power->getNewVal()=%d", power->getNewVal());
Serial.printf(",level->getNewVal()=%d", level->getNewVal());
Serial.printf(",colorTemperature->getNewVal()=%d\n",
colorTemperature->getNewVal());
ledPin->fade(power->getNewVal() * level->getNewVal(), 2000,
LedPin::PROPORTIONAL);
while (ledPin->fadeStatus() == LedPin::FADING)
;

return (true);
}

void loop() override {
if (ledPin->fadeStatus() == LedPin::COMPLETED) {
power->setVal(1 - power->getVal());
level->setVal(power->getVal() ? 100 : 0);
}
}
};

//////////////////////////////////

void setup() {
pinMode(5, OUTPUT);
pinMode(10, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(10, LOW);
Serial.begin(115200);
digitalWrite(10, HIGH);

Serial.println("Wi-Fi is Connected!");
homeSpan.enableOTA("12345678");
homeSpan.setPairingCode("11223344");
homeSpan.begin(Category::Lighting, "Lamp++");

new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::ColorTemperature(200, true);
new FadingLED(4);
}

//////////////////////////////////////

void loop() {
homeSpan.poll();
}

1
2
3
4
5
6
7
8
9
10
11
12
[env:airm2m_core_esp32c3]
platform = espressif32@5.4.0
board = airm2m_core_esp32c3
framework = arduino
monitor_speed = 115200
lib_deps = homespan/HomeSpan@^1.8.0
; upload_protocol = espota
; upload_flags = --auth=12345678
; upload_port = 192.168.0.104
build_flags =
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1

效果展示

Preview2

参考资料

© 2025 Do U Find IT? All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero