-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProcessValues.cpp
449 lines (334 loc) · 11.5 KB
/
ProcessValues.cpp
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
////////////////////////////////////////////////////////////////////////////////////////
//
// humifand - the humidity fan deamon
//
// Please check www.way2.net for more information
//
// (c) Copyright 2014 by way2.net Services.
//
////////////////////////////////////////////////////////////////////////////////////////
#include "ProcessValues.h"
#include "RPi_SHT1x.h"
#include "conffile.h"
#include "logger.h"
#include "fan.h"
#include <rrd.h>
#include <iostream>
#include <iomanip>
#include <sstream>
////////////////////////////////////////////////////////////////////////////////////////
// --- true here means that the fan will run in doubt in the first check, so hysteresis
// will not be checked until the first "change" has occurred
bool g_min_inside_temp_oldstate = true;
bool g_min_outside_temp_oldstate = true;
bool g_min_inside_rh_oldstate = true;
////////////////////////////////////////////////////////////////////////////////////////
int GetTimeValue(int h,int m)
{
return h*60 + m;
}
////////////////////////////////////////////////////////////////////////////////////////
int GetTimeValueStr(std::string &f_s)
{
std::size_t found = f_s.find(":");
if ( found == std::string::npos) return -1;
std::string l_sh = f_s.substr(0,found); trim(l_sh);
std::string l_sm = f_s.substr(found+1); trim(l_sm);
//printf("GetTimeValueStr '%s' '%s' '%s'\n",f_s.c_str(),l_sh.c_str(),l_sm.c_str());
return GetTimeValue(atoi(l_sh.c_str()),atoi(l_sm.c_str()));
}
////////////////////////////////////////////////////////////////////////////////////////
bool IsWeekdayOk(std::string &f_s,struct tm *f_now)
{
bool l_ret;
switch (f_now->tm_wday)
{
case 0:
l_ret = (f_s.find("So") != std::string::npos);
break;
case 1:
l_ret = (f_s.find("Mo") != std::string::npos);
break;
case 2:
l_ret = (f_s.find("Tu") != std::string::npos);
break;
case 3:
l_ret = (f_s.find("We") != std::string::npos);
break;
case 4:
l_ret = (f_s.find("Th") != std::string::npos);
break;
case 5:
l_ret = (f_s.find("Fr") != std::string::npos);
break;
case 6:
l_ret = (f_s.find("Sa") != std::string::npos);
break;
}
return l_ret;
}
////////////////////////////////////////////////////////////////////////////////////////
bool CheckTimeString(void)
{
char s[50];
// --- get the current time
time_t t = time(0);
struct tm *now = localtime(&t);
// --- there are max five values allowed. They have this format:
// active_time_1 = 8:00-16:00;Mo-Su
bool l_foundone = false;
bool l_foundoption = false;
for (int i=0;i<5;++i)
{
// --- create config name
sprintf(s,"active_time_%d",i);
//LOGGER->Log(s);
// --- check if there
if (CONF->isValid(s))
{
// --- remember that we found one option
l_foundoption = true;
// --- get the option string
std::string l_ts = CONF->GetOption(s);
//LOGGER->Log(l_ts);
std::size_t found_dash = l_ts.find("-");
if ( found_dash != std::string::npos)
{
std::string l_stime;
std::string l_dtime;
std::string l_WeekDays;
// --- this is the start time
l_stime = l_ts.substr(0,found_dash);
// --- check if weekdays supplied or not
std::size_t found_semi = l_ts.find(";");
if ( found_semi != std::string::npos)
{
l_dtime = l_ts.substr(found_dash+1,found_semi);
l_WeekDays = l_ts.substr(found_semi+1);
}
else
{
l_dtime = l_ts.substr(found_dash+1);
}
//LOGGER->Log("start %d",l_start_t);
//LOGGER->Log("end %d",l_end_t);
//LOGGER->Log(l_WeekDays);
// --- analyze if the weekday fits
bool l_WeekdayOk = true;
if (!l_WeekDays.empty()) l_WeekdayOk = IsWeekdayOk(l_WeekDays,now);
//LOGGER->Log("weekday %d",l_WeekdayOk);
if (l_WeekdayOk)
{
// --- calculate time values from the strings
int l_start_t = GetTimeValueStr(l_stime);
int l_end_t = GetTimeValueStr(l_dtime);
int l_nowtime_t = GetTimeValue(now->tm_hour,now->tm_min);
//LOGGER->Log("weekday %d",l_start_t);
//LOGGER->Log("weekday %d",l_end_t);
//LOGGER->Log("weekday %d",l_nowtime_t);
//LOGGER->Log("weekday %d",now->tm_hour);
//LOGGER->Log("weekday %d",now->tm_min);
// --- is the now time within the range?
if ( (l_nowtime_t >= l_start_t) && (l_nowtime_t <= l_end_t) ) l_foundone = true;
}
}
}
}
// --- if there is no allow time option, fan is allowed every time
if (l_foundoption)
return l_foundone;
else
return true;
}
////////////////////////////////////////////////////////////////////////////////////////
bool CheckHyst(float f_Value,float f_Threshold,float f_Hysteresis,bool f_oldState)
{
// --- if we're below hysteresis, it is false
if (f_Value < (f_Threshold-f_Hysteresis/2))
{
return false;
}
// --- if we're above hysteresis, it is true
if (f_Value > (f_Threshold+f_Hysteresis/2))
{
return true;
}
// --- for the range inbetween: don't change!
return f_oldState;
}
////////////////////////////////////////////////////////////////////////////////////////
bool IsFanAllowed(float f_it,float f_ih, float f_ot, float f_oh)
{
bool l_outcome = true;
// --- get some values from the config file
float l_min_inside_temp = CONF->GetOptionFloat("min_inside_temp");
float l_min_outside_temp = CONF->GetOptionFloat("min_outside_temp");
float l_min_inside_rh = CONF->GetOptionFloat("min_inside_rh");
float l_max_daily_fan_runtime = CONF->GetOptionFloat("max_daily_fan_runtime")*60;
float l_min_inside_temp_hyst = CONF->GetOptionFloatDefault("min_inside_temp_hyst", 1.0);
float l_min_outside_temp_hyst = CONF->GetOptionFloatDefault("min_outside_temp_hyst", 1.0);
float l_min_inside_rh_hyst = CONF->GetOptionFloatDefault("min_inside_rh_hyst", 2.0);
// --- l_min_inside_temp
g_min_inside_temp_oldstate = CheckHyst(f_it,l_min_inside_temp,l_min_inside_temp_hyst,g_min_inside_temp_oldstate);
if (g_min_inside_temp_oldstate == false)
{
if (CONF->coGetVerbose()) LOGGER->Log("Fan not allowed as inside temp (%f) below threshold (%f) and hysteresis (%f)",f_it,l_min_inside_temp,l_min_inside_temp_hyst);
l_outcome = false;
}
// --- l_min_outside_temp
g_min_outside_temp_oldstate = CheckHyst(f_ot,l_min_outside_temp,l_min_outside_temp_hyst,g_min_outside_temp_oldstate);
if (g_min_outside_temp_oldstate == false)
{
if (CONF->coGetVerbose()) LOGGER->Log("Fan not allowed as outside temp (%f) below threshold (%f) and hysteresis (%f)",f_ot,l_min_outside_temp,l_min_outside_temp_hyst);
l_outcome = false;
}
// --- l_min_inside_rh
g_min_inside_rh_oldstate = CheckHyst(f_ih,l_min_inside_rh,l_min_inside_rh_hyst,g_min_inside_rh_oldstate);
if (g_min_inside_rh_oldstate == false)
{
if (CONF->coGetVerbose()) LOGGER->Log("Fan not allowed as inside rH (%f) below threshold (%f) and hysteresis (%f)",f_ih,l_min_inside_rh,l_min_inside_rh_hyst);
l_outcome = false;
}
// --- l_max_daily_fan_runtime
if (CONF->isValid("max_daily_fan_runtime"))
{
if (CONF->coGetVerbose()) LOGGER->Log("Max daily runtime: %f Current daily runtime: %f",l_max_daily_fan_runtime,FAN->GetRuntime());
if (FAN->GetRuntime() > l_max_daily_fan_runtime)
{
if (CONF->coGetVerbose()) LOGGER->Log("Fan not allowed as max runtime (%f) reached: %f",l_max_daily_fan_runtime,FAN->GetRuntime());
l_outcome = false;
}
}
// --- check if the time fits
if (!CheckTimeString())
{
if (CONF->coGetVerbose()) LOGGER->Log("Fan not allowed as current time is not allowed");
l_outcome = false;
}
// --- if the time fits, we are allowed to switch on!
return l_outcome;
}
////////////////////////////////////////////////////////////////////////////////////////
void UpdateRRD(bool f_iok, float f_it,float f_ih,float f_iah,bool f_ook, float f_ot, float f_oh,float f_oah)
{
string l_s_it,l_s_ot, l_s_ih, l_s_oh, l_s_idp, l_s_odp, l_s_iah, l_s_oah;
char s[255];
// --- calculate internal and external dew point
float l_iDP = SHT1x::SHT1x_CalcDewpoint(f_ih,f_it);
float l_oDP = SHT1x::SHT1x_CalcDewpoint(f_oh,f_ot);
// --- replace invalid values with "U"
if (f_iok)
{
snprintf(s,30,"%f",f_it); l_s_it = s;
snprintf(s,30,"%f",f_ih); l_s_ih = s;
snprintf(s,30,"%f",l_iDP); l_s_idp = s;
snprintf(s,30,"%f",f_iah); l_s_iah = s;
}
else
{
l_s_it = "U";
l_s_ih = "U";
l_s_idp = "U";
l_s_iah = "U";
}
if (f_ook)
{
snprintf(s,30,"%f",f_ot); l_s_ot = s;
snprintf(s,30,"%f",f_oh); l_s_oh = s;
snprintf(s,30,"%f",l_oDP); l_s_odp = s;
snprintf(s,30,"%f",f_oah); l_s_oah = s;
}
else
{
l_s_ot = "U";
l_s_oh = "U";
l_s_odp = "U";
l_s_oah = "U";
}
// --- open the rrd file
if (CONF->isValid("rrd_file"))
{
std::string l_rrdfile = CONF->GetOption("rrd_file");
stringstream l_ss;
// --- format: temp;temp;rh;rh;ah:ah:dp:dp;fan
l_ss << "N:" << l_s_it << ":" << l_s_ot << ":" << l_s_ih << ":" << l_s_oh << ":"
<< l_s_iah << ":" << l_s_oah << ":"
<< l_s_idp << ":" << l_s_odp << ":";
if (FAN->IsFanSpinning())
l_ss << "1";
else
l_ss << "0";
strncpy(s,l_ss.str().c_str(),255);
const char *rrd_param[1];
rrd_param[0] = s;
if (CONF->coGetVerbose()) LOGGER->Log(l_ss.str());
int l_rrd_err = rrd_update_r(l_rrdfile.c_str(),NULL,1,rrd_param);
if (l_rrd_err == -1)
{
char *l_err = rrd_get_error();
LOGGER->Log("RRD ret code %s",l_err);
rrd_clear_error();
}
}
else
{
LOGGER->Log("Missing rrd file parameter in config file. No rrd update will happen.");
}
}
////////////////////////////////////////////////////////////////////////////////////////
int f_oldWeekday = -1;
////////////////////////////////////////////////////////////////////////////////////////
void ProcessValues(bool f_iok, float f_it,float f_ih,bool f_ook, float f_ot, float f_oh)
{
// TODO: debug fake
if (CONF->isValid("debug_ot"))
{
f_ook = true;
f_ot = CONF->GetOptionFloat("debug_ot");
f_oh = CONF->GetOptionFloat("debug_orh");
}
// --- calculate internal and external absolute hum
float l_iah = SHT1x::SHT1x_CalcAbsHumidity(f_ih,f_it);
float l_oah = SHT1x::SHT1x_CalcAbsHumidity(f_oh,f_ot);
// --- update the RRD file for the fancy graphics
UpdateRRD(f_iok,f_it,f_ih,l_iah,f_ook, f_ot, f_oh,l_oah);
// --- get some conf vars
float l_humi_diff_on = CONF->GetOptionFloat("humi_diff_on");
float l_humi_diff_off = CONF->GetOptionFloat("humi_diff_off");
if (CONF->coGetVerbose()) LOGGER->Log("diff on %f diff off %f",l_humi_diff_on,l_humi_diff_off);
// --- check if we can continue (both sensors need to be ok)
if (f_iok == true && f_ook == true)
{
if (IsFanAllowed(f_it,f_ih,f_ot,f_oh))
{
if ( l_iah > (l_oah+l_humi_diff_on) )
{
FAN->Start();
}
if ( l_iah < (l_oah+l_humi_diff_off) )
{
FAN->Stop();
}
}
else
{
// --- fan not allowed --> stop it
FAN->Stop();
}
}
else
{
if (CONF->coGetVerbose()) LOGGER->Log("Fan update not performed as one sensor value invalid");
}
// --- check for day change to reset the fan runtime
time_t t = time(0);
struct tm *now = localtime(&t);
if (f_oldWeekday != now->tm_wday)
{
if (CONF->coGetVerbose()) LOGGER->Log("Day change detected. Runtime was %f Reset to zero.",FAN->GetRuntime());
// --- clear it
FAN->ClearRuntime();
// --- remember the new day
f_oldWeekday = now->tm_wday;
}
}