WebSocketClientOTA.ino 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * WebSocketClientOTA.ino
  3. *
  4. * Created on: 25.10.2021
  5. *
  6. */
  7. #include <Arduino.h>
  8. #include <ArduinoJson.h>
  9. #ifdef ESP8266
  10. #include <ESP8266WiFi.h>
  11. #include <ESP8266mDNS.h>
  12. #include <Updater.h>
  13. #endif
  14. #ifdef ESP32
  15. #include "WiFi.h"
  16. #include "ESPmDNS.h"
  17. #include <Update.h>
  18. #endif
  19. #include <WiFiUdp.h>
  20. #include <ESP8266WiFiMulti.h>
  21. #include <WebSocketsClient.h>
  22. #include <Hash.h>
  23. ESP8266WiFiMulti WiFiMulti;
  24. WebSocketsClient webSocket;
  25. #define USE_SERIAL Serial
  26. // Variables:
  27. // Settable:
  28. const char *version = "1.0.0";
  29. const char *name = "mydevice";
  30. // Others:
  31. #ifdef ESP8266
  32. const char *chip = "esp8266";
  33. #endif
  34. #ifdef ESP32
  35. const char *chip = "esp32";
  36. #endif
  37. uint32_t maxSketchSpace = 0;
  38. int SketchSize = 0;
  39. bool ws_conn = false;
  40. String IpAddress2String(const IPAddress& ipAddress)
  41. {
  42. return String(ipAddress[0]) + String(".") +
  43. String(ipAddress[1]) + String(".") +
  44. String(ipAddress[2]) + String(".") +
  45. String(ipAddress[3]);
  46. }
  47. void greetings_(){
  48. StaticJsonDocument<200> doc;
  49. doc["type"] = "greetings";
  50. doc["mac"] = WiFi.macAddress();
  51. doc["ip"] = IpAddress2String(WiFi.localIP());
  52. doc["version"] = version;
  53. doc["name"] = name;
  54. doc["chip"] = chip;
  55. char data[200];
  56. serializeJson(doc, data);
  57. webSocket.sendTXT(data);
  58. }
  59. void register_(){
  60. StaticJsonDocument<200> doc;
  61. doc["type"] = "register";
  62. doc["mac"] = WiFi.macAddress();
  63. char data[200];
  64. serializeJson(doc, data);
  65. webSocket.sendTXT(data);
  66. ws_conn = true;
  67. }
  68. typedef void (*CALLBACK_FUNCTION)(JsonDocument &msg);
  69. typedef struct {
  70. char type[50];
  71. CALLBACK_FUNCTION func;
  72. } RESPONSES_STRUCT;
  73. void OTA(JsonDocument &msg){
  74. USE_SERIAL.print(F("[WSc] OTA mode: "));
  75. const char* go = "go";
  76. const char* ok = "ok";
  77. if(strncmp( msg["value"], go, strlen(go)) == 0 ) {
  78. USE_SERIAL.print(F("go\n"));
  79. SketchSize = int(msg["size"]);
  80. maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
  81. USE_SERIAL.printf("[WSc] Max sketch size: %u\n", maxSketchSpace);
  82. USE_SERIAL.printf("[WSc] Sketch size: %d\n", SketchSize);
  83. USE_SERIAL.setDebugOutput(true);
  84. if (!Update.begin(maxSketchSpace)) { //start with max available size
  85. Update.printError(Serial);
  86. ESP.restart();
  87. }
  88. } else if (strncmp( msg["value"], ok, strlen(ok)) == 0) {
  89. USE_SERIAL.print(F("OK\n"));
  90. register_();
  91. } else {
  92. USE_SERIAL.print(F("unknown value : "));
  93. USE_SERIAL.print(msg["value"].as<char>());
  94. USE_SERIAL.print(F("\n"));
  95. }
  96. }
  97. void STATE(JsonDocument &msg){
  98. // Do something with message
  99. }
  100. RESPONSES_STRUCT responses[] = {
  101. {"ota", OTA},
  102. {"state", STATE},
  103. };
  104. void text(uint8_t * payload, size_t length){
  105. // Convert mesage to something usable
  106. char msgch[length];
  107. for (unsigned int i = 0; i < length; i++)
  108. {
  109. USE_SERIAL.print((char)payload[i]);
  110. msgch[i] = ((char)payload[i]);
  111. }
  112. msgch[length] = '\0';
  113. // Parse Json
  114. StaticJsonDocument<200> doc_in;
  115. DeserializationError error = deserializeJson(doc_in, msgch);
  116. if (error) {
  117. USE_SERIAL.print(F("deserializeJson() failed: "));
  118. USE_SERIAL.println(error.c_str());
  119. return;
  120. }
  121. // Handle each TYPE of message
  122. int b = 0;
  123. for( b=0 ; strlen(responses[b].type) ; b++ )
  124. {
  125. if( strncmp(doc_in["type"], responses[b].type, strlen(responses[b].type)) == 0 ) {
  126. responses[b].func(doc_in);
  127. }
  128. }
  129. }
  130. void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
  131. switch(type) {
  132. case WStype_DISCONNECTED:
  133. USE_SERIAL.printf("[WSc] Disconnected!\n");
  134. break;
  135. case WStype_CONNECTED: {
  136. USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
  137. // send message to server when Connected
  138. // webSocket.sendTXT("Connected");
  139. greetings_();
  140. }
  141. break;
  142. case WStype_TEXT:
  143. USE_SERIAL.printf("[WSc] get text: %s\n", payload);
  144. // send message to server
  145. // webSocket.sendTXT("message here");
  146. text(payload, length);
  147. break;
  148. case WStype_BIN:
  149. USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
  150. // hexdump(payload, length);
  151. if (Update.write(payload, length) != length) {
  152. Update.printError(Serial);
  153. ESP.restart();
  154. }
  155. yield();
  156. SketchSize -= length;
  157. USE_SERIAL.printf("[WSc] Sketch size left: %u\n", SketchSize);
  158. if (SketchSize < 1){
  159. if (Update.end(true)) { //true to set the size to the current progress
  160. USE_SERIAL.printf("Update Success: \nRebooting...\n");
  161. delay(5);
  162. yield();
  163. ESP.restart();
  164. } else {
  165. Update.printError(USE_SERIAL);
  166. ESP.restart();
  167. }
  168. USE_SERIAL.setDebugOutput(false);
  169. }
  170. // send data to server
  171. // webSocket.sendBIN(payload, length);
  172. break;
  173. case WStype_PING:
  174. // pong will be send automatically
  175. USE_SERIAL.printf("[WSc] get ping\n");
  176. break;
  177. case WStype_PONG:
  178. // answer to a ping we send
  179. USE_SERIAL.printf("[WSc] get pong\n");
  180. break;
  181. }
  182. }
  183. void setup() {
  184. // USE_SERIAL.begin(921600);
  185. USE_SERIAL.begin(115200);
  186. //Serial.setDebugOutput(true);
  187. USE_SERIAL.setDebugOutput(true);
  188. USE_SERIAL.print(F("\nMAC: "));
  189. USE_SERIAL.println(WiFi.macAddress());
  190. USE_SERIAL.print(F("\nDevice: "));
  191. USE_SERIAL.println(name);
  192. USE_SERIAL.printf("\nVersion: %s\n", version);
  193. for(uint8_t t = 4; t > 0; t--) {
  194. USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
  195. USE_SERIAL.flush();
  196. delay(1000);
  197. }
  198. WiFiMulti.addAP("SSID", "PASS");
  199. //WiFi.disconnect();
  200. while(WiFiMulti.run() != WL_CONNECTED) {
  201. delay(100);
  202. }
  203. // server address, port and URL
  204. webSocket.begin("10.0.1.5", 8081, "/");
  205. // event handler
  206. webSocket.onEvent(webSocketEvent);
  207. // use HTTP Basic Authorization this is optional remove if not needed
  208. // webSocket.setAuthorization("USER", "PASS");
  209. // try ever 5000 again if connection has failed
  210. webSocket.setReconnectInterval(5000);
  211. // start heartbeat (optional)
  212. // ping server every 15000 ms
  213. // expect pong from server within 3000 ms
  214. // consider connection disconnected if pong is not received 2 times
  215. webSocket.enableHeartbeat(15000, 3000, 2);
  216. }
  217. void loop() {
  218. webSocket.loop();
  219. }