<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>张书樵</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <icon>https://zhangshuqiao.org/icon.png</icon>
  <id>https://zhangshuqiao.org/</id>
  <link href="https://zhangshuqiao.org/" rel="alternate"/>
  <link href="https://zhangshuqiao.org/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, 张书樵</rights>
  <subtitle>做了一点微小的工作</subtitle>
  <title>米米的博客</title>
  <updated>2026-08-05T09:18:02.377Z</updated>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-07/%E4%B8%AD%E5%85%B4F410GV9%E5%85%89%E7%8C%AB%E6%8C%81%E4%B9%85%E5%8C%96Telnet/</id>
    <link href="https://zhangshuqiao.org/2026-07/%E4%B8%AD%E5%85%B4F410GV9%E5%85%89%E7%8C%AB%E6%8C%81%E4%B9%85%E5%8C%96Telnet/"/>
    <published>2026-07-30T10:19:41.000Z</published>
    <summary>
      <![CDATA[<p>中兴 F410GV9 恢复出厂设置后，Web 管理仍然可以正常访问，但 Telnet 会回到关闭状态。临时进入 FactoryMode 虽然能够取得 root shell，却只在当前运行周期内有效；设备重启或 FactoryMode 超时后，临时账号和 Telnet 服务都可能失效。</p>
<p>如果后续需要备份配置、排查服务或研究设备内部数据，更方便的做法是先通过 FactoryMode 开启一次临时 Telnet，再把 LAN 侧 Telnet 配置写入设备数据库。这样重启后可以使用自己设置的账号密码重新登录。</p>
<p>本文记录一次在 F410GV9 上实际验证成功的配置过程。Telnet 只对局域网开放，WAN 侧开关始终保持关闭。操作修改前建议备份现有配置。</p>
<h2 id="环境与准备"><a href="#环境与准备" class="headerlink" title="环境与准备"></a>环境与准备</h2><p>本次设备和网络状态如下：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>实测值</th>
</tr>
</thead>
<tbody><tr>
<td>型号</td>
<td><code>F410GV9</code></td>
</tr>
<tr>
<td>管理地址</td>
<td><code>192.168.1.1</code></td>
</tr>
<tr>
<td>Web 管理</td>
<td>HTTP <code>80</code></td>
</tr>
<tr>
<td>FactoryMode 服务</td>
<td>HTTP <code>8080</code></td>
</tr>
<tr>
<td>Telnet 端口</td>
<td>TCP <code>23</code></td>
</tr>
<tr>
<td>初始 Telnet 状态</td>
<td>关闭</td>
</tr>
<tr>
<td>系统</td>
<td>BusyBox 1.17.2</td>
</tr>
<tr>
<td>内核</td>
<td>Linux 4.1.25，ARMv7</td>
</tr>
<tr>
<td>固件构建时间</td>
<td>2021-08-19</td>
</tr>
</tbody></table>
<p>电脑需要连接到光猫 LAN 侧，并与 <code>192.168.1.1</code> 处于同一网段。可以先确认设备在线，以及 Telnet 尚未开放：</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ping 192.168.1.1</span><br><span class="line">nc -vz 192.168.1.1 23</span><br></pre></td></tr></tbody></table></figure>

<p>开启临时 Telnet 使用 <a href="https://github.com/Septrum101/zteOnu">zteOnu</a>。准备好 Go 环境后直接使用上游源码即可：</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/Septrum101/zteOnu.git</span><br><span class="line"><span class="built_in">cd</span> zteOnu</span><br><span class="line">go <span class="built_in">test</span> ./...</span><br></pre></td></tr></tbody></table></figure>

<h2 id="开启临时-FactoryMode-Telnet"><a href="#开启临时-FactoryMode-Telnet" class="headerlink" title="开启临时 FactoryMode Telnet"></a>开启临时 FactoryMode Telnet</h2><p>F410GV9 的普通 Web 管理位于 <code>80</code>，FactoryMode 接口位于 <code>8080</code>。<code>zteOnu</code> 默认端口就是 <code>8080</code>，下面仍显式写出端口，避免把两个服务混淆。</p>
<p>本机实测可用的 FactoryMode 用户名是 <code>factorymode</code>，密码是 <code>nE%jA@5b</code>。这组凭据来自公开项目 <a href="https://github.com/douniwan5788/zte_modem_tools">zte_modem_tools</a> 内置的默认候选表，并不是设备独有的密码，也不是 Web 管理账号。不同运营商和固件可能使用其他组合。</p>
<p>执行：</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">go run . \</span><br><span class="line">  --ip 192.168.1.1 \</span><br><span class="line">  --port 8080 \</span><br><span class="line">  --user factorymode \</span><br><span class="line">  --pass <span class="string">'nE%jA@5b'</span></span><br></pre></td></tr></tbody></table></figure>

<p>握手成功时，工具会依次完成 FactoryMode 复位、随机数交换、认证和模式切换，并返回一组临时 Telnet 凭据：</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">step [0] reset factory: ok</span><br><span class="line">step [1] request factory mode: ok</span><br><span class="line">step [2] send sq: ok</span><br><span class="line">step [3] check login auth: ok</span><br><span class="line">step [4] enter factory mode: ok</span><br><span class="line">user: &lt;TEMP_USER&gt;</span><br><span class="line">pass: &lt;TEMP_PASSWORD&gt;</span><br></pre></td></tr></tbody></table></figure>

<p>输出中的 <code>&lt;TEMP_USER&gt;</code> 和 <code>&lt;TEMP_PASSWORD&gt;</code> 由设备为本次 FactoryMode 会话动态生成，每次运行都可能不同。这组账号也不是准备写入数据库的持久账号。FactoryMode 可能在数分钟后超时，拿到凭据后应尽快继续。</p>
<p>使用临时账号连接光猫：</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">telnet 192.168.1.1 23</span><br></pre></td></tr></tbody></table></figure>

<p>成功后会看到设备型号和 BusyBox shell。先用只读命令确认权限：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">id</span></span><br><span class="line"><span class="built_in">uname</span> -a</span><br></pre></td></tr></tbody></table></figure>

<p>实测结果为：</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">uid=0(root) gid=0(root)</span><br><span class="line">Linux F410GV9 4.1.25 #1 Thu Aug 19 13:16:08 CST 2021 armv7l GNU/Linux</span><br></pre></td></tr></tbody></table></figure>]]>
    </summary>
    <title>中兴 F410GV9 光猫持久化 Telnet</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-07/XG-140G-TF%E5%85%89%E7%8C%AB%E5%90%AF%E7%94%A8IPv6%20PD%E5%89%8D%E7%BC%80%E5%88%86%E5%8F%91/</id>
    <link href="https://zhangshuqiao.org/2026-07/XG-140G-TF%E5%85%89%E7%8C%AB%E5%90%AF%E7%94%A8IPv6%20PD%E5%89%8D%E7%BC%80%E5%88%86%E5%8F%91/"/>
    <published>2026-07-29T06:28:51.000Z</published>
    <summary>
      <![CDATA[<p>家里的电信光猫使用路由模式，由光猫完成 PPPoE 拨号，下游再连接自己的路由器。这样的配置方式 IPv4 使用起来没什么问题，IPv6 也可以拿到地址，但是实际使用时却发现了一个问题：光猫已经从电信获得了一个<code>/60</code> IPv6 前缀，直连光猫的设备也有 IPv6，但下游 OpenWrt 只能在 WAN 口获得一个<code>/64</code>地址，LAN 侧始终没有公网 IPv6 前缀。换句话说，光猫默认没有启用下游 IPv6 PD 前缀分发。这对于 Tailscale 之类需要打洞的场景不友好：OpenWrt 的 LAN 侧只能使用 ULA、NAT66 或 IPv6 Relay，也失去了利用原生 IPv6 进行 Tailscale 直连的条件。</p>
<p>把光猫改成桥接、由主路由拨号当然可以解决 IPv6 前缀分配问题，但 XG-140G-TF 本身的转发性能足够，而主路由是软路由，PPPoE 本身也非常吃单核性能，所以我还是希望保留光猫拨号。进一步检查后发现，XG-140G-TF 的固件中其实包含下游 DHCPv6-PD Server，只是电信配置默认没有开启对应的产品级开关。</p>
<p>本文记录如何在保留光猫拨号的情况下，开启 XG-140G-TF 的 IPv6 PD 前缀分发。光猫的管理员登录、Telnet 开启和 root 密码获取方法，请先参考<a href="/2025-11/%E9%85%8D%E7%BD%AEXG-040G-TF%E5%85%89%E7%8C%AB/">配置 XG-140G-TF 光猫</a>。</p>
<h2 id="问题现象"><a href="#问题现象" class="headerlink" title="问题现象"></a>问题现象</h2><p>光猫的 IPv6 状态显示，WAN 连接已经通过 Prefix Delegation 从电信取得了<code>/60</code>前缀，例如：</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2001:db8:1234:690::/60</span><br></pre></td></tr></tbody></table></figure>

<p>一个<code>/60</code>可以划分为 16 个<code>/64</code>子网。在这个例子中，范围是：</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">2001:db8:1234:690::/64</span><br><span class="line">2001:db8:1234:691::/64</span><br><span class="line">……</span><br><span class="line">2001:db8:1234:69f::/64</span><br></pre></td></tr></tbody></table></figure>

<p>光猫使用第一个<code>690::/64</code>作为自己的 LAN 网段，通过 RA 广播给直连设备。但在修改前，下游 OpenWrt 的 WAN6 状态只有一个地址：</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2001:db8:1234:690:6c59:4eff:fecb:61f4/64</span><br></pre></td></tr></tbody></table></figure>

<p>容易产生误解的是，这只是 OpenWrt WAN 接口通过 SLAAC 获得的一个 IPv6 地址，并不是可供 OpenWrt 继续划分给 LAN 的前缀。检查 WAN6 状态时可以看到：</p>
<figure class="highlight json"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">"ipv6-prefix"</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span></span><br></pre></td></tr></tbody></table></figure>

<p>由于没有获得 IA_PD，OpenWrt 的 LAN 只能继续使用 ULA 地址，日志中还会出现：</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A default route is present but there is no public prefix on lan</span><br></pre></td></tr></tbody></table></figure>]]>
    </summary>
    <title>XG-140G-TF 光猫启用 IPv6 PD 前缀分发</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-07/%E6%B9%96%E5%8C%97%E7%94%B5%E4%BF%A1IPTV%E6%9C%BA%E9%A1%B6%E7%9B%92%E4%B8%8E%E5%B1%80%E5%9F%9F%E7%BD%91%E7%BB%84%E6%92%AD%E5%85%B1%E5%AD%98/</id>
    <link href="https://zhangshuqiao.org/2026-07/%E6%B9%96%E5%8C%97%E7%94%B5%E4%BF%A1IPTV%E6%9C%BA%E9%A1%B6%E7%9B%92%E4%B8%8E%E5%B1%80%E5%9F%9F%E7%BD%91%E7%BB%84%E6%92%AD%E5%85%B1%E5%AD%98/"/>
    <published>2026-07-26T14:26:30.000Z</published>
    <summary>
      <![CDATA[<p>家里开通了电信 IPTV，但套餐只包含了一台机顶盒，家中有多台电视时使用起来并不方便。很早以前我就知道可以通过 <code>igmpproxy</code> 转发组播，再配合 <code>udpxy</code> 将组播转换为普通 HTTP 单播，但此前一直没有配置成功。</p>
<p>最近重新梳理了一遍光猫、机顶盒和组播之间的关系，终于实现了以下目标：</p>
<ul>
<li>原装 IPTV 机顶盒继续正常使用，直播和点播均不受影响；</li>
<li>局域网中的其他设备（电视、电脑、手机等）可以收看直播。</li>
</ul>
<p>本文记录的是我在<strong>湖北武汉电信</strong>网络中的实际配置。不同地区的 VLAN 和认证方式都可能不同，请不要直接照抄参数。修改光猫前，建议先备份配置，并记录每一处原始设置。</p>
<h2 id="原始网络结构"><a href="#原始网络结构" class="headerlink" title="原始网络结构"></a>原始网络结构</h2><p>光猫中原本有两项主要业务：</p>
<ol>
<li>上网业务，采用路由模式，本文不讨论；</li>
<li>iTV 业务，采用桥接模式，仅绑定到光猫的 LAN2 口。</li>
</ol>
<p>iTV 桥接连接的关键参数如下：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>原始设置</th>
</tr>
</thead>
<tbody><tr>
<td>业务类型</td>
<td>OTHER</td>
</tr>
<tr>
<td>连接模式</td>
<td>桥接</td>
</tr>
<tr>
<td>IP 模式</td>
<td>IPv4</td>
</tr>
<tr>
<td>业务 VLAN ID</td>
<td><code>3542</code></td>
</tr>
<tr>
<td>端口绑定</td>
<td>LAN2（iTV 口）</td>
</tr>
</tbody></table>
<p><img src="/images/2026/07/settings-bridge.png" loading="lazy"></p>
<p>在这一结构下，电信机顶盒连接 LAN2，并由机顶盒自己进行 PPPoE 拨号。机顶盒的网络设置中可以看到 IPTV 账号，但密码通常不会直接显示。</p>
<p><img src="/images/2026/07/stb-pppoe.jpg" loading="lazy"></p>
<p>这里有一个容易踩的坑：IPTV 密码可能由机房或装维系统下发。即使通过 10000 客服重置或查询到了一个密码，也不一定能在现网环境中成功拨号。如果确认账号无误但始终认证失败，最好直接联系当地装维人员，获取当前线路实际使用的 IPTV 密码。</p>
<h2 id="失败的尝试：让两个设备分别拨号"><a href="#失败的尝试：让两个设备分别拨号" class="headerlink" title="失败的尝试：让两个设备分别拨号"></a>失败的尝试：让两个设备分别拨号</h2><p>我最初的思路很直接：在光猫的 iTV 桥接连接中，除 LAN2 外再绑定一个 LAN3，让原装机顶盒连接 LAN2，另一个路由器或小主机连接 LAN3。两台设备分别使用同一组 IPTV 账号、密码拨号，小主机负责运行 <code>igmpproxy</code>，就可以实现局域网组播。</p>
<p>实际测试发现，这种方式行不通：只要其中一台设备已经拨号成功，第二台设备的拨号就会被拒绝。至少在我的线路上，同一个 IPTV 账号无法同时建立两个 PPPoE 会话。这意味着如果光猫桥接，让下游设备拨号，原装机顶盒和独立组播代理只能二选一。</p>
<h2 id="关键调整：改由光猫拨号"><a href="#关键调整：改由光猫拨号" class="headerlink" title="关键调整：改由光猫拨号"></a>关键调整：改由光猫拨号</h2><p>进一步查看机顶盒设置时，我发现它除了 PPPoE，还支持 DHCP 联网。由此可以换一种思路：</p>
<blockquote>
<p>不再让机顶盒直接拨号，而是让光猫建立 IPTV PPPoE 连接，再通过 DHCP 给 LAN2、LAN3 下游设备分配地址。</p>
</blockquote>
<p>我将光猫中的 iTV 连接从桥接模式改为路由模式，填写 IPTV PPPoE 账号和密码，并同时绑定 LAN2、LAN3。</p>
<p><img src="/images/2026/07/settings-pppoe.png" loading="lazy"></p>
<p>修改后，光猫成功获得了运营商 IPTV 网络中的 <code>10.x.x.x</code> 地址，机顶盒改为 DHCP 后也能取得光猫下发的局域网地址。</p>
<p><img src="/images/2026/07/network-info.png" loading="lazy"></p>
<p>此时测试结果如下：</p>
<ul>
<li>IPTV 平台登录正常；</li>
<li>菜单和业务页面正常；</li>
<li>点播节目可以播放；</li>
<li><strong>直播频道仍然黑屏</strong>。</li>
</ul>
<p>这个现象很有价值。它说明 PPPoE 认证、DHCP 和普通 IP 通信已经正常，机顶盒也没有被限制为必须自行拨号；但<strong>直播所需的组播链路尚未打通</strong>。点播通常走普通单播，而直播依赖 IGMP 和运营商的组播 VLAN，因此两者完全可能出现一个正常、另一个黑屏的情况。</p>]]>
    </summary>
    <title>湖北电信 IPTV 机顶盒与局域网组播共存</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-06/XiaoAI%20Agent%EF%BC%9A%E8%AE%A9%E5%B0%8F%E7%88%B1%E9%9F%B3%E7%AE%B1%E7%9C%9F%E6%AD%A3%E8%B7%91%E8%B5%B7%E8%87%AA%E5%B7%B1%E7%9A%84%E8%AF%AD%E9%9F%B3%20Agent/</id>
    <link href="https://zhangshuqiao.org/2026-06/XiaoAI%20Agent%EF%BC%9A%E8%AE%A9%E5%B0%8F%E7%88%B1%E9%9F%B3%E7%AE%B1%E7%9C%9F%E6%AD%A3%E8%B7%91%E8%B5%B7%E8%87%AA%E5%B7%B1%E7%9A%84%E8%AF%AD%E9%9F%B3%20Agent/"/>
    <published>2026-06-29T03:41:44.000Z</published>
    <summary>
      <![CDATA[<p>过去几年里，大模型把语音助手的想象空间重新打开了。我们已经习惯了在手机、网页和电脑上和 AI 对话，但家里的智能音箱却常常还停留在比较固定的指令式体验里：问天气、放音乐、控制设备可以，但想要更自然的连续对话、更灵活的工具调用，或者接入自己选择的大模型服务，就没那么顺手了。</p>
<p><code>xiaoai-agent</code> 想解决的正是这个问题：让小爱音箱不只是一个云端语音入口，而是变成一台可以常驻运行的端侧语音 Agent 设备。</p>
<video src="/files/xiaoai-agent.mp4" preload="metadata" controlslist="nodownload" controls="" playsinline="" poster=""></video>

<p>项目地址：<a href="https://github.com/stevenjoezhang/xiaoai-agent">github.com/stevenjoezhang/xiaoai-agent</a></p>
<h2 id="背景：小爱音箱还有很多潜力"><a href="#背景：小爱音箱还有很多潜力" class="headerlink" title="背景：小爱音箱还有很多潜力"></a>背景：小爱音箱还有很多潜力</h2><p>小爱音箱本身是一类很适合承载语音 Agent 的设备。它有麦克风阵列，有扬声器，有唤醒能力，也有成熟的音频播放和 TTS 链路。换句话说，它的硬件形态已经非常接近「家里的 AI 入口」。</p>
<p>但现实使用中会遇到几个限制：</p>
<ul>
<li>原生小爱同学的对话能力和可扩展性有限，很难按自己的偏好接入新的大模型、ASR 或工具。</li>
<li>一些改造方案需要额外部署服务器或桥接服务，链路变长，维护成本也会变高。</li>
<li>原生小爱同学仍然可能监听麦克风，出现抢麦、抢答，甚至触发小米云端控制的情况。</li>
<li>音频体验很难做好，比如唤醒、录音、回声消除、连续对话、中途打断等细节，任何一个环节不稳都会影响日常可用性。</li>
</ul>
<p><code>xiaoai-agent</code> 的方向，是尽量把这些能力收回到音箱端侧，让音箱自己完成唤醒、录音、识别、思考、工具调用和回复。</p>
<h2 id="现有方案与不足"><a href="#现有方案与不足" class="headerlink" title="现有方案与不足"></a>现有方案与不足</h2><p>在 <code>xiaoai-agent</code> 之前，已经有不少项目尝试把小爱音箱和大模型连接起来。这些探索证明了小爱音箱的可玩性，也把很多底层路径跑通了。</p>
<p>比如原生小爱同学提供了稳定的唤醒、TTS、设备控制和生态接入能力，适合普通用户日常使用。但它的对话能力、模型选择和工具扩展都比较固定，用户很难把自己的 ASR、大模型或智能家居工作流接进去。</p>
<p>Open-XiaoAI 这类项目则打开了更底层的设备改造路径，让音箱具备 SSH、启动脚本和自定义部署的可能。它解决的是「能不能进入设备、能不能运行自己的东西」的问题，为后续折腾提供了基础。</p>
<p>MiGPT 等桥接类方案则更进一步，把大模型对话接入到小爱音箱体验里，让用户可以用自然语言和 AI 聊天。这类方案的优势是思路清晰、上手相对友好，但通常需要额外服务端或桥接层来承载 Agent 逻辑，音箱本身更像前端入口。</p>
<p>这些方案各有价值，但也留下了一些共同痛点：语音链路复杂、部署组件偏多、原生小爱可能抢麦或抢答、云端控制可能被误触发，音频细节也容易受多层转发影响。<code>xiaoai-agent</code> 正是在这些探索之上，尝试把 Agent 主流程进一步收回到音箱端侧。</p>
<h2 id="它解决了什么痛点"><a href="#它解决了什么痛点" class="headerlink" title="它解决了什么痛点"></a>它解决了什么痛点</h2><p><code>xiaoai-agent</code> 最核心的价值，是把小爱音箱改造成一个更开放、更可控的语音 Agent 载体。</p>
<p>首先，它避免了「两个助手同时工作」的混乱。项目会让原生小爱同学的麦克风输入静音，由 <code>xiaoai-agent</code> 接管真实麦克风音频。这样可以减少抢麦、抢答，以及误触发小米云端控制的问题。</p>
<p>其次，它降低了长期运行的复杂度。传统方案常常需要在局域网里额外跑一个服务，音箱和服务之间再做消息转发。<code>xiaoai-agent</code> 选择直接在音箱端侧运行 Agent，部署链路更短，也更像一台独立设备。</p>
<p>第三，它复用了音箱原本已经做好的音频能力。唤醒、VPM 音频回调、TTS 播报、播放控制等能力都来自设备原生系统，日常交互会更接近「真正的音箱体验」，而不是把音箱当作一个简单的外设。</p>
<p>最后，它给用户留下了足够多的选择空间。ASR 可以使用兼容 OpenAI <code>POST /v1/audio/transcriptions</code> 的服务，大模型也可以接入 OpenAI-compatible API。你可以按自己的预算、延迟和隐私偏好选择服务，而不是被固定在单一路径里。</p>
<h2 id="主要特性"><a href="#主要特性" class="headerlink" title="主要特性"></a>主要特性</h2><p><code>xiaoai-agent</code> 是一个非官方技术研究项目，核心 Agent 使用 Rust 编写，运行在小爱音箱端侧。目前项目已经在 <strong>Xiaomi 智能音箱 Pro（OH2P）固件 1.62.2</strong> 上测试成功。</p>
<p>它目前已经具备一套完整的语音 Agent 闭环：</p>
<ul>
<li>端侧常驻运行：Agent 直接运行在音箱上，不需要额外部署专门服务端。</li>
<li>完整语音流程：支持唤醒、录音、ASR、大模型对话、工具调用和 TTS 回复。</li>
<li>更自然的交互：支持连续对话、VAD、中途打断、回声消除和播放时录音。</li>
<li>开放模型接入：ASR 和 LLM 均可配置为兼容 OpenAI API 的服务。</li>
<li>工具与设备控制：内置时间、天气、音乐播放等工具，并可通过 Home Assistant MCP 控制智能家居。</li>
<li>保留部分系统能力：语音对话由 Agent 接管，但蓝牙网关等非语音服务不应受到影响。</li>
<li>可自定义体验：可以调整唤醒响应、LED 状态、音乐服务和运行参数。</li>
</ul>
<p>项目仓库中也包含补丁固件制作、刷机辅助、示例配置和部署说明，方便用户从设备准备一路走到 Agent 常驻运行。需要特别说明的是，它不是官方项目，也不是面向所有型号的一键通用方案；现阶段更适合愿意折腾、理解刷机风险，并且手上有对应设备的用户尝试。</p>
<p>这套能力组合起来，小爱音箱就不再只是一个固定功能的智能音箱，而更像是家里可以听、可以说、可以调用工具的 AI 节点。</p>]]>
    </summary>
    <title>XiaoAI Agent：让小爱音箱真正跑起自己的语音 Agent</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-05/%E5%B0%864Kn%20Windows%E8%BF%81%E7%A7%BB%E5%88%B0512%E5%AD%97%E8%8A%82%E6%89%87%E5%8C%BA%E7%A3%81%E7%9B%98/</id>
    <link href="https://zhangshuqiao.org/2026-05/%E5%B0%864Kn%20Windows%E8%BF%81%E7%A7%BB%E5%88%B0512%E5%AD%97%E8%8A%82%E6%89%87%E5%8C%BA%E7%A3%81%E7%9B%98/"/>
    <published>2026-05-16T01:08:10.000Z</published>
    <summary>
      <![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>笔者很久以前在 Mac 上通过 Boot Camp 安装了 Windows 系统，最近计划将这个系统迁移到 ESXi]]>
    </summary>
    <title>将 4Kn Windows 迁移到 512 字节扇区磁盘</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-04/%E5%88%A9%E7%94%A8PowerShell%E8%84%9A%E6%9C%AC%E6%81%A2%E5%A4%8DVMware%E5%8A%A0%E5%AF%86%E5%AF%86%E7%A0%81/</id>
    <link href="https://zhangshuqiao.org/2026-04/%E5%88%A9%E7%94%A8PowerShell%E8%84%9A%E6%9C%AC%E6%81%A2%E5%A4%8DVMware%E5%8A%A0%E5%AF%86%E5%AF%86%E7%A0%81/"/>
    <published>2026-04-30T06:12:03.000Z</published>
    <summary>
      <![CDATA[<p>本文记录了我在忘记 VMware Workstation 虚拟机加密密码后，通过 PowerShell 调用 Windows 凭据管理器 API 成功恢复密码的完整过程。如果你也遇到了同样的问题，希望这篇文章能帮到你。</p>
<h2 id="起因"><a]]>
    </summary>
    <title>利用 PowerShell 脚本恢复 VMware 加密密码</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-02/%E5%B0%86Yeelight%E7%83%9B%E5%85%89%E6%B0%9B%E5%9B%B4%E7%81%AF%E6%8E%A5%E5%85%A5Home%20Assistant/</id>
    <link href="https://zhangshuqiao.org/2026-02/%E5%B0%86Yeelight%E7%83%9B%E5%85%89%E6%B0%9B%E5%9B%B4%E7%81%AF%E6%8E%A5%E5%85%A5Home%20Assistant/"/>
    <published>2026-02-17T02:26:00.000Z</published>
    <summary>
      <![CDATA[<p>在五年前的文章<a href="/2021-07/%E5%B0%86Yeelight%E7%83%9B%E5%85%89%E6%B0%9B%E5%9B%B4%E7%81%AF%E6%8E%A5%E5%85%A5Apple%20HomeKit/">将 Yeelight]]>
    </summary>
    <title>将 Yeelight 烛光氛围灯接入 Home Assistant</title>
    <updated>2026-08-05T09:18:02.376Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2026-02/%E5%B0%86%E8%8F%B2%E6%96%AF%E6%9B%BC%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5Home%20Assistant/</id>
    <link href="https://zhangshuqiao.org/2026-02/%E5%B0%86%E8%8F%B2%E6%96%AF%E6%9B%BC%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5Home%20Assistant/"/>
    <published>2026-02-16T05:25:57.000Z</published>
    <summary>
      <![CDATA[<p>在文章<a href="/2023-02/%E5%B0%86%E5%85%AC%E7%89%9B%E6%99%BA%E5%AE%B6%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5Home%20Assistant/">将公牛智家设备接入 Home]]>
    </summary>
    <title>将菲斯曼设备接入 Home Assistant</title>
    <updated>2026-08-05T09:18:02.377Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-12/%E5%9C%A8TrueNAS%E4%B8%8A%E5%AE%89%E8%A3%85Shairport%20Sync/</id>
    <link href="https://zhangshuqiao.org/2025-12/%E5%9C%A8TrueNAS%E4%B8%8A%E5%AE%89%E8%A3%85Shairport%20Sync/"/>
    <published>2025-12-14T04:00:31.000Z</published>
    <summary>
      <![CDATA[<p>笔者有一台小爱音箱，可惜它并不支持 AirPlay 协议。如果要将 Mac 上的音乐串流到这台音箱上播放，就需要通过蓝牙配对，体验并不理想。幸运的是，这个型号的音箱配备了 USB 接口，并且可以通过 USB 声卡的方式被电脑识别为音频输出设备。这就意味着，可以通过 Shairport Sync 等软件进行 AirPlay 协议配对，然后通过 USB 将音频流发送到这台音箱上播放。<br>这台音箱摆放位置旁边就是 NAS 服务器，运行着 TrueNAS Scale 25.04 系统。直接在 NAS 服务器上安装 Shairport Sync 并连接音箱是一个不错的选择。这个版本的 TrueNAS 支持运行 Docker 容器，因此软件安装上非常方便，不过在调试过程中还是踩了很多坑。本文记录一下安装过程，供参考。</p>
<h2 id="检查Alsa配置"><a href="#检查Alsa配置" class="headerlink" title="检查Alsa配置"></a>检查 Alsa 配置</h2><p>首先，通过 SSH 登陆到 TrueNAS 服务器上，执行<code>cat /proc/asound/cards</code>检查声卡是否正确识别：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">admin@truenas[~]$ <span class="built_in">cat</span> /proc/asound/cards</span><br><span class="line"> 0 [PCH            ]: HDA-Intel - HDA Intel PCH</span><br><span class="line">                      HDA Intel PCH at 0x6005220000 irq 199</span><br><span class="line"> 1 [Pro7990        ]: USB-Audio - 智能音箱 Pro-7990</span><br><span class="line">                      Xiaomi Corporation 智能音箱 Pro-7990 at usb-0000:00:14.0-5, high speed</span><br></pre></td></tr></tbody></table></figure>

<p>可以看到，智能音箱声卡已经被正确识别为<code>Pro7990</code>。接下来，我们需要检查 Alsa 的配置（特别是 Mixer）。虽然 TrueNAS 系统基于 Debian，但它本身并不包含 Alsa 工具，因此我们需要先创建一个 Ubuntu 容器，并将声卡设备映射进去。可以通过 TrueNAS 的 Web 界面创建一个 Docker 容器，选择「通过 YAML 进行安装」，并添加如下配置：</p>
<figure class="highlight yml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">alsa-check:</span></span><br><span class="line">    <span class="attr">command:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">bash</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">'-c'</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">sleep</span> <span class="string">infinity</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">alsa_mixer_check</span></span><br><span class="line">    <span class="attr">devices:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/dev/snd:/dev/snd</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">DEBIAN_FRONTEND=noninteractive</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">ubuntu:24.04</span></span><br><span class="line">    <span class="attr">privileged:</span> <span class="literal">True</span></span><br><span class="line">    <span class="attr">stdin_open:</span> <span class="literal">True</span></span><br><span class="line">    <span class="attr">tty:</span> <span class="literal">True</span></span><br></pre></td></tr></tbody></table></figure>

<p>Ubuntu 的 Docker 容器启动成功后，进入容器内部的命令行，安装 Alsa 工具：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apt update</span><br><span class="line">apt install -y alsa-utils</span><br></pre></td></tr></tbody></table></figure>]]>
    </summary>
    <title>在 TrueNAS 上安装 Shairport Sync</title>
    <updated>2026-08-05T09:18:02.376Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-12/%E5%9C%A8Ubuntu%E4%B8%8A%E9%87%8D%E6%96%B0%E7%BC%96%E8%AF%91%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97/</id>
    <link href="https://zhangshuqiao.org/2025-12/%E5%9C%A8Ubuntu%E4%B8%8A%E9%87%8D%E6%96%B0%E7%BC%96%E8%AF%91%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97/"/>
    <published>2025-12-12T03:38:12.000Z</published>
    <summary>
      <![CDATA[<p>在 Ubuntu 系统上，有时我们需要对某些内核模块进行定制化修改，例如更新补丁、进行调试或加入额外日志等。完整重新编译内核会非常耗时，但好消息是：Linux 的内核构建系统允许我们仅重新编译目标模块，而不需要构建整个内核。</p>
<p>本文介绍如何在 Ubuntu]]>
    </summary>
    <title>在 Ubuntu 上重新编译内核模块</title>
    <updated>2026-08-05T09:18:02.376Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-11/%E4%BD%BF%E7%94%A8OpenWRT%E9%85%8D%E7%BD%AEPXE%E5%90%AF%E5%8A%A8/</id>
    <link href="https://zhangshuqiao.org/2025-11/%E4%BD%BF%E7%94%A8OpenWRT%E9%85%8D%E7%BD%AEPXE%E5%90%AF%E5%8A%A8/"/>
    <published>2025-11-30T06:44:38.000Z</published>
    <summary>
      <![CDATA[<p>在家庭服务器环境或小型机房中，通过网络（PXE）启动服务器可以显著简化设备的安装流程。本文将介绍如何在 OpenWRT 路由器 + 一台内网 Linux 服务器的组合下，搭建可用于 UEFI 启动的 PXE 环境，并支持 iPXE、HTTP 启动等现代特性。</p>
<p>本文实验成功的环境：</p>
<ul>
<li>路由器：OpenWRT（系统版本 24.10）</li>
<li>TFTP/HTTP 服务器：一台内网 Linux 服务器（安装 Ubuntu 系统）</li>
<li>客户端：支持 UEFI PXE 的服务器主板</li>
</ul>
<h2 id="PXE-启动原理"><a href="#PXE-启动原理" class="headerlink" title="PXE 启动原理"></a>PXE 启动原理</h2><p>PXE（Preboot eXecution Environment）启动主要由以下步骤组成：</p>
<ol>
<li>客户端通过网络发送 DHCP Discover</li>
<li>DHCP 服务器返回 IP 地址，并附加 PXE 相关字段：<ul>
<li>next-server（TFTP server 的 IP）</li>
<li>filename（要下载的启动文件，如 <code>snponly.efi</code>）</li>
</ul>
</li>
<li>客户端向 TFTP 服务器请求文件</li>
<li>使用下载到的引导器加载后续启动流程，例如：<ul>
<li>iPXE（支持 HTTP、iSCSI 等）</li>
<li>Linux kernel + initrd</li>
</ul>
</li>
</ol>
<p>OpenWRT 的 dnsmasq 内置了 PXE 支持，并且可以方便地通过 LuCI 界面配置。</p>
<h2 id="配置-TFTP-服务"><a href="#配置-TFTP-服务" class="headerlink" title="配置 TFTP 服务"></a>配置 TFTP 服务</h2><p>首先，在内网 Linux 服务器上安装 TFTP 服务，用于提供必要的文件。以 tftpd-hpa 为例：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install tftpd-hpa</span><br></pre></td></tr></tbody></table></figure>
<p>编辑 <code>/etc/default/tftpd-hpa</code>：</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">TFTP_USERNAME="tftp"</span><br><span class="line">TFTP_DIRECTORY="/srv/tftp"</span><br><span class="line">TFTP_ADDRESS=":69"</span><br><span class="line">TFTP_OPTIONS="--secure"</span><br></pre></td></tr></tbody></table></figure>
<p>重启服务：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart tftpd-hpa</span><br></pre></td></tr></tbody></table></figure>

<h2 id="配置-HTTP-服务"><a href="#配置-HTTP-服务" class="headerlink" title="配置 HTTP 服务"></a>配置 HTTP 服务</h2><p>以 Nginx 为例：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install nginx</span><br></pre></td></tr></tbody></table></figure>
<p>重启服务：</p>
<figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart nginx</span><br></pre></td></tr></tbody></table></figure>]]>
    </summary>
    <title>使用 OpenWRT 配置 PXE 启动</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-11/%E9%85%8D%E7%BD%AEXG-040G-TF%E5%85%89%E7%8C%AB/</id>
    <link href="https://zhangshuqiao.org/2025-11/%E9%85%8D%E7%BD%AEXG-040G-TF%E5%85%89%E7%8C%AB/"/>
    <published>2025-11-29T02:41:02.000Z</published>
    <summary>
      <![CDATA[<p>XG-140G-TF (ONU) 是诺基亚贝尔生产的一款光猫，为电信定制版本。这款光猫支持 2.5G 网口，配置非常不错，而且闲鱼上价格已经降到 40 元左右，性价比很高。相比于 XG-040G 等类似型号，XG-140G-TF (ONU)]]>
    </summary>
    <title>配置 XG-140G-TF 光猫</title>
    <updated>2026-08-05T09:18:02.376Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-11/%E6%90%AD%E5%BB%BA%E8%BD%BB%E9%87%8F%E7%BA%A7Docker%E4%BB%A3%E7%90%86/</id>
    <link href="https://zhangshuqiao.org/2025-11/%E6%90%AD%E5%BB%BA%E8%BD%BB%E9%87%8F%E7%BA%A7Docker%E4%BB%A3%E7%90%86/"/>
    <published>2025-11-24T09:56:06.000Z</published>
    <summary>
      <![CDATA[<p>在日常开发中，经常会遇到 Docker 拉取镜像缓慢、连接不稳定、某些仓库国内访问困难等问题。为了解决这些实际痛点，我<del>实现</del>重复造轮子了一个轻量级 Docker Registry 反向代理，用于中转和加速 Docker 客户端的镜像拉取请求。项目采用]]>
    </summary>
    <title>搭建轻量级 Docker 代理</title>
    <updated>2026-08-05T09:18:02.376Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-10/%E8%A7%A3%E5%86%B3%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%89%93%E5%BC%80VS%20Code%20Server%E5%90%8E%E5%A4%B1%E5%8E%BB%E5%93%8D%E5%BA%94%E7%9A%84%E9%97%AE%E9%A2%98/</id>
    <link href="https://zhangshuqiao.org/2025-10/%E8%A7%A3%E5%86%B3%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%89%93%E5%BC%80VS%20Code%20Server%E5%90%8E%E5%A4%B1%E5%8E%BB%E5%93%8D%E5%BA%94%E7%9A%84%E9%97%AE%E9%A2%98/"/>
    <published>2025-10-17T06:23:21.000Z</published>
    <summary>
      <![CDATA[<p>我在一台阿里云轻量云服务器上部署了 VS Code Server，用于远程开发。这台服务器配置为 2 核 CPU + 2GB 内存，我额外添加了 8GB 的 swap，希望应对 VS Code Server 启动后的内存压力。然而，在实际使用中，每次通过 SSH 启动]]>
    </summary>
    <title>解决云服务器打开 VS Code Server 后失去响应的问题</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-08/LuCI%20App%20Auth%20THU/</id>
    <link href="https://zhangshuqiao.org/2025-08/LuCI%20App%20Auth%20THU/"/>
    <published>2025-08-12T14:35:39.000Z</published>
    <summary>
      <![CDATA[<p>本文将介绍在 OpenWrt 路由器上托管清华校园网认证的 LuCI 插件 <a href="https://github.com/stevenjoezhang/luci-app-auth-thu">luci-app-auth-thu</a>。该插件的底层由 <a]]>
    </summary>
    <title>LuCI App Auth THU</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-08/%E6%9B%B4%E6%8D%A2%E5%A5%94%E9%A9%B0CLA200%E8%BE%85%E5%8A%A9%E8%93%84%E7%94%B5%E6%B1%A0/</id>
    <link href="https://zhangshuqiao.org/2025-08/%E6%9B%B4%E6%8D%A2%E5%A5%94%E9%A9%B0CLA200%E8%BE%85%E5%8A%A9%E8%93%84%E7%94%B5%E6%B1%A0/"/>
    <published>2025-08-12T09:36:12.000Z</published>
    <summary>
      <![CDATA[<p>最近，笔者家中的一辆 2015 款奔驰 CLA200 汽车出现了「辅助蓄电池故障」的警告。咨询 4S 店后得知，这一故障是因为辅助蓄电池电压不足导致，通常是损坏了，需要更换。CLA200 的辅助蓄电池是一个单独的小电瓶，更换过程较为复杂。由于 4S 店报价较高，且电瓶没有现货需要等待预定，因此笔者决定自己动手更换。</p>
<p></p><figure><img src="/images/2025/08/cla200-battery-warning.jpg" alt="辅助蓄电池故障警告" loading="lazy"><figcaption aria-hidden="true">辅助蓄电池故障警告</figcaption></figure>
<h2 id="购买辅助蓄电池"><a href="#购买辅助蓄电池" class="headerlink" title="购买辅助蓄电池"></a>购买辅助蓄电池</h2><p>通过咨询多家淘宝上售卖相关电瓶配件的店铺，得知需要更换的电瓶外观如下所示。这款电瓶售价普遍在 200 多元。笔者挑选了一家看上去比较靠谱的店铺进行购买，但是也没有很好的办法验证真伪，毕竟这个电瓶看上去就很容易用旧的翻新。只能希望不要出现安全隐患。</p>
<p></p><figure><img src="/images/2025/08/cla200-battery.jpg" alt="辅助蓄电池外观" loading="lazy"><figcaption aria-hidden="true">辅助蓄电池外观</figcaption></figure>
<h2 id="更换过程"><a href="#更换过程" class="headerlink" title="更换过程"></a>更换过程</h2><p>与其它一些奔驰汽车不同，CLA200 的辅助蓄电池位于副驾驶的脚底，而不是后备箱中。在更换时，需要先将副驾驶侧的地垫揭开。</p>
<p></p><figure><img src="/images/2025/08/cla200-battery-mat.jpg" alt="揭开地垫" loading="lazy"><figcaption aria-hidden="true">揭开地垫</figcaption></figure>
<p>这时，地垫下面的情况就很清楚了，左上角部分的塑料保护盖下方就是辅助蓄电池，还可以看到两侧的接线端子。</p>
<p></p><figure><img src="/images/2025/08/cla200-battery-location.jpg" alt="辅助蓄电池位置" loading="lazy"><figcaption aria-hidden="true">辅助蓄电池位置</figcaption></figure>]]>
    </summary>
    <title>更换奔驰 CLA200 辅助蓄电池</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-08/LuCI%20App%20AdGuard%20Home/</id>
    <link href="https://zhangshuqiao.org/2025-08/LuCI%20App%20AdGuard%20Home/"/>
    <published>2025-08-12T08:14:14.000Z</published>
    <summary>
      <![CDATA[<p>AdGuard Home 是一个自托管的广告拦截器，旨在 DNS 层面通过拦截跟踪域名和广告域名来提升用户隐私和网络体验。它可以运行在本地网络的网关或旁路由上，无需在每个终端设备上单独安装插件。AdGuard Home]]>
    </summary>
    <title>LuCI App AdGuard Home</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-08/LuCI%20App%20Cloudflare%20Speed%20Test/</id>
    <link href="https://zhangshuqiao.org/2025-08/LuCI%20App%20Cloudflare%20Speed%20Test/"/>
    <published>2025-08-12T03:52:52.000Z</published>
    <summary>
      <![CDATA[<p>笔者近期在 OpenWrt 路由器上配置了 Cloudflare IP 优选工具 luci-app-cloudflarespeedtest，但是在使用过程中发现还是有一些影响体验的小问题没有解决。由于原仓库已经被作者归档并只读，因此我 fork]]>
    </summary>
    <title>LuCI App Cloudflare Speed Test</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-05/%E4%BD%BF%E7%94%A8EfiGuard%E5%85%B3%E9%97%ADPatchGuard/</id>
    <link href="https://zhangshuqiao.org/2025-05/%E4%BD%BF%E7%94%A8EfiGuard%E5%85%B3%E9%97%ADPatchGuard/"/>
    <published>2025-05-27T05:31:45.000Z</published>
    <summary>
      <![CDATA[<p>PatchGuard 是 Windows 内核中的防御机制，用于检查内核中关键的数据结构和代码是否被恶意软件或驱动程序篡改。如果发现异常，PatchGuard]]>
    </summary>
    <title>使用 EfiGuard 关闭 PatchGuard</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
  <entry>
    <author>
      <name>张书樵</name>
    </author>
    <category term="技术" scheme="https://zhangshuqiao.org/categories/%E6%8A%80%E6%9C%AF/"/>
    <id>https://zhangshuqiao.org/2025-04/Enigma%E5%AF%86%E7%A0%81%E7%A0%B4%E8%A7%A3/</id>
    <link href="https://zhangshuqiao.org/2025-04/Enigma%E5%AF%86%E7%A0%81%E7%A0%B4%E8%A7%A3/"/>
    <published>2025-04-05T03:38:06.000Z</published>
    <summary>
      <![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>Enigma 机是二战时德军使用的加密装置。它拥有三个可以转动的转子，一个固定的反射器，插线板，键盘，灯板等组件。插线板能够交换两个字母，转子可以将一个字母映射为另一个字母。这都是通过电路实现的。使用者点击键盘上的按键输入明文字母后，机器中电池产生的电流将通过插线板、三个转子、反射器，然后折返，再次通过三个转子和插线板，将灯板上的密文字母对应的灯泡点亮。每次按下按键时，转子会产生旋转，并且在到达特定位置时会产生进位。因此，每次加密时导通的电路会发生变化，使得 Enigma 机的加密过程难以被破解。Enigma 的实现和软件模拟器可以参考前面的文章<a href="/2018-08/%E8%87%AA%E5%B7%B1%E6%89%93%E9%80%A0%E4%B8%80%E5%8F%B0%E6%81%A9%E5%B0%BC%E6%A0%BC%E7%8E%9B%E5%AF%86%E7%A0%81%E6%9C%BA/">自己打造一台恩尼格玛密码机</a>。</p>
<p>在二战后期，德军使用的 Enigma 机允许操作者从多个转子中选择 3 个，每个转子有 26 种初始位置，并且插线板上可以交换 10 组字母。这产生了一个巨大的密钥空间，看上去使 Enigma 机坚不可摧。然而，波兰数学家 Rejewski 在 30 年代就发现了 Enigma 机操作流程上存在的弱点，并针对其设计了破解方法。在二战爆发后，相关的技术被共享给了盟军的情报机构，但德军也加强了 Enigma 密码的安全性。英国数学家和计算机科学家 Turing 进一步地设计了已知明文攻击的方法，成功破解了 Enigma 机，为世界反法西斯战争的胜利做出了重要的贡献。笔者复现了 Rejewski 和 Turing 破解 Enigma 机使用的方法，并将在本文中详细介绍。</p>
<h2 id="算法原理"><a href="#算法原理" class="headerlink" title="算法原理"></a>算法原理</h2><h3 id="Rejewski的破解方法"><a href="#Rejewski的破解方法" class="headerlink" title="Rejewski的破解方法"></a>Rejewski 的破解方法</h3><p>在上世纪三十年代，Enigma 机的操作流程是：每天所有人都会使用相同的日密钥，但日密钥不用于加密信息；在发送一条信息时，操作者需要先随机生成三个字母的信息密钥。操作者会首先使用日密钥，将信息密钥输入两次，产生的 6 个字母的密文作为开头。随后，操作者将机器的转子调整为信息密钥所对应的转子位置，并开始加密信息。信息密钥输入两次的原因是为了避免信息传输中因为干扰出现错误，收信方如果发现通过日密钥解码出的前 6 个字母明文不是重复两次的格式，则可以发现问题。但是，重复是加密的敌人，Rejewski 敏锐地观察到了这一点。第一个字母和第四个字母是同一个明文加密出来的，并且输入第一个字母时，转子的设置都是日密钥，是完全相同的。于是，在某一天中收到的所有由 Enigma 机加密的密文，都会满足类似这样的规则：</p>
<ul>
<li>如果第 1 个字母为 A，那么第 4 个字母为 E；</li>
<li>如果第 1 个字母为 B，那么第 4 个字母为 L；</li>
<li>如果第 1 个字母为 C，那么第 4 个字母为 C；</li>
<li>…</li>
</ul>
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th>H</th>
<th>I</th>
<th>J</th>
<th>K</th>
<th>L</th>
<th>M</th>
<th>N</th>
<th>…</th>
</tr>
</thead>
<tbody><tr>
<td>E</td>
<td>L</td>
<td>C</td>
<td>O</td>
<td>N</td>
<td>W</td>
<td>D</td>
<td>I</td>
<td>A</td>
<td>P</td>
<td>K</td>
<td>S</td>
<td>Z</td>
<td>H</td>
<td>…</td>
</tr>
</tbody></table>
<p><strong>表：密文的第一个字母和第四个字母的对应表格（部分）</strong></p>
<p>将结果列出，如上表所示。Rejewski 发现，表中的字母存在一些 “链”，例如，上一行的字母 A 对应下一行的字母 E，上一行的字母 E 对应下一行的字母 N，以此类推，最后又回到字母 A。这样就产生了字母链 AENHI。同时，也可以找到其它的字母链：BLSJP，C，DOFWVG，K，MZURTY，Q，X。如果机器的初始状态相同，那么得到的字母链自然也是相同的。更重要的是，Rejewski 发现，插线板的存在只会改变字母链中的字母，但不会影响各个字母链的长度。<br>例如，在上面的场景中，额外将 A 和 C 之间加入一条接线，那么，原先的 AENHI 链会变为 CENHI，C 链会变为 A 链；但两条链的长度是不变的。因此，字母链的长度特征是插线板作用下的不变量，它只和转子的初始位置有关，由此可以将插线板的作用和转子的初始位置解耦合。波兰的破译团队用了一年的时间进行预计算，得到了所有转子初始位置与字母链的长度的对应关系。此后，在收到新的密文后，破译者可以查表，将字母链的长度与预计算的结果进行比较，得到可能的转子的初始位置。在成功恢复出转子初始位置后，破译者可以对密文进行解密，之后进一步地分析插线板的状态。具体的算法原理如下。</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">输入：前6个密文字母的对应表格 T</span><br><span class="line">输出：解集 Solutions</span><br><span class="line"></span><br><span class="line">预计算阶段：</span><br><span class="line">----------------------------------------</span><br><span class="line"># 由波兰 Bomba 机模拟的 Enigma 机</span><br><span class="line">E ← Enigma()</span><br><span class="line"></span><br><span class="line"># 存储的数据库，用于之后查表</span><br><span class="line">Database ← Map()</span><br><span class="line"></span><br><span class="line">for each S in PossibleSettings:</span><br><span class="line">    E.setPosition(S)</span><br><span class="line">    C ← FindChainsByEnigma(E)</span><br><span class="line">    Database.store(S, C)</span><br><span class="line"></span><br><span class="line">破解过程：</span><br><span class="line">----------------------------------------</span><br><span class="line">Solutions ← Set()</span><br><span class="line"></span><br><span class="line">for each S in PossibleSettings:</span><br><span class="line">    Matched ← true</span><br><span class="line"></span><br><span class="line">    for i ← 1 to 3:</span><br><span class="line">        Chain ← FindChainsInTableRow(T[i], T[i+3])</span><br><span class="line">        Expected ← Database.get(S + i)</span><br><span class="line"></span><br><span class="line">        if Chain ≠ Expected:</span><br><span class="line">            # 字母链没有通过检验</span><br><span class="line">            Matched ← false</span><br><span class="line"></span><br><span class="line">    if Matched = true:</span><br><span class="line">        # 当前初始状态对应的字母链通过了检验</span><br><span class="line">        # 将可能的解加入解集</span><br><span class="line">        Solutions.add(S)</span><br></pre></td></tr></tbody></table></figure>]]>
    </summary>
    <title>Enigma 密码破解</title>
    <updated>2026-08-05T09:18:02.375Z</updated>
  </entry>
</feed>
