mirror of
https://github.com/m5stack/M5SwitchC6-ESP-NOW.git
synced 2026-05-20 11:41:16 -07:00
Init
This commit is contained in:
+167
@@ -0,0 +1,167 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: true
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: Auto
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
...
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 M5Stack Technology CO LTD
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
# M5SwitchC6
|
||||
|
||||
## Overview
|
||||
|
||||
### SKU:K140
|
||||
|
||||
ESP-NOW based library to control and manage Switch-C6 smart switch devices.
|
||||
|
||||
## Related Link
|
||||
|
||||
- [Function Guide (CN)](./README_FUNCTION_CN.md)
|
||||
- [Function Guide (EN)](./README_FUNCTION_EN.md)
|
||||
|
||||
## Required Libraries:
|
||||
|
||||
- [Arduino-ESP32](https://github.com/espressif/arduino-esp32)
|
||||
- [M5Unified (optional)](https://github.com/m5stack/M5Unified)
|
||||
|
||||
## License
|
||||
|
||||
- [M5SwitchC6 - MIT](LICENSE)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
# 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)
|
||||
@@ -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"
|
||||
```
|
||||
|
||||
## Button广播
|
||||
|
||||
* 单击一次
|
||||
|
||||
SwitchC6广播并且开关状态切换一次
|
||||
```C
|
||||
"FFFF-FFFF-FFFF;0;z.zzV" 或 "FFFF-FFFF-FFFF;1;z.zzV"
|
||||
```
|
||||
|
||||
* 长按5s
|
||||
|
||||
SwitchC6广播
|
||||
```C
|
||||
"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(广播地址)。
|
||||
|
||||
## ESP32-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 发送其中一条控制指令
|
||||
// 此处发送第 0 条指令,即:开启继电器,且不等待响应
|
||||
esp_now_send(broadcast_mac_addr, (const uint8_t *)send_cmd[0], strlen(send_cmd[0]));
|
||||
|
||||
```
|
||||
Binary file not shown.
@@ -0,0 +1,108 @@
|
||||
// Switch-C6 ESP-NOW 广播扫描器 / Switch-C6 ESP-NOW Broadcast Scanner
|
||||
// 使用 M5SwitchC6 库监听和解析广播数据 / Listen and parse broadcast frames using M5SwitchC6
|
||||
// 串口输出可见: MAC地址 / RSSI / 信道 / 状态 / 电压 / Serial output: MAC / RSSI / Channel / State / Voltage
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <M5Switchc6.h>
|
||||
|
||||
// ===== 可调参数 / Configurable parameters =====
|
||||
static const uint8_t FIXED_CHANNEL = 6; // 目标信道,需与对端一致;设为 0 则不改 / Target channel; must match the peer; set to 0 to keep unchanged
|
||||
static const uint16_t MAX_DEVICES = 20; // 最大设备数量 / Maximum number of devices
|
||||
// ===================
|
||||
|
||||
// 创建 M5SwitchC6 实例 / Create M5SwitchC6 instance
|
||||
M5SwitchC6 switchC6(MAX_DEVICES);
|
||||
|
||||
// 上次显示设备列表的时间 / Timestamp of last device list print
|
||||
unsigned long lastDisplayTime = 0;
|
||||
const unsigned long DISPLAY_INTERVAL = 5000; // 每5秒显示一次设备列表 / Print the device list every 5 seconds
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
|
||||
Serial.println("========================================");
|
||||
Serial.println("Switch-C6 Broadcast Scanner Starting");
|
||||
Serial.println("========================================");
|
||||
|
||||
// 1) 启动 Wi-Fi:STA(Station,工作站)模式 / Start Wi-Fi in STA (station) mode
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(); // 仅初始化协议栈,不必真的连 AP / Initialize stack only; no real AP connection
|
||||
WiFi.disconnect(false, true); // 不关闭无线,仅清理历史热点 / Keep radio on; clear saved hotspots
|
||||
|
||||
// 2) 初始化 M5SwitchC6 库 / Initialize M5SwitchC6 library
|
||||
if (!switchC6.begin()) {
|
||||
Serial.println("ERROR: M5SwitchC6 initialization failed!");
|
||||
while (true) delay(1000);
|
||||
}
|
||||
|
||||
// 3) 设置信道 / Set Wi-Fi channel
|
||||
if (FIXED_CHANNEL >= 1 && FIXED_CHANNEL <= 14) {
|
||||
if (switchC6.setChannel(FIXED_CHANNEL)) {
|
||||
Serial.printf("Channel set successfully: %u\n", FIXED_CHANNEL);
|
||||
} else {
|
||||
Serial.printf("Channel set failed: %u\n", FIXED_CHANNEL);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t currentChannel = switchC6.getChannel();
|
||||
Serial.printf("Current channel: %u\n", currentChannel);
|
||||
|
||||
// 4) 设置自动清理过期设备(每60秒检查一次,设备超5分钟无响应则清理) / Enable auto cleanup of expired devices (check every 60 s; remove if silent > 5 min)
|
||||
switchC6.setAutoCleanup(60000, 300000);
|
||||
|
||||
Serial.println("ESP-NOW broadcast scanner ready");
|
||||
Serial.println("========================================");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// 检查是否有自动清理过期设备 / Check whether expired devices were auto-cleaned
|
||||
uint16_t removedCount = switchC6.checkAutoCleanup();
|
||||
if (removedCount > 0) {
|
||||
Serial.printf("Auto cleaned %u expired devices\n", removedCount);
|
||||
}
|
||||
|
||||
// 定期显示设备列表 / Periodically display the device list
|
||||
unsigned long currentTime = millis();
|
||||
if (currentTime - lastDisplayTime >= DISPLAY_INTERVAL) {
|
||||
lastDisplayTime = currentTime;
|
||||
|
||||
uint16_t peerCount = switchC6.getPeerCount();
|
||||
|
||||
if (peerCount > 0) {
|
||||
Serial.println("========================================");
|
||||
Serial.printf("Discovered devices count: %u\n", peerCount);
|
||||
Serial.println("----------------------------------------");
|
||||
|
||||
for (uint16_t i = 0; i < peerCount; i++) {
|
||||
broadcast_packet_with_mac_t peerInfo;
|
||||
if (switchC6.getPeerInfo(i, &peerInfo)) {
|
||||
// 转换MAC地址为字符串格式 / Convert MAC address to string
|
||||
char macStr[18];
|
||||
snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
peerInfo.senderMac[0], peerInfo.senderMac[1], peerInfo.senderMac[2],
|
||||
peerInfo.senderMac[3], peerInfo.senderMac[4], peerInfo.senderMac[5]);
|
||||
|
||||
// 计算设备静默时间 / Calculate device silent time
|
||||
unsigned long silentTime = (currentTime - peerInfo.lastReceiveTime) / 1000;
|
||||
|
||||
Serial.printf("Device %d:\n", i + 1);
|
||||
Serial.printf(" MAC: %s\n", macStr);
|
||||
Serial.printf(" Channel: %u\n", peerInfo.channel);
|
||||
Serial.printf(" RSSI: %d dBm\n", peerInfo.rssi);
|
||||
Serial.printf(" Status: %s\n", peerInfo.status ? "ON" : "OFF");
|
||||
Serial.printf(" Last data: %s\n", peerInfo.lastData.c_str());
|
||||
Serial.printf(" Silent time: %lu seconds\n", silentTime);
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
Serial.println("========================================");
|
||||
} else {
|
||||
Serial.println("No devices discovered yet...");
|
||||
}
|
||||
}
|
||||
|
||||
// 主循环延迟 / Main loop delay
|
||||
delay(100);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
#include <M5Unified.h>
|
||||
#include <WiFi.h>
|
||||
#include <M5Switchc6.h>
|
||||
|
||||
// 创建 M5SwitchC6 实例,最大节点数量为16,可自定义大小 / Create M5SwitchC6 instance with max peers set to 16, customizable size
|
||||
M5SwitchC6 switchC6(16);
|
||||
//填入你的SwitchC6设备MAC地址 / Fill in your SwitchC6 device MAC address
|
||||
const String DEVICE_MAC = "E4B3-2386-18C4";
|
||||
|
||||
//是否启用wifi连接 / Enable Wi-Fi connection
|
||||
// #define USE_WIFI
|
||||
#ifdef USE_WIFI
|
||||
const char *ssid = "your_ssid";
|
||||
const char *password = "your_password";
|
||||
#endif
|
||||
|
||||
// 等待动画控制变量 / Control flag for waiting animation
|
||||
volatile bool showAnimation = false;
|
||||
TaskHandle_t animationTaskHandle = NULL;
|
||||
SemaphoreHandle_t displayMutex = NULL;
|
||||
|
||||
// 等待动画任务 / Waiting animation task
|
||||
void animationTask(void *parameter) {
|
||||
while (true) {
|
||||
if (showAnimation) {
|
||||
// 获取互斥锁 / Acquire mutex
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(50)) == pdTRUE) {
|
||||
int centerX = M5.Display.width() / 2;
|
||||
int centerY = M5.Display.height() / 2;
|
||||
static int dots = 1;
|
||||
|
||||
// 清除点号区域 - 只清除动画区域 / Clear dots area (only the animation region)
|
||||
M5.Display.fillRect(centerX - 30, centerY, 60, 20, BLACK);
|
||||
|
||||
// 显示当前数量的点号 / Draw current number of dots
|
||||
M5.Display.setCursor(centerX - dots * 6, centerY);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
for (int i = 0; i < dots; i++) {
|
||||
M5.Display.print(".");
|
||||
}
|
||||
|
||||
// 释放互斥锁 / Release mutex
|
||||
xSemaphoreGive(displayMutex);
|
||||
|
||||
dots++;
|
||||
if (dots > 5) {
|
||||
dots = 1;
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS); // 200ms延迟 / 200 ms delay
|
||||
} else {
|
||||
// 清除动画时也需要获取锁 / Also need the lock when clearing animation
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(50)) == pdTRUE) {
|
||||
int centerX = M5.Display.width() / 2;
|
||||
int centerY = M5.Display.height() / 2 + 20;
|
||||
|
||||
// 清除动画区域 / Clear animation region
|
||||
M5.Display.fillRect(centerX - 30, centerY - 10, 60, 30, BLACK);
|
||||
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 开始等待动画 / Start waiting animation
|
||||
void startWaitingAnimation() {
|
||||
showAnimation = true;
|
||||
}
|
||||
|
||||
// 停止等待动画 / Stop waiting animation
|
||||
void stopWaitingAnimation() {
|
||||
showAnimation = false;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
M5.begin();
|
||||
// M5.Display.setRotation(1);
|
||||
M5.Display.setTextSize(2);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
#ifdef USE_WIFI
|
||||
// 连接到Wi-Fi网络 / Connect to Wi-Fi network
|
||||
WiFi.begin(ssid, password);
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print("Connecting to Wi-Fi");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(500);
|
||||
}
|
||||
Serial.println("\nConnected to Wi-Fi!");
|
||||
// 串口打印连接信息 / Print connection info to serial
|
||||
Serial.printf("SSID: %s\r\n", WiFi.SSID().c_str());
|
||||
Serial.printf("IP Address: %s\r\n", WiFi.localIP().toString().c_str());
|
||||
Serial.printf("MAC Address: %s\r\n", WiFi.macAddress().c_str());
|
||||
Serial.printf("Channel: %d\r\n", WiFi.channel());
|
||||
|
||||
} else {
|
||||
Serial.println("Already connected to Wi-Fi.");
|
||||
}
|
||||
#else
|
||||
WiFi.begin();
|
||||
switchC6.setChannel(11); // 设置信道为11 / Set channel to 11
|
||||
#endif
|
||||
|
||||
M5.Display.clear();
|
||||
|
||||
// 创建互斥锁 / Create mutex
|
||||
displayMutex = xSemaphoreCreateMutex();
|
||||
|
||||
// 创建canvas,使用正确的屏幕尺寸 / Prepare display with proper size
|
||||
M5.Display.fillScreen(BLACK);
|
||||
M5.Display.setTextSize(2);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
|
||||
M5.Display.setCursor(10, 10);
|
||||
M5.Display.println("M5Switchc6 Controller");
|
||||
|
||||
if (switchC6.begin()) {
|
||||
M5.Display.setCursor(10, 60);
|
||||
M5.Display.println("A:ON B:OFF C:STATUS");
|
||||
}
|
||||
|
||||
|
||||
// 创建等待动画任务 / Create waiting animation task
|
||||
xTaskCreate(
|
||||
animationTask, // 任务函数 / Task function
|
||||
"AnimationTask", // 任务名称 / Task name
|
||||
4096, // 增加堆栈大小 / Stack size
|
||||
NULL, // 参数 / Parameter
|
||||
1, // 优先级 / Priority
|
||||
&animationTaskHandle // 任务句柄 / Task handle
|
||||
);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
M5.update();
|
||||
|
||||
// 先定义按钮变量,在互斥锁外部 / Define button layout variables outside the mutex
|
||||
int screenWidth = M5.Display.width();
|
||||
int screenHeight = M5.Display.height();
|
||||
int buttonWidth = screenWidth / 3;
|
||||
int buttonHeight = 40;
|
||||
int buttonY = screenHeight - buttonHeight;
|
||||
int button3Width = screenWidth - buttonWidth * 2; // 剩余宽度 / Remaining width
|
||||
|
||||
// 获取互斥锁后再操作canvas / Lock before drawing on the display
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
// 绘制3个按钮 / Draw 3 buttons
|
||||
// 按钮A - ON / Button A - ON
|
||||
M5.Display.fillRect(0, buttonY, buttonWidth, buttonHeight, GREEN);
|
||||
M5.Display.drawRect(0, buttonY, buttonWidth, buttonHeight, WHITE);
|
||||
M5.Display.setTextColor(BLACK);
|
||||
M5.Display.setCursor(buttonWidth/2 - 10, buttonY + 15);
|
||||
M5.Display.println("ON");
|
||||
|
||||
// 按钮B - OFF / Button B - OFF
|
||||
M5.Display.fillRect(buttonWidth, buttonY, buttonWidth, buttonHeight, RED);
|
||||
M5.Display.drawRect(buttonWidth, buttonY, buttonWidth, buttonHeight, WHITE);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.setCursor(buttonWidth + buttonWidth/2 - 15, buttonY + 15);
|
||||
M5.Display.println("OFF");
|
||||
|
||||
// 按钮C - STATUS(使用计算后的宽度避免溢出) / Button C - STATUS (use computed width to avoid overflow)
|
||||
M5.Display.fillRect(buttonWidth * 2, buttonY, button3Width, buttonHeight, BLUE);
|
||||
M5.Display.drawRect(buttonWidth * 2, buttonY, button3Width, buttonHeight, WHITE);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.setCursor(buttonWidth * 2 + button3Width/2 - 25, buttonY + 15);
|
||||
M5.Display.println("STATUS");
|
||||
|
||||
M5.Display.setTextColor(WHITE); // 恢复默认文本颜色 / Restore default text color
|
||||
|
||||
|
||||
|
||||
// 释放互斥锁 / Release mutex
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
bool deviceOn = false;
|
||||
bool deviceOff = false;
|
||||
bool deviceStatus = false;
|
||||
|
||||
// 检测物理按键(适用于有按键的设备) / Handle physical buttons (if available)
|
||||
if (M5.BtnA.wasPressed()) {
|
||||
deviceOn = true;
|
||||
}
|
||||
if (M5.BtnB.wasPressed()) {
|
||||
deviceOff = true;
|
||||
}
|
||||
if (M5.BtnC.wasPressed()) {
|
||||
deviceStatus = true;
|
||||
}
|
||||
|
||||
// 检测触摸事件(适用于有触摸屏的设备) / Handle touch events (if touch screen)
|
||||
auto touch = M5.Touch.getDetail();
|
||||
if (touch.wasPressed()) {
|
||||
int touchX = touch.x;
|
||||
int touchY = touch.y;
|
||||
|
||||
// 检查是否点击了按钮区域 / Check whether a button area is tapped
|
||||
if (touchY >= buttonY) {
|
||||
if (touchX < buttonWidth) {
|
||||
deviceOn = true;
|
||||
} else if (touchX < buttonWidth * 2) {
|
||||
deviceOff = true;
|
||||
} else {
|
||||
deviceStatus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行相应的设备控制逻辑 / Execute device control logic
|
||||
if (deviceOn) {
|
||||
// 开始等待动画 / Start waiting animation
|
||||
startWaitingAnimation();
|
||||
|
||||
// 开启设备 / Turn device ON
|
||||
if (switchC6.sendSwitchCommandWithResponse(DEVICE_MAC, true, 10000)) {
|
||||
Serial.println("开启命令发送成功"); // ON command sent successfully
|
||||
stopWaitingAnimation();
|
||||
|
||||
// 获取互斥锁后更新状态显示 / Update status display with mutex
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
M5.Display.fillRect(10, 160, 300, 30, BLACK);
|
||||
M5.Display.setCursor(10, 160);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.println("Device ON sent");
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.println("开启命令发送失败"); // Failed to send ON command
|
||||
stopWaitingAnimation();
|
||||
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
M5.Display.fillRect(10, 160, 300, 30, BLACK);
|
||||
M5.Display.setCursor(10, 160);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.println("Device ON failed");
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceOff) {
|
||||
// 开始等待动画 / Start waiting animation
|
||||
startWaitingAnimation();
|
||||
|
||||
// 关闭设备 / Turn device OFF
|
||||
if (switchC6.sendSwitchCommandWithResponse(DEVICE_MAC, false, 10000)) {
|
||||
Serial.println("关闭命令发送成功"); // OFF command sent successfully
|
||||
stopWaitingAnimation();
|
||||
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
M5.Display.fillRect(10, 160, 300, 30, BLACK);
|
||||
M5.Display.setCursor(10, 160);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.println("Device OFF sent");
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.println("关闭命令发送失败"); // Failed to send OFF command
|
||||
stopWaitingAnimation();
|
||||
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
M5.Display.fillRect(10, 160, 300, 30, BLACK);
|
||||
M5.Display.setCursor(10, 160);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.println("Device OFF failed");
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceStatus) {
|
||||
// 开始等待动画 / Start waiting animation
|
||||
startWaitingAnimation();
|
||||
|
||||
// 查询状态 / Query status
|
||||
SwitchC6ParsedData_t response;
|
||||
if (switchC6.sendStatusQueryWithResponse(DEVICE_MAC, 10000, &response)) {
|
||||
Serial.printf("设备状态: %s, 电压: %.2fV\n",
|
||||
response.switchState ? "开启" : "关闭", response.voltage); // Device status and voltage
|
||||
stopWaitingAnimation();
|
||||
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
M5.Display.fillRect(10, 160, 300, 30, BLACK);
|
||||
M5.Display.setCursor(10, 160);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.printf("S:%s V:%.2fV",
|
||||
response.switchState ? "ON" : "OFF", response.voltage);
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
} else {
|
||||
stopWaitingAnimation();
|
||||
|
||||
if (xSemaphoreTake(displayMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
M5.Display.fillRect(10, 160, 300, 30, BLACK);
|
||||
M5.Display.setCursor(10, 160);
|
||||
M5.Display.setTextColor(WHITE);
|
||||
M5.Display.println("Query failed");
|
||||
|
||||
xSemaphoreGive(displayMutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delay(20); // 减少循环频率,降低系统负载 / Slow down the loop to reduce load
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "M5SwitchC6-ESP-NOW",
|
||||
"description": "M5Stack Library of M5SwitchC6",
|
||||
"keywords": "M5Stack,M5SwitchC6",
|
||||
"authors": {
|
||||
"name": "M5Stack",
|
||||
"url": "http://www.m5stack.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/m5stack/M5SwitchC6-ESP-NOW.git"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"platforms": [
|
||||
"espressif32",
|
||||
"native"
|
||||
],
|
||||
"headers": "M5Switchc6.h",
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
name=M5SwitchC6-ESP-NOW
|
||||
version=1.1.2
|
||||
author=M5Stack
|
||||
maintainer=M5Stack
|
||||
sentence=M5Stack Library of M5SwitchC6
|
||||
paragraph=M5Stack,M5SwitchC6, See more on http://M5Stack.com
|
||||
category=Device Control
|
||||
url=https://github.com/m5stack/M5SwitchC6-ESP-NOW.git
|
||||
architectures=esp32
|
||||
includes=M5Switchc6.h
|
||||
+1463
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user