1- #include "OThreadCLI.h"
2- #include "OThreadCLI_Util.h"
3-
4- #define USER_BUTTON 9 // C6/H2 Boot button
5- #define OT_CHANNEL "24"
6- #define OT_NETWORK_KEY "00112233445566778899aabbccddeeff"
7- #define OT_MCAST_ADDR "ff05::abcd"
8- #define OT_COAP_RESOURCE_NAME "Lamp"
9-
10- const char *otSetupChild[] = {
11- // clear/disable all
12- " coap" , " stop" , " thread" , " stop" , " ifconfig" , " down" , " dataset" , " clear" ,
13- // set dataset
14- " dataset channel" , OT_CHANNEL, "dataset networkkey", OT_NETWORK_KEY, "dataset", "commit active",
15- // network start
16- " ifconfig" , " up" , " thread" , " start"
17- };
18-
19- const char *otCoapSwitch[] = {
20- // start and create a CoAP resource
21- " coap" ,
22- " start" ,
23- };
24-
25- bool otDeviceSetup(
26- const char **otSetupCmds, uint8_t nCmds1, const char **otCoapCmds, uint8_t nCmds2, ot_device_role_t expectedRole1, ot_device_role_t expectedRole2
27- ) {
28- Serial.println("Starting OpenThread.");
29- Serial.println("Running as Switch - use the BOOT button to toggle the other C6/H2 as a Lamp");
30- uint8_t i;
31- for (i = 0; i < nCmds1; i++) {
32- if (!otExecCommand(otSetupCmds[i * 2], otSetupCmds[i * 2 + 1])) {
33- break;
34- }
35- }
36- if (i != nCmds1) {
37- log_e("Sorry, OpenThread Network setup failed!");
38- neopixelWrite(RGB_BUILTIN, 255, 0, 0); // RED ... failed!
39- return false;
40- }
41- Serial.println("OpenThread started.\r\nWaiting for activating correct Device Role.");
42- // wait for the expected Device Role to start
43- uint8_t tries = 24; // 24 x 2.5 sec = 1 min
44- while (tries && otGetDeviceRole() != expectedRole1 && otGetDeviceRole() != expectedRole2) {
45- Serial.print(".");
46- delay(2500);
47- tries--;
48- }
49- Serial.println();
50- if (!tries) {
51- log_e("Sorry, Device Role failed by timeout! Current Role: %s.", otGetStringDeviceRole());
52- neopixelWrite(RGB_BUILTIN, 255, 0, 0); // RED ... failed!
53- return false;
54- }
55- Serial.printf("Device is %s.\r\n", otGetStringDeviceRole());
56- for (i = 0; i < nCmds2; i++) {
57- if (!otExecCommand(otCoapCmds[i * 2], otCoapCmds[i * 2 + 1])) {
58- break;
59- }
60- }
61- if (i != nCmds2) {
62- log_e("Sorry, OpenThread CoAP setup failed!");
63- neopixelWrite(RGB_BUILTIN, 255, 0, 0); // RED ... failed!
64- return false;
65- }
66- Serial.println("OpenThread setup done. Node is ready.");
67- // all fine! LED goes and stays Blue
68- neopixelWrite(RGB_BUILTIN, 0, 0, 64); // BLUE ... Swtich is ready!
69- return true;
70- }
71-
72- void setupNode() {
73- // tries to set the Thread Network node and only returns when succeded
74- bool startedCorrectly = false;
75- while (!startedCorrectly) {
76- startedCorrectly |= otDeviceSetup(
77- otSetupChild, sizeof(otSetupChild) / sizeof(char *) / 2, otCoapSwitch, sizeof(otCoapSwitch) / sizeof(char *) / 2, OT_ROLE_CHILD, OT_ROLE_ROUTER
78- );
79- if (!startedCorrectly) {
80- Serial.println("Setup Failed...\r\nTrying again...");
81- }
82- }
83- }
84-
85- // Sends the CoAP frame to the Lamp node
86- bool otCoapPUT(bool lampState) {
87- bool gotDone = false, gotConfirmation = false;
88- String coapMsg = "coap put ";
89- coapMsg += OT_MCAST_ADDR;
90- coapMsg += " ";
91- coapMsg += OT_COAP_RESOURCE_NAME;
92- coapMsg += " con 0";
93-
94- // final command is "coap put ff05::abcd Lamp con 1" or "coap put ff05::abcd Lamp con 0"
95- if (lampState) {
96- coapMsg[coapMsg.length() - 1] = '1';
97- }
98- OThreadCLI.println(coapMsg.c_str());
99- log_d("Send CLI CMD:[%s]", coapMsg.c_str());
100-
101- char cliResp[256];
102- // waits for the CoAP confirmation and Done message for about 1.25 seconds
103- // timeout is based on Stream::setTimeout()
104- // Example of the expected confirmation response: "coap response from fdae:3289:1783:5c3f:fd84:c714:7e83:6122"
105- uint8_t tries = 5;
106- *cliResp = '\0';
107- while (tries && !(gotDone && gotConfirmation)) {
108- size_t len = OThreadCLI.readBytesUntil('\n', cliResp, sizeof(cliResp));
109- cliResp[len - 1] = '\0';
110- log_d("Try[%d]::MSG[%s]", tries, cliResp);
111- if (strlen(cliResp)) {
112- if (!strncmp(cliResp, "coap response from", 18)) {
113- gotConfirmation = true;
114- }
115- if (!strncmp(cliResp, "Done", 4)) {
116- gotDone = true;
117- }
118- }
119- tries--;
120- }
121- if (gotDone && gotConfirmation) {
122- return true;
123- }
124- return false;
125- }
126-
127- // this fucntion is used by the Switch mode to check the BOOT Button and send the user action to the Lamp node
128- void checkUserButton() {
129- static long unsigned int lastPress = 0;
130- const long unsigned int debounceTime = 500;
131- static bool lastLampState = true; // first button press will turn the Lamp OFF from inital Green
132-
133- pinMode(USER_BUTTON, INPUT_PULLUP); // C6/H2 User Button
134- if (millis() > lastPress + debounceTime && digitalRead(USER_BUTTON) == LOW) {
135- lastLampState = !lastLampState;
136- if (!otCoapPUT(lastLampState)) { // failed: Lamp Node is not responding due to be off or unreachable
137- // timeout from the CoAP PUT message... restart the node.
138- neopixelWrite(RGB_BUILTIN, 255, 0, 0); // RED ... something failed!
139- Serial.println("Reseting the Node as Switch... wait.");
140- // start over...
141- setupNode();
142- }
143- lastPress = millis();
144- }
145- }
146-
147- void setup() {
148- Serial.begin(115200);
149- // LED starts RED, indicating not connected to Thread network.
150- neopixelWrite(RGB_BUILTIN, 64, 0, 0);
151- OThreadCLI.begin(false); // No AutoStart is necessary
152- OThreadCLI.setTimeout(250); // waits 250ms for the OpenThread CLI response
153- setupNode();
154- // LED goes and keeps Blue when all is ready and Red when failed.
155- }
156-
157- void loop() {
158- checkUserButton();
159- delay(10);
160- }
1+ {
2+ "targets" : {
3+ "esp32" : false ,
4+ "esp32c2" : false ,
5+ "esp32c3" : false ,
6+ "esp32s2" : false ,
7+ "esp32s3" : false
8+ }
9+ }
0 commit comments