|
@@ -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(")");
|