米米的博客

做了一点微小的工作

笔者最近在折腾一台深圳海冈 - 敖阳 MPPT 太阳能控制器。机器可以通过附带的 Wi-Fi 模块接入「涂鸦智能」App,查看电池状态和调整参数。虽然通过涂鸦集成也能接入 Home Assistant,但笔者还是希望进一步摆脱云端依赖,用 ESP32 和 ESPHome 直接与控制器主板通信。

要实现这个目标,首先需要弄清楚 Wi-Fi 模块和主控之间交换的是什么数据。于是,笔者拆开控制器,拆焊原本的 Wi-Fi 模块,设计了一块用于引出信号的转接板,再接入逻辑分析仪进行被动抓包。

目前已经确认:这台设备使用的是 9600 baud、8N1 的标准涂鸦 MCU 串口协议。双向通信中的心跳、DP 下发和状态上报都已通过长度及校验和验证;电池电压、电量相关的数据也有了初步对应关系。本文记录从拆机到协议解析的过程,ESPHome 替换模块的部分留待后续验证。

原机 Wi-Fi 模块

打开控制器后,可以看到主板上焊接固定了 Wi-Fi 模块,连接位置附近印有WIFI。下图中可以看到两块板之间的连接引脚及焊点。

原机Wi-Fi模块通过六路引脚直接焊接固定在主控板上

模块上带有CBU字样,标签型号为CBU-IPEX,并带有二维码和外接天线。原机能够使用涂鸦 App,是判断协议方向的一条线索。不过,仅凭模块标签还不能确定主控侧的通信格式,需要抓到实际数据才能验证。

阅读全文 »

在文章将菲斯曼设备接入 Home Assistant 中,笔者介绍了支持接入菲斯曼设备的 Home Assistant 集成。不过,对于如何安装所需的 Wi-Fi 模块硬件还没有展开介绍。本文将详细记录。

笔者家中使用的是一台菲斯曼(Viessmann)Vitopend 100-W 燃气壁挂炉,具体型号为 L1P33-A1JD。它有夏季和冬季两种主要运行模式:夏季模式只供应生活热水,冬季模式还会启用采暖。机器自带的 LCD 控制面板可以查看状态和设置温度,但每次切换模式都要到壁挂炉前操作,还是不够方便。

菲斯曼的官方产品资料显示,A1JD/A1HD 系列可以选配 Wi-Fi 模块。于是笔者购买了与这台机器匹配的模块,标签上的名称是 GME WiFi Gateway。安装完成后,就可以通过手机远程切换模式、设置采暖和热水温度,并查看壁挂炉的运行状态。

下面记录实际安装成功的过程。不同型号的内部结构和接口可能不同,购买模块前要先确认兼容性。

准备工作

需要准备的东西很简单:

  • 与壁挂炉型号匹配的 Wi-Fi 模块;
  • 一把十字螺丝刀;
  • 安装了「菲斯曼互联」应用的手机,以及可用的家庭 Wi-Fi 网络。

壁挂炉的电控盒中有市电线路。拆机前必须关闭壁挂炉并从外部断开电源,不能只按控制面板上的开关键。确认显示屏已经熄灭后再操作。如果不熟悉电气设备,建议让菲斯曼售后或专业人员安装。

拆下前盖

壁挂炉前盖由底部的螺钉固定。断电后,从机器底部找到左右两侧的固定螺钉,用十字螺丝刀将它们松开。

松开壁挂炉前盖底部的固定螺钉

螺钉松开后,从前盖下部轻轻向外拉,再向上提起,使前盖脱离上方的挂钩。取下前盖后,就能看到金属炉体和下方的控制单元。

拆下前盖后的壁挂炉内部
阅读全文 »

在文章将公牛智家设备接入 Home Assistant将菲斯曼设备接入 Home Assistant 中,笔者分别介绍了通过分析厂商 App,将原本封闭的智能家居设备接入 Home Assistant 的方法。最近,笔者又遇到了一个类似的需求:把「网上国网」中的用电量、电费账单和账户余额也接入 Home Assistant。

网上国网 App 本身已经可以查看每日用电量和月度账单,但每次都要打开 App 查询并不方便,也无法直接参与 Home Assistant 的能源统计和自动化。例如,接入以后可以在家庭仪表盘中统一查看本月累计用电量,在电量异常增加时发送通知,或者结合其他设备分析空调、暖气等大功率电器的使用情况。

目前已经有一些通过国家电网网页获取数据的开源项目,不过这类方案通常需要运行 Docker 和浏览器,利用 Playwright 等工具模拟网页登录;遇到图形验证码时,还可能需要额外配置 OCR 或大模型服务。为了减少部署组件和长期维护成本,笔者开发了原生 Home Assistant 集成 hass-state-grid,直接使用网上国网 App 的接口获取数据,不依赖 Docker、浏览器或验证码识别服务。

阅读全文 »

项目地址:
astra-dns
luci-app-astra-dns

在 OpenWrt 上折腾 DNS,很多人最后都会走到一个相似的场景:我想让路由器负责全家的 DNS,同时希望它能做广告过滤,还希望访问 Cloudflare 站点时可以自动返回一个更快、更稳定的优选 IP。

单独看,这些需求都不罕见。

广告过滤可以交给 AdGuard Home。DNS 转发、分流、重写可以交给 MosDNS。Cloudflare 优选 IP 可以通过 CloudflareSpeedTest 之类的工具定期测速,再把结果写进 DNS 规则里。代理相关的域名处理,还可能再接入 Mihomo 等组件。

这些工具都很好,也都各自解决了真实问题。但当它们被串在一起时,整个 DNS 链路就会变得有些重。

一个典型的 motivating example

假设我们在 OpenWrt 上已经用了 MosDNS。MosDNS 很适合做 DNS 转发、分流和规则化处理,也可以把某些域名的解析结果改写到指定 IP。于是,如果我们想做 Cloudflare 优选 IP,一个自然的方案是:

  1. 用 CloudflareSpeedTest 定期测出当前网络下表现最好的 Cloudflare IP。
  2. 把这些 IP 写入 MosDNS 的 rewrite 规则。
  3. 当域名解析结果落在 Cloudflare 地址段时,让 MosDNS 返回优选 IP。

这条链路本身是合理的。

但问题来了:MosDNS 并不是广告过滤器。它可以做规则匹配和 DNS 编排,却不直接提供 AdGuard Home 那种完整的广告过滤体验。如果我们还想拦截广告域名,就往往需要再引入一个 DNS 服务,比如 AdGuard Home。

于是原本的需求变成了这样:

1
2
3
4
5
客户端
-> OpenWrt DNS 入口(dnsmasq)
-> AdGuard Home 负责广告过滤
-> MosDNS 负责分流、转发和 Cloudflare IP 重写
-> 上游 DNS

这当然能工作,很多成熟配置也正是这么搭起来的。但它带来的代价也很明显:

  • 查询链路变长,每个 DNS 请求都可能跨过多个进程。
  • 每个组件都有自己的配置文件、缓存、日志和排错方式。
  • 出现问题时,很难第一时间判断到底是广告规则、rewrite 规则、上游 DNS,还是服务转发顺序出了问题。
  • OpenWrt 设备资源有限,长期运行多个 DNS 服务并不总是优雅。
  • 对普通用户来说,理解整条链路的心智成本很高。

Astra DNS 正是为了解决这个具体场景而设计的:当你只是想在路由器上同时获得广告过滤、DNS 转发和 Cloudflare 优选 IP 重写时,能不能不要把多个 DNS 服务串起来?

阅读全文 »

中兴 F410GV9 恢复出厂设置后,Web 管理仍然可以正常访问,但 Telnet 会回到关闭状态。临时进入 FactoryMode 虽然能够取得 root shell,却只在当前运行周期内有效;设备重启或 FactoryMode 超时后,临时账号和 Telnet 服务都可能失效。

如果后续需要备份配置、排查服务或研究设备内部数据,更方便的做法是先通过 FactoryMode 开启一次临时 Telnet,再把 LAN 侧 Telnet 配置写入设备数据库。这样重启后可以使用自己设置的账号密码重新登录。

本文记录一次在 F410GV9 上实际验证成功的配置过程。Telnet 只对局域网开放,WAN 侧开关始终保持关闭。操作修改前建议备份现有配置。

环境与准备

本次设备和网络状态如下:

项目实测值
型号F410GV9
管理地址192.168.1.1
Web 管理HTTP 80
FactoryMode 服务HTTP 8080
Telnet 端口TCP 23
初始 Telnet 状态关闭
系统BusyBox 1.17.2
内核Linux 4.1.25,ARMv7
固件构建时间2021-08-19

电脑需要连接到光猫 LAN 侧,并与 192.168.1.1 处于同一网段。可以先确认设备在线,以及 Telnet 尚未开放:

1
2
ping 192.168.1.1
nc -vz 192.168.1.1 23

开启临时 Telnet 使用 zteOnu。准备好 Go 环境后直接使用上游源码即可:

1
2
3
git clone https://github.com/Septrum101/zteOnu.git
cd zteOnu
go test ./...

开启临时 FactoryMode Telnet

F410GV9 的普通 Web 管理位于 80,FactoryMode 接口位于 8080zteOnu 默认端口就是 8080,下面仍显式写出端口,避免把两个服务混淆。

本机实测可用的 FactoryMode 用户名是 factorymode,密码是 nE%jA@5b。这组凭据来自公开项目 zte_modem_tools 内置的默认候选表,并不是设备独有的密码,也不是 Web 管理账号。不同运营商和固件可能使用其他组合。

执行:

1
2
3
4
5
go run . \
--ip 192.168.1.1 \
--port 8080 \
--user factorymode \
--pass 'nE%jA@5b'

握手成功时,工具会依次完成 FactoryMode 复位、随机数交换、认证和模式切换,并返回一组临时 Telnet 凭据:

1
2
3
4
5
6
7
step [0] reset factory: ok
step [1] request factory mode: ok
step [2] send sq: ok
step [3] check login auth: ok
step [4] enter factory mode: ok
user: <TEMP_USER>
pass: <TEMP_PASSWORD>

输出中的 <TEMP_USER><TEMP_PASSWORD> 由设备为本次 FactoryMode 会话动态生成,每次运行都可能不同。这组账号也不是准备写入数据库的持久账号。FactoryMode 可能在数分钟后超时,拿到凭据后应尽快继续。

使用临时账号连接光猫:

1
telnet 192.168.1.1 23

成功后会看到设备型号和 BusyBox shell。先用只读命令确认权限:

1
2
id
uname -a

实测结果为:

1
2
uid=0(root) gid=0(root)
Linux F410GV9 4.1.25 #1 Thu Aug 19 13:16:08 CST 2021 armv7l GNU/Linux
阅读全文 »

家里的电信光猫使用路由模式,由光猫完成 PPPoE 拨号,下游再连接自己的路由器。这样的配置方式 IPv4 使用起来没什么问题,IPv6 也可以拿到地址,但是实际使用时却发现了一个问题:光猫已经从电信获得了一个/60 IPv6 前缀,直连光猫的设备也有 IPv6,但下游 OpenWrt 只能在 WAN 口获得一个/64地址,LAN 侧始终没有公网 IPv6 前缀。换句话说,光猫默认没有启用下游 IPv6 PD 前缀分发。这对于 Tailscale 之类需要打洞的场景不友好:OpenWrt 的 LAN 侧只能使用 ULA、NAT66 或 IPv6 Relay,也失去了利用原生 IPv6 进行 Tailscale 直连的条件。

把光猫改成桥接、由主路由拨号当然可以解决 IPv6 前缀分配问题,但 XG-140G-TF 本身的转发性能足够,而主路由是软路由,PPPoE 本身也非常吃单核性能,所以我还是希望保留光猫拨号。进一步检查后发现,XG-140G-TF 的固件中其实包含下游 DHCPv6-PD Server,只是电信配置默认没有开启对应的产品级开关。

本文记录如何在保留光猫拨号的情况下,开启 XG-140G-TF 的 IPv6 PD 前缀分发。光猫的管理员登录、Telnet 开启和 root 密码获取方法,请先参考配置 XG-140G-TF 光猫

问题现象

光猫的 IPv6 状态显示,WAN 连接已经通过 Prefix Delegation 从电信取得了/60前缀,例如:

1
2001:db8:1234:690::/60

一个/60可以划分为 16 个/64子网。在这个例子中,范围是:

1
2
3
4
2001:db8:1234:690::/64
2001:db8:1234:691::/64
……
2001:db8:1234:69f::/64

光猫使用第一个690::/64作为自己的 LAN 网段,通过 RA 广播给直连设备。但在修改前,下游 OpenWrt 的 WAN6 状态只有一个地址:

1
2001:db8:1234:690:6c59:4eff:fecb:61f4/64

容易产生误解的是,这只是 OpenWrt WAN 接口通过 SLAAC 获得的一个 IPv6 地址,并不是可供 OpenWrt 继续划分给 LAN 的前缀。检查 WAN6 状态时可以看到:

1
"ipv6-prefix": []

由于没有获得 IA_PD,OpenWrt 的 LAN 只能继续使用 ULA 地址,日志中还会出现:

1
A default route is present but there is no public prefix on lan
阅读全文 »
0%