Opcodeffm/petkit-local

GitHub: Opcodeffm/petkit-local

一个完全本地化的 Home Assistant 自定义集成,通过逆向 Petkit 云端协议让 D4 喂食器和 CTW3 饮水机脱离云端独立运行,消除隐私泄露和安全隐患。

Stars: 0 | Forks: 0

Petkit Local — Fresh Element Solo (D4) + Eversweet Max 2 Cordless (CTW3)

Petkit Local

一个完全本地化的 Home Assistant 集成,适用于 Petkit Fresh Element Solo (D4) 喂食器
和 Eversweet Max 2 Cordless (CTW3) 饮水机。
零字节发送至 Petkit。零云端依赖。零向中国发送遥测数据。

## 为什么会有这个项目? Petkit 的 Fresh Element Solo 是一款不错的智能喂食器,但它会不断向总部发送数据:通过明文 HTTP 每 11 秒向 `api.eu-pet.com` 发送一次心跳,与 `eu-central-prod.mqtt.iotgds.aliyuncs.com`(阿里云)保持持久的 MQTT 会话,而且它的移动应用仅仅为了读取你的 WiFi SSID 就要求获取位置权限。 它还存在[真正的安全问题](SECURITY.md) —— 通过普通 HTTP 进行未经身份验证的远程设备控制,没有 TLS,对 BLE 配网没有完整性检查。如果你能拦截 HTTP 流量,你就可以控制这台喂食器。 如果你还拥有 **Eversweet Max 2 Cordless (CTW3) 饮水机**,同样的问题依然存在 —— 而且这台饮水机自身没有 Wi-Fi,因此它完全依赖低功耗蓝牙通过配对的设备(你手机上的 Petkit 应用,或与其共享账号的喂食器)连接到云端。本集成同时处理了这两种情况:D4 作为 CTW3 的透明 BLE 中继,因此将饮水机添加到 Home Assistant 是可选的,并且**要求 D4 喂食器已运行此集成**。 配置过程仅在初始设置时进行一次云端查询,之后一切都在本地运行。 独立支持饮水机(无需 D4)被刻意排除在范围之外 —— 如果这是你的情况,请参阅[相关项目](#related-projects) 以寻找替代方案。 所以:**我们用一个本地 Home Assistant 集成取代了云端**,它重新实现了刚好足够的 D4 协议以保持喂食器正常运行(并为可选的饮水机进行 BLE 中继),同时永远不会向 Petkit 或阿里发送哪怕一个字节的数据。 ## 问题的规模 当你不进行拦截时会发生什么: - **心跳** 每约 11 秒一次 → 每台设备每天约 8,000 次 - **状态报告** 每约 14 分钟一次 → 每台设备每天约 100 次 - 合并负载:**每台设备每天约 850 KB** 发送至 Petkit + 阿里云 - 保守估计全球部署了 5 到 1千万台 Petkit 设备 → **每年 1.5–3 PB 的宠物喂食器遥测数据**,其中绝大部分仅仅是在陈述喂食器在线这一事实 数据量甚至不是最可怕的部分 —— 可怕的是这些负载包含的内容: | 字段 | 泄露的内容 | |---|---| | `ssid`, `bssid` | 你的 WiFi 名称 + 路由器 MAC → **通过 WiGLE / Apple / Google WPS 数据库进行精度约 10 米的地理定位** | | 每次喂食的时间戳 | 日常作息、工作日程、度假检测 | | `rsq` (WiFi RSSI) | 推断移动轨迹 / 设备放置位置 | | 同一 SSID 上的多台 Petkit 设备 | 家庭拓扑重构 | | `runtime`, 固件版本 | 断电模式、更新状态 | 喂食器的工作根本不需要这些数据。这个项目证明了这一点 —— 设备可以在没有任何数据传出家庭的情况下无限期运行。 ## 功能特性 - 📅 **喂食时间表** —— 每个工作日最多 10 个条目,可从 HA 的 UI 中管理 - 🍽️ **手动喂食** —— 用于按需出粮的按钮 / 服务 - 🔋 **电池监控** —— 百分比电量、mV 电压(诊断)、电源类型(市电 vs 电池) - 🏠 **完整设备状态** —— 食物容器、干燥剂计时器、WiFi 信号、固件版本 - 🚨 **错误检测** —— 电机错误、RTC 错误、红外传感器、DC 错误显示为二进制传感器 - 💾 **持久化** —— 时间表和设备状态在 HA 重启后依然保留 - 🌍 **国际化** —— 开箱即支持英语和德语,其他语言可通过 PR 支持 - 🔒 **零云端** —— 配置完成后,喂食器永远不会连接到 `api.eu-pet.com` 或 `aliyuncs.com` ## 屏幕截图

Device page with all entities
The full device view — controls, sensors, and diagnostic entities, all grouped natively in HA.


Schedule editor menu
Options flow — manage the feeding plan.
Add entry form
Add-entry form with time picker, portion dropdown, weekdays.

Lovelace dashboard card
Optional Lovelace card — drop-in YAML in docs/dashboard_card.yaml.


CTW3 water fountain — overview
Eversweet Max 2 (CTW3) — drink counters, pump status, mode select, controls.
CTW3 — settings + diagnostics
Settings + diagnostics — DND, motion sensors, LED, filter, battery.
## 工作原理 ``` ┌───────────────────┐ ┌──────────────────────┐ │ Petkit Fresh │ │ Home Assistant │ │ Element Solo │ ── HTTP (port 80) ─► │ custom_component │ │ (D4, FW 1.267) │ ◄── responses ────── │ emulates cloud │ └───────────────────┘ └──────────────────────┘ ▲ │ │ ▼ Feeder is provisioned Feed commands, via BLE to point at schedule, settings, your HA server (port 80) error monitoring ``` 喂食器通过一次性的 BLE 配网或 DNS 重写,被重定向到你的 Home Assistant 内部的一个本地 HTTP 服务器。该服务器仅实现了足以让喂食器正常工作的 Petkit 云 API:心跳、设备注册、时间表下发、事件报告和命令推送。 ## 支持的设备 ### 已测试 ✅ - **Petkit Fresh Element Solo (D4)**,固件 `1.267` —— 全功能支持 - **Petkit Eversweet Max 2 Cordless (CTW3)**,固件 `1.11` —— 全功能支持,通过 D4 进行 BLE 中继(自身无 WiFi)。请参阅下方的[饮水机(可选)](#water-fountain-optional)了解配置过程。 ### 可能兼容喂食功能,但不兼容视频(我们未经测试) 这些喂食器使用相同的 `/d4/` 协议 —— 喂食时间表、电池、心跳,以及所有非视频功能的工作方式完全相同: - **Petkit YumShare Solo** —— 喂食 ✅,摄像头 ❌ - **Petkit YumShare Dual-Hopper** —— 喂食 ✅(双料仓逻辑未经测试),摄像头 ❌ **为什么没有摄像头:** Petkit 通过 **Agora.io**(一家商业 WebRTC-SaaS,中国基础设施)路由视频,并使用服务端签名的 token。这与我们拦截的普通 HTTP 有着根本不同的架构 —— 如果没有 Petkit 的私钥,任何 DNS 重定向或本地代理都无法替代 Agora 签名的会话代理。 现有的集成([Jezza34000/homeassistant_petkit](https://github.com/Jezza34000/homeassistant_petkit))确实可以在 Home Assistant 中显示 YumShare 视频,但视频流物理上仍然需要经过 Petkit + Agora 云基础设施传输 —— 它不是本地的。如果你是一个注重隐私的用户,这就违背了初衷。 **尊重隐私的替代方案:** Fresh Element Solo + 独立的 ONVIF 摄像头(Reolink E1、Tapo C200,任何支持 RTSP 的设备)+ Frigate。成本与 YumShare 差不多,可为你提供 100% 的本地 AI 监控,并允许你日后独立于喂食器更换摄像头。 ### 不兼容 ❌ - Petkit Mate D2 / D3 —— 协议不同,端点不同 - 任何主要功能是摄像头的 Petkit 设备(Cozy Cam、Cyber 宠物摄像头等) —— 它们使用的是 Agora,而不是 D4 ## 安装 ### 前置要求 - Home Assistant 2024.1 或更新版本 - 一台 Petkit D4 系列喂食器 - 能够在**端口 80** 上运行 Home Assistant 的能力(见[下文](#port-80-and-home-assistant)) - 一种将喂食器对 `api.eu-pet.com` 的 DNS 或 IP 重定向到你的 Home Assistant 的方法(见[下文](#network-setup)) ### 1. 安装集成 **通过 HACS(合并后推荐使用):** 1. HACS → Integrations → ⋮ → Custom repositories 2. 添加 `https://github.com/Opcodeffm/petkit-local`,类别为 *Integration* 3. 安装 *Petkit Local*,重启 HA **手动安装:** 1. 将 `custom_components/petkit_feeder/` 复制到你的 `config/custom_components/` 目录中 2. 重启 HA ### 2. 网络设置 喂食器的固件硬编码了 `api.eu-pet.com`。你必须在喂食器所在的本地网络上,将该主机名重定向到你的 HA 实例。 **方案 A — DNS 重写(推荐):** 在你的路由器 / Pi-hole / UniFi DNS 上: - 添加一条 A 记录:`api.eu-pet.com` → `<你的-HA-ip>` - *(可选,双管齐下)* 屏蔽喂食器 IP 的出站互联网连接,以强制其使用你的服务器,即使在 DNS 被绕过的情况下。 - *(可选)* 将 `eu-central-prod.mqtt.iotgds.aliyuncs.com` 解析到黑洞 —— 当 MQTT 不可达时,喂食器会回退到 HTTP,这正是我们想要的。 **方案 B — MITM / NAT:** 如果你无法进行 DNS 重写,请通过防火墙 NAT 将 `203.0.113.X:80`(或 `api.eu-pet.com` 当时解析到的任何地址)重定向到你的 HA。DNS 具有多条轮换的 A 记录;DNS 重写更为可靠。 ### 3. 端口 80 和 Home Assistant 喂食器使用端口 80 上的 HTTP 协议 —— 在喂食器端**不可**配置。Home Assistant 自己的前端通常运行在端口 8123 上,因此端口 80 通常是空闲的。该集成会在端口 80 上绑定第二个 aiohttp 服务器,专门用于处理喂食器流量。 如果你的 HA 主机上已有其他服务绑定到端口 80,你将在日志中看到 `OSError: [Errno 98] Address already in use`。停止其他服务(例如,如果你不使用 SSL 反向代理,请停止 NGINX 插件)即可使集成正常工作。 ### 4. 配网喂食器 **情况 A —— 喂食器已在 Petkit 云端设置完毕:** 一旦 DNS 被重定向到你的 HA,重启喂食器电源。大约 30 秒后,它应该会连接到你的本地服务器,集成会自动检测到它 —— 无需进一步配置。 **情况 B —— 全新开箱:** 你需要为喂食器配置你的 WiFi 凭据。有两种途径: 1. **通过 Petkit 应用**(最简单,非侵入式) —— 正常设置,然后进行 DNS 重写,接着重启电源。你以后再也不需要这个应用了;它只是为了初始握手而与云端通信。 2. **通过来自 HA 的 BLE** —— 完全绕过 Petkit 应用,使用此仓库 `research/` 文件夹中的脚本。需要具备一定的技术基础;详见 `research/README.md` 了解流程。 ### 5. 在 HA 中添加集成 设置 → 设备与服务 → 添加集成 → "Petkit Local" → 确认。喂食器将在下一次心跳时(约 10 秒)自动注册。 ## 使用方法 ### 编辑喂食时间表 设置 → 设备与服务 → *Petkit Local* → **配置**。 将出现一个菜单: - **添加条目** —— 时间选择器,份量下拉菜单(10 克 / 20 克 / 50 克 —— 符合喂食器的硬件精度),工作日复选框,可选名称 - **移除条目** —— 选择并删除 - **清除所有** - **保存并关闭** —— 推送到喂食器,并在 HA 重启后依然保留 时间表存在于 **Home Assistant** 中,而不是喂食器的闪存中。时间更改监听器每分钟触发一次,并通过现有的 `queue_feed()` 路径推送手动喂食命令 —— 这样即使 D4 固件处于周期性的堆内存看门狗停滞状态时,计划的喂食也能送达(喂食器在恢复后的下一次心跳时会赶上执行排队的命令)。 ### 服务 - `petkit_feeder.set_schedule` —— 替换整个时间表 - `petkit_feeder.clear_schedule` —— 清除所有条目 - `petkit_feeder.feed` —— 手动出粮(接受以克为单位的 `amount`) - `petkit_feeder.reset_desiccant` —— 更换硅胶包后重置干燥剂计时器 - `petkit_feeder.set_food_full` —— 标记粮桶已重新装满(将*剩余粮食(估算)*传感器重置为 100%) - `petkit_feeder.set_food_tank_capacity` —— 覆盖假定的满桶容量(默认 1700 克) ### 仪表板卡片 [`docs/dashboard_card.yaml`](docs/dashboard_card.yaml) 中提供了一个可直接粘贴的 Lovelace 卡片。 ### 固件更改警报(推荐) 一旦集成到位,喂食器的固件就不应再发生更改 —— 我们的本地服务器总是告诉它“没有可用的更新”([详情](FIRMWARE_PROTECTION.md))。**如果版本确实发生了变化,说明有东西绕过了这种保护**(例如 Petkit通过 BLE/LAN 短暂连接到了喂食器、DNS 泄漏等)。可以使用以下自动化来检测它: ``` # configuration.yaml (或 设置 → Automations → “Edit in YAML”) alias: "Petkit — firmware changed (unexpected!)" description: "Firmware is pinned by the local integration. A change means something reached Petkit's cloud." trigger: - platform: state entity_id: sensor.petkit_feeder_firmware # adjust to YOUR entity ID # Fires on any state change … condition: # … except the normal "unknown → " on first load after restart. - condition: template value_template: "{{ trigger.from_state.state not in ['unknown', 'unavailable', ''] }}" action: - service: persistent_notification.create data: title: "⚠️ Petkit firmware changed" message: >- Firmware changed from {{ trigger.from_state.state }} to {{ trigger.to_state.state }} at {{ now() }}. This should never happen with the local integration — check FIRMWARE_PROTECTION.md in the repo. notification_id: petkit_firmware_change # Optional: also push to mobile app # - service: notify.mobile_app_your_phone # data: # title: "⚠️ Petkit firmware changed" # message: "{{ trigger.from_state.state }} → {{ trigger.to_state.state }}" mode: single ``` 将 `sensor.petkit_feeder_firmware` 替换为你实际的实体 ID(在设置 → 设备与服务 → Petkit Local → 该设备 → *Firmware* 诊断实体下找到它)。 ## 饮水机(可选) 该集成还支持 **Petkit Eversweet Max 2 Cordless (CTW3)** 饮水机。该饮水机自身没有 WiFi —— 它通过蓝牙经 D4 中继所有内容。经过一次性的配网步骤后,饮水机将**完全在本地运行**:与喂食器相同,正常运行期间没有云端调用。 ### 为什么需要一次性的云端步骤 每台饮水机都有一个 `secret`,这是由 Petkit 云端在出厂配对时生成的。饮水机在 D4 开启的每个 BLE 会话中都会验证此密钥。我们无法从饮水机本身提取这个密钥(我们测试过),所以我们必须从 Petkit 云端获取一次,将其存储在本地,并在饮水机后续的运行中不再调用云端。 配网完成后,唯一持续的云端交互是在当地时间 03:30 的每日 `/user/refreshsession` 调用,以保持会话 token 的有效性。如果云端完全中断,你的饮水机仍会继续工作 —— 只是添加*新*饮水机的功能会失效。 ### 如何添加饮水机 设置 → 设备与服务 → *Petkit Local* → **配置** → **添加饮水机**。选择以下三种身份验证途径之一: #### 1. 邮箱 + 密码(大多数用户) 如果你使用邮箱和密码注册了 Petkit 账号,只需输入它们即可。我们会调用一次 `/user/login`,将生成的会话 token 存储在本地,然后继续。**你的密码不会被存储** —— 只有它的 MD5 哈希值被发送到 Petkit(根据其 API 的要求),并且我们在登录调用返回后就会丢弃它。 #### 2. 会话 token(Apple / Google / 微信登录用户) 如果你通过 Apple/Google/微信登录,你是没有密码的。取而代之的是,捕获一次你的 `X-Session` token 并粘贴过来。该 token 的老化方式与普通会话相同,因此每日刷新会使它永远保持有效。 要捕获该 token: - **最简单的方法(Mac/Linux 笔记本):** 运行 `mitmproxy --listen-port 8080`,将你 iPhone 的 Wi-Fi 代理设置为你的 laptop:8080,在手机上安装 `mitmproxy-ca-cert.pem` 描述文件,打开 Petkit 应用,在设备列表上下拉刷新。在 mitmproxy 中,找到任何发往 `api.eu-pet.com` 的请求,查找 `X-Session` header,复制其值。 - **iOS 应用替代方案:** 安装 [HTTP Catcher](https://apps.apple.com/app/http-catcher/id1502865661)(免费,无需越狱),启用 HTTPS 解密,安装其证书描述文件,打开 Petkit。找到任何 `api.eu-pet.com` 请求并复制 `X-Session` header。 - **Android 应用替代方案:** [HttpCanary](https://github.com/MegatronKing/HttpCanary) 的工作原理类似。 该 token 是一个 52 个字符的字符串。将其粘贴到表单中,点击提交,完成。 #### 3. 手动输入(高级) 如果你已经通过自己先前的抓包获取了饮水机的 `id`、`mac` 和 `secret`,你可以直接输入它们。此途径完全不进行云端调用。适用于高级用户和测试。 ### 身份验证之后 无论你采取了哪种途径,下一步都会要求提供饮水机的 **MAC 地址**和**序列号**。这两者都可以在官方 Petkit 应用的*设备 → 设置 → 信息*中看到。输入它们,点击提交,集成会调用一次 `/ctw3/signup` 来获取所有其他信息。 一张确认卡片将显示获取到的设备数据(出于安全考虑,密钥会被截断)。点击 *Add this fountain*,集成将重新加载,暴露出饮水机的实体。 ### 饮水机集成不做的事情 - 我们不会自动发现饮水机。你需要提供 MAC + SN。这是设计使然 —— Petkit 的 `/discovery/device_roster_v2` 对我们的测试账户返回为空,而 `/ctw3/owndevices` 同样不可靠。从应用中复制的 MAC + SN 是唯一可靠的途径。 - 我们不配对新饮水机。请先通过官方 Petkit 应用进行配对;我们的集成是将一台*已配对*的饮水机接入 HA。 - 我们不写入任何云端配置。所有设置(模式、亮度、休眠定时器、运动传感器等)都是通过 BLE 经由 D4 中继发送的。 ### 相关项目 [`maksym-pasichnyk/PetKit-Eversweet-Max`](https://github.com/maksym-pasichnyk/PetKit-Eversweet-Max) 采用了另一种架构:手机作为 BLE 代理直接连接到 CTW3,无需 D4 参与。这是一种不同的权衡 —— 如果你只有饮水机(没有 D4 喂食器),它非常有用,但需要保持手机式的 BLE 代理每天 24/7 运行。 ## 计时与怪癖 - **HA 重启后**:喂食器大约每 14 分钟发送一次状态报告。在第一次报告到达之前,固件 / WiFi / 电池可能会显示为 `unknown`。这是正常现象;集成会在重启过程中保留上次已知的值。 - **冷启动后的首次手动喂食**:延迟约 15-25 秒。心跳处于 11 秒的轮询周期,而电机本身也需要几秒钟的时间。这不是 bug。 - **启动时的 RTC 错误**(`rtc_c: 1`):如果喂食器断电已有一段时间,可能会发生这种情况。我们的集成通过心跳响应传输时间;喂食器会在大约一小时内重新同步。 - **“使用电池运行”与“使用市电”**:状态报告中的 `ubat` 字段会切换;`power_source` 传感器会实时反映这一点。 ## 实体 | 实体 | 用途 | |---|---| | `binary_sensor.*_verbindung` / `_connection` | 在线 / 离线(180 秒后过期检测) | | `binary_sensor.*_motor_fehler` / `_motor_error` | 电机卡死 / 故障 | | `binary_sensor.*_rtc_fehler` / `_rtc_error` | 喂食器没有有效时间(时间表将不会运行!) | | `binary_sensor.*_ir_sensor_fehler` *(可选启用)* | 红外传感器错误(食物检测) | | `binary_sensor.*_dc_fehler` *(可选启用)* | DC 输入错误 | | `sensor.*_futterungsplan` / `_feed_schedule` | 人类可读的时间表摘要 + 原始属性 | | `sensor.*_batterie` / `_battery` | 电池电量百分比(5× AA,6500–8000 mV 范围) | | `sensor.*_batteriestatus` / `_battery_status` | 正常 / 电量低 / 使用电池运行 / 无电池 | | `sensor.*_stromquelle` / `_power_source` | 市电 (USB/DC) vs. 电池 | | `sensor.*_futterbehalter` / `_food_container` | 正常 / 低 / 空 / 未知(固件枚举值,非百分比) | | `sensor.*_food_remaining_estimated` | 估算的粮桶填充百分比(计算自上次补充以来的克数,对比 `tank_capacity_g`,默认 1700g;当固件报告补充时自动重置,也可通过 `set_food_full` 手动重置) | | *(诊断,可选启用)* `sensor.*_food_remaining_grams` | 同上,但以克为单位 | | `sensor.*_trockenmittel_tage_ubrig` / `_desiccant_days_left` | 0–30 天倒数计时 | | `sensor.*_futterungen_heute` / `_feedings_today` | 今天的喂食次数 | | `sensor.*_futtermenge_heute` / `_food_amount_today` | 今天出粮的总克数 | | *(诊断)* `sensor.*_firmware` | 固件版本 | | *(诊断)* `sensor.*_wifi_signal` | WiFi RSSI (dBm) | | *(诊断)* `sensor.*_letzter_heartbeat` / `_last_heartbeat` | 时间戳 | | *(诊断)* `sensor.*_laufzeit` / `_uptime` | 喂食器运行时间 | | *(诊断,可选启用)* `sensor.*_batteriespannung` | 原始 mV 电压 | | *(诊断,可选启用)* `sensor.*_ram_frei` | ESP32 空闲堆内存 | | `switch.*_futterungston` / `_feed_sound` | 喂食提示音开/关 | | `switch.*_tastensperre` / `_manual_lock` | 物理按键锁定 | | `switch.*_led_anzeige` / `_led_display` | LED 指示灯开/关 | | `button.*_futtern_*` / `_feed_*` | 手动喂食按钮(10 克 / 20 克 / 50 克) | | `button.*_trockenmittel_zurucksetzen` / `_reset_desiccant` | 重置干燥剂计数器 | ## 安全性 请参阅 [SECURITY.md](SECURITY.md) 了解我们在 Petkit 的云端和 BLE 协议中发现的漏洞。这些是促成该项目的真实问题。如果你计划申请引用这些发现的 CVE ID,该文档的格式已适合提交给 MITRE。 ## 防御未来的固件更新 原则上,Petkit 可以推送破坏此集成的固件更新。请参阅 [FIRMWARE_PROTECTION.md](FIRMWARE_PROTECTION.md) 了解分层防御措施(OTA 拦截、互联网防火墙、不使用应用、固件更改检测自动化)。简要来说:我们的服务器已经拒绝所有 OTA 查询,并阻止喂食器连接公共互联网,这使该设置几乎做到了防更新。 ## 免责声明 此集成以一种未经 Petkit 授权的方式修改了你的 Petkit 喂食器的行为。**一切风险由你自己承担。** 作者与 Petkit 没有任何关联。如果你触及固件或拆开设备,你的保修可能会失效。此集成本身不会修改固件 —— 它只更改喂食器发送其 HTTP 流量的目标 —— 但我们无法保证 Petkit 未来的固件更新不会默默还原这些设置。 “Petkit”和“Fresh Element Solo”是 Petkit Network Technology Co., Ltd. 的商标,在此仅用于兼容性标识。 ## 贡献 欢迎提交 PR 以支持: - 支持其他 D4 系列喂食器(YumShare、Dual-Hopper 等) - 添加其他语言的翻译(`translations/.json`) - 改进时间表 UI(自定义 Lovelace 卡片?) - Bug 修复和协议改进 请注意: - 保持集成**纯本地**。无云端回调,无遥测。 - 不要提交真实的 MAC 地址、SSID、密码或固件抓包。 - 如果你添加了新功能,请更新 README 中的实体表。 ## 致谢 D4 云端和 BLE 协议的逆向工程以及 Home Assistant 集成代码,均在 [Claude](https://www.anthropic.com/claude) (Anthropic) 的大量协助下完成。硬件测试、数据包捕获、假设验证以及所有设计决策均由 [Opcodeffm](https://github.com/Opcodeffm) 完成。 ## 许可证 MIT —— 见 [LICENSE](LICENSE)。
标签:BLE, BLE中继, CTW3, D4, Home Assistant, IoT安全, IP 地址批量处理, MIT协议, Petkit, TTP服务器, 去云化, 宠物喂食器, 宠物饮水机, 家庭自动化, 小佩宠物, 局域网控制, 嵌入式, 开源, 智能家居, 智能硬件, 本地控制, 物联网, 网络安全, 网络调试, 自动化, 蓝牙低功耗, 逆向工具, 隐私保护, 零云依赖