Browse Source

Added auto modes. Moved defines to new header.

Thomas Buck 1 month ago
parent
commit
6ec37d4764
5 changed files with 257 additions and 36 deletions
  1. 6
    3
      include/Statemachine.h
  2. 17
    0
      include/config.h
  3. 14
    0
      src/Plants.cpp
  4. 219
    27
      src/Statemachine.cpp
  5. 1
    6
      src/main.cpp

+ 6
- 3
include/Statemachine.h View File

@@ -9,9 +9,12 @@ public:
9 9
         init,
10 10
         menu, // auto, pumps, valves
11 11
         
12
-        menu_auto, // select plant
13
-        menu_auto_mode, // select mode
14
-        menu_auto_go, // running
12
+        menu_auto, // select mode
13
+        menu_auto_fertilizer, // select fertilizer
14
+        menu_auto_fertilizer_running,
15
+        menu_auto_reservoir_running,
16
+        menu_auto_plant, // select plant
17
+        menu_auto_plant_running,
15 18
         menu_auto_done,
16 19
         
17 20
         menu_pumps, // selet pump

+ 17
- 0
include/config.h View File

@@ -0,0 +1,17 @@
1
+#ifndef _CONFIG_H_
2
+#define _CONFIG_H_
3
+
4
+//#define DEBUG_WAIT_FOR_SERIAL_CONN
5
+
6
+#define DEBUG_ENABLE_LCD_OUTPUT_ON_SERIAL
7
+#define DEBUG_ENABLE_KEYPAD_INPUT_ON_SERIAL
8
+
9
+// in milliseconds
10
+#define DISPLAY_BACKLIGHT_TIMEOUT (5UL * 60UL * 1000UL)
11
+
12
+// in seconds
13
+#define MAX_TANK_FILL_TIME 10
14
+#define AUTO_PUMP_RUNTIME 5
15
+#define MAX_AUTO_PLANT_RUNTIME 15
16
+
17
+#endif // _CONFIG_H_

+ 14
- 0
src/Plants.cpp View File

@@ -47,10 +47,12 @@ Plants::Waterlevel Plants::getWaterlevel(void) {
47 47
 }
48 48
 
49 49
 void Plants::openWaterInlet(void) {
50
+    Serial.println("Plants::openWaterInlet");
50 51
     valves.setPin(countPlants(), true);
51 52
 }
52 53
 
53 54
 void Plants::closeWaterInlet(void) {
55
+    Serial.println("Plants::closeWaterInlet");
54 56
     valves.setPin(countPlants(), false);
55 57
 }
56 58
 
@@ -59,12 +61,18 @@ int Plants::countFertilizers(void) {
59 61
 }
60 62
 
61 63
 void Plants::startFertilizer(int id) {
64
+    Serial.print("Plants::startFertilizer ");
65
+    Serial.println(id);
66
+    
62 67
     if ((id >= 0) && (id < countFertilizers())) {
63 68
         pumps.setPin(id, true);
64 69
     }
65 70
 }
66 71
 
67 72
 void Plants::stopFertilizer(int id) {
73
+    Serial.print("Plants::stopFertilizer ");
74
+    Serial.println(id);
75
+    
68 76
     if ((id >= 0) && (id < countFertilizers())) {
69 77
         pumps.setPin(id, false);
70 78
     }
@@ -81,12 +89,18 @@ int Plants::countPlants(void) {
81 89
 }
82 90
 
83 91
 void Plants::startPlant(int id) {
92
+    Serial.print("Plants::startPlant ");
93
+    Serial.println(id);
94
+    
84 95
     if ((id >= 0) && (id < countPlants())) {
85 96
         valves.setPin(id, true);
86 97
     }
87 98
 }
88 99
 
89 100
 void Plants::stopPlant(int id) {
101
+    Serial.print("Plants::stopPlant ");
102
+    Serial.println(id);
103
+    
90 104
     if ((id >= 0) && (id < countPlants())) {
91 105
         valves.setPin(id, false);
92 106
     }

+ 219
- 27
src/Statemachine.cpp View File

@@ -1,5 +1,6 @@
1 1
 #include "Plants.h"
2 2
 #include "Statemachine.h"
3
+#include "config.h"
3 4
 
4 5
 Statemachine::DigitBuffer::DigitBuffer(int _size) {
5 6
     size = _size;
@@ -83,13 +84,104 @@ void Statemachine::input(int n) {
83 84
             switch_to(init);
84 85
         }
85 86
     } else if (state == menu_auto) {
86
-        switch_to(menu);
87
-    } else if (state == menu_auto_mode) {
88
-        switch_to(menu);
89
-    } else if (state == menu_auto_go) {
90
-        switch_to(menu);
87
+        if (n == 1) {
88
+            switch_to(menu_auto_fertilizer);
89
+        } else if (n == 2) {
90
+            auto wl = plants.getWaterlevel();
91
+            if ((wl != Plants::full) && (wl != Plants::invalid)) {
92
+                plants.openWaterInlet();
93
+                selected_id = plants.countPlants() + 1;
94
+                selected_time = MAX_TANK_FILL_TIME;
95
+                start_time = millis();
96
+                switch_to(menu_auto_reservoir_running);
97
+            } else if (wl == Plants::full) {
98
+                stop_time = millis();
99
+                switch_to(menu_auto);
100
+            } else if (wl == Plants::invalid) {
101
+                error_condition = "Invalid sensor state";
102
+                state = menu_auto;
103
+                switch_to(error);
104
+            }
105
+        } else if (n == 3) {
106
+            switch_to(menu_auto_plant);
107
+        } else if ((n == -1) || (n == -2)) {
108
+            switch_to(menu);
109
+        }
110
+    } else if (state == menu_auto_fertilizer) {
111
+        if ((n >= 1) && (n <= 3)) {
112
+            auto wl = plants.getWaterlevel();
113
+            if ((wl != Plants::full) && (wl != Plants::invalid)) {
114
+                plants.startFertilizer(n - 1);
115
+                selected_id = n;
116
+                selected_time = AUTO_PUMP_RUNTIME;
117
+                start_time = millis();
118
+                switch_to(menu_auto_fertilizer_running);
119
+            } else if (wl == Plants::full) {
120
+                stop_time = millis();
121
+                switch_to(menu_auto);
122
+            } else if (wl == Plants::invalid) {
123
+                error_condition = "Invalid sensor state";
124
+                state = menu_auto;
125
+                switch_to(error);
126
+            }
127
+        } else if ((n == -1) || (n == -2)) {
128
+            switch_to(menu_auto);
129
+        }
130
+    } else if (state == menu_auto_fertilizer_running) {
131
+            plants.abort();
132
+            stop_time = millis();
133
+            switch_to(menu_auto_done);
134
+    } else if (state == menu_auto_reservoir_running) {
135
+            plants.abort();
136
+            stop_time = millis();
137
+            switch_to(menu_auto_done);
138
+    } else if (state == menu_auto_plant) {
139
+        if (n == -1) {
140
+            if (db.hasDigits()) {
141
+                backspace();
142
+                db.removeDigit();
143
+            } else {
144
+                switch_to(menu_auto);
145
+            }
146
+        } else if (n == -2) {
147
+            if (!db.hasDigits()) {
148
+                return;
149
+            }
150
+            
151
+            selected_id = number_input();
152
+            
153
+            if ((selected_id <= 0) || (selected_id > plants.countPlants())) {
154
+                error_condition = "Invalid plant ID!";
155
+                switch_to(error);
156
+            } else {
157
+                auto wl = plants.getWaterlevel();
158
+                if ((wl != Plants::empty) && (wl != Plants::invalid)) {
159
+                    plants.startPlant(selected_id - 1);
160
+                    selected_time = MAX_AUTO_PLANT_RUNTIME;
161
+                    start_time = millis();
162
+                    switch_to(menu_auto_plant_running);
163
+                } else if (wl == Plants::empty) {
164
+                    stop_time = millis();
165
+                    switch_to(menu_auto);
166
+                } else if (wl == Plants::invalid) {
167
+                    error_condition = "Invalid sensor state";
168
+                    state = menu_auto;
169
+                    switch_to(error);
170
+                }
171
+            }
172
+        } else {
173
+            if (db.spaceLeft()) {
174
+                db.addDigit(n);
175
+            } else {
176
+                backspace();
177
+            }
178
+        }
179
+    } else if (state == menu_auto_plant_running) {
180
+            plants.abort();
181
+            stop_time = millis();
182
+            switch_to(menu_auto_done);
91 183
     } else if (state == menu_auto_done) {
92
-        switch_to(menu);
184
+        switch_to(menu_auto);
93 185
     } else if (state == menu_pumps) {
94 186
         if (n == -1) {
95 187
             if (db.hasDigits()) {
@@ -311,13 +403,64 @@ void Statemachine::act(void) {
311 403
             switch_to(error);
312 404
         }
313 405
     }
406
+    
407
+    if ((state == menu_auto_fertilizer_running) || (state == menu_auto_reservoir_running)) {
408
+        unsigned long runtime = millis() - start_time;
409
+        if ((runtime / 1000UL) >= selected_time) {
410
+            // stop if timeout has been reached
411
+            plants.abort();
412
+            stop_time = millis();
413
+            switch_to(menu_auto_done);
414
+        } else if ((millis() - last_animation_time) >= 500) {
415
+            // update animation if needed
416
+            last_animation_time = millis();
417
+            switch_to(state);
418
+        }
419
+        
420
+        // check water level state
421
+        auto wl = plants.getWaterlevel();
422
+        if (wl == Plants::full) {
423
+            plants.abort();
424
+            stop_time = millis();
425
+            switch_to(menu_auto_done);
426
+        } else if (wl == Plants::invalid) {
427
+            plants.abort();
428
+            error_condition = "Invalid sensor state";
429
+            state = menu_auto;
430
+            switch_to(error);
431
+        }
432
+    }
433
+        
434
+    if (state == menu_auto_plant_running) {
435
+        unsigned long runtime = millis() - start_time;
436
+        if ((runtime / 1000UL) >= selected_time) {
437
+            // stop if timeout has been reached
438
+            plants.abort();
439
+            stop_time = millis();
440
+            switch_to(menu_auto_done);
441
+        } else if ((millis() - last_animation_time) >= 500) {
442
+            // update animation if needed
443
+            last_animation_time = millis();
444
+            switch_to(state);
445
+        }
446
+        
447
+        // check water level state
448
+        auto wl = plants.getWaterlevel();
449
+        if (wl == Plants::empty) {
450
+            plants.abort();
451
+            stop_time = millis();
452
+            switch_to(menu_auto_done);
453
+        } else if (wl == Plants::invalid) {
454
+            plants.abort();
455
+            error_condition = "Invalid sensor state";
456
+            state = menu_auto;
457
+            switch_to(error);
458
+        }
459
+    }
314 460
 }
315 461
 
316 462
 void Statemachine::switch_to(States s) {
317
-    if (s == error) {
318
-        old_state = state;
319
-    }
320
-    
463
+    old_state = state;
321 464
     state = s;
322 465
     
323 466
     if (s == init) {
@@ -334,27 +477,76 @@ void Statemachine::switch_to(States s) {
334 477
               -1);
335 478
     } else if (s == menu_auto) {
336 479
         print("------- Auto -------",
337
-              "",
338
-              "TODO not implemented",
339
-              "",
480
+              "1: Add Fertilizer",
481
+              "2: Fill Reservoir",
482
+              "3: Water a plant",
340 483
               -1);
341
-    } else if (s == menu_auto_mode) {
342
-        print("menu_auto_mode",
343
-              "",
344
-              "TODO not implemented",
345
-              "",
484
+    } else if (s == menu_auto_fertilizer) {
485
+        print("---- Fertilizer ----",
486
+              "1: Vegetation Phase",
487
+              "2: Bloom Phase",
488
+              "3: Special",
346 489
               -1);
347
-    } else if (s == menu_auto_go) {
348
-        print("menu_auto_go",
349
-              "",
350
-              "TODO not implemented",
351
-              "",
490
+    } else if (s == menu_auto_fertilizer_running) {
491
+        unsigned long runtime = millis() - start_time;
492
+        String a = String("Runtime: ") + String(runtime / 1000UL) + String("s / ") + String(selected_time) + String('s');
493
+        
494
+        unsigned long anim = runtime * 20UL / (selected_time * 1000UL);
495
+        String b;
496
+        for (unsigned long i = 0; i < anim; i++) {
497
+            b += '#';
498
+        }
499
+        
500
+        print("---- Dispensing ----",
501
+              a.c_str(),
502
+              b.c_str(),
503
+              "Hit any key to stop!",
504
+              -1);
505
+    } else if (s == menu_auto_reservoir_running) {
506
+        unsigned long runtime = millis() - start_time;
507
+        String a = String("Runtime: ") + String(runtime / 1000UL) + String("s / ") + String(selected_time) + String('s');
508
+        
509
+        unsigned long anim = runtime * 20UL / (selected_time * 1000UL);
510
+        String b;
511
+        for (unsigned long i = 0; i < anim; i++) {
512
+            b += '#';
513
+        }
514
+        
515
+        print("--- Filling Tank ---",
516
+              a.c_str(),
517
+              b.c_str(),
518
+              "Hit any key to stop!",
519
+              -1);
520
+    } else if (s == menu_auto_plant) {
521
+        String a = String("(Input 1 to ") + String(plants.countPlants()) + String(")");
522
+        
523
+        print("--- Select Plant ---",
524
+              "Which plant to water",
525
+              a.c_str(),
526
+              "Plant: ",
527
+              3);
528
+    } else if (s == menu_auto_plant_running) {
529
+        unsigned long runtime = millis() - start_time;
530
+        String a = String("Runtime: ") + String(runtime / 1000UL) + String("s / ") + String(selected_time) + String('s');
531
+        
532
+        unsigned long anim = runtime * 20UL / (selected_time * 1000UL);
533
+        String b;
534
+        for (unsigned long i = 0; i < anim; i++) {
535
+            b += '#';
536
+        }
537
+        
538
+        print("----- Watering -----",
539
+              a.c_str(),
540
+              b.c_str(),
541
+              "Hit any key to stop!",
352 542
               -1);
353 543
     } else if (s == menu_auto_done) {
354
-        print("menu_auto_done",
355
-              "",
356
-              "TODO not implemented",
357
-              "",
544
+        String a = String("after ") + String((stop_time - start_time) / 1000UL) + String("s.");
545
+        
546
+        print("------- Done -------",
547
+              "Dispensing finished",
548
+              a.c_str(),
549
+              "Hit any key for menu",
358 550
               -1);
359 551
     } else if (s == menu_pumps) {
360 552
         String a = String("(Input 1 to ") + String(plants.countFertilizers()) + String(")");

+ 1
- 6
src/main.cpp View File

@@ -3,11 +3,7 @@
3 3
 #include "SerialLCD.h"
4 4
 #include "Statemachine.h"
5 5
 #include "Plants.h"
6
-
7
-//#define DEBUG_WAIT_FOR_SERIAL_CONN
8
-
9
-#define DEBUG_ENABLE_LCD_OUTPUT_ON_SERIAL
10
-#define DEBUG_ENABLE_KEYPAD_INPUT_ON_SERIAL
6
+#include "config.h"
11 7
 
12 8
 SerialLCD lcd(9);
13 9
 
@@ -19,7 +15,6 @@ int valve_pins[5] = { 10, 11, 12, 13, 14 };
19 15
 int pump_pins[3] = { 15, 16, 17 };
20 16
 int switch_pins[2] = { 18, 19 };
21 17
 
22
-#define DISPLAY_BACKLIGHT_TIMEOUT (5UL * 60UL * 1000UL)
23 18
 unsigned long last_input_time = 0;
24 19
 bool backlight_state = true;
25 20
 

Loading…
Cancel
Save