
ESPectre 设备发现机制全解析DNS-SD/mDNS 发布、浏览器 Bootstrap 与 /devices 扫描资源【免费下载链接】espectreWi-Fi CSI motion sensing for ESP32. C SDK, ESPHome, Native, and Matter frontends, browser tools, and a CLI for the full device lifecycle. GPLv3 and commercial licensing.项目地址: https://gitcode.com/GitHub_Trending/es/espectre本文是 ESPectre 项目设备发现层的技术指南完整覆盖 DNS-SD/mDNS 服务发布、TXT 记录契约、浏览器 Bootstrap 一次性应答、/devices对等扫描资源以及客户端验证与回退策略。阅读完成后你将掌握 ESPectre 固件Native / ESPHome / Matter / Micro 四种前端在局域网内被发现、被espectre devices命令枚举、被浏览器门户精确定位的完整链路以及每一条协议的边界约束与序列化限制。本文对应的权威规范文档为 docs/DISCOVERY.md它同时是设备 API 契约 docs/API.md 的姊妹篇发现层负责“找到设备”API 层负责“操作设备”。一、发现体系总览三层分工与端口约定ESPectre 的发现体系由三层组成每层解决一个不同的问题DNS-SD / mDNS 服务发布每个联网前端在局域网内发布_espectre._tcp.local.服务用于定位 Direct HTTP 端点。这是主机端 CLI 与对等设备扫描的基础。浏览器 Bootstrap非一次性引导Web 页面无法直接枚举 DNS-SD因此固件额外应答形如espectre-devices-{nonce}.local的一次性主机名查询帮助浏览器门户先找到一个可用的同网段设备。/devices扫描资源由“已找到的引导设备”代为发起一次_espectre._tcp.local.的 PTR 浏览把同网段设备清单以 JSON 形式返回给浏览器。Direct HTTP 固定监听 TCP 端口625870xF47B该常量定义在 src/cpp/runtime/direct_http_protocol.h对应的基础路径为/espectre/v1、传输标识为http同文件 L22-L24。主机端 CLI 在 src/python/espectre_cli/device_discovery.py 中同样定义了_espectre._tcp.local.、端口62587与服务标记两端契约严格一致。二、DNS-SD 服务发布四个前端共用一套标识2.1 服务实例与主机名每个联网前端发布服务类型_espectre._tcp.local.TCP 端口62587稳定主机名espectre-{device_id}.local身份标识device_id16 位小写十六进制服务实例名与显示名可以使用配置的 label但消费者一律以device_id作为身份依据一条 DNS-SD 浏览从服务类型的 PTR 记录开始每个实例再依次通过 SRV、TXT 和地址记录解析。主机端 CLI 只接受 IPv4 A 记录如果一条广告只能通过 AAAA 解析会被直接排除。2.2 四种前端的服务矩阵前端服务类型Direct SRV 端口其他前端服务Native_espectre._tcp.local.62587可选 MQTTESPHome_espectre._tcp.local.62587ESPHome native APIMatter_espectre._tcp.local.62587Matter operational 与 commissioning 服务Micro_espectre._tcp.local.62587无要点手动输入的 Direct 端点可以指定其他端口但客户端不会去探测历史遗留端口无 legacy 端口探测逻辑。ESPHome 与 Matter 会继续发布它们各自上游的服务记录但./espectre devices命令只浏览_espectre._tcp.local.。从源码看固件侧的服务发布由 src/cpp/runtime/esp_idf/mdns_discovery_service.cpp 实现setup()依次完成mdns_init()、mdns_hostname_set()、mdns_service_add()最后通过mdns_service_txt_set()写入 TXT 记录L35-L81。MdnsResponderMode枚举区分“独占 responder”与“复用现有 responder”两种模式mdns_discovery_service.h这正是 ESPHome / Matter 共享 mDNS responder 生命周期的实现基础。2.3 TXT 记录契约每个服务实例携带如下 TXT 键值Key值txtvers1protovers1.0device_id16 位小写十六进制字符name生效的显示名frontendnative、esphome、matter或microtransporthttppath/espectre/v1firmware运行中的固件版本chip当前目标芯片如esp32c3capabilities有界、逗号分隔的发现提示协议语义没有eventsTXT 键。客户端从path推导出资源、/events与/csi的 URL然后通过GET /capabilities协商精确的能力面。发现能力 token 只是展示提示不是授权或 UI 功能门控。txtvers对 TXT 键值 schema 进行版本化protovers与capabilities.protocol_version是同一个应用版本1.0不是独立的 Direct 版本。未知的 TXT 键可以被忽略但未知的txtvers或protovers值意味着不兼容。固件侧常量可交叉验证ESPECTRE_DNS_SD_TXT_SCHEMA_VERSION 1与ESPECTRE_PROTOCOL_VERSION 1.0定义在 src/cpp/runtime/espectre_protocol.htransport与path常量在 src/cpp/runtime/direct_http_protocol.h。2.4 CLI 的验收条件./espectre devices实现见 src/python/espectre_cli/device_discovery.py 的run_devices_command只接受满足以下全部条件的记录具有 IPv4 地址非零SRV 端口非零device_id合法16 位小写十六进制frontend属于native/esphome/matter/microtxtvers、protovers、transport、path与上述常量精确相等path/espectre/v1。name、firmware、chip、capabilities仅用于信息展示不参与身份识别。CLI 侧默认发现超时为 2.5 秒并带 0.35 秒安静窗口device_discovery.py浏览时只启用 IPv4Zeroconf(ip_versionIPVersion.V4Only)。固件侧的对等候选校验逻辑在 src/cpp/runtime/peer_discovery.cpp其valid_candidate()与 CLI 验收条件完全同构。三、服务生命周期跟随 STA 网络状态服务只在站点接口拥有可用 IPv4 地址时对外可用独占 mDNS responder 的前端在干净断连时发送尽力而为的 goodbye重连或地址变化后重新宣告。ESPHome 与 Matter保留对 responder 生命周期的所有权ESPectre 只增删自己的服务绝不触碰上游 responder。各前端的具体行为Native使用espectre-{device_id}.local保存的 label 变化后更新 TXTname通过update_txt()见 mdns_discovery_service.cpp。ESPHome使用相同的稳定 ESPectre 主机身份但不改变YAML 名称、native API 身份或 entity ID。Matter只有在 fabric 完成 commissioning 后才发布 ESPectre 服务移除最后一个 fabric 会移除服务并停止 Direct HTTP。固件实现通过MDNS_EVENT_ANNOUNCE_IP4、MDNS_EVENT_ENABLE_IP4、MDNS_EVENT_DISABLE_IP4事件动作驱动mdns_discovery_service.cppon_wifi_connected()在独占模式下宣告或启用 IPv4on_wifi_disconnected()在独占模式下禁用 IPv4从而精确落实“服务随站点 IPv4 存在”的生命周期约束。四、浏览器 Bootstrap一次性 nonce 主机名4.1 动机与 nonce 生成Web 页面无法枚举 DNS-SD 服务。为此每次自动发现尝试时门户从 Web Crypto 获取 96 位随机数编码为24 位小写十六进制字符并解析一个全新的主机名espectre-devices-{nonce}.local每次使用全新名称可以防止缓存的正面或负面答案满足后续尝试。需要特别注意静态别名espectre-devices.local不受支持固件也不为不同的 bootstrap 契约提供兼容性回退。固件侧前缀常量BOOTSTRAP_PREFIX espectre-devices-与NONCE_HEX_LENGTH 24定义在 src/cpp/runtime/esp_idf/mdns_bootstrap_responder.cpp 和 mdns_bootstrap_responder.h。4.2 Bootstrap DNS 应答行为Native、ESPHome、Matter 只应答合法、未压缩、class-IN 的 A 或 AAAA 问题且 owner 必须匹配 nonce 形式。一条 A 应答具有以下全部特征重复查询的 owner 名称携带 responder 当前的站点 IPv4 地址TTL 为10 秒常量RESPONSE_TTL_SECONDS 10U见 mdns_bootstrap_responder.h清空 cache-flush 位使多个 responder 可以各自贡献一个地址附带一条 NSEC 记录其位图声明存在 A 而不存在 AAAA。AAAA-only 的问题收到同样的 NSEC 否定断言且不给地址——responder 从不广告 IPv6。它接受 multicast、QU带 unicast-response 位的查询和 legacy-unicast 查询。限速与排队约束常量集中在 mdns_bootstrap_responder.hmulticast 应答最多占用4 个待发送槽位分别延迟25、50、75、100 ms步进常量RESPONSE_DELAY_STEP_US 25000见 mdns_bootstrap_responder.cpp每秒最多发送8 个应答超出窗口的应答被丢弃IPv4 变更、Wi-Fi 断连或重新配置后待发送的应答被全部丢弃。最重要的是nonce responder 是无状态的它不注册、不保留、不宣告、也不为被查询的名称发送 goodbye。实现上它通过包装__wrap_mdns_priv_receive_action在 Espressif responder 过滤未注册主机名之前观察 bootstrap 问题mdns_bootstrap_responder.cpp然后复用 responder 现有 socket 直接应答。这些行为均有单元测试覆盖见 test/cpp/suites/runtime/test_mdns_discovery_service.cpp包括 multicast A 应答的有界延迟、QU 与 legacy-unicast 处理、Chrome 压缩 AAAA 问题的兼容以及 AAAA 否定应答NSEC 断言。五、/devices扫描资源对等设备清单5.1 请求与并发约束解析到一个 bootstrap responder 后门户以与任何 Direct 请求相同的 Origin 策略请求GET /espectre/v1/devices客户端超时10 秒Native、ESPHome、Matter 实现该资源Micro 不支持请求不接受任何参数服务端发起一次异步的_espectre._tcp.local.PTR 浏览查询窗口固定为3,000 ms固件常量ESPECTRE_PEER_DISCOVERY_TIMEOUT_MS 3000U见 src/cpp/runtime/peer_discovery.h并发扫描返回 HTTP409携带 codeconflict扫描无法启动返回 codeunavailable关闭请求连接会阻止后续投递不产生 waiter也不维护持久化的对等设备清单。设备端扫描服务由 src/cpp/runtime/esp_idf/peer_discovery_service_esp_idf.cpp 实现start()调用mdns_query_async_new(nullptr, _espectre, _tcp, MDNS_TYPE_PTR, 3000, ...)L99-L117loop()在异步查询完成后进入finish_()把原始mdns_result_t转换为候选并对本机 STA 子网做校验。5.2 结果 JSON Schema{ schema_version: 2, elapsed_ms: 3019, status: complete, truncated: false, rejected_results: 0, devices: [ { device_id: 0123456789abcdef, instance: ESPectre 0123456789abcdef, hostname: espectre-0123456789abcdef, name: ESPectre C3 abcdef, frontend: native, dns_sd_schema_version: 1, protocol_version: 1.0, transport: http, path: /espectre/v1, firmware: 3.0.0-rc1, chip: esp32c3, port: 62587, capabilities: [config, csi, monitor], addresses: [192.168.1.29] } ] }顶层字段约束字段类型与约束schema_version整数等于2elapsed_ms整数0到10000报告设备端扫描耗时statuscomplete或timeouttimeout 仍可能携带已接受的记录truncated布尔设备、地址或序列化限制触发裁剪时为 truerejected_results非负整数统计无效记录与身份冲突devices数组最多 8 个已验证的设备对象单个设备对象约束字段类型与约束device_id16 位小写十六进制字符串instance可打印 ASCII1 到 63 字符hostname1 到 63 个字母、数字、-或_不含.local后缀name可打印 ASCII0 到 63 字符frontendnative、esphome、matter或microdns_sd_schema_version整数等于1protocol_version字符串等于1.0transport字符串等于httppath字符串等于/espectre/v1firmware可打印 ASCII1 到 48 字符chip1 到 16 个字母、数字、-或_port整数1到65535capabilities1 到 8 个唯一 token每个至多 32 字符addresses1 到 2 个经校验的 on-link IPv4 地址字符串设备对象的 JSON 序列化在 src/cpp/runtime/peer_discovery.cpp 中按上述字段逐项生成dns_sd_schema_version直接写入常量值。5.3 去重、合并与拒绝规则结果包含应答设备自身即使底层 Espressif 查询 API 省略了它自己的广告finish_()会把local_candidate_与当前 STA IPv4 合并进候选列表见 peer_discovery_service_esp_idf.cpp设备按device_id去重并按字典序排序同一身份 同一端点的记录合并地址同一身份出现冲突的 hostname、frontend、port 或 path时该身份整体被拒绝并计入rejected_results地址按数值排序。5.4 地址校验被接受的地址必须是responder 站点子网内的 IPv4 单播地址。未指定地址0.0.0.0、网络地址、广播地址、回环、组播以及 off-link 地址全部被拒绝。校验函数on_link_unicast()在 src/cpp/runtime/peer_discovery.cpp 中同时检查子网掩码匹配、主机位非零非全一以及首字节范围。整个响应不包含任何凭据、配置密钥、运动事件、CSI 或 broker 细节——它是纯设备清单。六、序列化限制确定性裁剪TXT 的capabilities逗号分隔值至多128 字符capability token 只含字母、数字、-、_重复 token 会使整条记录失效见 peer_discovery.cpp 的capability_tokens()完整结果对象限制为3,584 字节设备数、地址数与输出体积超过限制时保留确定性的前序结果并将truncated置为 true。七、客户端验证与回退策略浏览器门户在渲染设备或构造端点之前会验证完整结果只记住选中的唯一地址绝不记住共享的 bootstrap 名称或对等列表选中后请求GET /device与GET /capabilitiesdevice_id、frontend、协议版本与基础路径必须与发现结果一致。如果没有任何合格的 responder 可达依次回退到直连私有设备 IP唯一的espectre-{device_id}.local主机名记住的端点Improv Serial串口引导。需要特别强调的是路由网络、组播过滤、客户端隔离client isolation以及浏览器本地网络权限都可能阻断发现却不会阻断 Direct 连接——即“发现不到 ≠ 连不上”遇到这种情况应优先排查网络层面的组播可达性而不是固件本身。八、源码证据地图关注点位置发现规范文档本文依据docs/DISCOVERY.md设备 API 契约/capabilities、/device等docs/API.md端口、base path、transport 常量src/cpp/runtime/direct_http_protocol.h协议版本与 TXT schema 版本常量src/cpp/runtime/espectre_protocol.hmDNS 服务发布与生命周期src/cpp/runtime/esp_idf/mdns_discovery_service.cppBootstrap nonce 应答器src/cpp/runtime/esp_idf/mdns_bootstrap_responder.cpp对等扫描3,000 ms PTR 查询src/cpp/runtime/esp_idf/peer_discovery_service_esp_idf.cpp候选校验与 JSON 序列化src/cpp/runtime/peer_discovery.cppCLIdevices命令与 zeroconf 浏览src/python/espectre_cli/device_discovery.pyBootstrap / 发现的固件侧单元测试test/cpp/suites/runtime/test_mdns_discovery_service.cpp/devices路由的 HTTP 测试test/cpp/suites/runtime/test_direct_http_service.cppCLI 使用说明docs/CLI.mdMicro 前端的 Direct HTTP 面说明src/python/micro_espectre/README.md九、结语ESPectre 的发现层把“主机端枚举、浏览器引导、设备间互助扫描”三种场景统一收敛到_espectre._tcp.local. 固定端口62587 严格的 TXT 契约之下txtvers/protovers/transport/path的精确匹配保证了跨前端的一致性nonce bootstrap 应答器的无状态设计规避了 Web 缓存污染/devices的结果校验与序列化限制则保证了输出在任何拓扑下都可预测、可安全渲染。理解这套契约无论是排查“设备发现不到”、编写新的前端集成还是二次开发 CLI 工具都能有的放矢。【免费下载链接】espectreWi-Fi CSI motion sensing for ESP32. C SDK, ESPHome, Native, and Matter frontends, browser tools, and a CLI for the full device lifecycle. GPLv3 and commercial licensing.项目地址: https://gitcode.com/GitHub_Trending/es/espectre创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考