Browse Source

added gpio status to websocket and webui

Thomas Buck 1 month ago
parent
commit
3b6145cef3
10 changed files with 294 additions and 13 deletions
  1. 4
    0
      include/Functionality.h
  2. 2
    0
      include/GPIOBank.h
  3. 4
    0
      include/Plants.h
  4. 2
    0
      include/WifiStuff.h
  5. 1
    0
      include/config.h
  6. 6
    3
      include/config_pins.h
  7. 7
    1
      src/Functionality.cpp
  8. 35
    4
      src/GPIOBank.cpp
  9. 15
    2
      src/Plants.cpp
  10. 218
    3
      src/WifiStuff.cpp

+ 4
- 0
include/Functionality.h View File

@@ -12,6 +12,8 @@ void ui_run(void);
12 12
 
13 13
 #ifdef FUNCTION_CONTROL
14 14
 
15
+#include "Plants.h"
16
+
15 17
 void control_setup(void);
16 18
 void control_begin(void);
17 19
 void control_run(void);
@@ -19,6 +21,8 @@ void control_run(void);
19 21
 const char *control_state_name(void);
20 22
 void control_act_input(int n);
21 23
 
24
+Plants *get_plants(void);
25
+
22 26
 #endif // FUNCTION_CONTROL
23 27
 
24 28
 // ----------------------------------------------------------------------------

+ 2
- 0
include/GPIOBank.h View File

@@ -18,6 +18,8 @@ public:
18 18
 private:
19 19
     int size;
20 20
     int *pins;
21
+    bool *out_state;
22
+    bool is_output;
21 23
 };
22 24
 
23 25
 #endif // _GPIO_BANK_H_

+ 4
- 0
include/Plants.h View File

@@ -37,6 +37,10 @@ public:
37 37
     void stopPlant(int id);
38 38
     void stopAllPlants(void);
39 39
     
40
+    GPIOBank *getValves(void);
41
+    GPIOBank *getPumps(void);
42
+    GPIOBank *getSwitches(void);
43
+    
40 44
 private:
41 45
     GPIOBank valves;
42 46
     GPIOBank pumps;

+ 2
- 0
include/WifiStuff.h View File

@@ -7,6 +7,8 @@ void wifi_setup();
7 7
 void wifi_run();
8 8
 
9 9
 void wifi_set_message_buffer(String a, String b, String c, String d);
10
+void wifi_schedule_websocket(void);
11
+void wifi_send_websocket(void);
10 12
 
11 13
 #endif
12 14
 

+ 1
- 0
include/config.h View File

@@ -19,6 +19,7 @@
19 19
 
20 20
 // all given in milliseconds
21 21
 #define SERVER_HANDLE_INTERVAL 10
22
+#define WEBSOCKET_UPDATE_INTERVAL 500
22 23
 #define LED_BLINK_INTERVAL 500
23 24
 #define LED_INIT_BLINK_INTERVAL 500
24 25
 #define LED_CONNECT_BLINK_INTERVAL 250

+ 6
- 3
include/config_pins.h View File

@@ -57,14 +57,17 @@
57 57
 
58 58
 #ifdef FUNCTION_CONTROL
59 59
 
60
+// R1 R2 R3 R4  R5 R6 R7 R8
61
+//  4  0  2 15  18  5 17 16
62
+
60 63
 #define VALVE_COUNT 5
61
-#define VALVE_PINS 9, 11, 12, 13, 14
64
+#define VALVE_PINS 4, 0, 2, 15, 18
62 65
 
63 66
 #define PUMP_COUNT 3
64
-#define PUMP_PINS 15, 16, 17
67
+#define PUMP_PINS 5, 17, 16
65 68
 
66 69
 #define SWITCH_COUNT 2
67
-#define SWITCH_PINS 18, 19
70
+#define SWITCH_PINS 22, 23
68 71
 
69 72
 #endif // FUNCTION_CONTROL
70 73
 

+ 7
- 1
src/Functionality.cpp View File

@@ -421,6 +421,10 @@ void control_act_input(int n) {
421 421
     sm.input(n);
422 422
 }
423 423
 
424
+Plants *get_plants(void) {
425
+    return &plants;
426
+}
427
+
424 428
 void control_setup(void) {
425 429
     plants.setValvePins(valve_pins);
426 430
     plants.setPumpPins(pump_pins);
@@ -521,8 +525,10 @@ void write_to_all(const char *a, const char *b,
521 525
     Wire.write((int8_t)num_input);
522 526
     Wire.endTransmission();
523 527
     
524
-    wifi_set_message_buffer(a, b, c, d);
525 528
     write_lcd_to_serial(a, b, c, d);
529
+    
530
+    wifi_set_message_buffer(a, b, c, d);
531
+    wifi_send_websocket();
526 532
 }
527 533
 
528 534
 #endif // ! FUNCTION_UI

+ 35
- 4
src/GPIOBank.cpp View File

@@ -1,13 +1,21 @@
1 1
 #include <Arduino.h>
2
+
2 3
 #include "GPIOBank.h"
3 4
 
5
+#ifdef PLATFORM_ESP
6
+#include "WifiStuff.h"
7
+#endif // PLATFORM_ESP
8
+
4 9
 GPIOBank::GPIOBank(int _size) {
5 10
     size = _size;
6 11
     pins = new int[size];
12
+    out_state = new bool[size];
13
+    is_output = false;
7 14
 }
8 15
 
9 16
 GPIOBank::~GPIOBank(void) {
10 17
     delete pins;
18
+    delete out_state;
11 19
 }
12 20
 
13 21
 void GPIOBank::setPinNumbers(int _pins[]) {
@@ -18,8 +26,10 @@ void GPIOBank::setPinNumbers(int _pins[]) {
18 26
 
19 27
 void GPIOBank::setOutput(void) {
20 28
     for (int i = 0; i < size; i++) {
21
-        pinMode(pins[i], OUTPUT);
29
+        pinMode(pins[i], INPUT);
30
+        out_state[i] = true;
22 31
     }
32
+    is_output = true;
23 33
 }
24 34
 
25 35
 void GPIOBank::setInput(bool pullup) {
@@ -30,6 +40,7 @@ void GPIOBank::setInput(bool pullup) {
30 40
             pinMode(pins[i], INPUT);
31 41
         }
32 42
     }
43
+    is_output = false;
33 44
 }
34 45
 
35 46
 int GPIOBank::getSize(void) {
@@ -37,8 +48,24 @@ int GPIOBank::getSize(void) {
37 48
 }
38 49
 
39 50
 void GPIOBank::setPin(int n, bool state) {
51
+    if (!is_output) {
52
+        return;
53
+    }
54
+    
40 55
     if ((n >= 0) && (n < size)) {
41
-        digitalWrite(pins[n], state ? HIGH : LOW);
56
+        //digitalWrite(pins[n], (!state) ? HIGH : LOW);
57
+        
58
+        if (state) {
59
+            pinMode(pins[n], OUTPUT);
60
+            digitalWrite(pins[n], LOW);
61
+        } else {
62
+            pinMode(pins[n], INPUT);
63
+        }
64
+        out_state[n] = !state;
65
+        
66
+#ifdef PLATFORM_ESP
67
+        wifi_schedule_websocket();
68
+#endif // PLATFORM_ESP
42 69
     }
43 70
 }
44 71
 
@@ -50,8 +77,12 @@ void GPIOBank::setAll(bool state) {
50 77
 
51 78
 bool GPIOBank::getPin(int n) {
52 79
     if ((n >= 0) && (n < size)) {
53
-        return digitalRead(pins[n]);
80
+        if (is_output) {
81
+            return !out_state[n];
82
+        } else {
83
+            return (!digitalRead(pins[n]));
84
+        }
54 85
     } else {
55
-        return LOW;
86
+        return false;
56 87
     }
57 88
 }

+ 15
- 2
src/Plants.cpp View File

@@ -8,6 +8,19 @@ Plants::Plants(int valve_count, int pump_count, int switch_count) :
8 8
         valves(valve_count), pumps(pump_count), switches(switch_count) {
9 9
 }
10 10
 
11
+    
12
+GPIOBank *Plants::getValves(void) {
13
+    return &valves;
14
+}
15
+
16
+GPIOBank *Plants::getPumps(void) {
17
+    return &pumps;
18
+}
19
+
20
+GPIOBank *Plants::getSwitches(void) {
21
+    return &switches;
22
+}
23
+
11 24
 void Plants::setValvePins(int pins[]) {
12 25
     valves.setPinNumbers(pins);
13 26
     valves.setOutput();
@@ -32,8 +45,8 @@ void Plants::abort(void) {
32 45
 }
33 46
 
34 47
 Plants::Waterlevel Plants::getWaterlevel(void) {
35
-    bool low = !switches.getPin(0);
36
-    bool high = !switches.getPin(1);
48
+    bool low = switches.getPin(0);
49
+    bool high = switches.getPin(1);
37 50
     
38 51
     if ((!low) && (!high)) {
39 52
         return empty;

+ 218
- 3
src/WifiStuff.cpp View File

@@ -29,6 +29,7 @@ UPDATE_WEB_SERVER server(80);
29 29
 WebSocketsServer socket = WebSocketsServer(81);
30 30
 SimpleUpdater updater;
31 31
 unsigned long last_server_handle_time = 0;
32
+unsigned long last_websocket_update_time = 0;
32 33
 
33 34
 String message_buffer_a;
34 35
 String message_buffer_b;
@@ -40,6 +41,17 @@ void wifi_set_message_buffer(String a, String b, String c, String d) {
40 41
     message_buffer_b = b;
41 42
     message_buffer_c = c;
42 43
     message_buffer_d = d;
44
+}
45
+
46
+void wifi_schedule_websocket(void) {
47
+    last_websocket_update_time = 0;
48
+}
49
+
50
+void wifi_send_websocket(void) {
51
+    String a = message_buffer_a ;
52
+    String b = message_buffer_b;
53
+    String c = message_buffer_c;
54
+    String d = message_buffer_d;
43 55
     
44 56
     a.replace("\"", "'");
45 57
     b.replace("\"", "'");
@@ -47,12 +59,64 @@ void wifi_set_message_buffer(String a, String b, String c, String d) {
47 59
     d.replace("\"", "'");
48 60
     
49 61
     String ws = "{\n";
62
+    
50 63
     ws += "\"a\": \"" + a + "\",\n";
51 64
     ws += "\"b\": \"" + b + "\",\n";
52 65
     ws += "\"c\": \"" + c + "\",\n";
53 66
     ws += "\"d\": \"" + d + "\",\n";
54
-    ws += "\"state\": \"" + String(control_state_name()) + "\"\n";
67
+    
68
+    ws += "\"state\": \"" + String(control_state_name()) + "\",\n";
69
+    
70
+    ws += F("\"valves\": [ ");
71
+    for (int i = 0; i < VALVE_COUNT; i++) {
72
+        ws += "\"";
73
+        ws += get_plants()->getValves()->getPin(i) ? "1" : "0";
74
+        ws += "\"";
75
+        
76
+        if (i < (VALVE_COUNT - 1)) {
77
+            ws += ", ";
78
+        }
79
+    }
80
+    ws += " ],\n";
81
+    
82
+    ws += F("\"pumps\": [ ");
83
+    for (int i = 0; i < PUMP_COUNT; i++) {
84
+        ws += "\"";
85
+        ws += get_plants()->getPumps()->getPin(i) ? "1" : "0";
86
+        ws += "\"";
87
+        
88
+        if (i < (PUMP_COUNT - 1)) {
89
+            ws += ", ";
90
+        }
91
+    }
92
+    ws += " ],\n";
93
+    
94
+    ws += F("\"switches\": [ ");
95
+    for (int i = 0; i < SWITCH_COUNT; i++) {
96
+        ws += "\"";
97
+        ws += get_plants()->getSwitches()->getPin(i) ? "1" : "0";
98
+        ws += "\"";
99
+        
100
+        if (i < (SWITCH_COUNT - 1)) {
101
+            ws += ", ";
102
+        }
103
+    }
104
+    ws += " ],\n";
105
+    
106
+    ws += "\"switchstate\": \"";
107
+    Plants::Waterlevel wl = get_plants()->getWaterlevel();
108
+    if (wl == Plants::empty) {
109
+        ws += F("tank empty");
110
+    } else if (wl == Plants::inbetween) {
111
+        ws += F("tank half-filled");
112
+    } else if (wl == Plants::full) {
113
+        ws += F("tank full");
114
+    } else {
115
+        ws += F("invalid sensor state");
116
+    }
117
+    ws += "\"\n";
55 118
     ws += "}";
119
+    
56 120
     socket.broadcastTXT(ws);
57 121
 }
58 122
 
@@ -70,18 +134,57 @@ void handleRoot() {
70 134
     
71 135
     message += F(".ui {\n");
72 136
     message += F("width: max-content;\n");
137
+    message += F("height: max-content;\n");
73 138
     message += F("margin-right: 1em;\n");
74 139
     message += F("padding: 0 1.0em;\n");
75 140
     message += F("border: 1px dashed black;\n");
76 141
     message += F("}\n");
77 142
     
143
+    message += F(".io {\n");
144
+    message += F("width: max-content;\n");
145
+    message += F("height: max-content;\n");
146
+    message += F("margin-right: 1em;\n");
147
+    message += F("padding: 0.8em 1.0em;\n");
148
+    message += F("border: 1px dashed black;\n");
149
+    message += F("font-family: monospace;\n");
150
+    message += F("}\n");
151
+    
152
+    message += F(".switch {\n");
153
+    message += F("width: max-content;\n");
154
+    message += F("border: 1px solid black;\n");
155
+    message += F("border-radius: 50%;\n");
156
+    message += F("padding: 2em;\n");
157
+    message += F("margin: 1em;\n");
158
+    message += F("}\n");
159
+    
160
+    message += F(".valve {\n");
161
+    message += F("width: max-content;\n");
162
+    message += F("border: 1px solid black;\n");
163
+    message += F("border-radius: 50%;\n");
164
+    message += F("padding: 2em;\n");
165
+    message += F("margin: 1em;\n");
166
+    message += F("}\n");
167
+    
168
+    message += F(".pump {\n");
169
+    message += F("width: max-content;\n");
170
+    message += F("border: 1px solid black;\n");
171
+    message += F("border-radius: 50%;\n");
172
+    message += F("padding: 2em;\n");
173
+    message += F("margin: 1em;\n");
174
+    message += F("}\n");
175
+    
78 176
     message += F(".info {\n");
79
-    message += F("flex-grow: 1;\n");
177
+    message += F("width: max-content;\n");
178
+    message += F("height: max-content;\n");
179
+    message += F("padding: 0 1.0em;\n");
180
+    message += F("border: 1px dashed black;\n");
181
+    message += F("font-family: monospace;\n");
80 182
     message += F("}\n");
81 183
     
82 184
     message += F(".pad {\n");
83 185
     message += F("background: black;\n");
84 186
     message += F("border: 3px solid black;\n");
187
+    message += F("border-radius: 20px;\n");
85 188
     message += F("width: max-content;\n");
86 189
     message += F("padding: 1.5em;\n");
87 190
     message += F("margin-left: auto;\n");
@@ -90,8 +193,10 @@ void handleRoot() {
90 193
     
91 194
     message += F(".pad input {\n");
92 195
     message += F("background: #fff0cf;\n");
196
+    message += F("border-radius: 6px;\n");
93 197
     message += F("font-weight: bold;\n");
94 198
     message += F("font-family: monospace;\n");
199
+    message += F("font-size: 1.2em;\n");
95 200
     message += F("padding: 0.5em 1em;\n");
96 201
     message += F("margin: 0.5em;\n");
97 202
     message += F("}\n");
@@ -100,7 +205,8 @@ void handleRoot() {
100 205
     message += F(".lcd {\n");
101 206
     //message += F("background: #9ea18c;\n");
102 207
     message += F("background: #9ed18c;\n");
103
-    message += F("border: 3px solid black;\n");
208
+    message += F("border: 5px solid black;\n");
209
+    message += F("border-radius: 10px;\n");
104 210
     message += F("width: max-content;\n");
105 211
     message += F("padding: 0.65em 1em;\n");
106 212
     message += F("box-shadow: inset 0 0 5px 5px rgba(0,0,0,.1);\n");
@@ -111,6 +217,12 @@ void handleRoot() {
111 217
     message += F("line-height: 160%;\n");
112 218
     message += F("color: #21230e;\n");
113 219
     message += F("text-shadow: -1px 2px 1px rgba(0,0,0,.1);\n");
220
+    message += F("margin-left: auto;\n");
221
+    message += F("margin-right: auto;\n");
222
+    message += F("}\n");
223
+    
224
+    message += F("#state {\n");
225
+    message += F("text-align: center;\n");
114 226
     message += F("}\n");
115 227
     message += F("</style>\n");
116 228
     
@@ -149,6 +261,68 @@ void handleRoot() {
149 261
     message += control_state_name();
150 262
     message += F("</p></div>\n");
151 263
     
264
+    message += F("<div class='io'>\n");
265
+    message += F("Switches: <span id='switchstate'>");
266
+    
267
+    Plants::Waterlevel wl = get_plants()->getWaterlevel();
268
+    if (wl == Plants::empty) {
269
+        message += F("tank empty");
270
+    } else if (wl == Plants::inbetween) {
271
+        message += F("tank half-filled");
272
+    } else if (wl == Plants::full) {
273
+        message += F("tank full");
274
+    } else {
275
+        message += F("invalid sensor state");
276
+    }
277
+    message += F("</span>");
278
+    
279
+    message += F("<div class='container'>\n");
280
+    for (int i = 0; i < SWITCH_COUNT; i++) {
281
+        message += F("<div class='switch' style='background-color: ");
282
+        if (get_plants()->getSwitches()->getPin(i)) {
283
+            message += F("red");
284
+        } else {
285
+            message += F("green");
286
+        }
287
+        message += F(";'>S");
288
+        message += String(i + 1);
289
+        message += F("</div>");
290
+    }
291
+    message += F("</div><hr>\n");
292
+    
293
+    message += F("Valves:\n");
294
+    message += F("<div class='container'>\n");
295
+    for (int i = 0; i < VALVE_COUNT; i++) {
296
+        message += F("<div class='valve' style='background-color: ");
297
+        if (get_plants()->getValves()->getPin(i)) {
298
+            message += F("red");
299
+        } else {
300
+            message += F("green");
301
+        }
302
+        message += F(";'>V");
303
+        message += String(i + 1);
304
+        message += F("</div>");
305
+    }
306
+    message += F("</div><hr>\n");
307
+    
308
+    message += F("Pumps:\n");
309
+    message += F("<div class='container'>\n");
310
+    for (int i = 0; i < PUMP_COUNT; i++) {
311
+        message += F("<div class='pump' style='background-color: ");
312
+        if (get_plants()->getPumps()->getPin(i)) {
313
+            message += F("red");
314
+        } else {
315
+            message += F("green");
316
+        }
317
+        message += F(";'>P");
318
+        message += String(i + 1);
319
+        message += F("</div>");
320
+    }
321
+    message += F("</div><hr>\n");
322
+    message += F("Green means valve is closed / pump is off / switch is not submersed.\n");
323
+    message += F("<br>\n");
324
+    message += F("Red means valve is open / pump is running / switch is submersed.</div>\n");
325
+    
152 326
     message += F("<div class='info'><p>\n");
153 327
     message += F("Version: ");
154 328
     message += FIRMWARE_VERSION;
@@ -214,6 +388,42 @@ void handleRoot() {
214 388
     message += F(    "lcd[0].innerHTML = str;\n");
215 389
     message += F(    "var state = document.getElementById('state');\n");
216 390
     message += F(    "state.innerHTML = \"State: \" + msg.state;\n");
391
+    
392
+    message += F(    "for (let i = 0; i < ");
393
+    message += String(VALVE_COUNT);
394
+    message += F("; i++) {\n");
395
+    message += F(       "var valves = document.getElementsByClassName('valve');\n");
396
+    message += F(       "if (msg.valves[i] == '0') {\n");
397
+    message += F(           "valves[i].style = 'background-color: green;';\n");
398
+    message += F(       "} else {\n");
399
+    message += F(           "valves[i].style = 'background-color: red;';\n");
400
+    message += F(       "}\n");
401
+    message += F(    "}\n");
402
+    
403
+    message += F(    "for (let i = 0; i < ");
404
+    message += String(PUMP_COUNT);
405
+    message += F("; i++) {\n");
406
+    message += F(       "var pumps = document.getElementsByClassName('pump');\n");
407
+    message += F(       "if (msg.pumps[i] == '0') {\n");
408
+    message += F(           "pumps[i].style = 'background-color: green;';\n");
409
+    message += F(       "} else {\n");
410
+    message += F(           "pumps[i].style = 'background-color: red;';\n");
411
+    message += F(       "}\n");
412
+    message += F(    "}\n");
413
+    
414
+    message += F(    "for (let i = 0; i < ");
415
+    message += String(SWITCH_COUNT);
416
+    message += F("; i++) {\n");
417
+    message += F(       "var switches = document.getElementsByClassName('switch');\n");
418
+    message += F(       "if (msg.switches[i] == '0') {\n");
419
+    message += F(           "switches[i].style = 'background-color: green;';\n");
420
+    message += F(       "} else {\n");
421
+    message += F(           "switches[i].style = 'background-color: red;';\n");
422
+    message += F(       "}\n");
423
+    message += F(    "}\n");
424
+    
425
+    message += F(    "var switchstate = document.getElementById('switchstate');\n");
426
+    message += F(    "switchstate.innerHTML = msg.switchstate;\n");
217 427
     message += F("};\n");
218 428
     
219 429
     message += F("var buttons = document.getElementsByTagName('input');\n");
@@ -325,6 +535,11 @@ void wifi_run() {
325 535
 #endif // ARDUINO_ARCH_ESP8266
326 536
     }
327 537
     
538
+    if ((millis() - last_websocket_update_time) >= WEBSOCKET_UPDATE_INTERVAL) {
539
+        last_websocket_update_time = millis();
540
+        wifi_send_websocket();
541
+    }
542
+    
328 543
     // reset ESP every 6h to be safe
329 544
     if (millis() >= (6 * 60 * 60 * 1000)) {
330 545
         ESP.restart();

Loading…
Cancel
Save