diff --git a/README_FUNCTION_CN.md b/README_FUNCTION_CN.md index 191a733..edca6a1 100644 --- a/README_FUNCTION_CN.md +++ b/README_FUNCTION_CN.md @@ -23,8 +23,6 @@ M5-SwitchC6 是一个基于ESP-NOW协议的智能开关控制库,用于控制 1. **ESP32系列** (推荐) 2. **M5Stack系列设备** -### 完善的示例项目:https://gitlab.m5stack.com/moyongming/m5iot-switchc6-demo-pio - ## 快速开始 ### 基础使用 diff --git a/README_FUNCTION_EN.md b/README_FUNCTION_EN.md index 6ee2b64..da37cb4 100644 --- a/README_FUNCTION_EN.md +++ b/README_FUNCTION_EN.md @@ -23,8 +23,6 @@ M5-SwitchC6 is an ESP-NOW based smart switch control library for controlling and 1. ESP32 family (recommended) 2. M5Stack devices -### Full example project: https://gitlab.m5stack.com/moyongming/m5iot-switchc6-demo-pio - ## Quick Start ### Basic usage diff --git a/docs/M5SwitchC6_SoftwareFlow_CN_useAI.md b/docs/M5SwitchC6_SoftwareFlow_CN_useAI.md deleted file mode 100644 index d2a0706..0000000 --- a/docs/M5SwitchC6_SoftwareFlow_CN_useAI.md +++ /dev/null @@ -1,221 +0,0 @@ -# M5SwitchC6 软件流程图(基于 src/M5Switchc6.cpp) - -更新时间:2025-08-13 - -本文基于 `src/M5Switchc6.cpp` 与 `src/M5Switchc6.h` 提炼核心流程,给出总览流程图与收发应答时序图,帮助理解 ESP-NOW 初始化、数据接收/解析、命令发送与应答等待、设备清理等关键路径。 - -提示:VS Code Markdown 预览已原生支持 Mermaid。打开本文件后,使用“在侧边打开预览”即可查看图表。 - ---- - -## 一、总览流程图 - -### 1.1 初始化流程 (begin) - -```mermaid -flowchart TB - A[begin] --> B{Platform ESP32 or ESP8266} - B -->|No| A0[Not supported return false] - B -->|Yes| C{mutexLock == NULL} - C -->|Yes| C1[Create mutex] - C1 --> D{dataQueue == nullptr} - C -->|No| D - D -->|Yes| D1[Create queue 10] - D1 --> E{parseTaskHandle == nullptr} - D -->|No| E - E -->|Yes| E1[Create task parseDataTask] - E1 --> F{peers == nullptr} - E -->|No| F - F -->|Yes| F1[Alloc init peers max_broadcast_peers] - F1 --> G{WiFi.getMode} - F -->|No| G - G -->|WIFI_OFF| A1[WiFi is off return false] - G -->|WIFI_AP| A2[WiFi is AP mode return false] - G -->|WIFI_STA or WIFI_AP_STA| H[Continue WiFi OK] - H --> I[acquireMutex] - I --> J[esp_now_init] - J -->|ESP_OK| K[Register recv cb lambda] - J -->|fail| J1[releaseMutex return false] - K --> L[Register send cb lambda] - L --> M[releaseMutex return true] -``` - -### 1.2 接收路径 (回调 -> 队列 -> 解析) - -```mermaid -flowchart TB - R0[recv_cb with esp_now_info data len] --> R1{esp_now_info and src_addr and instance} - R1 -->|Yes| R2[acquireMutex] - R1 -->|No| R0A[Log unknown MAC] - R2 --> R3[Extract MAC channel rssi from rx_ctrl] - R3 --> R4[Find or add peer in peers array] - R4 --> R5[Update lastData status lastReceiveTime] - R5 --> R6[releaseMutex] - R6 --> R7[enqueueData with senderMac] - R0A --> R7B[enqueueData without senderMac] - R7 --> Q[(Queue size 10)] - R7B --> Q - Q -->|xQueueReceive 100ms| T[parseDataTask infinite loop] - T --> T1{queuedData received} - T1 -->|Yes| P0[parseData with data len senderMac] - T1 -->|No| T2[vTaskDelay 1ms continue] - P0 --> P1[parseDataStructured] - P1 -->|isValid true| P2[handleReceivedResponse with senderMac] - P1 -->|isValid false| P3[log Parse error] - T2 --> T -``` - -### 1.3 发送路径 (构建命令 -> 发送广播) - -```mermaid -flowchart TB - S1[sendSwitchCommand / sendStatusQuery / sendVersionQuery / sendCustomMessage] --> S2[Validate channel 1-14] - S2 -->|invalid| S2A[return false] - S2 -->|valid| S3[Validate MAC format] - S3 -->|invalid| S3A[return false] - S3 -->|valid| S4[Build command string with channel] - S4 --> S5[acquireMutex] - S5 --> S6[Check broadcast peer exists] - S6 -->|not exist| S6A[Add broadcast peer FF:FF:FF:FF:FF:FF] - S6 -->|exist| S7 - S6A --> S7[esp_now_send broadcast] - S7 --> S8[releaseMutex] - S8 -->|ESP_OK| S9[Log success] - S8 -->|fail| S10[Log fail] - S7 --> S11[send_cb status log] -``` - -### 1.4 应答等待机制 (可选) - -```mermaid -flowchart TB - W0[sendSwitchCommandWithResponse] --> W1[addResponseWait deviceMac timeoutMs] - W1 -->|success| W2[Send with needResponse true] - W1 -->|fail| W1A[return false] - W2 -->|success| W3[millis startTime lastSendTime] - W2 -->|fail| W2A[removeResponseWait return false] - W3 --> W4{millis - startTime < timeoutMs} - W4 -->|Yes| W5[checkResponseTimeouts] - W5 --> W6[findResponseWait index] - W6 -->|hasResponse true| W7[Copy response removeResponseWait return true] - W6 -->|hasResponse false| W8{millis - lastSendTime >= resendInterval} - W8 -->|Yes| W9[Resend command update lastSendTime] - W8 -->|No| W10[delay 1ms] - W9 --> W4 - W10 --> W4 - W4 -->|No timeout| W11[removeResponseWait return false] - - %% 从接收路径的响应匹配 - P2[handleReceivedResponse from RX path] -->|match normalized senderMAC| W6 -``` - -### 1.5 自动清理机制 (可选) - -```mermaid -flowchart TB - GC0[setAutoCleanup intervalMs deviceTimeoutMs] --> GC1[Save autoCleanupInterval deviceTimeout lastCleanupTime] - GC2[checkAutoCleanup] --> GC3{autoCleanupInterval == 0} - GC3 -->|Yes disabled| GC5[return 0] - GC3 -->|No| GC4{currentTime - lastCleanupTime >= autoCleanupInterval} - GC4 -->|No| GC5 - GC4 -->|Yes| GC6[clearExpiredDevices deviceTimeout] - GC6 --> GC7[Remove expired devices and response waits] - GC7 --> GC8[Update lastCleanupTime return removedCount] -``` - -说明: - -- **初始化流程**:严格按照源码顺序,包含所有条件检查(mutex/queue/task/peers的nullptr检查,WiFi模式的具体枚举值检查) -- **接收路径**:体现了 ESP-NOW 回调的完整处理逻辑,包括 esp_now_info 检查、MAC提取、peers更新、队列入队、解析任务循环 -- **发送路径**:包含参数验证(信道范围、MAC格式)、命令字符串构建、广播peer确保存在等完整步骤 -- **WithResponse机制**:详细展示了超时循环、重发间隔检查、响应匹配的完整逻辑,以及各种失败情况的处理 -- **自动清理**:体现了间隔检查、过期设备移除的完整流程,包括禁用状态的处理 - ---- - -## 二、收发与应答时序图 - -```mermaid -sequenceDiagram - participant App - participant M5 as M5SwitchC6 - participant ESP as ESP_NOW - participant Q as dataQueue - participant T as parseTask - - App->>M5: sendSwitchCommandWithResponse(deviceMac, switchOn, timeoutMs) - M5->>M5: addResponseWait(deviceMac, timeoutMs) - alt addResponseWait success - M5->>M5: sendSwitchCommand(deviceMac, switchOn, needResponse=true) - alt sendSwitchCommand success - M5->>M5: normalizeMacAddress + build command string - M5->>M5: acquireMutex - M5->>ESP: esp_now_send(FF:FF:FF:FF:FF:FF, command) - ESP-->>M5: send_cb(mac, status) - M5->>M5: releaseMutex - - Note over M5: Start timeout loop with resend logic - - loop while millis() - startTime < timeoutMs - M5->>M5: checkResponseTimeouts() - M5->>M5: findResponseWait(deviceMac) - alt hasResponse == true - M5->>App: return response data (success) - else resend interval reached - M5->>ESP: esp_now_send (resend command) - else - M5->>M5: delay(1) - end - end - - M5->>App: timeout - return false - else - M5->>M5: removeResponseWait(deviceMac) - M5->>App: send failed - return false - end - else - M5->>App: addResponseWait failed - return false - end - - Note over ESP,M5: Remote device receives and replies - - ESP-->>M5: recv_cb(esp_now_info, data, len) - M5->>M5: acquireMutex - M5->>M5: extract senderMAC from esp_now_info.src_addr - M5->>M5: find/add peer in peers array - M5->>M5: update peers MAC/channel/RSSI/lastData/status/time - M5->>M5: releaseMutex - M5->>Q: enqueueData(data, len, senderMAC) - - T->>Q: xQueueReceive(dataQueue, queuedData, 100ms) - Q-->>T: data, len, senderMAC - T->>M5: parseData(data, len, senderMAC) - M5->>M5: parseDataStructured(data, len) -> parsed - alt parsed.isValid == true - M5->>M5: handleReceivedResponse(parsed, senderMacStr) - M5->>M5: findResponseWait(senderMacStr) - alt waiting device found - M5->>M5: set hasResponse = true, copy parsed data - Note over M5: This breaks the timeout loop above - end - else - M5->>M5: log parse error - end -``` - ---- - -## 参考与扩展 - -- 关键接口: - - - 初始化与通道:`begin()`, `setChannel()`, `getChannel()` - - 发送:`sendSwitchCommand()`, `sendStatusQuery()`, `sendVersionQuery()`, `sendCustomMessage()` - - 带应答:`sendSwitchCommandWithResponse()`, `sendStatusQueryWithResponse()`, `sendVersionQueryWithResponse()` - - 解析:`parseData()`, `parseDataStructured()` - - 等待/匹配:`addResponseWait()`, `findResponseWait()`, `removeResponseWait()`, `checkResponseTimeouts()`, `handleReceivedResponse()` - - 清理:`clearPeersData()`, `clearResponseWaits()`, `clearAllData()`, `clearDeviceData()`, `clearExpiredDevices()`, `setAutoCleanup()`, `checkAutoCleanup()` -- 预览方式: - - 1) 在 VS Code 中打开本文件 - 2) 右上角“在侧边打开预览”(或快捷键 Ctrl+K V) diff --git a/docs/SwitchC6-ESP-NOW-控制协议-20250722.pdf b/docs/SwitchC6-ESP-NOW-控制协议-20250722.pdf deleted file mode 100644 index 52fa5b8..0000000 Binary files a/docs/SwitchC6-ESP-NOW-控制协议-20250722.pdf and /dev/null differ diff --git a/docs/SwitchC6-ESP-NOW-控制协议-20250722.md b/protocol/SwitchC6-ESP-NOW-Protocol-CN.md similarity index 82% rename from docs/SwitchC6-ESP-NOW-控制协议-20250722.md rename to protocol/SwitchC6-ESP-NOW-Protocol-CN.md index ba8fb48..6be4eb3 100644 --- a/docs/SwitchC6-ESP-NOW-控制协议-20250722.md +++ b/protocol/SwitchC6-ESP-NOW-Protocol-CN.md @@ -1,6 +1,6 @@ -# SwitchC6 ESP-NOW控制协议 +# SwitchC6 ESP-NOW 控制协议 -## SwitchC6开(不返回) +## SwitchC6开启(不返回) * 命令 @@ -14,7 +14,8 @@ ```C "AABB-CCDD-EEFF=1;ch=6" 或 "aabb-ccdd-eeff=1;ch=6" 或 "aaBB-CCdd-eeFF=1;ch=6" ``` -## SwitchC6开(带返回) + +## SwitchC6开启(带返回) * 命令 @@ -39,7 +40,7 @@ "1122-AABB-CCGG;1;3.30V" 或 "1122-aabb-ccgg;1;3.30V" 或 "1122-aaBB-ccgg;1;3.30V" ``` -## SwitchC6关(不返回) +## SwitchC6关闭(不返回) * 命令 @@ -54,7 +55,7 @@ "AABB-CCDD-EEFF=0;ch=6" 或 "aabb-ccdd-eeff=0;ch=6" 或 "aaBB-CCdd-eeFF=0;ch=6" ``` -## SwitchC6关(带返回) +## SwitchC6关闭(带返回) * 命令 @@ -101,7 +102,7 @@ SwitchC6返回 ```C - "1122-AABB-CCGG;0;3.30V" 或 "1122-aabb-ccgg;0;3.30V" 或 "1122-aaBB-ccgg;0;3.30V" + "1122-AABB-CCGG;0;3.30V" 或 "1122-aabb-ccgg;0;3.30V" 或 "1122-aaBB-ccgg;0;3.30V" 或 "1122-AABB-CCGG;1;3.30V" 或 "1122-aabb-ccgg;1;3.30V" 或 "1122-aaBB-ccgg;1;3.30V" ``` @@ -151,24 +152,24 @@ "FFFF-FFFF-FFFF;0;z.zzV" 或 "FFFF-FFFF-FFFF;1;z.zzV" ``` -### 说明: +## 说明: -* 数据发送和接收均采用字符串格式 -* "XXXX-XXXX-XXXX" 表示单火设备的 MAC 地址,使用字符形式,兼容大小写 -* "YYYY-YYYY-YYYY" 表示主机的 MAC 地址,使用字符形式,兼容大小写 -* 设备的通信采用广播方式,主机需要将广播地址(FF:FF:FF:FF:FF:FF)添加为对等节点。SwitchC6 也通过广播发送返回数据。主机可以通过 "YYYY-YYYY-YYYY" 判断接收到的数据包是否属于本设备,而 SwitchC6 则通过 "XXXX-XXXX-XXXX" 判断是否为需要自己处理的数据包 -* "ch=n" 中的 n 表示主机的 Wi-Fi 通道,取值范围为 1~14,主机发送的命令中必须填入正确的通道 -* 主机发送的命令中,MAC 地址后紧跟的第一个字符为 "=" -* SwitchC6 返回的命令中,MAC 地址后紧跟的第一个字符为 ";" -* "z.zzV" 表示电容电压 -* 返回数据中的继电器状态与电容电压使用 ";" 分隔 -* SwitchC6 是否需要回复由主机发送数据包的最后一位是否为 ";" 来判断:如果末尾是 ";",则需要返回数据 -* LED 灯状态与继电器状态绑定:继电器闭合时,LED 灯点亮;继电器断开时,LED 灯熄灭 -* 按下按钮时,设备会广播自身状态。Switch-C6 会在 1~14 通道各发送一次数据包,且数据包中携带的地址为 FFFF-FFFF-FFFF(广播地址)。 +* 数据发送和接收均采用字符串格式。 +* "XXXX-XXXX-XXXX" 表示单火开关 SwitchC6 的 MAC 地址,使用字符形式,不区分大小写。 +* "YYYY-YYYY-YYYY" 表示主机的 MAC 地址,使用字符形式,不区分大小写。 +* 设备的通信采用广播方式,主机需要将广播地址(FF:FF:FF:FF:FF:FF)添加为对等节点。SwitchC6 也通过广播发送返回数据。主机可以通过 "YYYY-YYYY-YYYY" 判断接收到的数据包是否属于本设备,而 SwitchC6 则通过 "XXXX-XXXX-XXXX" 判断是否为需要自己处理的数据包。 +* "ch=n" 中的 n 表示主机的 Wi-Fi 通道,取值范围为 1~14,主机发送的命令中必须填入正确的通道。 +* 主机发送的命令中,MAC 地址后紧跟的第一个字符为 "="。 +* SwitchC6 返回的命令中,MAC 地址后紧跟的第一个字符为 ";"。 +* "z.zzV" 表示电容电压。 +* 返回数据中的继电器状态与电容电压使用 ";" 分隔。 +* SwitchC6 是否需要回复由主机发送数据包的最后一位是否为 ";" 来判断:如果末尾是 ";",则需要返回数据。 +* 绿色 LED 灯状态与继电器状态绑定:继电器闭合时,绿色 LED 灯点亮;继电器断开时,绿色 LED 灯熄灭。 +* 按下按钮时,设备会广播自身状态。SwitchC6 会在 1~14 通道各发送一次数据包,且数据包中的地址为 FFFF-FFFF-FFFF(广播地址)。 -## ESP32-IDF使用示例 +## ESP-IDF使用示例 -* esp now 发送 +* ESP-NOW 发送 ```C // 广播 MAC 地址(表示将数据发送给所有接收范围内的 ESP-NOW 设备) @@ -195,6 +196,5 @@ // 使用 ESP-NOW 发送其中一条控制指令 // 此处发送第 0 条指令,即:开启继电器,且不等待响应 - esp_now_send(broadcast_mac_addr, (const uint8_t *)send_cmd[0], strlen(send_cmd[0])); - - ``` \ No newline at end of file + esp_now_send(broadcast_mac_addr, (const uint8_t *)send_cmd[0], strlen(send_cmd[0])); + ``` diff --git a/protocol/SwitchC6-ESP-NOW-Protocol-CN.pdf b/protocol/SwitchC6-ESP-NOW-Protocol-CN.pdf new file mode 100644 index 0000000..383f8ff Binary files /dev/null and b/protocol/SwitchC6-ESP-NOW-Protocol-CN.pdf differ diff --git a/protocol/SwitchC6-ESP-NOW-Protocol-EN.md b/protocol/SwitchC6-ESP-NOW-Protocol-EN.md new file mode 100644 index 0000000..c404148 --- /dev/null +++ b/protocol/SwitchC6-ESP-NOW-Protocol-EN.md @@ -0,0 +1,200 @@ +# SwitchC6 ESP-NOW Control Protocol + +## SwitchC6 ON (no response) + +* Command + + Host sends + ```C + "XXXX-XXXX-XXXX=1;ch=n" + ``` +* Example + + Host sends + ```C + "AABB-CCDD-EEFF=1;ch=6" or "aabb-ccdd-eeff=1;ch=6" or "aaBB-CCdd-eeFF=1;ch=6" + ``` + +## SwitchC6 ON (with response) + +* Command + + Host sends + ```C + "XXXX-XXXX-XXXX=1;ch=n;" + ``` + + SwitchC6 responds + ```C + "YYYY-YYYY-YYYY;1;z.zzV" + ``` +* Example + + Host sends + ```C + "AABB-CCDD-EEFF=1;ch=6;" or "aabb-ccdd-eeff=1;ch=6;" or "aaBB-CCdd-eeFF=1;ch=6;" + ``` + + SwitchC6 responds + ```C + "1122-AABB-CCGG;1;3.30V" or "1122-aabb-ccgg;1;3.30V" or "1122-aaBB-ccgg;1;3.30V" + ``` + +## SwitchC6 OFF (no response) + +* Command + + Host sends + ```C + "YYYY-YYYY-YYYY=0;ch=n" + ``` +* Example + + Host sends + ```C + "AABB-CCDD-EEFF=0;ch=6" or "aabb-ccdd-eeff=0;ch=6" or "aaBB-CCdd-eeFF=0;ch=6" + ``` + +## SwitchC6 OFF (with response) + +* Command + + Host sends + ```C + "XXXX-XXXX-XXXX=0;ch=n;" + ``` + + SwitchC6 responds + ```C + "YYYY-YYYY-YYYY;0;z.zzV" + ``` +* Example + + Host sends + ```C + "AABB-CCDD-EEFF=0;ch=6;" or "aabb-ccdd-eeff=0;ch=6;" or "aaBB-CCdd-eeFF=0;ch=6;" + ``` + + SwitchC6 responds + ```C + "1122-AABB-CCGG;0;3.30V" or "1122-aabb-ccgg;0;3.30V" or "1122-aaBB-ccgg;0;3.30V" + ``` + +## Read device status + +* Command + + Host sends + ```C + "XXXX-XXXX-XXXX=?;ch=n;" + ``` + + SwitchC6 responds + ```C + "YYYY-YYYY-YYYY;0;z.zzV" or "YYYY-YYYY-YYYY;1;z.zzV" + ``` +* Example + + Host sends + ```C + "AABB-CCDD-EEFF=?;ch=6;" or "aabb-ccdd-eeff=?;ch=6;" or "aaBB-CCdd-eeFF=?;ch=6;" + ``` + + SwitchC6 responds + ```C + "1122-AABB-CCGG;0;3.30V" or "1122-aabb-ccgg;0;3.30V" or "1122-aaBB-ccgg;0;3.30V" or + "1122-AABB-CCGG;1;3.30V" or "1122-aabb-ccgg;1;3.30V" or "1122-aaBB-ccgg;1;3.30V" + ``` + +## Version query + +* Command + + Host sends + + ```C + "XXXX-XXXX-XXXX=V;ch=n;" + ``` + + SwitchC6 responds + + ```C + "YYYY-YYYY-YYYY;ver" + ``` + +* Example + + Host sends + + ```C + "AABB-CCDD-EEFF=V;ch=6;" or "aabb-ccdd-eeff=V;ch=6;" or "aaBB-CCdd-eeFF=V;ch=6;" + ``` + + SwitchC6 responds + + ```C + "1122-AABB-CCGG;1.0.0" or "1122-aabb-ccgg;1.0.0" or "1122-aaBB-ccgg;1.0.0" + ``` + +## Button broadcast + +* Single press + + SwitchC6 broadcasts and toggles the switch state once + ```C + "FFFF-FFFF-FFFF;0;z.zzV" or "FFFF-FFFF-FFFF;1;z.zzV" + ``` + +* Long press for 5 s + + SwitchC6 broadcasts + ```C + "FFFF-FFFF-FFFF;0;z.zzV" or "FFFF-FFFF-FFFF;1;z.zzV" + ``` + +## Notes + +* Both transmitted and received data are in string format. +* "XXXX-XXXX-XXXX" denotes the MAC address of the single-live-wire switch (SwitchC6), in character form, case-insensitive. +* "YYYY-YYYY-YYYY" denotes the host MAC address, in character form, case-insensitive. +* Communication uses broadcast. The host must add the broadcast address (FF:FF:FF:FF:FF:FF) as a peer. SwitchC6 also sends return data via broadcast. The host can determine whether a received packet is intended for itself by checking "YYYY-YYYY-YYYY", while SwitchC6 determines whether it should process a command by checking "XXXX-XXXX-XXXX". +* In "ch=n", n is the host's Wi‑Fi channel, in the range 1–14. The host must include the correct channel in the command it sends. +* In commands sent by the host, the first character immediately following the MAC address is "=". +* In commands returned by SwitchC6, the first character immediately following the MAC address is ";". +* "z.zzV" represents the capacitor voltage. +* In the return data, the relay state and capacitor voltage are separated by ";". +* Whether SwitchC6 needs to reply is determined by whether the last character of the packet sent by the host is ";": if it ends with ";", a reply is required. +* The green LED state is tied to the relay state: when the relay is closed, the green LED is on; when the relay is open, the green LED is off. +* When the button is pressed, the device broadcasts its own state. SwitchC6 sends one packet on each of channels 1–14, and the destination address in the packet is FFFF-FFFF-FFFF (broadcast address). + +## ESP-IDF usage example + +* ESP-NOW sending + + ```C + // Broadcast MAC address (send data to all ESP-NOW devices within range) + const uint8_t broadcast_mac_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + // Target device MAC address (here, the MAC of SwitchC6) + const uint8_t switchc6_mac[6] = {0xE4, 0xB3, 0x23, 0x86, 0x18, 0xC4}; + + /** + * @brief List of control commands to send (string format) + * + * Format: MAC=operation;ch=channel; + * - operation: 1 = ON, 0 = OFF, ? = read status + * - ch=6 means the current Wi‑Fi operating channel is 6 + * - The trailing semicolon (;) indicates whether a device response is required (if present, a response is required) + */ + const char *send_cmd[] = { + "E4B3-2386-18C4=1;ch=6", // Turn on the relay; no device response required + "E4B3-2386-18C4=1;ch=6;", // Turn on the relay; device response required + "E4B3-2386-18C4=0;ch=6", // Turn off the relay; no device response required + "E4B3-2386-18C4=0;ch=6;", // Turn off the relay; device response required + "E4B3-2386-18C4=?;ch=6;", // Query relay status; device response required + }; + + // Use ESP-NOW to send one of the control commands. + // Here we send index 0: turn on the relay without waiting for a response. + esp_now_send(broadcast_mac_addr, (const uint8_t *)send_cmd[0], strlen(send_cmd[0])); + ``` diff --git a/protocol/SwitchC6-ESP-NOW-Protocol-EN.pdf b/protocol/SwitchC6-ESP-NOW-Protocol-EN.pdf new file mode 100644 index 0000000..c594e69 Binary files /dev/null and b/protocol/SwitchC6-ESP-NOW-Protocol-EN.pdf differ diff --git a/protocol/SwitchC6-ESP-NOW-Protocol-JP.md b/protocol/SwitchC6-ESP-NOW-Protocol-JP.md new file mode 100644 index 0000000..7cdd2d4 --- /dev/null +++ b/protocol/SwitchC6-ESP-NOW-Protocol-JP.md @@ -0,0 +1,200 @@ +# SwitchC6 ESP-NOW 制御プロトコル + +## SwitchC6 オン(応答なし) + +* コマンド + + ホストが送信 + ```C + "XXXX-XXXX-XXXX=1;ch=n" + ``` +* 例 + + ホストが送信 + ```C + "AABB-CCDD-EEFF=1;ch=6" または "aabb-ccdd-eeff=1;ch=6" または "aaBB-CCdd-eeFF=1;ch=6" + ``` + +## SwitchC6 オン(応答あり) + +* コマンド + + ホストが送信 + ```C + "XXXX-XXXX-XXXX=1;ch=n;" + ``` + + SwitchC6 が応答 + ```C + "YYYY-YYYY-YYYY;1;z.zzV" + ``` +* 例 + + ホストが送信 + ```C + "AABB-CCDD-EEFF=1;ch=6;" または "aabb-ccdd-eeff=1;ch=6;" または "aaBB-CCdd-eeFF=1;ch=6;" + ``` + + SwitchC6 が応答 + ```C + "1122-AABB-CCGG;1;3.30V" または "1122-aabb-ccgg;1;3.30V" または "1122-aaBB-ccgg;1;3.30V" + ``` + +## SwitchC6 オフ(応答なし) + +* コマンド + + ホストが送信 + ```C + "YYYY-YYYY-YYYY=0;ch=n" + ``` +* 例 + + ホストが送信 + ```C + "AABB-CCDD-EEFF=0;ch=6" または "aabb-ccdd-eeff=0;ch=6" または "aaBB-CCdd-eeFF=0;ch=6" + ``` + +## SwitchC6 オフ(応答あり) + +* コマンド + + ホストが送信 + ```C + "XXXX-XXXX-XXXX=0;ch=n;" + ``` + + SwitchC6 が応答 + ```C + "YYYY-YYYY-YYYY;0;z.zzV" + ``` +* 例 + + ホストが送信 + ```C + "AABB-CCDD-EEFF=0;ch=6;" または "aabb-ccdd-eeff=0;ch=6;" または "aaBB-CCdd-eeFF=0;ch=6;" + ``` + + SwitchC6 が応答 + ```C + "1122-AABB-CCGG;0;3.30V" または "1122-aabb-ccgg;0;3.30V" または "1122-aaBB-ccgg;0;3.30V" + ``` + +## デバイス状態の読み取り + +* コマンド + + ホストが送信 + ```C + "XXXX-XXXX-XXXX=?;ch=n;" + ``` + + SwitchC6 が応答 + ```C + "YYYY-YYYY-YYYY;0;z.zzV" または "YYYY-YYYY-YYYY;1;z.zzV" + ``` +* 例 + + ホストが送信 + ```C + "AABB-CCDD-EEFF=?;ch=6;" または "aabb-ccdd-eeff=?;ch=6;" または "aaBB-CCdd-eeFF=?;ch=6;" + ``` + + SwitchC6 が応答 + ```C + "1122-AABB-CCGG;0;3.30V" または "1122-aabb-ccgg;0;3.30V" または "1122-aaBB-ccgg;0;3.30V" または + "1122-AABB-CCGG;1;3.30V" または "1122-aabb-ccgg;1;3.30V" または "1122-aaBB-ccgg;1;3.30V" + ``` + +## バージョン照会 + +* コマンド + + ホストが送信 + + ```C + "XXXX-XXXX-XXXX=V;ch=n;" + ``` + + SwitchC6 が応答 + + ```C + "YYYY-YYYY-YYYY;ver" + ``` + +* 例 + + ホストが送信 + + ```C + "AABB-CCDD-EEFF=V;ch=6;" または "aabb-ccdd-eeff=V;ch=6;" または "aaBB-CCdd-eeFF=V;ch=6;" + ``` + + SwitchC6 が応答 + + ```C + "1122-AABB-CCGG;1.0.0" または "1122-aabb-ccgg;1.0.0" または "1122-aaBB-ccgg;1.0.0" + ``` + +## ボタンのブロードキャスト + +* 単押し + + SwitchC6 がブロードキャストし、スイッチ状態が 1 回トグルされます + ```C + "FFFF-FFFF-FFFF;0;z.zzV" または "FFFF-FFFF-FFFF;1;z.zzV" + ``` + +* 5 秒長押し + + SwitchC6 がブロードキャスト + ```C + "FFFF-FFFF-FFFF;0;z.zzV" または "FFFF-FFFF-FFFF;1;z.zzV" + ``` + +## 備考 + +* 送受信されるデータは文字列形式です。 +* "XXXX-XXXX-XXXX" は SwitchC6 の MAC アドレスを表し、文字列形式で大文字小文字は区別しません。 +* "YYYY-YYYY-YYYY" はホストの MAC アドレスを表し、文字列形式で大文字小文字は区別しません。 +* 通信はブロードキャストで行います。ホストはブロードキャストアドレス(FF:FF:FF:FF:FF:FF)をピアに追加する必要があります。SwitchC6 もブロードキャストで応答を送信します。ホストは "YYYY-YYYY-YYYY" により受信したパケットが自分宛かどうかを判断し、SwitchC6 は "XXXX-XXXX-XXXX" により処理対象かどうかを判断します。 +* "ch=n" の n はホストの Wi‑Fi チャネル(1〜14)です。ホストが送信するコマンドには正しいチャネルを記入する必要があります。 +* ホストが送信するコマンドでは、MAC アドレス直後の最初の文字は "=" です。 +* SwitchC6 が返すコマンドでは、MAC アドレス直後の最初の文字は ";" です。 +* "z.zzV" はコンデンサ電圧を表します。 +* 応答データでは、リレー状態とコンデンサ電圧は ";" で区切られます。 +* SwitchC6 が返信するかどうかは、ホストが送信するパケット末尾の文字が ";" かどうかで判断します。末尾が ";" の場合は返信が必要です。 +* 緑色 LED の状態はリレー状態に連動します。リレーが閉成(オン)のとき点灯し、開放(オフ)のとき消灯します。 +* ボタンが押されると、デバイスは自身の状態をブロードキャストします。SwitchC6 はチャネル 1〜14 の各チャネルで 1 回ずつパケットを送信し、パケットの宛先アドレスは FFFF-FFFF-FFFF(ブロードキャストアドレス)です。 + +## ESP-IDF 使用例 + +* ESP-NOW 送信 + + ```C + // ブロードキャスト MAC アドレス(電波範囲内のすべての ESP-NOW デバイスに送信) + const uint8_t broadcast_mac_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + // 対象デバイスの MAC アドレス(ここでは SwitchC6 の MAC) + const uint8_t switchc6_mac[6] = {0xE4, 0xB3, 0x23, 0x86, 0x18, 0xC4}; + + /** + * @brief 送信する制御コマンド一覧(文字列形式) + * + * 形式:MAC=操作;ch=チャネル; + * - 操作:1 = オン、0 = オフ、? = 状態読み取り + * - ch=6 は現在の Wi‑Fi 動作チャネルが 6 を意味します + * - 末尾のセミコロン(;)はデバイス応答が必要かどうかを示します(存在すれば応答が必要) + */ + const char *send_cmd[] = { + "E4B3-2386-18C4=1;ch=6", // リレーをオン(応答不要) + "E4B3-2386-18C4=1;ch=6;", // リレーをオン(応答必要) + "E4B3-2386-18C4=0;ch=6", // リレーをオフ(応答不要) + "E4B3-2386-18C4=0;ch=6;", // リレーをオフ(応答必要) + "E4B3-2386-18C4=?;ch=6;", // リレー状態を照会(応答必要) + }; + + // ESP-NOW を用いて上記の制御コマンドの 1 つを送信します。 + // ここでは 0 番目を送信:リレーをオン(応答待ちなし)。 + esp_now_send(broadcast_mac_addr, (const uint8_t *)send_cmd[0], strlen(send_cmd[0])); + ``` diff --git a/protocol/SwitchC6-ESP-NOW-Protocol-JP.pdf b/protocol/SwitchC6-ESP-NOW-Protocol-JP.pdf new file mode 100644 index 0000000..3e29ce2 Binary files /dev/null and b/protocol/SwitchC6-ESP-NOW-Protocol-JP.pdf differ