-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhydro-mega.ino
391 lines (364 loc) · 9.02 KB
/
hydro-mega.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
/*
* Copyright (C), 2020 Christopher F. Moran
* This code controls a simple hydroponic pump for Ebb * Flow operation
*
* It is intended to be modular, and features can be added or removed by
* defining conditions within sysconfig.h. The logic behind this structure is
* that the final code can get very close to maximum memory on some controllers
* which may cause stability problems.
*/
#include "hydro.h"
void setup() {
// pinMode(LED_BUILTIN, OUTPUT);
#ifdef _HAS_PUMP_RELAY
pinMode(PIN_PUMP, OUTPUT);
digitalWrite(PIN_PUMP, RLY_OFF);
#endif
#ifdef _HAS_LAMP_RELAY
pinMode(PIN_LAMP, OUTPUT);
#endif
Serial.begin(115200);
Serial.println();
#ifdef _DEBUG
Serial.println("Compiled modules:");
#ifdef _HAS_SSD1306
Serial.println("SSD1306 Display");
#endif
#ifdef _HAS_THINGSPEAK
Serial.println("ThingSpeak");
#endif
#ifdef _HAS_ETHERNET
Serial.println("Ethernet");
#endif
#ifdef _HAS_WIFI_ESP
Serial.println("ESP WiFi");
#endif
#ifdef _HAS_DALLAS
Serial.println("DS18B20");
#endif
#ifdef _HAS_DHT
Serial.println("DHT");
#endif
#ifdef _HAS_PUMP_RELAY
Serial.println("Pump Relay");
#endif
#ifdef _HAS_LAMP_RELAY
Serial.println("Lamp Relay");
#endif
#ifdef _HAS_PH
Serial.println("pH Sensor");
#endif
#ifdef _HAS_EC
Serial.println("Ec Sensor");
#endif
#ifdef _HAS_VBATT
Serial.println("Battery Voltage");
#endif
#ifdef _HAS_DS1307
Serial.println("DS1307 RTC");
#endif
#endif
Serial.println("Starting up");
#ifdef _HAS_SSD1306
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
while(true); // Can't continue
}
display.clearDisplay();
display.drawPixel(10, 10, SSD1306_WHITE);
display.display();
#endif
#ifdef _HAS_ETHERNET
Ethernet.init(10);
if(Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
if(Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet hardware not found");
while(true); // Can't continue
}
if(Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable not connected");
while(true); // Can't continue
}
Ethernet.begin(mac, ip, dns);
}
// Allow the Ethernet hardware to start up fully
delay(1500);
#endif
#ifdef _HAS_WIFI
int wifiStatus = WL_IDLE_STATUS;
Serial3.begin(115200);
WiFi.init(&Serial3);
if(WiFi.status() == WL_NO_SHIELD) {
Serial.println("No WiFi Shield");
while(true); // Can't continue
}
while(wifiStatus != WL_CONNECTED) {
wifiStatus = WiFi.begin(ssid, pass);
delay(1000);
}
#endif
#ifdef _HAS_SSD1306
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.println("Started OK");
display.display();
#endif
#ifdef _HAS_DS1307
if(!rtc.begin()) {
Serial.println("Could not find DS1307 RTC");
while(true); // Can't continue
}
if(!rtc.isrunning()) {
Serial.println("RTC is not running");
// Set date and time to last compile
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
#ifdef _HAS_SSD1306
display.println("RTC On");
#endif
#endif
#ifdef _HAS_DHT
dht.begin();
#ifdef _HAS_SSD1306
display.println("DHT On");
#endif
#endif
#ifdef _HAS_DALLAS
sensors.begin();
#ifdef _HAS_SSD1306
display.println("18B20 On");
#endif
#endif
#ifdef _HAS_THINGSPEAK
ThingSpeak.begin(client);
#ifdef _HAS_SSD1306
display.println("ThingSpeak On");
#endif
#endif
#ifdef _HAS_SSD1306
display.display();
#endif
}
#ifdef _HAS_PUMP_RELAY
void setPump(void) {
#ifdef _DEBUG
Serial.println("Checking pump " + String(mins) + " min (" + String(idlePump) + ")");
#endif
if(idlePump == 0 && mins > RUN_MINUTES) {
idlePump = 1;
Serial.println("Stop Pump");
digitalWrite(PIN_PUMP, RLY_OFF);
#ifdef _HAS_THINGSPEAK
ThingSpeak.setStatus("Pump Stopped");
#endif
mins = 0;
}
if(idlePump == 1 && mins > IDLE_MINUTES) {
idlePump = 0;
Serial.println("Start Pump");
digitalWrite(PIN_PUMP, RLY_ON);
#ifdef _HAS_THINGSPEAK
ThingSpeak.setStatus("Pump Started");
#endif
mins = 0;
}
}
#endif
#ifdef _HAS_EC
// Reference
// https://hackaday.io/project/7008-fly-wars-a-hackers-solution-to-world-hunger/log/24646-three-dollar-ec-ppm-meter-arduino
float readEc(float fluidTemp) {
int r1 = 1000;
int rA = 25;
float ppmConversion = 0.7;
float temperatureCoef = 0.019;
float k = 2.88;
float raw = 0.0;
float vIn = 5.0;
float vDrop = 0.0;
float rC = 0;
float eC = 0.0;
digitalWrite(EC_POWER_PIN, HIGH); // Power on
digitalWrite(EC_SINK_PIN, LOW);
raw= analogRead(PIN_EC);
raw= analogRead(PIN_EC); // Needs to be run twice, based on experimental results. See source article.
digitalWrite(EC_POWER_PIN,HIGH); // Power off
vDrop = (vIn * raw) / 1024.0;
rC = (vDrop * r1) / (vIn - vDrop) - rA;
eC = (1000 / (rC * k)) / (1+ temperatureCoef*(fluidTemp - 25.0));
return eC;
}
#endif
#ifdef _HAS_DS1307
void printTime() {
char buffer[50];
DateTime now = rtc.now();
sprintf(buffer, "%4d/%02d/%02d %02d:%02d:%02d",now.year(),now.month(),now.day(),now.hour(),now.minute(),now.second());
Serial.println(buffer);
}
#endif
void loop() {
#ifdef _HAS_DS1307
printTime();
#endif
#ifdef _HAS_DHT
float airHumidity = 0.0;
float airTemp = 0.0;
#endif
#ifdef _HAS_DALLAS
float fluidTemp = 0.0;
#endif
#ifdef _HAS_PH
float pH = 7.0;
#endif
#ifdef _HAS_EC
float eC = 0.0;
#endif
#ifdef _HAS_VBATT
float vBatt = 12.0;
#endif
// digitalWrite(LED_BUILTIN, stat);
stat = !stat;
if(secs == 59) {
secs = 0;
mins++;
#ifdef _HAS_PUMP_RELAY
setPump();
#endif
#ifdef _HAS_SSD1306
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.display();
#endif
#ifdef _HAS_DHT
airTemp = dht.readTemperature();
airHumidity = dht.readHumidity();
if(isnan(airTemp)) {
Serial.println("Error getting airTemp");
airTemp = 0.0;
}
else {
Serial.println("Air Temp: " + String(airTemp) + "C");
#ifdef _HAS_THINGSPEAK
ThingSpeak.setField(1, airTemp);
#endif
}
#ifdef _HAS_SSD1306
display.println("Temp: " + String(airTemp) + "C");
#endif
if(isnan(airHumidity)) {
Serial.println("Error getting airHumidity");
airHumidity = 0.0;
}
else {
Serial.println("Humidity: " + String(airHumidity) + "%");
#ifdef _HAS_THINGSPEAK
ThingSpeak.setField(2, airHumidity);
#endif
}
#ifdef _HAS_SSD1306
display.println("Hum: " + String(airHumidity) + "%");
#endif
#endif
#ifdef _HAS_DALLAS
sensors.requestTemperatures();
fluidTemp = sensors.getTempCByIndex(0);
if(isnan(fluidTemp) || fluidTemp < -10) {
Serial.println("Error getting fluidTemp");
fluidTemp = 0.0;
}
else {
Serial.println("Nutr Temp: " + String(fluidTemp) + "C");
#ifdef _HAS_THINGSPEAK
ThingSpeak.setField(3, fluidTemp);
#endif
if(fluidTemp < fluidAlarmLow) {
Serial.println("ALARM: LOW NUTRIENT TEMPERATURE");
}
if(fluidTemp > fluidAlarmHigh) {
Serial.println("ALARM: HIGH NUTRIENT TEMPERATURE");
}
}
#ifdef _HAS_SSD1306
display.println("Nutrient: " + String(fluidTemp) + "C");
#endif
#endif
#ifdef _HAS_PH
pH = (float)analogRead(PIN_PH) / 1024.0 * 5.0 * 1.45;
if(isnan(pH) || pH < 0 || pH > 14) {
Serial.println("Error getting pH");
pH = 7.0;
}
else {
Serial.println("pH: " + String(pH));
#ifdef _HAS_THINGSPEAK
ThingSpeak.setField(4, pH);
#endif
#ifdef _HAS_SSD1306
display.println("pH: " + String(pH));
#endif
}
#endif
#ifdef _HAS_DALLAS
#ifdef _HAS_EC
eC = readEc(fluidTemp);
if(isnan(eC) || eC < 0) {
Serial.println("Error getting eC");
eC = 0.0;
}
else {
Serial.println("Ec: " + String(eC));
#ifdef _HAS_THINGSPEAK
ThingSpeak.setField(5, eC);
#endif
}
#ifdef _HAS_SSD1306
display.println("Ec: " + String(eC));
#endif
#endif
#endif
#ifdef _HAS_VBATT
vBatt = (float)analogRead(PIN_VBATT) / 1024 * batFactor;
if(isnan(pH)) {
Serial.println("Error getting vBatt");
vBatt = 12.0;
}
else {
Serial.println("vBatt: " + String(vBatt));
#ifdef _HAS_THINGSPEAK
ThingSpeak.setField(8, vBatt);
#endif
}
#ifdef _HAS_SSD1306
display.println("vBatt: " + String(vBatt) + "V");
#endif
#endif
#ifdef _HAS_THINGSPEAK
int x = ThingSpeak.writeFields(channelId, writeApiKey);
if(x != 200) {
Serial.println("Error " + String(x) + " sending to ThingSpeak");
}
#endif
#ifdef _HAS_SSD1306
#ifdef _HAS_PUMP_RELAY
if(idlePump == 0) {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE) ; // Reverse Text
display.println("Pump: ON");
}
else {
display.println("Pump: OFF");
}
#endif
display.display();
#endif
}
delay(1000);
secs++;
}