Browse Source

Added auto modes. Moved defines to new header.

Thomas Buck 3 years 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
         init,
9
         init,
10
         menu, // auto, pumps, valves
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
         menu_auto_done,
18
         menu_auto_done,
16
         
19
         
17
         menu_pumps, // selet pump
20
         menu_pumps, // selet pump

+ 17
- 0
include/config.h View File

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

+ 219
- 27
src/Statemachine.cpp View File

1
 #include "Plants.h"
1
 #include "Plants.h"
2
 #include "Statemachine.h"
2
 #include "Statemachine.h"
3
+#include "config.h"
3
 
4
 
4
 Statemachine::DigitBuffer::DigitBuffer(int _size) {
5
 Statemachine::DigitBuffer::DigitBuffer(int _size) {
5
     size = _size;
6
     size = _size;
83
             switch_to(init);
84
             switch_to(init);
84
         }
85
         }
85
     } else if (state == menu_auto) {
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
     } else if (state == menu_auto_done) {
183
     } else if (state == menu_auto_done) {
92
-        switch_to(menu);
184
+        switch_to(menu_auto);
93
     } else if (state == menu_pumps) {
185
     } else if (state == menu_pumps) {
94
         if (n == -1) {
186
         if (n == -1) {
95
             if (db.hasDigits()) {
187
             if (db.hasDigits()) {
311
             switch_to(error);
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
 void Statemachine::switch_to(States s) {
462
 void Statemachine::switch_to(States s) {
317
-    if (s == error) {
318
-        old_state = state;
319
-    }
320
-    
463
+    old_state = state;
321
     state = s;
464
     state = s;
322
     
465
     
323
     if (s == init) {
466
     if (s == init) {
334
               -1);
477
               -1);
335
     } else if (s == menu_auto) {
478
     } else if (s == menu_auto) {
336
         print("------- Auto -------",
479
         print("------- Auto -------",
337
-              "",
338
-              "TODO not implemented",
339
-              "",
480
+              "1: Add Fertilizer",
481
+              "2: Fill Reservoir",
482
+              "3: Water a plant",
340
               -1);
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
               -1);
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
               -1);
542
               -1);
353
     } else if (s == menu_auto_done) {
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
               -1);
550
               -1);
359
     } else if (s == menu_pumps) {
551
     } else if (s == menu_pumps) {
360
         String a = String("(Input 1 to ") + String(plants.countFertilizers()) + String(")");
552
         String a = String("(Input 1 to ") + String(plants.countFertilizers()) + String(")");

+ 1
- 6
src/main.cpp View File

3
 #include "SerialLCD.h"
3
 #include "SerialLCD.h"
4
 #include "Statemachine.h"
4
 #include "Statemachine.h"
5
 #include "Plants.h"
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
 SerialLCD lcd(9);
8
 SerialLCD lcd(9);
13
 
9
 
19
 int pump_pins[3] = { 15, 16, 17 };
15
 int pump_pins[3] = { 15, 16, 17 };
20
 int switch_pins[2] = { 18, 19 };
16
 int switch_pins[2] = { 18, 19 };
21
 
17
 
22
-#define DISPLAY_BACKLIGHT_TIMEOUT (5UL * 60UL * 1000UL)
23
 unsigned long last_input_time = 0;
18
 unsigned long last_input_time = 0;
24
 bool backlight_state = true;
19
 bool backlight_state = true;
25
 
20
 

Loading…
Cancel
Save