-
Notifications
You must be signed in to change notification settings - Fork 5
/
zone_ctrl.c
276 lines (240 loc) · 9.63 KB
/
zone_ctrl.c
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
#ifdef USE_WIRINGPI
#include <wiringPi.h>
#else
#include "GPIO_Pi.h"
#endif
#include "zone_ctrl.h"
#include "config.h"
#include "utils.h"
bool zc_start(int zone);
bool zc_stop(int zone);
void zc_master(zcState state);
int calc_timeleft() {
if (_sdconfig_.currentZone.zone != -1) {
// See if the duration time changed since we started, on was not a cron request.
//if ( _sdconfig_.currentZone.type != zcCRON && _sdconfig_.currentZone.duration != _sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime)
// _sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime;
time_t now;
time(&now);
_sdconfig_.currentZone.timeleft = (_sdconfig_.currentZone.duration * SEC2MIN) - difftime(now, _sdconfig_.currentZone.started_time);
} else {
_sdconfig_.currentZone.timeleft = 0;
}
//logMessage (LOG_DEBUG, "Zone %d time left %d %d min\n",_sdconfig_.currentZone.zone, _sdconfig_.currentZone.timeleft, (_sdconfig_.currentZone.timeleft / 60) +1);
return _sdconfig_.currentZone.timeleft;
}
zcState zc_state(int zone) {
if (zone > 0 && zone <= _sdconfig_.zones) {
return (digitalRead(_sdconfig_.zonecfg[zone].pin) == _sdconfig_.zonecfg[zone].on_state ? zcON : zcOFF);
} else {
return zcOFF; // If invalid zone just return off, maybe change to NULL
}
}
int start_next_zone(int startz) {
int zone = startz+1;
while( _sdconfig_.zonecfg[zone].default_runtime <= 0 || !validGPIO( _sdconfig_.zonecfg[zone].pin) ) {
//logMessage (LOG_INFO, "Run Zone, skipping zone %d due to runtime of %d\n",zone,_sdconfig_.zonecfg[zone].default_runtime);
logMessage (LOG_INFO, "Run Zone, skipping zone %d due to %s\n",zone,_sdconfig_.zonecfg[zone].default_runtime<=0?" runtime of 0":" bad GPIO pin#");
zone++;
if (zone > _sdconfig_.zones) { // No more zones left to run, turn everything off
_sdconfig_.currentZone.type=zcNONE;
_sdconfig_.currentZone.zone=-1;
_sdconfig_.currentZone.timeleft = 0;
zc_master(zcOFF);
return -1;
}
}
if ( zc_start(zone) == true) {
_sdconfig_.currentZone.zone=zone;
zc_master(zcON);
time(&_sdconfig_.currentZone.started_time);
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime;
calc_timeleft();
} else {
logMessage (LOG_ERR, "Run Zone, failed to start zone %d, check GPIO\n",zone);
return start_next_zone(zone);
}
return zone;
}
void zc_update_runtime(int zone) {
if (zone > 0 && zone < _sdconfig_.zones && zone == _sdconfig_.currentZone.zone) {
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[zone].default_runtime;
}
}
bool zc_check() {
// check what's running, and if time now is greater than duration Stop if grater
// Move onto next zone if (all) runtype
if ( _sdconfig_.currentZone.type == zcNONE)
return false;
//time_t now;
//time(&now);
//int secleft = (_sdconfig_.currentZone.duration * SEC2MIN) - difftime(now, _sdconfig_.currentZone.started_time);
//_sdconfig_.currentZone.timeleft = secleft / 60 + 1;
logMessage (LOG_DEBUG, "Zone running is %d of type %d\n",_sdconfig_.currentZone.zone, _sdconfig_.currentZone.type);
//if (difftime(now, _sdconfig_.currentZone.started_time) > _sdconfig_.currentZone.duration * SEC2MIN){
if (calc_timeleft() <= 0){
if (_sdconfig_.currentZone.type==zcALL && _sdconfig_.currentZone.zone < _sdconfig_.zones) {
zc_stop(_sdconfig_.currentZone.zone);
start_next_zone(_sdconfig_.currentZone.zone);
} else {
zc_master(zcOFF);
zc_stop(_sdconfig_.currentZone.zone);
_sdconfig_.currentZone.type=zcNONE;
_sdconfig_.currentZone.zone=-1;
_sdconfig_.currentZone.timeleft = 0;
}
return true;
}
return false;
}
void zc_rain_delay_enabeled() {
// Turn off any running zone that was enabeled by cron, leave on any zones that were manually turned on.
if(_sdconfig_.currentZone.type==zcCRON && _sdconfig_.currentZone.zone > 0) {
logMessage (LOG_INFO, "Turning off zone %d '%s' due to rain delay\n",_sdconfig_.currentZone.zone, _sdconfig_.zonecfg[_sdconfig_.currentZone.zone].name);
zc_zone(zcSINGLE, _sdconfig_.currentZone.zone, zcOFF, 0);
}
}
void zc_master(zcState state) {
if (!_sdconfig_.master_valve)
return;
if (state == zcON && _sdconfig_.zonecfg[0].on_state != digitalRead (_sdconfig_.zonecfg[0].pin ))
zc_start(0);
else if (state == zcOFF && _sdconfig_.zonecfg[0].on_state == digitalRead (_sdconfig_.zonecfg[0].pin ))
zc_stop(0);
}
bool zc_zone(zcRunType type, int zone, zcState state, int length) {
int i;
// Check to see if duplicate request
logMessage (LOG_DEBUG, "Request to turn zone %d %s for %d min requesttype %d\n",zone,(state==zcON?"on":"off"),length,type);
if (zone > 0 && zone <= _sdconfig_.zones) {
zcState cstate = _sdconfig_.zonecfg[zone].on_state==digitalRead (_sdconfig_.zonecfg[zone].pin)?zcON:zcOFF;
if (cstate == state) {
logMessage (LOG_INFO, "Request to turn zone %d %s. Ignored, zone is already %s\n",zone,state==zcON?"ON":"OFF",cstate==zcON?"ON":"OFF");
return false;
}
} else if (type == zcALL && ( (state == zcON && _sdconfig_.currentZone.type == zcALL) || (state == zcOFF && _sdconfig_.currentZone.type != zcALL)) ) {
logMessage (LOG_INFO, "Ignore request to cycle all zones %s\n",state==zcON?"ON":"OFF");
return false;
}
if (type == zcCRON && state == zcON && (_sdconfig_.calendar == false || _sdconfig_.delay24h == true) ) {
logMessage (LOG_WARNING, "Request to turn zone %d on. Ignored due to %s!\n",zone,_sdconfig_.delay24h?"Rain Delay active":"Calendar off");
return false;
// Check cal & 24hdelay, return if cal=false or 24hdelay=true
} else if (type == zcALL) {
// If we are turning on we ned to start with all zones off, if off, turn them off anyway.
for (i=1; i <= _sdconfig_.zones ; i++)
{
zc_master(zcOFF);
if ( _sdconfig_.zonecfg[i].on_state == digitalRead(_sdconfig_.zonecfg[i].pin) )
zc_stop(i);
}
_sdconfig_.currentZone.type=zcNONE;
if (state == zcON) {
if ( start_next_zone(0) != -1 ) { // Pass 0 as start_next_zone will incrument zone
_sdconfig_.currentZone.type=zcALL;
}
}
return true;
}
if (length == 0) {
//get default length here
length = _sdconfig_.zonecfg[zone].default_runtime;
logMessage (LOG_DEBUG, "Use default time of %d\n",length);
}
if (state == zcON) {
if ( length > 0) {
for (i=1; i <= _sdconfig_.zones ; i++)
{
if ( _sdconfig_.zonecfg[i].on_state == digitalRead (_sdconfig_.zonecfg[i].pin)) {
if (zone == i) {
logMessage (LOG_DEBUG, "Request to turn zone %d on. Zone %d is already on, ignoring!\n",zone,zone);
return false;
}
zc_stop(i);
}
}
if ( zc_start(zone) == true) {
zc_master(zcON);
_sdconfig_.currentZone.type=type;
_sdconfig_.currentZone.zone=zone;
_sdconfig_.currentZone.duration=length;
logMessage (LOG_DEBUG, "set runtime to %d and %d\n",length,_sdconfig_.currentZone.duration);
time(&_sdconfig_.currentZone.started_time);
calc_timeleft();
return true;
} else {
logMessage (LOG_ERR, "Request to turn on zone %d failed, check GPIO\n",zone);
return false;
}
} else {
logMessage (LOG_WARNING, "Request to turn zone %d on. Ignored due to runtime being %d\n",zone,length);
return false;
}
} else if (state == zcOFF) {
if (_sdconfig_.currentZone.type == zcALL) { // If all zones, and told to turn off current, run next zone
_sdconfig_.currentZone.started_time = _sdconfig_.currentZone.started_time - (_sdconfig_.currentZone.duration * SEC2MIN) - 1;
zc_check();
} else {
zc_master(zcOFF);
zc_stop(zone);
_sdconfig_.currentZone.type=zcNONE;
_sdconfig_.currentZone.zone=-1;
}
return true;
}
return false;
}
bool zc_start(/*zcRunType type,*/ int zone) {
int rtn = false;
// Check if zone is already on
if ( _sdconfig_.zonecfg[zone].on_state == digitalRead (_sdconfig_.zonecfg[zone].pin)) {
logMessage (LOG_DEBUG, "Request to turn zone %d on. Zone %d is already on, ignoring!\n",zone,zone);
return false;
}
logMessage (LOG_NOTICE, "Turning on Zone %d\n",zone);
#ifndef USE_WIRINGPI
//int rtn = digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state );
//logMessage (LOG_NOTICE, "digitalWrite return %d\n",rtn);
if (digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state ) == GPIO_OK )
rtn = true;
else
rtn = false;
#else
digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state );
int rtn = true;
#endif
_sdconfig_.eventToUpdateHappened = true;
return rtn;
// store what's running
//if (rtn == true)
// return true;
//else
// return false;
}
bool zc_stop(/*zcRunType type,*/ int zone) {
int rtn = false;
// Check if zone is alreay off
if ( _sdconfig_.zonecfg[zone].on_state != digitalRead (_sdconfig_.zonecfg[zone].pin)) {
logMessage (LOG_DEBUG, "Request to turn zone %d off. Zone %d is already off, ignoring!\n",zone,zone);
return false;
}
logMessage (LOG_NOTICE, "Turning off Zone %d\n",zone);
#ifndef USE_WIRINGPI
//int rtn = digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state );
if (digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state ) == GPIO_OK )
rtn = true;
else
rtn = false;
#else
digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state );
int rtn = true;
#endif
_sdconfig_.eventToUpdateHappened = true;
return rtn;
/*
if (rtn == true)
return true;
else
return false;
*/
}