Subversion Repositories heating

Rev

Rev 54 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 andreas 1
/*
2
 * Copyright (C) 2015 by Andreas Theofilu. All rights reserved!
3
 *
4
 * All rights reserved. No warranty, explicit or implicit, provided.
5
 *
6
 * NOTICE:  All information contained herein is, and remains
7
 * the property of Andreas Theofilu and his suppliers, if any.
8
 * The intellectual and technical concepts contained
9
 * herein are proprietary to Andreas Theofilu and its suppliers and
10
 * may be covered by European and Foreign Patents, patents in process,
11
 * and are protected by trade secret or copyright law.
12
 * Dissemination of this information or reproduction of this material
13
 * is strictly forbidden unless prior written permission is obtained
14
 * from Andreas Theofilu.
15
 * 
16
 * Author: Andreas Theofilu <andreas@theosys.at>
17
 */
18
#include <iostream>
19
#include <fstream>
20
#include <string>
4 andreas 21
#include <iomanip>
8 andreas 22
#include <thread>
3 andreas 23
#include <cstring>
24
#include <cctype>
25
#include <cstddef>
26
#include <cstdio>
27
#include <cstdlib>
4 andreas 28
#include <ctime>
3 andreas 29
#include <fstream>
30
#include <cerrno>
8 andreas 31
#include <cmath>
3 andreas 32
#include <unistd.h>
33
#include <syslog.h>
34
#include <sys/stat.h>
35
#include <sys/types.h>
36
#include <fcntl.h>
4 andreas 37
#include <sqlite3.h>
9 andreas 38
#include <bcm2835.h>
3 andreas 39
#include "heating.h"
17 andreas 40
#include "html.h"
3 andreas 41
#include "config.h"
42
#include "helper.h"
43
 
44
using namespace std;
45
 
9 andreas 46
#define PIN1	RPI_V2_GPIO_P1_03
47
#define PIN2	RPI_V2_GPIO_P1_05
48
#define PIN3	RPI_V2_GPIO_P1_07
49
#define PIN4	RPI_V2_GPIO_P1_11
50
#define PIN5	RPI_V2_GPIO_P1_13
51
#define PIN6	RPI_V2_GPIO_P1_15
52
#define PIN7	RPI_V2_GPIO_P1_16
53
#define PIN8	RPI_V2_GPIO_P1_18
54
#define PIN9	RPI_V2_GPIO_P1_22
8 andreas 55
 
3 andreas 56
heating::heating()
57
{
58
	enableDebug(Configure.debug);
59
	glb_minimal = 16.0;
4 andreas 60
	glb_night = 18.0;
3 andreas 61
	rm = 0;
12 andreas 62
	outSensor = 0;
5 andreas 63
	rstop = false;
64
	rrun = false;
3 andreas 65
	HeatConf = nullptr;
46 andreas 66
	HtmlServer = nullptr;
5 andreas 67
 
68
	for (int i = 0; i < 100; i++)
69
		s1[i] = -1;
70
 
4 andreas 71
	initialized = false;
72
 
73
	if (readConf())
74
	{
75
		if (buildDB())
18 andreas 76
		{
4 andreas 77
			initialized = true;
18 andreas 78
			debug("Initialisation successfully done.");
79
		}
80
		else
81
			debug("Error initializing database");
4 andreas 82
	}
18 andreas 83
	else
84
		debug("Error reading config file.");
3 andreas 85
}
86
 
87
heating::~heating()
88
{
89
	destroyHConf();
90
}
91
 
9 andreas 92
void heating::pthrTemps()
8 andreas 93
{
94
	trun();
95
}
96
 
17 andreas 97
void heating::pthrHtml()
98
{
46 andreas 99
	if (HtmlServer != nullptr)
100
		return;
101
 
17 andreas 102
	HtmlServer = new html();
103
	HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
49 andreas 104
	applyConfig();
105
 
106
	HtmlServer->run();
107
	delete HtmlServer;
108
	HtmlServer = nullptr;
109
}
110
 
111
void heating::applyConfig()
112
{
113
HCONF *akt = HeatConf;
114
html::HTCONF ht;
115
 
17 andreas 116
	while (akt)
117
	{
118
		strcpy (ht.rname, akt->rname);
119
		ht.rnum = akt->rnum;
120
		ht.soll = akt->soll;
121
		ht.night = akt->night;
122
		ht.minimal = akt->minimal;
35 andreas 123
		ht.start1 = akt->start;
124
		ht.end1 = akt->end;
125
		ht.start2 = akt->wstart;
126
		ht.end2 = akt->wend;
49 andreas 127
 
17 andreas 128
		HtmlServer->addConfig(&ht);
129
		akt = akt->next;
130
	}
131
}
132
 
4 andreas 133
void heating::run()
134
{
5 andreas 135
int i;
136
double tmp;
137
HCONF *akt;
52 andreas 138
time_t loctime = getTime();
4 andreas 139
 
5 andreas 140
	rstop = false;
141
	rrun = true;
142
	i = 0;
143
 
12 andreas 144
	debug ("heating::run() reached!");
8 andreas 145
	// First start the runtime routine of class temperature.
9 andreas 146
	// We need this to get our temperatures
147
	thread pthr_temps(&heating::pthrTemps, this);
148
	pthr_temps.detach();
12 andreas 149
	debug ("heating::run() started thread temperature::trun() and detached");
17 andreas 150
	// Then we start the HTML thread.
151
	thread pthr_html(&heating::pthrHtml, this);
152
	pthr_html.detach();
153
	debug("heating::run() started thread html");
9 andreas 154
	// Here we read the previous colected temperatures and evaluate them.
5 andreas 155
	while (!rstop)
156
	{
157
		akt = HeatConf;
9 andreas 158
 
46 andreas 159
		if (HtmlServer->hasChanged())
160
		{
161
			html::HTCONF *hta;
47 andreas 162
			string ans;
46 andreas 163
 
164
			glb_minimal = HtmlServer->getGlbAbsent();
165
			glb_night = HtmlServer->getGlbNight();
166
			onoff = HtmlServer->getRunMode();
47 andreas 167
			ans = "CONFIG:GLOBAL NIGHT:" + doubleToString(glb_night, 1) + ";";
168
			answer(ans);
169
			ans = "CONFIG:GLOBAL MINIMAL:" + doubleToString(glb_minimal, 1) + ";";
170
			answer(ans);
48 andreas 171
			ans = "POWER:";
172
			ans.append((onoff) ? "ON;" : "OFF;");
47 andreas 173
			answer(ans);
174
 
46 andreas 175
			hta = HtmlServer->getHConfig();
176
 
177
			while (hta)
178
			{
179
				akt = HeatConf;
180
 
181
				while (akt)
182
				{
183
					if (akt->rnum == hta->rnum)
184
					{
47 andreas 185
						stringstream stream;
186
 
46 andreas 187
						akt->soll = hta->soll;
188
						akt->night = hta->night;
189
						akt->minimal = hta->minimal;
190
						akt->start = hta->start1;
191
						akt->end = hta->end1;
192
						akt->wstart = hta->start2;
193
						akt->wend = hta->end2;
47 andreas 194
						stream << "CONFIG:ROOM:" << akt->rnum << ":" << string(akt->rname) << ":" << fixed <<
195
						setprecision(1) << akt->soll << ":" << akt->night << ":" <<
196
						akt->minimal << ":" << timeToStr(akt->start) << ":" << timeToStr(akt->end) << ":" <<
197
						timeToStr(akt->wstart) << ":" << timeToStr(akt->wend) << ";";
198
						answer(stream.str());
46 andreas 199
						break;
200
					}
201
 
202
					akt = akt->next;
203
				}
204
 
205
				hta = hta->next;
206
			}
207
 
208
			akt = HeatConf;
209
		}
210
 
5 andreas 211
		while (akt)
212
		{
52 andreas 213
			/// Set the mode for every room.
54 andreas 214
			if (onoff)
53 andreas 215
			{
216
				if (loctime >= akt->start && loctime <= akt->end)
217
					akt->status = NORMAL;
218
				else
219
					akt->status = NIGHT;
220
			}
52 andreas 221
			else
53 andreas 222
				akt->status = OFF;
52 andreas 223
 
5 andreas 224
			tmp = getTemp(akt->tempsensor);
225
 
226
			if (tmp < 99.0 && tmp > -99.0)
54 andreas 227
			{
5 andreas 228
				akt->ist = tmp;
229
 
54 andreas 230
				if (evaluateTemp(akt->rnum, tmp))		// Should we start heating?
231
					startHeat(akt->rnum);				// yes
232
				else									// Or should we stop heating
233
					stopHeat(akt->rnum);				// yes
55 andreas 234
 
235
				if (isHeating())						// As long as there is a room who need heating, this function returns true.
236
					controlHeat(0, true);
237
				else
238
					controlHeat(0, false);
54 andreas 239
			}
9 andreas 240
 
5 andreas 241
			akt = akt->next;
242
		}
243
 
244
		i++;
245
 
246
		if (i > 60)
247
		{
248
			i = 0;
249
			akt = HeatConf;
250
 
251
			while (akt)
252
			{
47 andreas 253
				answer("IST:" + itostring(akt->rnum) + ":" + doubleToString(akt->ist, 1) + ";");
5 andreas 254
				akt = akt->next;
255
			}
256
		}
257
 
258
		sleep(1);
259
	}
260
 
261
	rrun = false;
4 andreas 262
}
263
 
12 andreas 264
void heating::controlHeat (int room, bool stst)
9 andreas 265
{
266
HCONF *akt = HeatConf;
55 andreas 267
int pin, gpio;
9 andreas 268
 
55 andreas 269
	if (room > 0)
9 andreas 270
	{
55 andreas 271
		while (akt)
272
		{
273
			if (akt->rnum == room)
274
				break;
9 andreas 275
 
55 andreas 276
			akt = akt->next;
277
		}
9 andreas 278
 
55 andreas 279
		if (!akt)
280
		{
281
			syslog(LOG_WARNING, "controlHeat: Room %d not found!", room);
282
			return;
283
		}
9 andreas 284
 
55 andreas 285
		if (akt->valve != stst)
286
		{
287
			if (Configure.debug)
288
				syslog(LOG_DEBUG, "Heating for room %d switched %s", room, (stst) ? "ON" : "OFF");
54 andreas 289
 
55 andreas 290
			string h = "HEATING:";
291
			h.append(itostring(room) + ":");
292
			h.append((stst)? "ON;" : "OFF;");
293
			answer(h);
294
		}
295
 
296
		gpio = akt->gpio;
54 andreas 297
	}
55 andreas 298
	else if (heatIO <= 0)
299
		return;
300
	else
301
		gpio = heatIO;
54 andreas 302
 
55 andreas 303
	switch (gpio)
9 andreas 304
	{
305
		case 1: pin = PIN1; break;
306
		case 2: pin = PIN2; break;
307
		case 3: pin = PIN3; break;
308
		case 4: pin = PIN4; break;
309
		case 5: pin = PIN5; break;
310
		case 6: pin = PIN6; break;
311
		case 7: pin = PIN7; break;
312
		case 8: pin = PIN8; break;
313
		case 9: pin = PIN9; break;
314
		default:
315
			return;
316
	}
317
 
55 andreas 318
	if (room && akt)
319
		akt->valve = stst;
9 andreas 320
	// Enable the GPIO pin to start heating
54 andreas 321
	if (!bcmInitialized)
9 andreas 322
		return;
323
 
324
	// Set the pin to be an output
325
	bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
326
	// Turn it on
12 andreas 327
	bcm2835_gpio_write(pin, (stst)? HIGH : LOW);
9 andreas 328
}
329
 
4 andreas 330
double heating::incSoll(int room)
331
{
332
HCONF *akt;
333
char *zErrMsg = nullptr;
334
int rc;
335
sqlite3 *db;
336
sqlite3_stmt *res;
337
string query;
338
 
339
	rc = sqlite3_open(Configure.home, &db);
340
 
341
	if (rc)
342
	{
343
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
344
		return 0.0;
345
	}
346
 
347
	if ((akt = findRoom(room)) != nullptr)
348
	{
349
		if (akt->soll >= 30.0)
350
		{
351
			sqlite3_close(db);
352
			return akt->soll;
353
		}
354
 
355
		akt->soll += 0.5;
49 andreas 356
		applyConfig();
47 andreas 357
		query = "update heating set soll = " + doubleToString(akt->soll, 1) + " where id = " + itostring(room);
4 andreas 358
 
5 andreas 359
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 360
		{
361
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
362
			sqlite3_free(zErrMsg);
363
			sqlite3_close(db);
364
			akt->soll -= 0.5;
365
			return akt->soll;
366
		}
367
 
368
		sqlite3_close(db);
5 andreas 369
		stringstream stream;
49 andreas 370
		stream << "SOLL:" << fixed << setprecision(1) << akt->soll << ";";
5 andreas 371
		answer(stream.str());
4 andreas 372
		return akt->soll;
373
	}
374
 
375
	return 0.0;
376
}
377
 
378
double heating::decSoll(int room)
379
{
380
HCONF *akt;
381
char *zErrMsg = nullptr;
382
int rc;
383
sqlite3 *db;
384
sqlite3_stmt *res;
385
string query;
386
 
387
	rc = sqlite3_open(Configure.home, &db);
388
 
389
	if (rc)
390
	{
391
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
392
		return 0.0;
393
	}
394
 
395
	if ((akt = findRoom(room)) != nullptr)
396
	{
397
		if (akt->soll <= 10.0)
398
		{
399
			sqlite3_close(db);
400
			return akt->soll;
401
		}
402
 
403
		akt->soll -= 0.5;
49 andreas 404
		applyConfig();
47 andreas 405
		query = "update heating set soll = " + doubleToString(akt->soll, 1) + " where id = " + itostring(room);
4 andreas 406
 
5 andreas 407
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 408
		{
409
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
410
			sqlite3_free(zErrMsg);
411
			sqlite3_close(db);
412
			akt->soll += 0.5;
413
			return akt->soll;
414
		}
415
 
416
		sqlite3_close(db);
5 andreas 417
		stringstream stream;
49 andreas 418
		stream << "SOLL:" << fixed << setprecision(1) << akt->soll << ";";
5 andreas 419
		answer(stream.str());
4 andreas 420
		return akt->soll;
421
	}
422
 
423
	return 0.0;
424
}
425
 
9 andreas 426
void heating::setSoll (int room, double val)
427
{
428
HCONF *akt = HeatConf;
429
char *zErrMsg = nullptr;
430
int rc;
431
sqlite3 *db;
432
sqlite3_stmt *res;
433
string query;
434
 
435
	if (val < 10.0 || val > 30.0)
436
	{
437
		syslog(LOG_INFO, "Invalid value for maximum room temperature!");
438
		return;
439
	}
440
 
441
	rc = sqlite3_open(Configure.home, &db);
442
 
443
	if (rc)
444
	{
445
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
446
		return;
447
	}
448
 
449
	if (room > 0 && (akt = findRoom(room)) != nullptr)
450
	{
451
		akt->soll = val;
49 andreas 452
		applyConfig();
47 andreas 453
		query = "update heating set soll = " + doubleToString(val, 1) + " where id = " + itostring(room);
9 andreas 454
 
455
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
456
		{
457
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
458
			sqlite3_free(zErrMsg);
459
			sqlite3_close(db);
460
			return;
461
		}
462
 
47 andreas 463
		query = "SOLL:" + itostring(room) + ":" + doubleToString(val, 1) + ";";
9 andreas 464
		answer(query);
465
	}
466
 
467
	sqlite3_close(db);
468
}
469
 
4 andreas 470
void heating::setNight(int room, double val)
471
{
472
HCONF *akt;
473
char *zErrMsg = nullptr;
474
int rc;
475
sqlite3 *db;
476
sqlite3_stmt *res;
477
string query;
478
 
479
	if (val < 10.0 || val > 25.0)
480
	{
481
		syslog(LOG_INFO, "Invalid value for the night!");
482
		return;
483
	}
484
 
485
	rc = sqlite3_open(Configure.home, &db);
486
 
487
	if (rc)
488
	{
489
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
490
		return;
491
	}
492
 
493
	if (room > 0 && (akt = findRoom(room)) != nullptr)
494
	{
495
		akt->night = val;
49 andreas 496
		applyConfig();
47 andreas 497
		query = "update heating set night = " + doubleToString(val, 1) + " where id = " + itostring(room);
5 andreas 498
 
499
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 500
		{
501
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
502
			sqlite3_free(zErrMsg);
503
			sqlite3_close(db);
504
			return;
505
		}
506
 
47 andreas 507
		query = "NIGHT:" + itostring(room) + ":" + doubleToString(val, 1) + ";";
5 andreas 508
		answer(query);
4 andreas 509
	}
510
	else if (room == 0)
511
	{
512
		glb_night = val;
49 andreas 513
 
514
		if (HtmlServer != nullptr)
515
			HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
516
 
47 andreas 517
		query = "update glbheat set night = " + doubleToString(val, 1);
4 andreas 518
 
5 andreas 519
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 520
		{
521
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
522
			sqlite3_free(zErrMsg);
523
			sqlite3_close(db);
524
			return;
525
		}
5 andreas 526
 
47 andreas 527
		query = "CONFIG:GLOBAL NIGHT:" + doubleToString(val, 1) + ";";
5 andreas 528
		answer(query);
4 andreas 529
	}
530
 
531
	sqlite3_close(db);
532
}
533
 
534
void heating::setMinimal(int room, double val)
535
{
536
HCONF *akt;
537
char *zErrMsg = nullptr;
538
int rc;
539
sqlite3 *db;
540
sqlite3_stmt *res;
541
string query;
542
 
543
	if (val < 10.0 || val > 20.0)
544
	{
545
		syslog(LOG_INFO, "Invalid value for the night!");
546
		return;
547
	}
548
 
549
	rc = sqlite3_open(Configure.home, &db);
550
 
551
	if (rc)
552
	{
553
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
554
		return;
555
	}
556
 
557
	if (room > 0 && (akt = findRoom(room)) != nullptr)
558
	{
559
		akt->minimal = val;
49 andreas 560
		applyConfig();
47 andreas 561
		query = "update heating set minimal = " + doubleToString(val, 1) + " where id = " + itostring(room);
4 andreas 562
 
5 andreas 563
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 564
		{
565
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
566
			sqlite3_free(zErrMsg);
567
			sqlite3_close(db);
568
			return;
569
		}
5 andreas 570
 
47 andreas 571
		query = "MINIMAL:" + itostring(room) + ":" + doubleToString(val, 1) + ";";
5 andreas 572
		answer(query);
4 andreas 573
	}
574
	else if (room == 0)
575
	{
576
		glb_minimal = val;
49 andreas 577
 
578
		if (HtmlServer != nullptr)
579
			HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
580
 
47 andreas 581
		query = "update glbheat set minimal = " + doubleToString(val, 1);
4 andreas 582
 
5 andreas 583
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 584
		{
585
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
586
			sqlite3_free(zErrMsg);
587
			sqlite3_close(db);
588
			return;
589
		}
5 andreas 590
 
47 andreas 591
		query = "CONFIG:GLOBAL MINIMAL:" + doubleToString(val, 1) + ";";
5 andreas 592
		answer(query);
4 andreas 593
	}
594
 
595
	sqlite3_close(db);
596
}
597
 
598
bool heating::switchOnOff(bool what)
599
{
600
HCONF *akt;
601
char *zErrMsg = nullptr;
602
int rc;
603
sqlite3 *db;
604
sqlite3_stmt *res;
605
string query;
606
 
607
	rc = sqlite3_open(Configure.home, &db);
608
 
609
	if (rc)
610
	{
611
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
5 andreas 612
		return onoff;
4 andreas 613
	}
614
 
615
	onoff = what;
49 andreas 616
 
617
	if (HtmlServer != nullptr)
618
		HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
619
 
5 andreas 620
	query = "update glbheat set onoff = " + (what)?"1":"0";
4 andreas 621
 
5 andreas 622
	if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 623
	{
624
		syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
625
		sqlite3_free(zErrMsg);
626
		sqlite3_close(db);
5 andreas 627
		return onoff;
4 andreas 628
	}
629
 
630
	sqlite3_close(db);
49 andreas 631
	query = "POWER:";
632
	query.append((onoff) ? "ON;" : "OFF;");
5 andreas 633
	answer(query);
634
	return onoff;
4 andreas 635
}
636
 
637
double heating::getNight (int room)
638
{
639
HCONF *akt = findRoom(room);
640
 
641
	if (akt && akt->night > 0.0)
642
		return akt->night;
643
 
644
	return glb_night;
645
}
646
 
647
double heating::getMinimal (int room)
648
{
649
HCONF *akt = findRoom(room);
650
 
651
	if (akt && akt->minimal > 0.0)
652
		return akt->minimal;
653
 
654
	return glb_minimal;
655
}
656
 
3 andreas 657
void heating::destroyHConf()
658
{
659
HCONF *p, *next;
660
 
661
	p = HeatConf;
662
 
663
	while (p)
664
	{
665
		next = p->next;
666
		delete p;
667
		p = next;
668
	}
669
 
670
	HeatConf = nullptr;
671
}
672
 
5 andreas 673
void heating::getConfig (int s1)
674
{
675
HCONF *akt = HeatConf;
676
stringstream stream;
677
 
50 andreas 678
	stream << "CONFIG:GLOBAL NIGHT:" << fixed << setprecision(1) << glb_night << ";";
679
	stream << "CONFIG:GLOBAL MINIMAL:" << fixed << setprecision(1) << glb_minimal << ";";
49 andreas 680
	stream << "CONFIG:ONOFF:" << ((onoff) ? "ON;" : "OFF;");
5 andreas 681
 
682
	while (akt)
683
	{
50 andreas 684
		stream << "CONFIG:ROOM:" << itostring(akt->rnum) << ":" << string(akt->rname) << ":" <<
685
			fixed << setprecision(1) << akt->soll << ":" << akt->night << ":" <<
42 andreas 686
			akt->minimal << ":" << timeToStr(akt->start) << ":" << timeToStr(akt->end) << ":" <<
48 andreas 687
			timeToStr(akt->wstart) << ":" << timeToStr(akt->wend) << ";";
5 andreas 688
 
54 andreas 689
		stream << "HEATING:" << itostring(akt->rnum) << ":";
690
 
691
		if (akt->valve)
692
			stream << "ON;";
693
		else
694
			stream << "OFF;";
695
 
5 andreas 696
		akt = akt->next;
697
	}
49 andreas 698
 
699
	write(s1, stream.str().c_str(), stream.str().length());
5 andreas 700
}
701
 
4 andreas 702
heating::HCONF* heating::findRoom (int room)
703
{
704
HCONF *akt = HeatConf;
705
 
706
	while (akt)
707
	{
708
		if (akt->rnum == room)
709
			return akt;
710
 
711
		akt = akt->next;
712
	}
713
 
714
	return nullptr;
715
}
716
 
3 andreas 717
bool heating::readConf()
718
{
719
ifstream cfile;
720
char line[1024], hv0[256], hv1[128];
721
char *p;
4 andreas 722
CNFSTAT cs;
723
HCONF *akt = HeatConf;
3 andreas 724
 
725
	// If there's no config file, inform the user about it.
726
	cfile.open(Configure.heatconf, ios::in);
727
 
728
	if ((cfile.rdstate() & std::ifstream::failbit) != 0)
729
	{
730
		syslog(LOG_WARNING,"Error opening the config file: %s", strerror(errno));
731
		return false;
732
	}
733
 
734
	syslog(LOG_INFO, "Found config file %s.", Configure.heatconf);
4 andreas 735
	cs = NONE;
3 andreas 736
	// Here we've found a config file. We'll read it and set the
737
	// contents to the structure
738
	while (cfile.getline(&line[0], sizeof(line)))
739
	{
740
		int len;
741
 
742
		trim (&line[0]);
743
 
744
		if (line[0] == '#' || !char_traits<char>::length(line))
745
			continue;
746
 
4 andreas 747
		if ((p = findc(line, char_traits<char>::length(line), ']')) != NULL)
748
		{
749
			char *x;
750
 
751
			*(p+1) = 0;
752
 
753
			if (!compcase(line, "[global]"))
754
			{
755
				cs = GLOBAL;
756
				continue;
757
			}
758
 
759
			if ((x = findc(line, char_traits<char>::length(line), '[')) != NULL)
760
			{
761
				*p = 0;
762
				akt = appendHConf();
763
				strncpy(akt->rname, x+1, sizeof(akt->rname) - 1);
764
				akt->soll = 20.0;
765
				cs = ROOM;
766
				continue;
767
			}
768
			else
769
				cs = NONE;
770
		}
771
 
772
		if ((p = findc(line, char_traits<char>::length(line), '=')) == NULL || cs == NONE)
3 andreas 773
			continue;
774
 
775
		*p = 0;
776
		p++;
777
		len = char_traits<char>::length(line);
778
 
779
		if (len > (int)sizeof(hv0))
780
			len = (int)sizeof(hv0) - 1;
781
 
782
		strncpy(hv0, line, len);
783
		hv0[len] = 0;
784
		trim (hv0);
785
		len = char_traits<char>::length(p);
786
 
787
		if (len > (int)sizeof(hv1))
788
			len = (int)sizeof(hv0) - 1;
789
 
790
		strncpy(hv1, p, len);
791
		hv1[len] = 0;
792
		trim (hv1);
793
 
4 andreas 794
		if (!compcase(hv0, "minimal"))
795
		{
796
			if (cs == GLOBAL)
797
				glb_minimal = atof (hv1);
798
			else
799
				akt->minimal = atof (hv1);
800
		}
3 andreas 801
 
4 andreas 802
		if (!compcase(hv0, "night"))
803
		{
804
			if (cs == GLOBAL)
805
				glb_night = atof (hv1);
806
			else
807
				akt->night = atof (hv1);
808
		}
809
 
810
		if (!compcase(hv0, "OnOff") && cs == GLOBAL)
811
			onoff = ToBool(hv1);
812
 
12 andreas 813
		if (!compcase(hv0, "OutSensor") && cs == GLOBAL)
814
			outSensor = atoi(hv1);
815
 
55 andreas 816
		if (!compcase(hv0, "HeatIO") && cs == GLOBAL)
817
			heatIO = atoi(hv1);
818
 
4 andreas 819
		if (cs == ROOM)
820
		{
821
			if (!compcase(hv0, "soll"))
822
				akt->soll = atoi(hv1);
823
 
824
			if (!compcase(hv0, "Sensor"))
825
				akt->tempsensor = atoi(hv1);
826
 
827
			if (!compcase(hv0, "GPIO"))
828
				akt->gpio = atoi(hv1);
829
 
830
			if (!compcase(hv0, "StartTime"))
13 andreas 831
			{
4 andreas 832
				akt->start = strToTime(hv1);
14 andreas 833
				debug("StartTime: " + itostring(akt->start) + "(" + ToString(hv1) + ")");
13 andreas 834
			}
4 andreas 835
 
836
			if (!compcase(hv0, "EndTime"))
13 andreas 837
			{
4 andreas 838
				akt->end = strToTime(hv1);
14 andreas 839
				debug("EndTime: " + itostring(akt->end) + "(" + ToString(hv1) + ")");
13 andreas 840
			}
42 andreas 841
 
842
			if (!compcase(hv0, "WorkStartTime"))
843
			{
844
				akt->wstart = strToTime(hv1);
845
				debug("WorkStartTime: " + itostring(akt->wstart) + "(" + ToString(hv1) + ")");
846
			}
847
 
848
			if (!compcase(hv0, "WorkEndTime"))
849
			{
850
				akt->wend = strToTime(hv1);
851
				debug("WorkEndTime: " + itostring(akt->wend) + "(" + ToString(hv1) + ")");
852
			}
4 andreas 853
		}
854
	}
54 andreas 855
 
856
	akt = HeatConf;
857
	time_t loctime = getTime();
858
 
859
	while (akt)
860
	{
861
		if (onoff)
862
			akt->status = OFF;
863
		else if (loctime > akt->start && loctime < akt->end)
864
			akt->status = NORMAL;
865
		else
866
			akt->status = NIGHT;
867
 
868
		akt = akt->next;
869
	}
870
 
4 andreas 871
	cfile.close ();
55 andreas 872
 
873
	if (heatIO <= 0)
874
		syslog (LOG_DAEMON, "Missing the GPIO number to start and stop the heating! This heat control will not work!");
875
 
4 andreas 876
	return true;
877
}
878
 
879
 
880
bool heating::buildDB()
881
{
882
sqlite3 *db;
883
sqlite3_stmt *res;
884
int rc;
885
char *zErrMsg = nullptr;
886
string query;
887
 
888
	if (access(Configure.home, R_OK | W_OK))		// Try to create a new database if it doesn't exist
889
	{
890
		HCONF *akt;
891
 
18 andreas 892
		debug("Creating SQL3 database.");
4 andreas 893
		rc = sqlite3_open(Configure.home, &db);
894
 
895
		if (rc)
896
		{
897
			syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
898
			return false;
899
		}
900
 
901
		query = "create table \"main\".\"heating\" (";
902
		query.append("\"id\" INTEGER PRIMARY KEY NOT NULL,");
903
		query.append("\"name\" TEXT NOT NULL,");
904
		query.append("\"soll\" REAL,");
905
		query.append("\"night\" REAL,");
906
		query.append("\"minimal\" REAL,");
907
		query.append("\"start\" INTEGER,");
42 andreas 908
		query.append("\"end\" INTEGER,");
909
		query.append("\"wstart\" INTEGER,");
910
		query.append("\"wend\" INTEGER");
4 andreas 911
		query.append(")");
5 andreas 912
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
4 andreas 913
 
914
		if (rc != SQLITE_OK)
915
		{
916
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
917
			sqlite3_free(zErrMsg);
918
			sqlite3_close(db);
919
			return false;
920
		}
921
		else
922
			syslog(LOG_INFO, "Database \"heating\" was successfully created.");
923
 
10 andreas 924
		query = "create table \"main\".\"kitable\" (";
925
		query.append("\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
12 andreas 926
		query.append("\"rnum\" INTEGER NOT NULL,");
10 andreas 927
		query.append("\"diffout\" INTEGER,");
928
		query.append("\"diffin\" INTEGER,");
929
		query.append("\"heat\" INTEGER)");
930
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
931
 
932
		if (rc != SQLITE_OK)
933
		{
934
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
935
			sqlite3_free(zErrMsg);
936
			sqlite3_close(db);
937
			return false;
938
		}
939
		else
940
			syslog(LOG_INFO, "Database \"kitable\" was successfully created.");
941
 
942
		query = "create table \"main\".\"glbheat\" (";
943
		query.append("\"night\" REAL,");
944
		query.append("\"minimal\" REAL,");
945
		query.append("\"onoff\" INTEGER");
946
		query.append(")");
947
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
40 andreas 948
 
10 andreas 949
		if (rc != SQLITE_OK)
950
		{
951
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
952
			sqlite3_free(zErrMsg);
953
			sqlite3_close(db);
954
			return false;
955
		}
956
		else
957
			syslog(LOG_INFO, "Database \"glbheat\" was successfully created.");
40 andreas 958
 
4 andreas 959
		// Insert the values from the config file into the table
18 andreas 960
		debug("Inserting configuration into SQL3 database");
4 andreas 961
		akt = HeatConf;
40 andreas 962
 
4 andreas 963
		while (akt)
964
		{
42 andreas 965
			query = "insert into heating (id, name, soll, night, minimal, start, end, wstart, wend) values (";
4 andreas 966
			query.append(itostring(akt->rnum));
10 andreas 967
			query.append(",\""+string(akt->rname)+"\"");
47 andreas 968
			query.append(","+doubleToString(akt->soll, 1));
969
			query.append(","+doubleToString(akt->night, 1));
970
			query.append(","+doubleToString(akt->minimal, 1));
4 andreas 971
			query.append(","+itostring(akt->start));
972
			query.append(","+itostring(akt->end));
42 andreas 973
			query.append(","+itostring(akt->wstart));
974
			query.append(","+itostring(akt->wend));
4 andreas 975
			query.append(")");
5 andreas 976
			rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
4 andreas 977
 
978
			if (rc != SQLITE_OK)
979
			{
980
				syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
981
				sqlite3_free(zErrMsg);
982
				sqlite3_close(db);
983
				return false;
984
			}
985
 
986
			akt = akt->next;
15 andreas 987
		}
4 andreas 988
 
15 andreas 989
		query = "insert into glbheat (night, minimal, onoff) values (";
47 andreas 990
		query.append(doubleToString(glb_night, 1));
991
		query.append(","+doubleToString(glb_minimal, 1));
15 andreas 992
		query.append(","+itostring(onoff));
993
		query.append(")");
994
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
995
 
996
		if (rc != SQLITE_OK)
997
		{
998
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
999
			sqlite3_free(zErrMsg);
1000
			sqlite3_close(db);
1001
			return false;
4 andreas 1002
		}
1003
 
1004
		sqlite3_close(db);
1005
	}
1006
	else
1007
	{
1008
		HCONF *akt;
15 andreas 1009
 
18 andreas 1010
		debug("Reading configuration from SQL3 database");
4 andreas 1011
		rc = sqlite3_open(Configure.home, &db);
15 andreas 1012
 
4 andreas 1013
		if (rc)
1014
		{
1015
			syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
1016
			return false;
1017
		}
1018
 
1019
		akt = HeatConf;
54 andreas 1020
		time_t loctime = getTime();
40 andreas 1021
 
4 andreas 1022
		while (akt)
3 andreas 1023
		{
18 andreas 1024
			debug("Queriing "+itostring(akt->rnum)+", "+ToString(akt->rname));
4 andreas 1025
			query = "select id, name, soll, night, minimal, start, end from heating where id = "+itostring(akt->rnum);
1026
 
5 andreas 1027
			if (sqlite3_prepare(db, query.c_str(), -1, &res, NULL) != SQLITE_OK)
4 andreas 1028
			{
1029
				syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), sqlite3_errmsg(db));
1030
				sqlite3_close(db);
1031
				return false;
1032
			}
1033
 
1034
			if ((rc = sqlite3_step(res)) == SQLITE_ROW)
1035
			{
1036
				strncpy(akt->rname, (const char *)sqlite3_column_text(res, 1), sizeof(akt->rname) - 1);
1037
				akt->soll = sqlite3_column_double(res, 2);
1038
				akt->night = sqlite3_column_double(res, 3);
1039
				akt->minimal = sqlite3_column_double(res, 4);
1040
				akt->start = (time_t)sqlite3_column_int(res, 5);
1041
				akt->end = (time_t)sqlite3_column_int(res, 6);
1042
			}
1043
 
44 andreas 1044
			sqlite3_finalize(res);
12 andreas 1045
			query = "select rnum, diffout, diffin, heat from kitable where rnum = " + itostring(akt->rnum);
1046
 
1047
			if (sqlite3_prepare(db, query.c_str(), -1, &res, NULL) != SQLITE_OK)
1048
			{
1049
				syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), sqlite3_errmsg(db));
1050
				sqlite3_close(db);
1051
				return false;
1052
			}
1053
 
1054
			while ((rc = sqlite3_step(res)) == SQLITE_ROW)
1055
			{
1056
				HTABLE *tb = appendHTable(akt);
15 andreas 1057
				tb->tempDifferOut = sqlite3_column_double(res, 1);
1058
				tb->tempDifferIn = sqlite3_column_double(res, 2);
12 andreas 1059
				tb->heat = sqlite3_column_int(res, 3);
18 andreas 1060
				debug("KITABLE: read "+itostring(sqlite3_column_int(res, 0)));
12 andreas 1061
			}
1062
 
44 andreas 1063
			sqlite3_finalize(res);
54 andreas 1064
 
1065
			if (onoff)
1066
				akt->status = OFF;
1067
			else if (loctime > akt->start && loctime < akt->end)
1068
				akt->status = NORMAL;
1069
			else
1070
				akt->status = NIGHT;
1071
 
4 andreas 1072
			akt = akt->next;
3 andreas 1073
		}
4 andreas 1074
 
18 andreas 1075
		debug("Reading global parameters from SQL3 database");
4 andreas 1076
		query = "select night, minimal, onoff from glbheat";
1077
 
5 andreas 1078
		if (sqlite3_prepare(db, query.c_str(), -1, &res, NULL) != SQLITE_OK)
4 andreas 1079
		{
1080
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), sqlite3_errmsg(db));
1081
			sqlite3_close(db);
1082
			return false;
1083
		}
1084
 
1085
		if ((rc = sqlite3_step(res)) == SQLITE_ROW)
1086
		{
1087
			glb_night = sqlite3_column_double(res, 0);
1088
			glb_minimal = sqlite3_column_double(res, 1);
1089
			onoff = (time_t)sqlite3_column_int(res, 2);
1090
		}
1091
 
44 andreas 1092
		sqlite3_finalize(res);
4 andreas 1093
		sqlite3_close(db);
3 andreas 1094
	}
4 andreas 1095
 
18 andreas 1096
	debug("All database operations done");
3 andreas 1097
	return true;
1098
}
1099
 
5 andreas 1100
void heating::setHandle (int fd)
1101
{
1102
	// First look into table to make sure the handle isn't already in the table
1103
	for (int i = 0; i < 100; i++)
1104
	{
1105
		if (s1[i] == fd)
1106
			return;
1107
	}
1108
 
1109
	// Because we're here, the handle is not in the table. So insert it now.
1110
	for (int i = 0; i < 100; i++)
1111
	{
1112
		if (s1[i] < 0)
1113
		{
1114
			s1[i] = fd;
1115
			break;
1116
		}
1117
	}
1118
}
1119
 
1120
void heating::removeHandle (int fd)
1121
{
1122
	for (int i = 0; i < 100; i++)
1123
	{
1124
		if (s1[i] == fd)
1125
		{
1126
			s1[i] = -1;
1127
			break;
1128
		}
1129
	}
1130
}
1131
 
1132
void heating::answer (string msg)
1133
{
1134
	for (int i = 0; i < 100; i++)
1135
	{
1136
		if (s1[i] > 0)
1137
			write(s1[i], msg.c_str(), strlen(msg.c_str()));
1138
	}
1139
}
1140
 
4 andreas 1141
time_t heating::strToTime (char* str)
1142
{
14 andreas 1143
int hour, min;
4 andreas 1144
 
7 andreas 1145
	if (strchr(str, ':') != NULL)
1146
	{
14 andreas 1147
		sscanf(str, "%d:%d", &hour, &min);
1148
		return (time_t)hour * 3600 + (time_t)min * 60;
7 andreas 1149
	}
1150
 
1151
	return 0;
4 andreas 1152
}
1153
 
5 andreas 1154
string heating::timeToStr(time_t t)
1155
{
14 andreas 1156
int hour, min;
38 andreas 1157
char hv0[48];
5 andreas 1158
 
14 andreas 1159
	hour = (int)(t / 3600);
39 andreas 1160
	min = (int)((t - (time_t)hour * 3600) / 60);
38 andreas 1161
	sprintf(hv0, "%02d:%02d", hour, min);
1162
	string zeit(hv0);
5 andreas 1163
	return zeit;
1164
}
1165
 
8 andreas 1166
time_t heating::getTime()
1167
{
54 andreas 1168
tm *ltm;
8 andreas 1169
time_t t = time(NULL);
54 andreas 1170
time_t out;
8 andreas 1171
 
1172
	ltm = localtime(&t);
54 andreas 1173
	out = (time_t)(ltm->tm_hour * 3600 + ltm->tm_min * 60 + ltm->tm_sec);
1174
	return out;
8 andreas 1175
}
1176
 
3 andreas 1177
heating::HCONF* heating::appendHConf()
1178
{
1179
HCONF *akt, *p;
1180
 
1181
	akt = new HCONF;
1182
	memset(akt, 0, sizeof(HCONF));
54 andreas 1183
	akt->soll = 0.0;
1184
	akt->night = 0.0;
1185
	akt->minimal = 0.0;
1186
	akt->ist = 0.0;
3 andreas 1187
 
1188
	if (HeatConf == nullptr)
1189
		HeatConf = akt;
1190
	else
1191
	{
1192
		p = HeatConf;
1193
 
1194
		while (p->next)
1195
			p = p->next;
1196
 
1197
		p->next = akt;
1198
	}
1199
 
1200
	rm++;
1201
	akt->rnum = rm;
1202
	return akt;
1203
}
8 andreas 1204
 
55 andreas 1205
/*
1206
 * This function checks if there is a room where heating is requested.
1207
 * If only one room requests heating, it returns true. This means, that
1208
 * the therme, the heating, should start.
1209
 * Otherwise it should stop heating.
1210
 * This will work only, if there's a GPIO pin defined for the heating!
1211
 * Beside this the function checks whether the defined GPIO pin is
1212
 * unique. If not, it always returns false.
1213
 */
1214
bool heating::isHeating()
1215
{
1216
HCONF *akt = HeatConf;
1217
 
1218
	if (heatIO <= 0)
1219
		return false;
1220
 
1221
	// Make sure the defined GPIO pin for the heating is unique.
1222
	while (akt)
1223
	{
1224
		if (akt->gpio == heatIO)
1225
			return false;
1226
 
1227
		akt = akt->next;
1228
	}
1229
 
1230
	// Find out if there is a room who requested heating.
1231
	akt = HeatConf;
1232
 
1233
	while (akt)
1234
	{
1235
		if (akt->valve)
1236
			return true;
1237
 
1238
		akt = akt->next;
1239
	}
1240
 
1241
	return false;
1242
}
1243
 
8 andreas 1244
heating::HTABLE* heating::appendHTable(HCONF *ht)
1245
{
1246
HTABLE *akt, *p;
1247
 
1248
	akt = new HTABLE;
1249
	memset(akt, 0, sizeof(HTABLE));
1250
 
1251
	if (ht->hTable == nullptr)
1252
		ht->hTable = akt;
1253
	else
1254
	{
1255
		p = ht->hTable;
1256
 
1257
		while (p->next)
1258
			p = p->next;
1259
 
1260
		p->next = akt;
1261
	}
1262
 
1263
	return akt;
1264
}
1265
 
1266
bool heating::evaluateTemp (int room, double temp)
1267
{
1268
HCONF *akt;
9 andreas 1269
double soll, diffOut, diffIn;
52 andreas 1270
time_t loctime;
8 andreas 1271
 
1272
	akt = HeatConf;
1273
 
1274
	while (akt)
1275
	{
1276
		if (akt->rnum == room)
1277
			break;
1278
 
1279
		akt = akt->next;
1280
	}
1281
 
1282
	if (!akt)
54 andreas 1283
	{
1284
		syslog(LOG_WARNING, "evaluateTemp: Room %s not found!", room);
8 andreas 1285
		return false;
54 andreas 1286
	}
8 andreas 1287
 
52 andreas 1288
	loctime = getTime();
1289
 
9 andreas 1290
	switch(akt->status)
1291
	{
1292
		case NORMAL:
53 andreas 1293
			if (akt->wstart && akt->wstart < akt->wend && loctime >= akt->wstart && loctime <= akt->wend)
52 andreas 1294
				soll = akt->night;
1295
			else if ((loctime >= akt->start && loctime <= akt->wstart) ||
1296
				(loctime >= akt->wend && loctime <= akt->end)) 
1297
				soll = akt->soll;
1298
 
9 andreas 1299
			diffOut = trunc(soll - getOutside());
1300
			diffIn = trunc(soll - temp);
1301
		break;
1302
 
1303
		case NIGHT:
1304
			if (akt->night)
1305
				soll = akt->night;
1306
			else
1307
				soll = glb_night;
1308
 
1309
			diffOut = trunc(soll - getOutside());
1310
			diffIn = trunc(soll - temp);
1311
		break;
1312
 
1313
		case OFF:
1314
			if (akt->minimal)
1315
				soll = akt->minimal;
1316
			else
1317
				soll = glb_minimal;
1318
 
1319
			diffOut = trunc(soll - getOutside());
1320
			diffIn = trunc(soll - temp);
1321
		break;
1322
	}
1323
 
8 andreas 1324
	if (!akt->hTable)			// If we've no heating table, we've to evaluate the temperature difference
1325
	{
9 andreas 1326
		if (!akt->valve && temp <= (soll - 0.5))
8 andreas 1327
		{
1328
			HTABLE *tb;
1329
			tb = appendHTable(akt);
9 andreas 1330
			tb->tempDifferOut = trunc(soll - getOutside());
1331
			tb->tempDifferIn = trunc(soll - temp);
8 andreas 1332
			tb->start = getTime();
1333
			return true;
1334
		}
1335
 
9 andreas 1336
		if (akt->valve && temp < soll)
8 andreas 1337
			return true;
1338
		else
1339
			return false;
1340
	}
9 andreas 1341
	else if (akt->valve && temp < soll)
8 andreas 1342
		return true;
9 andreas 1343
	else if (akt->valve && temp >= soll)
8 andreas 1344
	{
1345
		HTABLE *tb = akt->hTable;
1346
 
9 andreas 1347
		while (tb)
1348
		{
1349
			if (tb->start)
1350
				break;
8 andreas 1351
 
9 andreas 1352
			if (tb->next)
1353
				tb = tb->next;
1354
			else
1355
				break;
1356
		}
1357
 
1358
		if (tb && tb->start)
8 andreas 1359
		{
53 andreas 1360
			if (loctime > tb->start)
1361
				tb->heat = loctime - tb->start;
8 andreas 1362
			else
53 andreas 1363
				tb->heat = (86400 + loctime) - tb->start;
8 andreas 1364
 
1365
			tb->start = 0;
1366
		}
1367
 
1368
		return false;
1369
	}
9 andreas 1370
	else if (!akt->valve && temp <= (soll - 0.5))		// If temperature is beyond soll, start immediately
53 andreas 1371
	{
1372
		HTABLE *tb = akt->hTable;
1373
		// Find out whether we've already a correct time in the table or not.
1374
		while (tb)
1375
		{
1376
			if (tb->tempDifferOut == diffOut && tb->tempDifferIn == diffIn)
1377
				break;
1378
 
1379
			tb = tb->next;
1380
		}
1381
 
1382
		if (!tb)
1383
		{
1384
			tb = appendHTable(akt);
1385
			tb->tempDifferOut = diffOut;
1386
			tb->tempDifferIn = diffIn;
1387
			tb->start = loctime;
1388
		}
1389
 
9 andreas 1390
		return true;
53 andreas 1391
	}
9 andreas 1392
	else
8 andreas 1393
	{
9 andreas 1394
		HTABLE *tb = akt->hTable;
1395
		time_t t = getTime();
1396
		// Check the current time and look in learned table whether we should
1397
		// start heating or not.
1398
		if (tb)											// Only if we already have a table!
1399
		{												// Yes there is one, so search through it.
1400
			bool strt = false;
1401
 
1402
			if (diffIn <= 0.0)							// Is it warmer inside than it should be?
1403
				return false;							// yes, then turn heating off
1404
 
1405
			if (akt->status == OFF && diffIn >= 0.5)	// Are we in off mode and is the temperature lower than it should be?
1406
				return true;							// yes, then start heating
1407
			else if (akt->status == OFF)				// otherwise ...
1408
				return false;							// no heating
1409
 
1410
			while (tb)									// Search through learned table
1411
			{
1412
				if (!tb->start && tb->tempDifferOut == diffOut && tb->tempDifferIn == diffIn)
1413
					break;
1414
 
1415
				tb = tb->next;
1416
			}
1417
 
1418
			if (tb)										// Have we found a known time to heat?
1419
			{											// Yes, then look if it's time to heat
1420
				if (akt->status == NORMAL)
1421
				{
1422
					if ((t + tb->heat) >= akt->start && (t + tb->heat) <= akt->end)
1423
						return true;
1424
				}
1425
				else if (akt->status == NIGHT)
1426
				{
1427
					if ((t + tb->heat) >= akt->end || t < (akt->end - tb->heat))
1428
						return true;
1429
				}
1430
			}
1431
			else										// None of the saved temperture differences match.
1432
			{											// So test if it's time to add a new one
1433
				if (akt->status == NORMAL)
1434
				{
1435
					if ((t + 600) >= akt->start && (t + 600) <= akt->end)
1436
						strt = true;
1437
				}
1438
				else if (akt->status == NIGHT)
1439
				{
1440
					if ((t + 600) >= akt->end || t < (akt->end - 600))
1441
						strt = true;
1442
				}
1443
 
1444
				if (strt)
1445
				{
1446
					bool add = true;
1447
 
1448
					// Make sure there is no open start
1449
					tb = akt->hTable;
1450
 
1451
					while (tb)
1452
					{
1453
						if (tb->start)
1454
						{
1455
							add = false;
1456
							break;
1457
						}
1458
 
1459
						tb = tb->next;
1460
					}
1461
 
1462
					if (add)
1463
						tb = appendHTable(akt);
1464
 
1465
					tb->tempDifferOut = diffOut;
1466
					tb->tempDifferIn = diffIn;
1467
					tb->start = t;
1468
					return true;
1469
				}
1470
			}
1471
		}
8 andreas 1472
	}
9 andreas 1473
 
1474
	return false;
8 andreas 1475
}
53 andreas 1476
 
1477
time_t heating::calcTime(double soll, double ist)
1478
{
1479
double pwm, len;
1480
double correct= 100;
1481
double parallel = 110;
1482
 
1483
	pwm = (log((soll - ist) + correct * 0.001) + parallel * 0.01) * 100.0;
1484
	len = (10 * 60) * pwm / 100.0;
1485
	return time_t(len * 10.0);
1486
}
1487