forked from NineteenFire/MrAqua
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MrAqua.ino
2611 lines (2385 loc) · 83.3 KB
/
MrAqua.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// iAqua Aquarium Controller w/ iPhone-like Interface
// Written by Dan Cunningham, aka AnotherHobby @ plantedtank.net
// Various updates added by Ryan Truss, aka MrMan
// Much code was swiped, modified, and integrated or otherwise inspired from other public works
// All code is public domain, feel free to use, abuse, edit, and share
// Written for Arduino Mega 2560
//
// MrAqua v2.5.3
// -Fixed feeding restart button to only re-start timer
// -Updated screen setting menu to update brightness as it's changed rather than waiting till it
// dims and then goes bright at a touch
//
// MrAqua v2.5.2
// -Updated feeding to allow not including outlets in feeding routine
// -Updated homescreen ATO display (empty reservoir shows as alarm instead of always displaying)
//
// MrAqua v2.5.0
// -Added watchdog to reset MCU on code freezing
// -Fixed bug where aux1 in timer mode would turn off aux2
// -Updated feeding screen/home screen to show exact time remaining instead of <x minutes
// -Swapped CO2 and Heater pin/icon locations, search for "swapped" to find all instaces and revert
// -Added code to use Serial2 to send/receive information from remote LED module (send LED values,
// fan state, reading LED heatsink temperature and request for LED values)
//
// MrAqua v2.4.0
// -Fix power schedule screen (45 degree text is unreadable)
// -Update auto-dimming to use an idle after x minutes timer instead of reading ambient light
// -Home screen now shows all 3 temperatures at the same time if more than just water sensor is enabled
//
// MrAqua v2.3.6
// -Add ability for Aux1 and Aux2 to be used as repeated timer rather than single 24Hr schedule
// -Updated some of the check boxes to on/off icon to fit with theme of the program
// -Updated power alarm behaviours during feeding to avoid devices turning on/off when they shouldn't
//
// MrAqua v2.3.5
// -Fixed startup where outputs would be ON but display showing them OFF
// -Added manual ATO turn-on by pressing section on home screen (runs for max run time)
//
// MrAqua v2.3.3 / 2.3.4
// -Fixed some bugs including heatsink temp sensor using wrong pin, dosing amount limits and PCB temp
// sensor not able to read in degrees F
//
// MrAqua v2.3.2
// -Added seperate screen function for IR lights using up/down arrows
// -Dosing alarms now trigger the start but main loop turns them off. This way the program doesn't
// freeze when it starts to dose
// -Corrected heatsink temp sensor to use correct device address
//
// MrAqua v2.3.1
// -Added code from alphabeta to add a second on/off schedule for lights
// -Updated light values/system so stored values are always 0-100
// -Updated home screen dosing to correctly draw tubes and not allow remaining volume to go below 0
//
// MrAqua
// -Updated feeding routine to only toggle filter/pump/aux outputs
// -Added graph display for LED channels
// -Added routine writeToLED(channel,value) to handle writing to either PCA or Mega PWM pins
// -Modified LED PWM code to optionally use PCA9685 for 12-bit dimming
// -Added 5th/6th LED channel, moved EEPROM for LED values to 400's
// -Added lunar cycle control
// -Added probe settings menu to enable/disable temp sensors and change display units between C and F
// -Added sub-settings menus for sensors to control when fans turn on/off (external fan
// controlled by heatsink sensor, internal fan controlled by internal temp) or heater in case of
// probe 1. Also added calibration offset for probes
// -Changed feeding, update time and screen dim tracking to using RTC instead of millis
// (millis only used for tracking touch timing for better resolution)
// -Changed code for 3 pumps, reworked schedule and setting screens to select a pump and then
// individual pump dose amounts
// -Added code for ATO
// -Changed LED color setting to bargraph (0-100%) instead of up/down button
// -Added color setting menu for changing bargraph colors
// -Added routine for sending commands to sat+ with the updated bargraphs
// -switched RTClib to DS1307RTC library
// -switched to sdfat and utft_sdraw library for accessing SD card files (can use larger SD
// cards and has faster loading speeds)
// -Added read of displayInCelcius to startup
// -Added boolean displayIn12Hr to change clock to 24Hr/12Hr
//
// Original iAqua revision documentation:
// CURRENT VERSION 1.0.4
// - the smart startup routine has been reworked and fixed by robsworld78 at The Planted Tank forums!
// - added a first run routine that will zero out all EEPROM data that is needed by iAqua
//
// VERSION 1.0.3
// - fixed smartstartup routine bugs
// - fixed dosing display when resevoir goes negative due to forgettig to hit fill
// - added robsworld78 at The Planted Tank's PWM smart startup lighting code
// - fixed issue when temp turned red, and then turned feeding time red
//
// VERSION: 1.0.2
// - more accurate math for how doses were calcualted on home screen
// - updated power schedules to update home screen immediately
// - day name was off using new RTC and Time library
//
// VERSION: 1.0.1
// - created smart startup routine
// - fixed math bug with dosing pump speed saving to eeprom
// - changed PWM pins for dosing pumps to make room for RGBW PWM pins
// - changed from previous RTC library to RTClib.h
//
// VERSION: 1.0
// - initial version
//
// EEPROM locations (saved settings)
// SPACE // DESCRIPTION
// 0 //
// 1 // feeding enable filter
// 2 // feeding enable circ
// 3 // feeding enable heat
// 4 // feeding enable co2
// 5 // feeding enable aux 1
// 6 // feeding enable aux 2
// 7 // feeding minutes setting
// 8 // feeding light 1 (0 off, 1 on)
// 9 // feeding pwr light 2 (0 off, 1 on)
// 10 // feeding pwr filter (0 off, 1 on)
// 11 // feeding pwr circ (0 off, 1 on)
// 12 // feeding pwr heat (0 off, 1 on)
// 13 // feeding pwr co2 (0 off, 1 on)
// 14 // feeding pwr aux 1 (0 off, 1 on)
// 15 // feeding pwr aux 2 (0 off, 1 on)
// 16 // NOT USED
// 17 // heater off temp
// 18 // heater on temp
// 19 // NOT USED
// 20 // pump 1 dose in mL
// 21 // pump 2 dose in mL
// 22 // pump 3 dose in mL
// 23 // pump 1 sec/ml
// 24 // pump 2 sec/ml
// 25 // pump 3 sec/ml
// 26 // dosing reseviors capacity in mL
// 27 //
// 28 // screen: return home
// 29 // screen: autodim level
// 30 // screen: autodim seconds
// 31 // screen: brightness if no dim
// 32 // pump 1 remaining volume high byte ^10th
// 33 // pump 1 remaining volume low byte
// 34 // pump 2 remaining volume high byte ^10th
// 35 // pump 2 remaining volume low byte
// 36 // pump 3 remaining volume high byte ^10th
// 37 // pump 3 remaining volume low byte
// ... //
// 40 // ATO Enabled
// 41 // Reservoir switch Enabled
// 42 // Low level wait time in minutes
// 43 // Max run-time / 10
// 44 // ATO alarm flagged
// ... //
// 50 // Temp sensor 1 installed (water)
// 51 // Temp sensor 2 installed (heatsink)
// 52 // Internal sensor installed (MCP9701)
// 53 // Heatsink fan on temperature
// 54 // Heatsink fan off temperature
// 55 // Internal fan on temperature
// 56 // Internal fan off temperature
// 57 // Display in celcius?
// 58 // sensor 1 calibration offset
// 59 // sensor 2 calibration offset
// 60 // sensor 3 calibration offset
// 61 // display sensor 1 on home screen
// 62 // display sensor 2 on home screen
// 63 // display sensor 3 on home screen
// ... //
// 70 // Lunar cycle enabled
// 71 // Clouds enabled
// 72 // Cloud start hour
// 73 // Cloud start minute
// 74 // Cloud run hours
// 75 // Cloud run minutes
// 76 // Cloud channels enabled (bit 0 = chan1, bit 1 = chan2...)
// ... //
// 80 // bar 1 color
// 81 // bar 2 color
// 82 // bar 3 color
// 83 // bar 4 color
// 84 // bar 5 color
// 85 // bar 6 color
// 86 // bar 7 color
// 87 // bar 8 color
// 88 // bar 9 color
// ... //
// 100-139 // power scheudle
// 220-243 // light ramp schedule
// 280-284 // light bar colors
// 300 // pump1 onHour
// 301 // pump1 onMin
// 302 // pump1 SUN
// 303 // pump1 MON
// 304 // pump1 TUE
// 305 // pump1 WED
// 306 // pump1 THUR
// 307 // pump1 FRI
// 308 // pump1 SAT
// 309-317 // pump2
// 318-326 // pump3
// ... //
// 400+ // LED values
#include <avr/wdt.h> //added for WDT
#include <Wire.h> // needed by tons of stuff
#include <EEPROM.h> // used to store and retrieve settings from memory
#include <UTFT.h> // used to interface with the TFT display
#include <SdFat.h>
#include <UTFT_SdRaw.h>
#include <URTouch.h> // used to interface with the touch controller on the TFT display
#include <DS1307RTC.h>
//#include <DS3232RTC.h>
#include <TimeLib.h>
#include <TimeAlarms.h> // used to power schedules
#include <IRremote.h> // used to send IR commands to the light, LED must be on pin 9
#include <OneWire.h> // network library to communicate with the DallasTemperature sensor,
#include <DallasTemperature.h> // library for the Temp sensor itself
#include <Adafruit_PWMServoDriver.h> //PCA9865
UTFT myGLCD(SSD1289,38,39,40,41); // start up an instance of the TFT screen
URTouch myTouch(46,45,44,43,42); // start up an instance of for touch
//URTouch myTouch(6, 5, 4, 3, 2); // For standard TFT shield
// file system object
SdFat sd;
const byte ChipSelect = 53; // For TFT Shield
UTFT_SdRaw myFiles(&myGLCD);
// Declare which fonts we will be using
extern uint8_t Sinclair_S[];
extern uint8_t arial_bold[];
//initialize PCA9865
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);
// define relay pins
const int pwrLight1Pin = A0;
const int pwrLight2Pin = A1;
const int pwrFilterPin = A2;
const int pwrCircPin = A3;
//const int pwrHeatPin = A4; //normal operation
//const int pwrCO2Pin = A5; //normal operation
const int pwrHeatPin = A5;//co2/heater pins swapped
const int pwrCO2Pin = A4; //co2/heater pins swapped
const int pwrAux1Pin = A6;
const int pwrAux2Pin = A7;
//define misc pins
const int lightSensorPin = A8; // analog pin for the ambient light sensor
const int pressureSensorPin = A9; // analog pin for the CO2 pressure sensor
const int fan1Pin = A11;
const int fan2Pin = A12;
const int internalTempPin = A13;
const int ATOFloatPin = A14;
const int TankFloatPin = A15;
const int screenBrightPin = 8; // pwm pin for the LCD backlight
//define pump pins
const int dosingPump1 = 10;
const int dosingPump2 = 11;
const int dosingPump3 = 12;
const int ATOPumpPin = 13;
// define RGBW PWM pins
const int led1Pin = 2;
const int led2Pin = 3;
const int led3Pin = 4;
const int led4Pin = 5;
const int led5Pin = 6;
const int led6Pin = 7;
// Pins for temperature sensor
#define ONE_WIRE_BUS_W 47 //water sensor on pin 47
#define ONE_WIRE_BUS_H 49 //Heatsink sensor on pin 49
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWireW(ONE_WIRE_BUS_W);
OneWire oneWireH(ONE_WIRE_BUS_H);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensorW(&oneWireW);
DallasTemperature sensorH(&oneWireH);
// Device address variables
DeviceAddress waterSensor;
DeviceAddress heatsinkSensor;
// create an IR instance
IRsend irsend;
byte dispScreen=0; // screens are listed below
//1-home
// 2-feeding
// 3-power
// 4-settings
// 5 - Light Settings
// 6 - clock
// 7 - feed settings
// 18- sensor settings
// 8 - heater settings
// 19- heatsink fan settings
// 20- internal fan settings
// 9 - Schedule
// 11 - Power schedule
// 12 - Power item
// 15 - Dosing
// 13 - Light ramps schedule screen
// 14 - light ramp schedule
// 10 - Dosing settings (index 1-3 for pump#)
// 16 - Screen settings
// 17 - ATO settings
// 21 - Lunar settings
// 22 - Light bargraph color settings
// 23 - LED graph
// 24 - Light Settings for IR lights
byte scheduleItem; // track which item is being scheduled
byte currentLightMode=0; //0=high sun, 1=mid sun, 2=low sun, 3=moon, 4=transition, 5=unknown
byte lightEditing=0; // track if we are actively editing lights
// the next 5 variables will be set at the start of a lighting fade
int fadeDurationSeconds = 0;
unsigned long fadeStartingSeconds = 0;
unsigned long fadeTimeLeft;
boolean fadeInProgress = false;
byte fadeFromMode = 0; //0=high sun, 1=mid sun, 2=low sun, 3=moon
byte fadeToMode = 0; //0=high sun, 1=mid sun, 2=low sun, 3=moon
struct RGBW // for storing light intensity values
{
unsigned int chan1;
unsigned int chan2;
unsigned int chan3;
unsigned int chan4;
unsigned int chan5;
unsigned int chan6;
};
typedef struct RGBW LightColor;
LightColor currentColor = {
0,0,0,0,0,0}; // The current color of the light (used for fading)
LightColor lastColor = {
0,0,0,0,0,0}; // The previous color of the light (used for fading)
LightColor targetColor = {
0,0,0,0,0,0}; // The target color of the light (used for fading)
LightColor tempColor = {
0,0,0,0,0,0}; // The temporary color of the light (used for updating sat+)
LightColor lightHighSun = {
0,0,0,0,0,0}; // store the RGBW values for the CS+ M1 button
LightColor lightMidSun = {
0,0,0,0,0,0}; // store the RGBW values for the CS+ M2 button
LightColor lightLowSun = {
0,0,0,0,0,0}; // store the RGBW values for the CS+ M3 button
LightColor lightMoon = {
0,0,0,0,0,0}; // store the RGBW values for the CS+ M4 button
//red, green, blue, white, yellow, violet, aqua
const unsigned int VGAColor[] = {0xF800, 0x07E0, 0x001F, 0xFFFF, 0xFFE0, 0xF81F, 0x07FF};
//store colours for bargraphs
byte barColors[6] = {0,1,2,3,4,5};
byte selectedChan = 0; // used for tracking which channel is selected when changing colors
// used for time
tmElements_t prevRTC, saveRTC;
boolean displayIn12Hr = true;
// used for storing power states of relays
struct PWR
{
byte pwrLight1;
byte pwrLight2;
byte pwrFilter;
byte pwrCirc;
byte pwrHeat;
byte pwrCO2;
byte pwrAux1;
byte pwrAux2;
}
feedPower, preFeedPower, globalPower;
// used for storing power states of relays
struct FEED
{
byte pwrLight1;
byte pwrLight2;
byte pwrFilter;
byte pwrCirc;
byte pwrHeat;
byte pwrCO2;
byte pwrAux1;
byte pwrAux2;
}
feedSetting;
// holds the schedule for power relays and light ramping
struct PWRSCHED
{
byte active;
byte onHour;
byte onMinute;
byte offHour;
byte offMinute;
byte timer;
}
schedLights1,schedLights1s2,schedLights2,schedLights2s2,schedCirc,schedCo2,schedAux1,schedAux2,
ramp1,ramp2,ramp3,ramp4,ramp5,ramp6;
unsigned long aux1TimerStart = 0;
unsigned long aux1TimerFinish = 0;
unsigned long aux2TimerStart = 0;
unsigned long aux2TimerFinish = 0;
boolean aux1TimerState = false;
boolean aux2TimerState = false;
// holds the schedulin for 2 dosing pumps
struct PUMPSCHED
{
byte onHour;
byte onMinute;
byte Sunday;
byte Monday;
byte Tuesday;
byte Wednesday;
byte Thursday;
byte Friday;
byte Saturday;
}
pump1, pump2, pump3;
int x, y; //touch coordinates
//Feeding variables
boolean feedingActive=false; // track if feeding is currently active
byte feedingMins=0; // stores how long the feeding should be
time_t lastFeedingTime; //time of last feeding
time_t startFeedingTime;
// Sensor variables
boolean displayInC = true;
boolean sensor1Enabled = true; // water
boolean sensor2Enabled = false; // heatsink
boolean sensor3Enabled = false; // internal
boolean displaySensor1 = true;
boolean displaySensor2 = true;
boolean displaySensor3 = false;
byte sensorToDisplay = 1;
float temperature = 0; // water temperature
float temperature2 = 0; // heatsink temperature
float temperature3 = 0; // internal temperature
float sensor1Calibration = 0.0; // calibration offset for sensor 1 (water)
float sensor2Calibration = 0.0; // calibration offset for sensor 2 (heatsink)
float sensor3Calibration = 0.0; // calibration offset for sensor 3 (internal)
boolean fan1status = false;
boolean fan2status = false;
byte internalFanOnTemp = 45;
byte internalFanOffTemp = 40;
byte heatsinkFanOnTemp = 40;
byte heatsinkFanOffTemp = 45;
//heater variables
boolean heaterWarning=false; // keeps track if there is an active overheating issue
boolean heaterWarningCleared=true; // keeps track if we clear the warning, impacts home screen icon
byte heatOffTemp = 30;
byte heatOnTemp = 25;
//dosing pump variables
boolean pump1State = false;
boolean pump2State = false;
boolean pump3State = false;
unsigned long pump1StartMillis = 0;
unsigned long pump2StartMillis = 0;
unsigned long pump3StartMillis = 0;
unsigned long pump1millis = 0;
unsigned long pump2millis = 0;
unsigned long pump3millis = 0;
//ATO variables
boolean ATOEnabled = true;
boolean ResSwitchEnabled = false;
boolean WaterLevel = HIGH;
boolean ReservoirLevel = HIGH;
boolean ATOAlarm = false;
boolean ATOPumpState = LOW;
time_t ATOStartTime = 0;
time_t ATOPumpStartTime = 0;
unsigned long ATORunTime = 120; //seconds to run ATO pump for before flagging an alarm
unsigned long ATOWaitTime = 60; //time to wait in minutes
// various millis to keep track of touch timing
unsigned long prevMillisTouch = 0;
unsigned int touchWaitTime = 350;
#define LONG_WAIT 500
#define MEDIUM_WAIT 150
#define SHORT_WAIT 25
// time variables to track clock updating, dimming timing and time to return home from a menu
time_t lastUpdateTime = 0; // track 5 seconds for refreshing clock and temp
time_t lastCheckTime = 0; // track 1 second for checking ATO and feeding
time_t dimTime = 0; // used for brightness adjustment
time_t homeTime = 0; // used for returning home after configured time
// screen settings corresponding to eeprom values 28-31
byte screenRetHome, screenDimLevel, screenDimSec, screenBrightMem, screenBrightness;
boolean idleScreenState = false;
byte backLight = 255; // startup brightness to 100%
boolean backlightTouch = true; // initial setting of true to start the screen bright after boot
// if you have a Current Satellite Plus, this is true
// if you are controlling your lights directly with PWM, this is false
boolean lightCSP = false;
int maxIR = 100; //using e-series
//If PCA9865 is installed this is true, otherwise it is false to use Arduino PWM pins
boolean PCA9685Installed = true;
//variable for Serial2 communication with remote arduino
#define INPUT_SIZE 20
char input[INPUT_SIZE+1];
/*
// REMOTE CONTROL CODES FOR CURRENT SATELLITE PLUS
const unsigned long POWER = 0x20DF02FD;
const unsigned long FULLORANGE = 0x20DF3AC5;
const unsigned long FULLLIGHTBLUE = 0x20DFBA45;
const unsigned long FULLPURPLE = 0x20DF827D;
const unsigned long FULLWHITE = 0x20DF1AE5;
//const unsigned long FULLYELLOW = 0x20DF9A65;
const unsigned long FULLSPECTRUM = 0x20DF9A65;
const unsigned long FULLBLUE = 0x20DFA25D;
const unsigned long REDUP = 0x20DF2AD5;
const unsigned long REDDOWN = 0x20DF0AF5;
const unsigned long GREENUP = 0x20DFAA55;
const unsigned long GREENDOWN = 0x20DF8A75;
const unsigned long BLUEUP = 0x20DF926D;
const unsigned long BLUEDOWN = 0x20DFB24D;
const unsigned long WHITEUP = 0x20DF12ED;
const unsigned long WHITEDOWN = 0x20DF32CD;
const unsigned long M1 = 0x20DF38C7;
const unsigned long M2 = 0x20DFB847;
const unsigned long M3 = 0x20DF7887;
const unsigned long M4 = 0x20DFF807;*/
// REMOTE CONTROL CODES FOR ECOXOTIC E-SERIES
const unsigned long POWER = 0x20DF02FD;
const unsigned long FULLSPECTRUM = 0x20DFAA55;
const unsigned long ENTER = 0x20DFA25D;
const unsigned long RESUME = 0x20DF22DD;
const unsigned long DYNAMICLIGHTNING = 0x20DFA857;
const unsigned long DYNAMICCLOUD = 0x20DF6897;
const unsigned long REDUP = 0x20DF0AF5;
const unsigned long REDDOWN = 0x20DF38C7;
const unsigned long GREENUP = 0x20DF8A75;
const unsigned long GREENDOWN = 0x20DFB847;
const unsigned long BLUEUP = 0x20DFB24D;
const unsigned long BLUEDOWN = 0x20DF7887;
const unsigned long WHITEUP = 0x20DF32CD;
const unsigned long WHITEDOWN = 0x20DFF807;
const unsigned long M1 = 0x20DF58A7; //Daylight on remote
const unsigned long M2 = 0x20DF9867;
const unsigned long M3 = 0x20DF18E7;
const unsigned long M4 = 0x20DFD827; //Moon on remote
// selected lights mode buttons for lights screen
char *lightModeS[] = {
"5hsunS.raw","5msunS.raw","5lsunS.raw","5moonS.raw"};
// off lights mode buttons for lights screen
char *lightModeF[] = {
"5hmsunF.raw","5lsunF.raw","5moonF.raw"};
// neutral lights mode buttons for lights screen
char *lightMode[] = {
"5hsun.raw","5msun.raw","5lsun.raw","5moon.raw"};
// editing buttons for the lights screen, disabled and enabled
char *lightEdit[] = {
"5editF.raw", "5editN.raw"};
char *lightSave[] = {
"5saveF.raw", "5saveN.raw"};
char *lightResync[] = {
"5resynF.raw", "5resynN.raw"};
char *lightCancel[] = {
"5canF.raw", "5canN.raw"};
// lights adjustment buttons for lights screen (RGBW up and down)
char *lightWhite[] = {
"5Wup.raw", "5Wdown.raw"};
char *lightRed[] = {
"5Rup.raw", "5Rdown.raw"};
char *lightGreen[] = {
"5Gup.raw", "5Gdown.raw"};
char *lightBlue[] = {
"5Bup.raw", "5Bdown.raw"};
char *lightGray[] = {
"5Fup.raw", "5Fdown.raw"}; // disabled button
// large power buttons for the power screen and the feeding configuration screen, off and on
char *pwrLightIcon[] = {
"3light_F.raw","3light_N.raw"};
char *pwrFilterIcon[] = {
"3filt_F.raw","3filt_N.raw"};
char *pwrCircIcon[] = {
"3circ_F.raw","3circ_N.raw"};
char *pwrHeatIcon[] = {
"3heat_F.raw","3heat_N.raw"};
char *pwrCO2Icon[] = {
"3co2_F.raw","3co2_N.raw"};
char *pwrAux1Icon[] = {
"3aux1_F.raw","3aux1_N.raw"};
char *pwrAux2Icon[] = {
"3aux2_F.raw","3aux2_N.raw"};
// on off power dot under each power button on the power screen and feeding config screen
char *pwrDot[] = {
"3dotR.raw","3dotG.raw"};
// small power icons for the home screen, off and on
char *pwrLightIconS[] = {
"1lightF.raw","1lightN.raw"};
char *pwrFilterIconS[] = {
"1filtF.raw","1filtN.raw"};
char *pwrCircIconS[] = {
"1circF.raw","1circN.raw"};
char *pwrHeatIconS[] = {
"1heatF.raw","1heatN.raw"};
char *pwrCO2IconS[] = {
"1co2F.raw","1co2N.raw"};
char *pwrAux1IconS[] = {
"1aux1F.raw","1aux1N.raw"};
char *pwrAux2IconS[] = {
"1aux2F.raw","1aux2N.raw"};
// small light mode icons for home screen
char *lightModeSm[] = {
"1hsun.raw","1msun.raw","1lsun.raw","1moon.raw"};
//moon images
// 0 = new moon, 1 = New Crescent, 2 = First Quarter, 3 = Waxing Gibbous, 4 = Full Moon,
// 5 = Waning Gibbous, 6 = Last Quarter, 7 = Old Crescent
char *moonImages[] = {
"21new.raw","21ncres.raw","21firstq.raw","21waxg.raw","21full.raw","21wang.raw",
"21lastq.raw","21ocres.raw"};
// 24 pixel up and down arrow buttons used on several screens
char *arrowButton[] = {
"24whUp.raw", "24whDn.raw"};
// enabled or not enabled small check boxes for the power schedule screen
char *schedActive[] = {
"11dis.raw","11enab.raw"};
// enabled or not enabled large check boxes for the power item schedule screen
char *schedActiveB[] = {
"11disB.raw","11enabB.raw"};
char *schedOnOff[] = {
"3off.raw","3on.raw"};
// high/low water level display icon
char *WaterIcon[] = {
"1wlow.raw","1whigh.raw"};
//watchdog timer definitions/variables
unsigned long resetTime = 0;
#define TIMEOUTPERIOD 10000 // You can make this time as long as you want
#define doggieTickle() resetTime = millis(); // This macro will reset the timer
void(* resetFunc) (void) = 0; //declare reset function @ address 0
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// END GLOBAL VARIABLES //
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void watchdogSetup()
{
cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF); // because the data sheet said to
/*
WDTCSR configuration:
WDIE = 1 :Interrupt Enable
WDE = 1 :Reset Enable - I won't be using this on the 2560
WDP3 = 1 :For 2000ms Time-out
WDP2 = 0 :bit pattern is
WDP1 = 0 :0111 change this for a different
WDP0 = 1 :timeout period.
*/
// Enter Watchdog Configuration mode:
WDTCSR = (1<<WDCE) | (1<<WDE);
// Set Watchdog settings: interrupte enable, 1001 for timer
WDTCSR = (1<<WDIE) | (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);
sei();
Serial.println(F("\nFinished watchdog setup")); // just here for testing
}
ISR(WDT_vect) // Watchdog timer interrupt.
{
if(millis() - resetTime > TIMEOUTPERIOD){
resetFunc(); // This will call location zero and cause a reboot.
}
}
int freeRam ()
{
// Returns available SRAM
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void setup()
{
Serial.begin(9600);
Serial2.begin(9600);
Wire.begin();
delay(100);
watchdogSetup();
pinMode(48,OUTPUT);
digitalWrite(48,HIGH);
// set default values for the first ever run
firstRunSetup();
// initiate the screen and touch
myGLCD.InitLCD(PORTRAIT);
myTouch.InitTouch(PORTRAIT);
myTouch.setPrecision(PREC_MEDIUM);
// init SD card
sd.begin(ChipSelect, SPI_FULL_SPEED);
// boot up logo
analogWrite(screenBrightPin, 255);
myGLCD.clrScr();
myFiles.load(26, 110, 188, 72, "iAqua.raw");
myGLCD.setColor(255,255,255);
myGLCD.setFont(arial_bold);
myGLCD.print(F("v2.5.3"), CENTER, 292);
Serial.println(F("v2.5.3"));
//Check RTC status
setSyncProvider(RTC.get);
delay(100);
if(timeStatus()!= timeSet)
{
Serial.print(F("Unable to sync with RTC"));
saveRTC.Year = 45;
saveRTC.Month = 1;
saveRTC.Day = 1;
saveRTC.Hour = 6;
saveRTC.Minute = 0;
saveRTC.Second = 0;
RTC.set(makeTime(saveRTC));
setTime(makeTime(saveRTC));
delay(500);
}
lastFeedingTime = now(); //not storing feeding time in eeprom due to high rate of writing
lastUpdateTime = now();
lastCheckTime = now();
// Start PCA9865
if(PCA9685Installed == true)
{
pwm.begin();
pwm.setPWMFreq(120);
}
// used for PWM lighting control
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(led3Pin, OUTPUT);
pinMode(led4Pin, OUTPUT);
pinMode(led5Pin, OUTPUT);
pinMode(led6Pin, OUTPUT);
// set all pin modes for output and inputs
pinMode(pwrLight1Pin, OUTPUT);
pinMode(pwrLight2Pin, OUTPUT);
pinMode(pwrFilterPin, OUTPUT);
pinMode(pwrCircPin, OUTPUT);
pinMode(pwrHeatPin, OUTPUT);
pinMode(pwrCO2Pin, OUTPUT);
pinMode(pwrAux2Pin, OUTPUT);
pinMode(pwrAux1Pin, OUTPUT);
pinMode(screenBrightPin, OUTPUT);
pinMode(lightSensorPin, INPUT);
pinMode(pressureSensorPin, INPUT);
pinMode(dosingPump1, OUTPUT);
pinMode(dosingPump2, OUTPUT);
pinMode(dosingPump3, OUTPUT);
pinMode(ATOPumpPin,OUTPUT);
pinMode(ATOFloatPin,INPUT);
pinMode(TankFloatPin,INPUT);
digitalWrite(dosingPump1,LOW);
digitalWrite(dosingPump2,LOW);
digitalWrite(dosingPump3,LOW);
digitalWrite(ATOPumpPin,LOW);
pinMode(internalTempPin,INPUT);
digitalWrite(fan1Pin,LOW);
digitalWrite(fan2Pin,LOW);
pinMode(fan1Pin,OUTPUT);
pinMode(fan2Pin,OUTPUT);
sensorW.begin(); //start up temperature library
sensorW.getAddress(waterSensor, 0); //get addresses of temperature sensor
sensorH.begin(); //start up temperature library
sensorH.getAddress(heatsinkSensor, 0); //get addresses of temperature sensor
// get bargraph colors
if (lightCSP==false)
{
readBargraphColors();
}
// get screen settings from eeprom
readScreenSettings();
analogWrite(screenBrightPin, screenBrightness); // turn up screen brightness right away
// get feeding settings from EEPROM
readFeedSettings();
// Read ATO settings
readATOSettings();
//Check which temp sensors are enabled and their settings
readSensorSettings();
// read in power schedule
readPowerSchedule();
// read in light ramping schedule
readRampSchedule();
// read in the dosing schedule
readDosingSchedule();
// synchronize the lights and read in the saved settings
resyncLights();
// create all alarams
updateAlarms();
// start up all power and set lighting mode according to schedudule
smartStartup();
delay(1400);
// Print available SRAM for debugging, comment out if you want
Serial.print(F("SRAM: "));
Serial.println(freeRam());
// display home screen
checkTemp(); //check temperature before drawing to screen
checkATO(); //check ato status before drawing to screen
screenHome();
dimTime = now(); // update millis to keep screen bright
Serial.println(F("\nEnd of setup."));
Serial2.print(F("Initialized."));
}
void loop()
{
unsigned long currentMillis = millis(); // get current millis
time_t currentTime = now();
//check temperature every 10 seconds
if(now() - lastUpdateTime >= 10)
{
lastUpdateTime=now();
checkTemp();
}
//check ATO/feeding and update time once per second
if(now() != lastCheckTime)
{
lastCheckTime=now();
updateTimeDate(false);//passing false results in updating screen only if time or date has changed
checkATO();
checkFeeding();
}
//Check status of current light ramp if applicable
checkLightRamp();
// check for touch events
if (myTouch.dataAvailable())
{
if (currentMillis - prevMillisTouch > touchWaitTime) // make sure it's been .X sec between touches
{
// set backlight touch if not already set and turn up brightness
if (backlightTouch==false) // backlight touch is for adjusting brightness after touch
{
Serial.println(F("Setting backlight to Bright value"));
backLight = map(screenBrightMem,1,10,10,255);
analogWrite(screenBrightPin, backLight);
backlightTouch=true;
}
prevMillisTouch=currentMillis; // reset the touch timer
dimTime = currentTime; // reset screen dim timer
homeTime = currentTime; // reset return home timer
processMyTouch();
}
}
// adjust brightness automatically unless touch event
unsigned long pastSeconds;
if (screenDimSec!=0) // if set to 0, we won't dim
{
if (screenDimLevel!=0) // if set to 0, we won't dim
{
if (backlightTouch==true)
{
pastSeconds = (currentTime - dimTime);
if (pastSeconds > screenDimSec)
{
Serial.println(F("Reducing backlight to dim level"));
backlightTouch=false;
idleBrightness();
}
}
}
}
// if we aren't on the home or feeding screen, we return after preset time of no interaction
if (screenRetHome != 0) // if set to 0, we don't return home
{
if ((dispScreen!=1)&&(dispScreen!=2))
{
pastSeconds = (currentTime - homeTime);
if (pastSeconds > (60*screenRetHome))
{
Serial.println(F("Returning to home"));
if (dispScreen==9) updateAlarms(); // this will rebuild all of the schedules
if (dispScreen==5)
{
smartStartupRamp();
setStartupLighting();
}
screenHome();
touchWaitTime = LONG_WAIT;
}
}
}
//Check dosing pumps
if(pump1State)
{
if(currentMillis > pump1StartMillis + pump1millis)
{
pump1State = false;
analogWrite(dosingPump1, 0);
Serial.print(F("Pump1 done.\n"));
if(dispScreen == 10)myFiles.load(92, 170, 48, 48, "10test.raw",2);
}
}
if(pump2State)
{
if(currentMillis > pump2StartMillis + pump2millis)
{
pump2State = false;
analogWrite(dosingPump2, 0);
Serial.print(F("Pump2 done.\n"));
if(dispScreen == 10)myFiles.load(92, 170, 48, 48, "10test.raw",2);
}
}
if(pump3State)
{
if(currentMillis > pump3StartMillis + pump3millis)
{
pump3State = false;
analogWrite(dosingPump3, 0);
Serial.print(F("Pump3 done.\n"));
if(dispScreen == 10)myFiles.load(92, 170, 48, 48, "10test.raw",2);
}
}
//Check aux1/2 timers
if(aux1TimerState)
{
if(currentMillis > (aux1TimerStart + aux1TimerFinish))