Browse Source

added websocket lib, UI control now possible via webinterface

Thomas Buck 1 month ago
parent
commit
829c587926
7 changed files with 242 additions and 79 deletions
  1. 3
    0
      include/Functionality.h
  2. 5
    1
      include/Statemachine.h
  3. 2
    0
      platformio.ini
  4. 8
    0
      src/Functionality.cpp
  5. 52
    40
      src/SimpleUpdater.cpp
  6. 27
    0
      src/Statemachine.cpp
  7. 145
    38
      src/WifiStuff.cpp

+ 3
- 0
include/Functionality.h View File

@@ -16,6 +16,9 @@ void control_setup(void);
16 16
 void control_begin(void);
17 17
 void control_run(void);
18 18
 
19
+const char *control_state_name(void);
20
+void control_act_input(int n);
21
+
19 22
 #endif // FUNCTION_CONTROL
20 23
 
21 24
 // ----------------------------------------------------------------------------

+ 5
- 1
include/Statemachine.h View File

@@ -3,10 +3,12 @@
3 3
 
4 4
 #include <Arduino.h>
5 5
 
6
+#define stringify( name ) # name
7
+
6 8
 class Statemachine {
7 9
 public:
8 10
     enum States {
9
-        init,
11
+        init = 0,
10 12
         menu, // auto, pumps, valves
11 13
         
12 14
         menu_auto, // select mode
@@ -63,6 +65,8 @@ public:
63 65
     void input(int n);
64 66
     void act(void);
65 67
     
68
+    const char *getStateName(void);
69
+    
66 70
 private:
67 71
     void switch_to(States s);
68 72
     uint32_t number_input(void);

+ 2
- 0
platformio.ini View File

@@ -18,6 +18,7 @@ framework = arduino
18 18
 build_flags = -D PLATFORM_ESP -D FUNCTION_CONTROL
19 19
 lib_deps =
20 20
     Wire
21
+    https://github.com/Links2004/arduinoWebSockets
21 22
 
22 23
 [env:esp32_main]
23 24
 platform = espressif32
@@ -28,6 +29,7 @@ upload_protocol = esptool
28 29
 upload_port = /dev/ttyUSB1
29 30
 lib_deps =
30 31
     Wire
32
+    https://github.com/Links2004/arduinoWebSockets
31 33
 
32 34
 [env:arduino_ui]
33 35
 platform = atmelavr

+ 8
- 0
src/Functionality.cpp View File

@@ -413,6 +413,14 @@ void blink_lcd(int n, int wait) {
413 413
 
414 414
 #ifdef FUNCTION_CONTROL
415 415
 
416
+const char *control_state_name(void) {
417
+    return sm.getStateName();
418
+}
419
+
420
+void control_act_input(int n) {
421
+    sm.input(n);
422
+}
423
+
416 424
 void control_setup(void) {
417 425
     plants.setValvePins(valve_pins);
418 426
     plants.setPumpPins(pump_pins);

+ 52
- 40
src/SimpleUpdater.cpp View File

@@ -23,46 +23,58 @@
23 23
 
24 24
 void SimpleUpdater::get(void) {
25 25
     String uploadPage = F(
26
-        "<html><head>"
27
-        "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
28
-        "<title>SimpleUpdater ESP32</title>"
29
-        "</head><body>"
30
-        "<h1>SimpleUpdater</h1>"
31
-        "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
32
-        "<input type='file' name='update'>"
33
-        "<input type='submit' value='Update'>"
34
-        "</form>"
35
-        "<div id='prg'>progress: 0%</div>"
36
-        "<a href=\"/\">Back to Main Page</a>"
37
-        "<script>"
38
-        "$('form').submit(function(e){"
39
-        "e.preventDefault();"
40
-        "var form = $('#upload_form')[0];"
41
-        "var data = new FormData(form);"
42
-        " $.ajax({"
43
-        "url: '/update',"
44
-        "type: 'POST',"
45
-        "data: data,"
46
-        "contentType: false,"
47
-        "processData:false,"
48
-        "xhr: function() {"
49
-        "var xhr = new window.XMLHttpRequest();"
50
-        "xhr.upload.addEventListener('progress', function(evt) {"
51
-        "if (evt.lengthComputable) {"
52
-        "var per = evt.loaded / evt.total;"
53
-        "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
54
-        "}"
55
-        "}, false);"
56
-        "return xhr;"
57
-        "},"
58
-        "success:function(d, s) {"
59
-        "console.log('success!')" 
60
-        "},"
61
-        "error: function (a, b, c) {"
62
-        "}"
63
-        "});"
64
-        "});"
65
-        "</script>"
26
+        "<!DOCTYPE html>\n"
27
+        "<html><head>\n"
28
+        "<meta charset='utf-8'/>\n"
29
+        "<meta name='viewport' content='width=device-width, initial-scale=1'/>\n"
30
+        "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>\n"
31
+        "<title>SimpleUpdater ESP32</title>\n"
32
+        "</head><body>\n"
33
+        
34
+        "<h1>SimpleUpdater</h1>\n"
35
+        "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>\n"
36
+        "<input type='file' name='update' accept='.bin'>\n"
37
+        "<input type='submit' value='Update'>\n"
38
+        "</form>\n"
39
+        "<div id='prg'>progress: 0%</div>\n"
40
+        "<a href=\"/\">Back to Main Page</a>\n"
41
+        
42
+        "<script>\n"
43
+        "$('form').submit(function(e){\n"
44
+            "e.preventDefault();\n"
45
+            "var form = $('#upload_form')[0];\n"
46
+            "var data = new FormData(form);\n"
47
+            " $.ajax({\n"
48
+                "url: '/update',\n"
49
+                "type: 'POST',\n"
50
+                "data: data,\n"
51
+                "contentType: false,\n"
52
+                "processData:false,\n"
53
+                "xhr: function() {\n"
54
+                    "var xhr = new window.XMLHttpRequest();\n"
55
+                    "xhr.upload.addEventListener('progress', function(evt) {\n"
56
+                        "if (evt.lengthComputable) {\n"
57
+                            "var per = evt.loaded / evt.total;\n"
58
+                            "$('#prg').html('progress: ' + Math.round(per*100) + '%');\n"
59
+                        "}\n"
60
+                    "}, false);\n"
61
+                    "return xhr;\n"
62
+                "},\n"
63
+                "success: function(d, s) {\n"
64
+                    "$('#prg').html('progress: success! redirecting...');\n"
65
+                    "setTimeout(function() {\n"
66
+                        "window.location.href = '/';\n"
67
+                    "}, 3000);\n"
68
+                "},\n"
69
+                "error: function(a, b, c) {\n"
70
+                    "$('#prg').html('progress: error! redirecting...');\n"
71
+                    "setTimeout(function() {\n"
72
+                        "window.location.href = '/';\n"
73
+                    "}, 1000);\n"
74
+                "}\n"
75
+            "});\n"
76
+        "});\n"
77
+        "</script>\n"
66 78
         "</body></html>"
67 79
     );
68 80
     

+ 27
- 0
src/Statemachine.cpp View File

@@ -51,6 +51,33 @@ uint32_t Statemachine::DigitBuffer::getNumber(void) {
51 51
     return sum;
52 52
 }
53 53
 
54
+static const char *state_names[] = {
55
+    stringify(init),
56
+    stringify(menu),
57
+    stringify(menu_auto),
58
+    stringify(menu_auto_fertilizer),
59
+    stringify(menu_auto_fertilizer_running),
60
+    stringify(menu_auto_reservoir_running),
61
+    stringify(menu_auto_plant),
62
+    stringify(menu_auto_plant_running),
63
+    stringify(menu_auto_done),
64
+    stringify(menu_pumps),
65
+    stringify(menu_pumps_time),
66
+    stringify(menu_pumps_go),
67
+    stringify(menu_pumps_running),
68
+    stringify(menu_pumps_done),
69
+    stringify(menu_valves),
70
+    stringify(menu_valves_time),
71
+    stringify(menu_valves_go),
72
+    stringify(menu_valves_running),
73
+    stringify(menu_valves_done),
74
+    stringify(error)
75
+};
76
+
77
+const char *Statemachine::getStateName(void) {
78
+    return state_names[state];
79
+}
80
+
54 81
 Statemachine::Statemachine(print_fn _print, backspace_fn _backspace)
55 82
         : db(7) {
56 83
     state = init;

+ 145
- 38
src/WifiStuff.cpp View File

@@ -16,13 +16,17 @@
16 16
 
17 17
 #endif
18 18
 
19
+#include <WebSocketsServer.h>
20
+
19 21
 #include "wifi.h"
20 22
 #include "config.h"
21 23
 #include "config_pins.h"
24
+#include "Functionality.h"
22 25
 #include "SimpleUpdater.h"
23 26
 #include "WifiStuff.h"
24 27
 
25 28
 UPDATE_WEB_SERVER server(80);
29
+WebSocketsServer socket = WebSocketsServer(81);
26 30
 SimpleUpdater updater;
27 31
 unsigned long last_server_handle_time = 0;
28 32
 
@@ -36,54 +40,116 @@ void wifi_set_message_buffer(String a, String b, String c, String d) {
36 40
     message_buffer_b = b;
37 41
     message_buffer_c = c;
38 42
     message_buffer_d = d;
43
+    
44
+    a.replace("\"", "'");
45
+    b.replace("\"", "'");
46
+    c.replace("\"", "'");
47
+    d.replace("\"", "'");
48
+    
49
+    String ws = "{\n";
50
+    ws += "\"a\": \"" + a + "\",\n";
51
+    ws += "\"b\": \"" + b + "\",\n";
52
+    ws += "\"c\": \"" + c + "\",\n";
53
+    ws += "\"d\": \"" + d + "\",\n";
54
+    ws += "\"state\": \"" + String(control_state_name()) + "\"\n";
55
+    ws += "}";
56
+    socket.broadcastTXT(ws);
39 57
 }
40 58
 
41 59
 void handleRoot() {
42
-    String message = F("<html><head>\n");
43
-    message += F("<title>Giess-o-mat</title>\n");
44
-    message += F("</head><body>\n");
45
-    message += F("<h1>Giess-o-mat</h1>\n");
60
+    String message = F("<!DOCTYPE html>\n");
61
+    message += F("<html><head>\n");
62
+    message += F("<meta charset='utf-8'/>\n");
63
+    message += F("<meta name='viewport' content='width=device-width, initial-scale=1'/>\n");
64
+    message += F("<title>Gieß-o-mat</title>\n");
46 65
     
47
-    message += F("\n<pre>\n");
48
-    message += F(" ----------------------\n");
66
+    message += F("<style type='text/css'>\n");
67
+    message += F(".container {\n");
68
+    message += F("display: flex;\n");
69
+    message += F("}\n");
49 70
     
50
-    message += F("| ");
51
-    message += message_buffer_a;
52
-    for (int i = 0; i < (20 - message_buffer_a.length()); i++) {
53
-        message += ' ';
54
-    }
55
-    message += F(" |\n");
71
+    message += F(".ui {\n");
72
+    message += F("width: max-content;\n");
73
+    message += F("margin-right: 1em;\n");
74
+    message += F("padding: 0 1.0em;\n");
75
+    message += F("border: 1px dashed black;\n");
76
+    message += F("}\n");
56 77
     
57
-    message += F("| ");
58
-    message += message_buffer_b;
59
-    for (int i = 0; i < (20 - message_buffer_b.length()); i++) {
60
-        message += ' ';
61
-    }
62
-    message += F(" |\n");
78
+    message += F(".info {\n");
79
+    message += F("flex-grow: 1;\n");
80
+    message += F("}\n");
63 81
     
64
-    message += F("| ");
65
-    message += message_buffer_c;
66
-    for (int i = 0; i < (20 - message_buffer_c.length()); i++) {
67
-        message += ' ';
68
-    }
69
-    message += F(" |\n");
82
+    message += F(".pad {\n");
83
+    message += F("background: black;\n");
84
+    message += F("border: 3px solid black;\n");
85
+    message += F("width: max-content;\n");
86
+    message += F("padding: 1.5em;\n");
87
+    message += F("margin-left: auto;\n");
88
+    message += F("margin-right: auto;\n");
89
+    message += F("}\n");
70 90
     
71
-    message += F("| ");
72
-    message += message_buffer_d;
73
-    for (int i = 0; i < (20 - message_buffer_d.length()); i++) {
74
-        message += ' ';
75
-    }
76
-    message += F(" |\n");
91
+    message += F(".pad input {\n");
92
+    message += F("background: #fff0cf;\n");
93
+    message += F("font-weight: bold;\n");
94
+    message += F("font-family: monospace;\n");
95
+    message += F("padding: 0.5em 1em;\n");
96
+    message += F("margin: 0.5em;\n");
97
+    message += F("}\n");
98
+    
99
+    // https://codepen.io/hawkz/pres/RpPaGK
100
+    message += F(".lcd {\n");
101
+    //message += F("background: #9ea18c;\n");
102
+    message += F("background: #9ed18c;\n");
103
+    message += F("border: 3px solid black;\n");
104
+    message += F("width: max-content;\n");
105
+    message += F("padding: 0.65em 1em;\n");
106
+    message += F("box-shadow: inset 0 0 5px 5px rgba(0,0,0,.1);\n");
107
+    message += F("font-weight: bold;\n");
108
+    message += F("font-family: monospace;\n");
109
+    message += F("letter-spacing: 0.1em;\n");
110
+    message += F("font-size: 1.2em;\n");
111
+    message += F("line-height: 160%;\n");
112
+    message += F("color: #21230e;\n");
113
+    message += F("text-shadow: -1px 2px 1px rgba(0,0,0,.1);\n");
114
+    message += F("}\n");
115
+    message += F("</style>\n");
77 116
     
78
-    message += F(" ----------------------\n");
117
+    message += F("</head><body>\n");
118
+    message += F("<h1>Gieß-o-mat</h1>\n");
119
+    
120
+    message += F("<div class='container'>\n");
121
+    message += F("<div class='ui'>\n");
122
+    message += F("<pre class='lcd'>\n");
123
+    message += message_buffer_a + '\n';
124
+    message += message_buffer_b + '\n';
125
+    message += message_buffer_c + '\n';
126
+    message += message_buffer_d + '\n';
79 127
     message += F("</pre>\n");
80 128
     
81
-    message += F("\n<p>\n");
129
+    message += F("<form class='pad'>\n");
130
+    message += F("<input type='button' value='1'>");
131
+    message += F("<input type='button' value='2'>");
132
+    message += F("<input type='button' value='3'>");
133
+    message += F("<br>\n");
134
+    message += F("<input type='button' value='4'>");
135
+    message += F("<input type='button' value='5'>");
136
+    message += F("<input type='button' value='6'>");
137
+    message += F("<br>\n");
138
+    message += F("<input type='button' value='7'>");
139
+    message += F("<input type='button' value='8'>");
140
+    message += F("<input type='button' value='9'>");
141
+    message += F("<br>\n");
142
+    message += F("<input type='button' value='*'>");
143
+    message += F("<input type='button' value='0'>");
144
+    message += F("<input type='button' value='#'>");
145
+    message += F("</form>\n");
146
+    
147
+    message += F("<p id='state'>\n");
82 148
     message += F("State: ");
83
-    // TODO
84
-    message += F("\n</p>\n");
149
+    message += control_state_name();
150
+    message += F("</p></div>\n");
85 151
     
86
-    message += F("\n<p>\n");
152
+    message += F("<div class='info'><p>\n");
87 153
     message += F("Version: ");
88 154
     message += FIRMWARE_VERSION;
89 155
     message += F("\n<br>\n");
@@ -134,13 +200,50 @@ void handleRoot() {
134 200
 #endif
135 201
 
136 202
     message += F("<p>\n");
137
-    message += F("Try <a href=\"/update\">/update</a> for OTA firmware updates!\n");
138
-    message += F("</p>\n");
139
-    message += F("</body></html>\n");
203
+    message += F("Try <a href='/update'>/update</a> for OTA firmware updates!\n");
204
+    message += F("</p></div>\n");
205
+    message += F("</div></body>\n");
206
+    
207
+    message += F("<script type='text/javascript'>\n");
208
+    message += F("var socket = new WebSocket('ws://' + window.location.hostname + ':81');\n");
209
+    message += F("socket.onmessage = function(e) {\n");
210
+    message += F(    "var msg = JSON.parse(e.data);\n");
211
+    message += F(    "var str = msg.a + '\\n' + msg.b + '\\n' + msg.c + '\\n' + msg.d;\n");
212
+    message += F(    "console.log(str);\n");
213
+    message += F(    "var lcd = document.getElementsByClassName('lcd');\n");
214
+    message += F(    "lcd[0].innerHTML = str;\n");
215
+    message += F(    "var state = document.getElementById('state');\n");
216
+    message += F(    "state.innerHTML = \"State: \" + msg.state;\n");
217
+    message += F("};\n");
218
+    
219
+    message += F("var buttons = document.getElementsByTagName('input');\n");
220
+    message += F("for (let i = 0; i < buttons.length; i++) {\n");
221
+    message += F(    "buttons[i].addEventListener('click', updateButton);\n");
222
+    message += F("}\n");
223
+    message += F("function updateButton() {\n");
224
+    message += F(    "socket.send(this.value);\n");
225
+    message += F("}\n");
226
+    message += F("</script>\n");
227
+    message += F("</html>\n");
140 228
 
141 229
     server.send(200, "text/html", message);
142 230
 }
143 231
 
232
+void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
233
+    if ((type != WStype_TEXT) || (length != 1)) {
234
+        return;
235
+    }
236
+    
237
+    char c = payload[0];
238
+    if ((c >= '0') && (c <= '9')) {
239
+        control_act_input(c - '0');
240
+    } else if (c == '*') {
241
+        control_act_input(-1);
242
+    } else if (c == '#') {
243
+        control_act_input(-2);
244
+    }
245
+}
246
+
144 247
 void wifi_setup() {
145 248
     // Build hostname string
146 249
     String hostname = "giess-o-mat";
@@ -205,6 +308,9 @@ void wifi_setup() {
205 308
     server.begin();
206 309
     MDNS.addService("http", "tcp", 80);
207 310
     
311
+    socket.begin();
312
+    socket.onEvent(webSocketEvent);
313
+    
208 314
     Serial.println("WiFi: setup done");
209 315
 }
210 316
 
@@ -212,6 +318,7 @@ void wifi_run() {
212 318
     if ((millis() - last_server_handle_time) >= SERVER_HANDLE_INTERVAL) {
213 319
         last_server_handle_time = millis();
214 320
         server.handleClient();
321
+        socket.loop();
215 322
         
216 323
 #ifdef ARDUINO_ARCH_ESP8266
217 324
         MDNS.update();

Loading…
Cancel
Save