WS_MQTT.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. #include "WS_MQTT.h"
  2. // The name and password of the WiFi access point
  3. const char* ssid = STASSID;
  4. const char* password = STAPSK;
  5. // Details about devices on the Waveshare cloud
  6. const char* mqtt_server = MQTT_Server;
  7. int PORT = MQTT_Port;
  8. const char* ID = MQTT_ID; // Defining device ID
  9. char pub[] = MQTT_Pub; // MQTT release topic
  10. char sub[] = MQTT_Sub; // MQTT subscribe to topics
  11. WiFiClient espClient; // MQTT initializes the contents
  12. PubSubClient client(espClient);
  13. WebServer server(80); // Declare the WebServer object
  14. StaticJsonDocument<400> sendJson;
  15. StaticJsonDocument<400> readJson;
  16. // unsigned long lastUpdateTime = 0;
  17. // const unsigned long updateInterval = 5000;
  18. bool WIFI_Connection = 0;
  19. char ipStr[16];
  20. void handleRoot() {
  21. String myhtmlPage =
  22. String("") +
  23. "<html>"+
  24. "<head>"+
  25. " <meta charset=\"utf-8\">"+
  26. " <title>ESP32 S3 Relay 6CH</title>"+
  27. " <style>" +
  28. " body {" +
  29. " font-family: Arial, sans-serif;" +
  30. " background-color: #f0f0f0;" +
  31. " margin: 0;" +
  32. " padding: 0;" +
  33. " }" +
  34. " .header {" +
  35. " text-align: center;" +
  36. " padding: 20px 0;" +
  37. " background-color: #333;" +
  38. " color: #fff;" +
  39. " margin-bottom: 20px;" +
  40. " }" +
  41. " .container {" +
  42. " max-width: 600px;" +
  43. " margin: 0 auto;" +
  44. " padding: 20px;" +
  45. " background-color: #fff;" +
  46. " border-radius: 5px;" +
  47. " box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);" +
  48. " }" +
  49. " .input-container { // " +
  50. " display: flex;" +
  51. " align-items: center;" +
  52. " margin-bottom: 10px;" +
  53. " }" +
  54. " .input-container label {" +
  55. " width: 80px;" +
  56. " margin-right: 10px;" +
  57. " }" +
  58. " .input-container input[type=\"text\"] {" +
  59. " flex: 1;" +
  60. " padding: 5px;" +
  61. " border: 1px solid #ccc;" +
  62. " border-radius: 3px;" +
  63. " margin-right: 10px; "+
  64. " }" +
  65. " .input-container button {" +
  66. " padding: 5px 10px;" +
  67. " background-color: #333;" +
  68. " color: #fff;" +
  69. " font-size: 14px;" +
  70. " font-weight: bold;" +
  71. " border: none;" +
  72. " border-radius: 3px;" +
  73. " text-transform: uppercase;" +
  74. " cursor: pointer;" +
  75. " }" +
  76. " .button-container {" +
  77. " margin-top: 20px;" +
  78. " text-align: center;" +
  79. " }" +
  80. " .button-container button {" +
  81. " margin: 0 5px;" +
  82. " padding: 10px 15px;" +
  83. " background-color: #333;" +
  84. " color: #fff;" +
  85. " font-size: 14px;" +
  86. " font-weight: bold;" +
  87. " border: none;" +
  88. " border-radius: 3px;" +
  89. " text-transform: uppercase;" +
  90. " cursor: pointer;" +
  91. " }" +
  92. " .button-container button:hover {" +
  93. " background-color: #555;" +
  94. " }" +
  95. " </style>" +
  96. "</head>"+
  97. "<body>"+
  98. " <script defer=\"defer\">"+
  99. " function ledSwitch(ledNumber) {"+
  100. " var xhttp = new XMLHttpRequest();" +
  101. " xhttp.onreadystatechange = function() {" +
  102. " if (this.readyState == 4 && this.status == 200) {" +
  103. " console.log('LED ' + ledNumber + ' state changed');" +
  104. " }" +
  105. " };" +
  106. " if (ledNumber < 7) {" +
  107. " xhttp.open('GET', '/Switch' + ledNumber, true);" +
  108. " }" +
  109. " else if(ledNumber == 7){" +
  110. " xhttp.open('GET', '/AllOn', true);" +
  111. " }" +
  112. " else if(ledNumber == 8){" +
  113. " xhttp.open('GET', '/AllOff', true);" +
  114. " }" +
  115. " xhttp.send();" +
  116. " }" +
  117. " function updateData() {"+
  118. " var xhr = new XMLHttpRequest();"+
  119. " xhr.open('GET', '/getData', true);"+
  120. // " displayErrorTextBox(false);"+
  121. " xhr.onreadystatechange = function() {"+
  122. " if (xhr.readyState === 4 && xhr.status === 200) {"+
  123. " var dataArray = JSON.parse(xhr.responseText);"+
  124. " document.getElementById('ch1').value = dataArray[0];"+
  125. " document.getElementById('ch2').value = dataArray[1];"+
  126. " document.getElementById('ch3').value = dataArray[2];"+
  127. " document.getElementById('ch4').value = dataArray[3];"+
  128. " document.getElementById('ch5').value = dataArray[4];"+
  129. " document.getElementById('ch6').value = dataArray[5];"+
  130. // " // 移除按钮的 disabled 属性,使其变为可点击状态"+
  131. " document.getElementById('btn1').removeAttribute(\'disabled\');"+
  132. " document.getElementById('btn2').removeAttribute(\'disabled\');"+
  133. " document.getElementById('btn3').removeAttribute(\'disabled\');"+
  134. " document.getElementById('btn4').removeAttribute(\'disabled\');"+
  135. " document.getElementById('btn5').removeAttribute(\'disabled\');"+
  136. " document.getElementById('btn6').removeAttribute(\'disabled\');"+
  137. " document.getElementById('btn7').removeAttribute(\'disabled\');"+
  138. " document.getElementById('btn8').removeAttribute(\'disabled\');"+
  139. // " resetErrorTextBox();"+
  140. // " displayErrorTextBox(false);"+
  141. " }"+
  142. " else if (xhr.readyState === 4 && xhr.status !== 200) {"+
  143. " displayErrorTextBox(true);"+
  144. " }"+
  145. " };"+
  146. " xhr.send();"+
  147. " }"+
  148. " function displayErrorTextBox(show) {"+
  149. " var errorTextbox = document.getElementById('errorTextbox');"+
  150. " errorTextbox.style.display = show ? 'block' : 'none';"+
  151. " }"+
  152. " function resetErrorTextBox() {"+
  153. " document.getElementById(\'errorTextbox\').value = \'\';"+
  154. " }"+
  155. " var refreshInterval = 10;"+ // Define a variable for timing, 100ms
  156. " setInterval(updateData, refreshInterval);"+ // The updateData function is executed periodically every 100ms
  157. " </script>" +
  158. "</head>"+
  159. "<body>"+
  160. " <div class=\"header\">"+
  161. " <h1>ESP32-S3-Relay-6CH</h1>"+
  162. " </div>"+
  163. " <div class=\"container\">"+
  164. " <div class=\"input-container\" style=\"margin-left: 140px;\">"+
  165. " <label for=\"input1\">CH1</label>"+
  166. " <input type=\"text\" id=\"ch1\" />"+
  167. " <button value=\"Switch1\" id=\"btn1\" disabled onclick=\"ledSwitch(1)\">Button 1</button>"+
  168. " </div>"+
  169. " <div class=\"input-container\" style=\"margin-left: 140px;\">"+
  170. " <label for=\"input2\">CH2</label>"+
  171. " <input type=\"text\" id=\"ch2\" />"+
  172. " <button value=\"Switch2\" id=\"btn2\" disabled onclick=\"ledSwitch(2)\">Button 2</button>"+
  173. " </div>"+
  174. " <div class=\"input-container\" style=\"margin-left: 140px;\">"+
  175. " <label for=\"input3\">CH3</label>"+
  176. " <input type=\"text\" id=\"ch3\" />"+
  177. " <button value=\"Switch3\" id=\"btn3\" disabled onclick=\"ledSwitch(3)\">Button 3</button>"+
  178. " </div>"+
  179. " <div class=\"input-container\" style=\"margin-left: 140px;\">"+
  180. " <label for=\"input4\">CH4</label>"+
  181. " <input type=\"text\" id=\"ch4\" />"+
  182. " <button value=\"Switch4\" id=\"btn4\" disabled onclick=\"ledSwitch(4)\">Button 4</button>"+
  183. " </div>"+
  184. " <div class=\"input-container\" style=\"margin-left: 140px;\">"+
  185. " <label for=\"input5\">CH5</label>"+
  186. " <input type=\"text\" id=\"ch5\" />"+
  187. " <button value=\"Switch5\" id=\"btn5\" disabled onclick=\"ledSwitch(5)\">Button 5</button>"+
  188. " </div>"+
  189. " <div class=\"input-container\" style=\"margin-left: 140px;\">"+
  190. " <label for=\"input6\">CH6</label>"+
  191. " <input type=\"text\" id=\"ch6\" />"+
  192. " <button value=\"Switch6\" id=\"btn6\" disabled onclick=\"ledSwitch(6)\">Button 6</button>"+
  193. " </div>"+
  194. " <div class=\"button-container\">"+
  195. " <button value=\"AllOn\" id=\"btn7\" disabled onclick=\"ledSwitch(7)\">All On</button>"+
  196. " <button value=\"AllOff\" id=\"btn8\" disabled onclick=\"ledSwitch(8)\">All Off</button>"+
  197. " </div>"+
  198. " <div id=\"errorTextbox\" style=\"display: none;\"> "+
  199. " <p>Please refresh the page</p>"+
  200. " <p>Chinese:请刷新页面</p>"+
  201. " </div>"+
  202. " </div>"+
  203. "</body>"+
  204. "</html>";
  205. server.send(200, "text/html", myhtmlPage);
  206. printf("The user visited the home page\r\n");
  207. }
  208. void handleGetData() {
  209. String json = "[";
  210. for (int i = 0; i < sizeof(Relay_Flag) / sizeof(Relay_Flag[0]); i++) {
  211. json += String(Relay_Flag[i]);
  212. if (i < sizeof(Relay_Flag) / sizeof(Relay_Flag[0]) - 1) {
  213. json += ",";
  214. }
  215. }
  216. json += "]";
  217. server.send(200, "application/json", json);
  218. }
  219. void handleSwitch(int ledNumber) {
  220. uint8_t Data[1]={0};
  221. Data[0]=ledNumber+48;
  222. Relay_Analysis(Data,WIFI_Mode);
  223. server.send(200, "text/plain", "OK");
  224. }
  225. void handleSwitch1() { handleSwitch(1); }
  226. void handleSwitch2() { handleSwitch(2); }
  227. void handleSwitch3() { handleSwitch(3); }
  228. void handleSwitch4() { handleSwitch(4); }
  229. void handleSwitch5() { handleSwitch(5); }
  230. void handleSwitch6() { handleSwitch(6); }
  231. void handleSwitch7() { handleSwitch(7); }
  232. void handleSwitch8() { handleSwitch(8); }
  233. /************************************************** MQTT *********************************************/
  234. // MQTT subscribes to callback functions for processing received messages
  235. void callback(char* topic, byte* payload, unsigned int length) {
  236. uint8_t CH_Flag = 0;
  237. String inputString;
  238. for (int i = 0; i < length; i++) {
  239. inputString += (char)payload[i];
  240. }
  241. printf("%s\r\n",inputString.c_str()); // Format of data sent back by the server {"data":{"CH1":1}}
  242. int dataBegin = inputString.indexOf("\"data\""); // Find if "data" exists in the string (quotes also)
  243. if (dataBegin == -1) {
  244. printf("Missing 'data' field in JSON. - MQTT\r\n"); // Finds if "data" exists in the string and prints if it does not
  245. return;
  246. }
  247. int CH_Begin = -1;
  248. if (inputString.indexOf("\"CH1\"", dataBegin) != -1){ // Find if "CH1" is present in the string (quotes also)
  249. CH_Flag = 1;
  250. CH_Begin = inputString.indexOf("\"CH1\"", dataBegin);
  251. }
  252. else if (inputString.indexOf("\"CH2\"", dataBegin) != -1){
  253. CH_Flag = 2;
  254. CH_Begin = inputString.indexOf("\"CH2\"", dataBegin);
  255. }
  256. else if (inputString.indexOf("\"CH3\"", dataBegin) != -1){
  257. CH_Flag = 3;
  258. CH_Begin = inputString.indexOf("\"CH3\"", dataBegin);
  259. }
  260. else if (inputString.indexOf("\"CH4\"", dataBegin) != -1){
  261. CH_Flag = 4;
  262. CH_Begin = inputString.indexOf("\"CH4\"", dataBegin);
  263. }
  264. else if (inputString.indexOf("\"CH5\"", dataBegin) != -1){
  265. CH_Flag = 5;
  266. CH_Begin = inputString.indexOf("\"CH5\"", dataBegin);
  267. }
  268. else if (inputString.indexOf("\"CH6\"", dataBegin) != -1){
  269. CH_Flag = 6;
  270. CH_Begin = inputString.indexOf("\"CH6\"", dataBegin);
  271. }
  272. else if (inputString.indexOf("\"ALL\"", dataBegin) != -1){
  273. CH_Flag = 7;
  274. CH_Begin = inputString.indexOf("\"ALL\"", dataBegin);
  275. }
  276. else{
  277. printf("Note : Non-instruction data was received - MQTT!\r\n");
  278. CH_Flag = 0;
  279. return;
  280. }
  281. int valueBegin = inputString.indexOf(':', CH_Begin);
  282. int valueEnd = inputString.indexOf('}', valueBegin);
  283. if (valueBegin != -1 && valueEnd != -1) {
  284. if(CH_Flag != 0)
  285. {
  286. String ValueStr = inputString.substring(valueBegin + 1, valueEnd);
  287. int Value = ValueStr.toInt();
  288. if(CH_Flag < 7){
  289. if(Value == 1 && Relay_Flag[CH_Flag - 1] == 0){
  290. uint8_t Data[1]={CH_Flag+48};
  291. Relay_Analysis(Data,MQTT_Mode);
  292. }
  293. else if(Value == 0 && Relay_Flag[CH_Flag - 1] == 1){
  294. uint8_t Data[1]={CH_Flag+48};
  295. Relay_Analysis(Data,MQTT_Mode);
  296. }
  297. }
  298. else if(CH_Flag == 7){
  299. if(Value == 1 && ((Relay_Flag[0] & Relay_Flag[1] & Relay_Flag[2] & Relay_Flag[3] & Relay_Flag[4] & Relay_Flag[5]) == 0)){
  300. uint8_t Data[1]={7+48};
  301. Relay_Analysis(Data,MQTT_Mode);
  302. }
  303. else if(Value == 0 && ((Relay_Flag[0] | Relay_Flag[1] | Relay_Flag[2] | Relay_Flag[3] | Relay_Flag[4] | Relay_Flag[5] )== 1)){
  304. uint8_t Data[1]={8+48};
  305. Relay_Analysis(Data,MQTT_Mode);
  306. }
  307. }
  308. }
  309. }
  310. }
  311. void setup_wifi() {
  312. uint8_t Count = 0;
  313. printf("Connecting to ");
  314. printf("%s\r\n",ssid);
  315. WiFi.mode(WIFI_STA);
  316. WiFi.begin(ssid, password);
  317. while (WiFi.status() != WL_CONNECTED) {
  318. Count++;
  319. delay(500);
  320. printf(".\r\n");
  321. if(Count % 2 == 0 && Count != 0){
  322. RGB_Light(60, 0, 0);
  323. delay(1000);
  324. RGB_Light(0, 0, 0);
  325. }
  326. if(Count % 10 == 0){ // 10 attempts failed to connect, cancel the connection, try again
  327. WiFi.disconnect();
  328. delay(100);
  329. WiFi.mode(WIFI_OFF);
  330. delay(100);
  331. WiFi.mode(WIFI_STA);
  332. delay(100);
  333. WiFi.begin(ssid, password);
  334. }
  335. if(Count > 22){ // connection fail
  336. break;
  337. }
  338. }
  339. delay(100);
  340. if(Count < 23){
  341. WIFI_Connection = 1;
  342. RGB_Light(0, 60, 0);
  343. delay(1000);
  344. RGB_Light(0, 0, 0);
  345. IPAddress myIP = WiFi.localIP();
  346. printf("AP IP address: ");
  347. sprintf(ipStr, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
  348. printf("%s\r\n", ipStr);
  349. // 注册回调函数
  350. server.on("/", handleRoot);
  351. server.on("/getData", handleGetData);
  352. server.on("/Switch1", handleSwitch1);
  353. server.on("/Switch2", handleSwitch2);
  354. server.on("/Switch3", handleSwitch3);
  355. server.on("/Switch4", handleSwitch4);
  356. server.on("/Switch5", handleSwitch5);
  357. server.on("/Switch6", handleSwitch6);
  358. server.on("/AllOn" , handleSwitch7);
  359. server.on("/AllOff" , handleSwitch8);
  360. server.begin();
  361. printf("Web server started\r\n");
  362. }
  363. else{
  364. WIFI_Connection = 0;
  365. printf("WIFI connection fails, you can use the Bluetooth debugging Assistant to control the device.\r\n");
  366. RGB_Light(60, 0, 0);
  367. }
  368. }
  369. // Reconnect to the MQTT server
  370. void reconnect() {
  371. uint8_t Count = 0;
  372. while (!client.connected()) {
  373. Count++;
  374. if (client.connect(ID)) {
  375. client.subscribe(sub);
  376. printf("Waveshare Cloud connection is successful and now you can use all features.\r\n");
  377. }
  378. else{
  379. delay(500);
  380. if(Count % 2 == 0 && Count != 0){
  381. printf("%d\r\n", client.state());
  382. RGB_Light(60, 0, 60);
  383. delay(1000);
  384. RGB_Light(0, 0, 0);
  385. }
  386. if(Count % 10 == 0){ // 10 attempts failed to connect, cancel the connection, try again
  387. client.disconnect();
  388. delay(100);
  389. client.setServer(mqtt_server, PORT);
  390. delay(100);
  391. client.setCallback(callback);
  392. delay(100);
  393. }
  394. if(Count > 32){ // connection fail
  395. Count = 0;
  396. printf("warning: Waveshare cloud connection fails. Currently, only Bluetooth control is available !!!\r\n");
  397. }
  398. }
  399. }
  400. }
  401. // Send data in JSON format to MQTT server
  402. void sendJsonData() {
  403. sendJson["ID"] = ID;
  404. String pubres;
  405. serializeJson(sendJson, pubres);
  406. int str_len = pubres.length() + 1;
  407. char char_array[str_len];
  408. pubres.toCharArray(char_array, str_len);
  409. client.publish(pub, char_array);
  410. }
  411. void MQTT_Init()
  412. {
  413. setup_wifi();
  414. if(WIFI_Connection == 1){
  415. client.setServer(mqtt_server, PORT);
  416. client.setCallback(callback);
  417. }
  418. }
  419. void MQTT_Loop()
  420. {
  421. if(WIFI_Connection == 1){
  422. // Web
  423. server.handleClient(); // Processing requests from clients
  424. // MQTT
  425. if (!client.connected()) {
  426. reconnect();
  427. }
  428. client.loop();
  429. // if (millis() - lastUpdateTime > updateInterval) { // Periodic data reporting
  430. // sendJsonData();
  431. // lastUpdateTime = millis();
  432. // }
  433. }
  434. }