Subversion Repositories heating

Rev

Rev 53 | Go to most recent revision | 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
234
			}
9 andreas 235
 
5 andreas 236
			akt = akt->next;
237
		}
238
 
239
		i++;
240
 
241
		if (i > 60)
242
		{
243
			i = 0;
244
			akt = HeatConf;
245
 
246
			while (akt)
247
			{
47 andreas 248
				answer("IST:" + itostring(akt->rnum) + ":" + doubleToString(akt->ist, 1) + ";");
5 andreas 249
				akt = akt->next;
250
			}
251
		}
252
 
253
		sleep(1);
254
	}
255
 
256
	rrun = false;
4 andreas 257
}
258
 
12 andreas 259
void heating::controlHeat (int room, bool stst)
9 andreas 260
{
261
HCONF *akt = HeatConf;
262
int pin;
263
 
264
	while (akt)
265
	{
266
		if (akt->rnum == room)
267
			break;
268
 
269
		akt = akt->next;
270
	}
271
 
54 andreas 272
	if (!akt)
273
	{
274
		syslog(LOG_WARNING, "controlHeat: Room %d not found!", room);
9 andreas 275
		return;
54 andreas 276
	}
9 andreas 277
 
54 andreas 278
	if (akt->valve != stst)
279
	{
280
		if (Configure.debug)
281
			syslog(LOG_DEBUG, "Heating for room %d switched %s", room, (stst) ? "ON" : "OFF");
282
 
283
		string h = "HEATING:";
284
		h.append(itostring(room) + ":");
285
		h.append((stst)? "ON;" : "OFF;");
286
		answer(h);
287
	}
288
 
9 andreas 289
	switch (akt->gpio)
290
	{
291
		case 1: pin = PIN1; break;
292
		case 2: pin = PIN2; break;
293
		case 3: pin = PIN3; break;
294
		case 4: pin = PIN4; break;
295
		case 5: pin = PIN5; break;
296
		case 6: pin = PIN6; break;
297
		case 7: pin = PIN7; break;
298
		case 8: pin = PIN8; break;
299
		case 9: pin = PIN9; break;
300
		default:
301
			return;
302
	}
303
 
54 andreas 304
	akt->valve = stst;
9 andreas 305
	// Enable the GPIO pin to start heating
54 andreas 306
	if (!bcmInitialized)
9 andreas 307
		return;
308
 
309
	// Set the pin to be an output
310
	bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
311
	// Turn it on
12 andreas 312
	bcm2835_gpio_write(pin, (stst)? HIGH : LOW);
9 andreas 313
}
314
 
4 andreas 315
double heating::incSoll(int room)
316
{
317
HCONF *akt;
318
char *zErrMsg = nullptr;
319
int rc;
320
sqlite3 *db;
321
sqlite3_stmt *res;
322
string query;
323
 
324
	rc = sqlite3_open(Configure.home, &db);
325
 
326
	if (rc)
327
	{
328
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
329
		return 0.0;
330
	}
331
 
332
	if ((akt = findRoom(room)) != nullptr)
333
	{
334
		if (akt->soll >= 30.0)
335
		{
336
			sqlite3_close(db);
337
			return akt->soll;
338
		}
339
 
340
		akt->soll += 0.5;
49 andreas 341
		applyConfig();
47 andreas 342
		query = "update heating set soll = " + doubleToString(akt->soll, 1) + " where id = " + itostring(room);
4 andreas 343
 
5 andreas 344
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 345
		{
346
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
347
			sqlite3_free(zErrMsg);
348
			sqlite3_close(db);
349
			akt->soll -= 0.5;
350
			return akt->soll;
351
		}
352
 
353
		sqlite3_close(db);
5 andreas 354
		stringstream stream;
49 andreas 355
		stream << "SOLL:" << fixed << setprecision(1) << akt->soll << ";";
5 andreas 356
		answer(stream.str());
4 andreas 357
		return akt->soll;
358
	}
359
 
360
	return 0.0;
361
}
362
 
363
double heating::decSoll(int room)
364
{
365
HCONF *akt;
366
char *zErrMsg = nullptr;
367
int rc;
368
sqlite3 *db;
369
sqlite3_stmt *res;
370
string query;
371
 
372
	rc = sqlite3_open(Configure.home, &db);
373
 
374
	if (rc)
375
	{
376
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
377
		return 0.0;
378
	}
379
 
380
	if ((akt = findRoom(room)) != nullptr)
381
	{
382
		if (akt->soll <= 10.0)
383
		{
384
			sqlite3_close(db);
385
			return akt->soll;
386
		}
387
 
388
		akt->soll -= 0.5;
49 andreas 389
		applyConfig();
47 andreas 390
		query = "update heating set soll = " + doubleToString(akt->soll, 1) + " where id = " + itostring(room);
4 andreas 391
 
5 andreas 392
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 393
		{
394
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
395
			sqlite3_free(zErrMsg);
396
			sqlite3_close(db);
397
			akt->soll += 0.5;
398
			return akt->soll;
399
		}
400
 
401
		sqlite3_close(db);
5 andreas 402
		stringstream stream;
49 andreas 403
		stream << "SOLL:" << fixed << setprecision(1) << akt->soll << ";";
5 andreas 404
		answer(stream.str());
4 andreas 405
		return akt->soll;
406
	}
407
 
408
	return 0.0;
409
}
410
 
9 andreas 411
void heating::setSoll (int room, double val)
412
{
413
HCONF *akt = HeatConf;
414
char *zErrMsg = nullptr;
415
int rc;
416
sqlite3 *db;
417
sqlite3_stmt *res;
418
string query;
419
 
420
	if (val < 10.0 || val > 30.0)
421
	{
422
		syslog(LOG_INFO, "Invalid value for maximum room temperature!");
423
		return;
424
	}
425
 
426
	rc = sqlite3_open(Configure.home, &db);
427
 
428
	if (rc)
429
	{
430
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
431
		return;
432
	}
433
 
434
	if (room > 0 && (akt = findRoom(room)) != nullptr)
435
	{
436
		akt->soll = val;
49 andreas 437
		applyConfig();
47 andreas 438
		query = "update heating set soll = " + doubleToString(val, 1) + " where id = " + itostring(room);
9 andreas 439
 
440
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
441
		{
442
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
443
			sqlite3_free(zErrMsg);
444
			sqlite3_close(db);
445
			return;
446
		}
447
 
47 andreas 448
		query = "SOLL:" + itostring(room) + ":" + doubleToString(val, 1) + ";";
9 andreas 449
		answer(query);
450
	}
451
 
452
	sqlite3_close(db);
453
}
454
 
4 andreas 455
void heating::setNight(int room, double val)
456
{
457
HCONF *akt;
458
char *zErrMsg = nullptr;
459
int rc;
460
sqlite3 *db;
461
sqlite3_stmt *res;
462
string query;
463
 
464
	if (val < 10.0 || val > 25.0)
465
	{
466
		syslog(LOG_INFO, "Invalid value for the night!");
467
		return;
468
	}
469
 
470
	rc = sqlite3_open(Configure.home, &db);
471
 
472
	if (rc)
473
	{
474
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
475
		return;
476
	}
477
 
478
	if (room > 0 && (akt = findRoom(room)) != nullptr)
479
	{
480
		akt->night = val;
49 andreas 481
		applyConfig();
47 andreas 482
		query = "update heating set night = " + doubleToString(val, 1) + " where id = " + itostring(room);
5 andreas 483
 
484
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 485
		{
486
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
487
			sqlite3_free(zErrMsg);
488
			sqlite3_close(db);
489
			return;
490
		}
491
 
47 andreas 492
		query = "NIGHT:" + itostring(room) + ":" + doubleToString(val, 1) + ";";
5 andreas 493
		answer(query);
4 andreas 494
	}
495
	else if (room == 0)
496
	{
497
		glb_night = val;
49 andreas 498
 
499
		if (HtmlServer != nullptr)
500
			HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
501
 
47 andreas 502
		query = "update glbheat set night = " + doubleToString(val, 1);
4 andreas 503
 
5 andreas 504
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 505
		{
506
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
507
			sqlite3_free(zErrMsg);
508
			sqlite3_close(db);
509
			return;
510
		}
5 andreas 511
 
47 andreas 512
		query = "CONFIG:GLOBAL NIGHT:" + doubleToString(val, 1) + ";";
5 andreas 513
		answer(query);
4 andreas 514
	}
515
 
516
	sqlite3_close(db);
517
}
518
 
519
void heating::setMinimal(int room, double val)
520
{
521
HCONF *akt;
522
char *zErrMsg = nullptr;
523
int rc;
524
sqlite3 *db;
525
sqlite3_stmt *res;
526
string query;
527
 
528
	if (val < 10.0 || val > 20.0)
529
	{
530
		syslog(LOG_INFO, "Invalid value for the night!");
531
		return;
532
	}
533
 
534
	rc = sqlite3_open(Configure.home, &db);
535
 
536
	if (rc)
537
	{
538
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
539
		return;
540
	}
541
 
542
	if (room > 0 && (akt = findRoom(room)) != nullptr)
543
	{
544
		akt->minimal = val;
49 andreas 545
		applyConfig();
47 andreas 546
		query = "update heating set minimal = " + doubleToString(val, 1) + " where id = " + itostring(room);
4 andreas 547
 
5 andreas 548
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 549
		{
550
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
551
			sqlite3_free(zErrMsg);
552
			sqlite3_close(db);
553
			return;
554
		}
5 andreas 555
 
47 andreas 556
		query = "MINIMAL:" + itostring(room) + ":" + doubleToString(val, 1) + ";";
5 andreas 557
		answer(query);
4 andreas 558
	}
559
	else if (room == 0)
560
	{
561
		glb_minimal = val;
49 andreas 562
 
563
		if (HtmlServer != nullptr)
564
			HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
565
 
47 andreas 566
		query = "update glbheat set minimal = " + doubleToString(val, 1);
4 andreas 567
 
5 andreas 568
		if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 569
		{
570
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
571
			sqlite3_free(zErrMsg);
572
			sqlite3_close(db);
573
			return;
574
		}
5 andreas 575
 
47 andreas 576
		query = "CONFIG:GLOBAL MINIMAL:" + doubleToString(val, 1) + ";";
5 andreas 577
		answer(query);
4 andreas 578
	}
579
 
580
	sqlite3_close(db);
581
}
582
 
583
bool heating::switchOnOff(bool what)
584
{
585
HCONF *akt;
586
char *zErrMsg = nullptr;
587
int rc;
588
sqlite3 *db;
589
sqlite3_stmt *res;
590
string query;
591
 
592
	rc = sqlite3_open(Configure.home, &db);
593
 
594
	if (rc)
595
	{
596
		syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
5 andreas 597
		return onoff;
4 andreas 598
	}
599
 
600
	onoff = what;
49 andreas 601
 
602
	if (HtmlServer != nullptr)
603
		HtmlServer->setGlobals(glb_night, glb_minimal, onoff);
604
 
5 andreas 605
	query = "update glbheat set onoff = " + (what)?"1":"0";
4 andreas 606
 
5 andreas 607
	if ((rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg)) != SQLITE_OK)
4 andreas 608
	{
609
		syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
610
		sqlite3_free(zErrMsg);
611
		sqlite3_close(db);
5 andreas 612
		return onoff;
4 andreas 613
	}
614
 
615
	sqlite3_close(db);
49 andreas 616
	query = "POWER:";
617
	query.append((onoff) ? "ON;" : "OFF;");
5 andreas 618
	answer(query);
619
	return onoff;
4 andreas 620
}
621
 
622
double heating::getNight (int room)
623
{
624
HCONF *akt = findRoom(room);
625
 
626
	if (akt && akt->night > 0.0)
627
		return akt->night;
628
 
629
	return glb_night;
630
}
631
 
632
double heating::getMinimal (int room)
633
{
634
HCONF *akt = findRoom(room);
635
 
636
	if (akt && akt->minimal > 0.0)
637
		return akt->minimal;
638
 
639
	return glb_minimal;
640
}
641
 
3 andreas 642
void heating::destroyHConf()
643
{
644
HCONF *p, *next;
645
 
646
	p = HeatConf;
647
 
648
	while (p)
649
	{
650
		next = p->next;
651
		delete p;
652
		p = next;
653
	}
654
 
655
	HeatConf = nullptr;
656
}
657
 
5 andreas 658
void heating::getConfig (int s1)
659
{
660
HCONF *akt = HeatConf;
661
stringstream stream;
662
 
50 andreas 663
	stream << "CONFIG:GLOBAL NIGHT:" << fixed << setprecision(1) << glb_night << ";";
664
	stream << "CONFIG:GLOBAL MINIMAL:" << fixed << setprecision(1) << glb_minimal << ";";
49 andreas 665
	stream << "CONFIG:ONOFF:" << ((onoff) ? "ON;" : "OFF;");
5 andreas 666
 
667
	while (akt)
668
	{
50 andreas 669
		stream << "CONFIG:ROOM:" << itostring(akt->rnum) << ":" << string(akt->rname) << ":" <<
670
			fixed << setprecision(1) << akt->soll << ":" << akt->night << ":" <<
42 andreas 671
			akt->minimal << ":" << timeToStr(akt->start) << ":" << timeToStr(akt->end) << ":" <<
48 andreas 672
			timeToStr(akt->wstart) << ":" << timeToStr(akt->wend) << ";";
5 andreas 673
 
54 andreas 674
		stream << "HEATING:" << itostring(akt->rnum) << ":";
675
 
676
		if (akt->valve)
677
			stream << "ON;";
678
		else
679
			stream << "OFF;";
680
 
5 andreas 681
		akt = akt->next;
682
	}
49 andreas 683
 
684
	write(s1, stream.str().c_str(), stream.str().length());
5 andreas 685
}
686
 
4 andreas 687
heating::HCONF* heating::findRoom (int room)
688
{
689
HCONF *akt = HeatConf;
690
 
691
	while (akt)
692
	{
693
		if (akt->rnum == room)
694
			return akt;
695
 
696
		akt = akt->next;
697
	}
698
 
699
	return nullptr;
700
}
701
 
3 andreas 702
bool heating::readConf()
703
{
704
ifstream cfile;
705
char line[1024], hv0[256], hv1[128];
706
char *p;
4 andreas 707
CNFSTAT cs;
708
HCONF *akt = HeatConf;
3 andreas 709
 
710
	// If there's no config file, inform the user about it.
711
	cfile.open(Configure.heatconf, ios::in);
712
 
713
	if ((cfile.rdstate() & std::ifstream::failbit) != 0)
714
	{
715
		syslog(LOG_WARNING,"Error opening the config file: %s", strerror(errno));
716
		return false;
717
	}
718
 
719
	syslog(LOG_INFO, "Found config file %s.", Configure.heatconf);
4 andreas 720
	cs = NONE;
3 andreas 721
	// Here we've found a config file. We'll read it and set the
722
	// contents to the structure
723
	while (cfile.getline(&line[0], sizeof(line)))
724
	{
725
		int len;
726
 
727
		trim (&line[0]);
728
 
729
		if (line[0] == '#' || !char_traits<char>::length(line))
730
			continue;
731
 
4 andreas 732
		if ((p = findc(line, char_traits<char>::length(line), ']')) != NULL)
733
		{
734
			char *x;
735
 
736
			*(p+1) = 0;
737
 
738
			if (!compcase(line, "[global]"))
739
			{
740
				cs = GLOBAL;
741
				continue;
742
			}
743
 
744
			if ((x = findc(line, char_traits<char>::length(line), '[')) != NULL)
745
			{
746
				*p = 0;
747
				akt = appendHConf();
748
				strncpy(akt->rname, x+1, sizeof(akt->rname) - 1);
749
				akt->soll = 20.0;
750
				cs = ROOM;
751
				continue;
752
			}
753
			else
754
				cs = NONE;
755
		}
756
 
757
		if ((p = findc(line, char_traits<char>::length(line), '=')) == NULL || cs == NONE)
3 andreas 758
			continue;
759
 
760
		*p = 0;
761
		p++;
762
		len = char_traits<char>::length(line);
763
 
764
		if (len > (int)sizeof(hv0))
765
			len = (int)sizeof(hv0) - 1;
766
 
767
		strncpy(hv0, line, len);
768
		hv0[len] = 0;
769
		trim (hv0);
770
		len = char_traits<char>::length(p);
771
 
772
		if (len > (int)sizeof(hv1))
773
			len = (int)sizeof(hv0) - 1;
774
 
775
		strncpy(hv1, p, len);
776
		hv1[len] = 0;
777
		trim (hv1);
778
 
4 andreas 779
		if (!compcase(hv0, "minimal"))
780
		{
781
			if (cs == GLOBAL)
782
				glb_minimal = atof (hv1);
783
			else
784
				akt->minimal = atof (hv1);
785
		}
3 andreas 786
 
4 andreas 787
		if (!compcase(hv0, "night"))
788
		{
789
			if (cs == GLOBAL)
790
				glb_night = atof (hv1);
791
			else
792
				akt->night = atof (hv1);
793
		}
794
 
795
		if (!compcase(hv0, "OnOff") && cs == GLOBAL)
796
			onoff = ToBool(hv1);
797
 
12 andreas 798
		if (!compcase(hv0, "OutSensor") && cs == GLOBAL)
799
			outSensor = atoi(hv1);
800
 
4 andreas 801
		if (cs == ROOM)
802
		{
803
			if (!compcase(hv0, "soll"))
804
				akt->soll = atoi(hv1);
805
 
806
			if (!compcase(hv0, "Sensor"))
807
				akt->tempsensor = atoi(hv1);
808
 
809
			if (!compcase(hv0, "GPIO"))
810
				akt->gpio = atoi(hv1);
811
 
812
			if (!compcase(hv0, "StartTime"))
13 andreas 813
			{
4 andreas 814
				akt->start = strToTime(hv1);
14 andreas 815
				debug("StartTime: " + itostring(akt->start) + "(" + ToString(hv1) + ")");
13 andreas 816
			}
4 andreas 817
 
818
			if (!compcase(hv0, "EndTime"))
13 andreas 819
			{
4 andreas 820
				akt->end = strToTime(hv1);
14 andreas 821
				debug("EndTime: " + itostring(akt->end) + "(" + ToString(hv1) + ")");
13 andreas 822
			}
42 andreas 823
 
824
			if (!compcase(hv0, "WorkStartTime"))
825
			{
826
				akt->wstart = strToTime(hv1);
827
				debug("WorkStartTime: " + itostring(akt->wstart) + "(" + ToString(hv1) + ")");
828
			}
829
 
830
			if (!compcase(hv0, "WorkEndTime"))
831
			{
832
				akt->wend = strToTime(hv1);
833
				debug("WorkEndTime: " + itostring(akt->wend) + "(" + ToString(hv1) + ")");
834
			}
4 andreas 835
		}
836
	}
54 andreas 837
 
838
	akt = HeatConf;
839
	time_t loctime = getTime();
840
 
841
	while (akt)
842
	{
843
		if (onoff)
844
			akt->status = OFF;
845
		else if (loctime > akt->start && loctime < akt->end)
846
			akt->status = NORMAL;
847
		else
848
			akt->status = NIGHT;
849
 
850
		akt = akt->next;
851
	}
852
 
4 andreas 853
	cfile.close ();
854
	return true;
855
}
856
 
857
 
858
bool heating::buildDB()
859
{
860
sqlite3 *db;
861
sqlite3_stmt *res;
862
int rc;
863
char *zErrMsg = nullptr;
864
string query;
865
 
866
	if (access(Configure.home, R_OK | W_OK))		// Try to create a new database if it doesn't exist
867
	{
868
		HCONF *akt;
869
 
18 andreas 870
		debug("Creating SQL3 database.");
4 andreas 871
		rc = sqlite3_open(Configure.home, &db);
872
 
873
		if (rc)
874
		{
875
			syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
876
			return false;
877
		}
878
 
879
		query = "create table \"main\".\"heating\" (";
880
		query.append("\"id\" INTEGER PRIMARY KEY NOT NULL,");
881
		query.append("\"name\" TEXT NOT NULL,");
882
		query.append("\"soll\" REAL,");
883
		query.append("\"night\" REAL,");
884
		query.append("\"minimal\" REAL,");
885
		query.append("\"start\" INTEGER,");
42 andreas 886
		query.append("\"end\" INTEGER,");
887
		query.append("\"wstart\" INTEGER,");
888
		query.append("\"wend\" INTEGER");
4 andreas 889
		query.append(")");
5 andreas 890
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
4 andreas 891
 
892
		if (rc != SQLITE_OK)
893
		{
894
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
895
			sqlite3_free(zErrMsg);
896
			sqlite3_close(db);
897
			return false;
898
		}
899
		else
900
			syslog(LOG_INFO, "Database \"heating\" was successfully created.");
901
 
10 andreas 902
		query = "create table \"main\".\"kitable\" (";
903
		query.append("\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,");
12 andreas 904
		query.append("\"rnum\" INTEGER NOT NULL,");
10 andreas 905
		query.append("\"diffout\" INTEGER,");
906
		query.append("\"diffin\" INTEGER,");
907
		query.append("\"heat\" INTEGER)");
908
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
909
 
910
		if (rc != SQLITE_OK)
911
		{
912
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
913
			sqlite3_free(zErrMsg);
914
			sqlite3_close(db);
915
			return false;
916
		}
917
		else
918
			syslog(LOG_INFO, "Database \"kitable\" was successfully created.");
919
 
920
		query = "create table \"main\".\"glbheat\" (";
921
		query.append("\"night\" REAL,");
922
		query.append("\"minimal\" REAL,");
923
		query.append("\"onoff\" INTEGER");
924
		query.append(")");
925
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
40 andreas 926
 
10 andreas 927
		if (rc != SQLITE_OK)
928
		{
929
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
930
			sqlite3_free(zErrMsg);
931
			sqlite3_close(db);
932
			return false;
933
		}
934
		else
935
			syslog(LOG_INFO, "Database \"glbheat\" was successfully created.");
40 andreas 936
 
4 andreas 937
		// Insert the values from the config file into the table
18 andreas 938
		debug("Inserting configuration into SQL3 database");
4 andreas 939
		akt = HeatConf;
40 andreas 940
 
4 andreas 941
		while (akt)
942
		{
42 andreas 943
			query = "insert into heating (id, name, soll, night, minimal, start, end, wstart, wend) values (";
4 andreas 944
			query.append(itostring(akt->rnum));
10 andreas 945
			query.append(",\""+string(akt->rname)+"\"");
47 andreas 946
			query.append(","+doubleToString(akt->soll, 1));
947
			query.append(","+doubleToString(akt->night, 1));
948
			query.append(","+doubleToString(akt->minimal, 1));
4 andreas 949
			query.append(","+itostring(akt->start));
950
			query.append(","+itostring(akt->end));
42 andreas 951
			query.append(","+itostring(akt->wstart));
952
			query.append(","+itostring(akt->wend));
4 andreas 953
			query.append(")");
5 andreas 954
			rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
4 andreas 955
 
956
			if (rc != SQLITE_OK)
957
			{
958
				syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
959
				sqlite3_free(zErrMsg);
960
				sqlite3_close(db);
961
				return false;
962
			}
963
 
964
			akt = akt->next;
15 andreas 965
		}
4 andreas 966
 
15 andreas 967
		query = "insert into glbheat (night, minimal, onoff) values (";
47 andreas 968
		query.append(doubleToString(glb_night, 1));
969
		query.append(","+doubleToString(glb_minimal, 1));
15 andreas 970
		query.append(","+itostring(onoff));
971
		query.append(")");
972
		rc = sqlite3_exec(db, query.c_str(), NULL, NULL, &zErrMsg);
973
 
974
		if (rc != SQLITE_OK)
975
		{
976
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), zErrMsg);
977
			sqlite3_free(zErrMsg);
978
			sqlite3_close(db);
979
			return false;
4 andreas 980
		}
981
 
982
		sqlite3_close(db);
983
	}
984
	else
985
	{
986
		HCONF *akt;
15 andreas 987
 
18 andreas 988
		debug("Reading configuration from SQL3 database");
4 andreas 989
		rc = sqlite3_open(Configure.home, &db);
15 andreas 990
 
4 andreas 991
		if (rc)
992
		{
993
			syslog(LOG_DAEMON, "Error opening database %s: %s", Configure.home, sqlite3_errmsg(db));
994
			return false;
995
		}
996
 
997
		akt = HeatConf;
54 andreas 998
		time_t loctime = getTime();
40 andreas 999
 
4 andreas 1000
		while (akt)
3 andreas 1001
		{
18 andreas 1002
			debug("Queriing "+itostring(akt->rnum)+", "+ToString(akt->rname));
4 andreas 1003
			query = "select id, name, soll, night, minimal, start, end from heating where id = "+itostring(akt->rnum);
1004
 
5 andreas 1005
			if (sqlite3_prepare(db, query.c_str(), -1, &res, NULL) != SQLITE_OK)
4 andreas 1006
			{
1007
				syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), sqlite3_errmsg(db));
1008
				sqlite3_close(db);
1009
				return false;
1010
			}
1011
 
1012
			if ((rc = sqlite3_step(res)) == SQLITE_ROW)
1013
			{
1014
				strncpy(akt->rname, (const char *)sqlite3_column_text(res, 1), sizeof(akt->rname) - 1);
1015
				akt->soll = sqlite3_column_double(res, 2);
1016
				akt->night = sqlite3_column_double(res, 3);
1017
				akt->minimal = sqlite3_column_double(res, 4);
1018
				akt->start = (time_t)sqlite3_column_int(res, 5);
1019
				akt->end = (time_t)sqlite3_column_int(res, 6);
1020
			}
1021
 
44 andreas 1022
			sqlite3_finalize(res);
12 andreas 1023
			query = "select rnum, diffout, diffin, heat from kitable where rnum = " + itostring(akt->rnum);
1024
 
1025
			if (sqlite3_prepare(db, query.c_str(), -1, &res, NULL) != SQLITE_OK)
1026
			{
1027
				syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), sqlite3_errmsg(db));
1028
				sqlite3_close(db);
1029
				return false;
1030
			}
1031
 
1032
			while ((rc = sqlite3_step(res)) == SQLITE_ROW)
1033
			{
1034
				HTABLE *tb = appendHTable(akt);
15 andreas 1035
				tb->tempDifferOut = sqlite3_column_double(res, 1);
1036
				tb->tempDifferIn = sqlite3_column_double(res, 2);
12 andreas 1037
				tb->heat = sqlite3_column_int(res, 3);
18 andreas 1038
				debug("KITABLE: read "+itostring(sqlite3_column_int(res, 0)));
12 andreas 1039
			}
1040
 
44 andreas 1041
			sqlite3_finalize(res);
54 andreas 1042
 
1043
			if (onoff)
1044
				akt->status = OFF;
1045
			else if (loctime > akt->start && loctime < akt->end)
1046
				akt->status = NORMAL;
1047
			else
1048
				akt->status = NIGHT;
1049
 
4 andreas 1050
			akt = akt->next;
3 andreas 1051
		}
4 andreas 1052
 
18 andreas 1053
		debug("Reading global parameters from SQL3 database");
4 andreas 1054
		query = "select night, minimal, onoff from glbheat";
1055
 
5 andreas 1056
		if (sqlite3_prepare(db, query.c_str(), -1, &res, NULL) != SQLITE_OK)
4 andreas 1057
		{
1058
			syslog(LOG_WARNING, "SQL error [%s]: %s", query.c_str(), sqlite3_errmsg(db));
1059
			sqlite3_close(db);
1060
			return false;
1061
		}
1062
 
1063
		if ((rc = sqlite3_step(res)) == SQLITE_ROW)
1064
		{
1065
			glb_night = sqlite3_column_double(res, 0);
1066
			glb_minimal = sqlite3_column_double(res, 1);
1067
			onoff = (time_t)sqlite3_column_int(res, 2);
1068
		}
1069
 
44 andreas 1070
		sqlite3_finalize(res);
4 andreas 1071
		sqlite3_close(db);
3 andreas 1072
	}
4 andreas 1073
 
18 andreas 1074
	debug("All database operations done");
3 andreas 1075
	return true;
1076
}
1077
 
5 andreas 1078
void heating::setHandle (int fd)
1079
{
1080
	// First look into table to make sure the handle isn't already in the table
1081
	for (int i = 0; i < 100; i++)
1082
	{
1083
		if (s1[i] == fd)
1084
			return;
1085
	}
1086
 
1087
	// Because we're here, the handle is not in the table. So insert it now.
1088
	for (int i = 0; i < 100; i++)
1089
	{
1090
		if (s1[i] < 0)
1091
		{
1092
			s1[i] = fd;
1093
			break;
1094
		}
1095
	}
1096
}
1097
 
1098
void heating::removeHandle (int fd)
1099
{
1100
	for (int i = 0; i < 100; i++)
1101
	{
1102
		if (s1[i] == fd)
1103
		{
1104
			s1[i] = -1;
1105
			break;
1106
		}
1107
	}
1108
}
1109
 
1110
void heating::answer (string msg)
1111
{
1112
	for (int i = 0; i < 100; i++)
1113
	{
1114
		if (s1[i] > 0)
1115
			write(s1[i], msg.c_str(), strlen(msg.c_str()));
1116
	}
1117
}
1118
 
4 andreas 1119
time_t heating::strToTime (char* str)
1120
{
14 andreas 1121
int hour, min;
4 andreas 1122
 
7 andreas 1123
	if (strchr(str, ':') != NULL)
1124
	{
14 andreas 1125
		sscanf(str, "%d:%d", &hour, &min);
1126
		return (time_t)hour * 3600 + (time_t)min * 60;
7 andreas 1127
	}
1128
 
1129
	return 0;
4 andreas 1130
}
1131
 
5 andreas 1132
string heating::timeToStr(time_t t)
1133
{
14 andreas 1134
int hour, min;
38 andreas 1135
char hv0[48];
5 andreas 1136
 
14 andreas 1137
	hour = (int)(t / 3600);
39 andreas 1138
	min = (int)((t - (time_t)hour * 3600) / 60);
38 andreas 1139
	sprintf(hv0, "%02d:%02d", hour, min);
1140
	string zeit(hv0);
5 andreas 1141
	return zeit;
1142
}
1143
 
8 andreas 1144
time_t heating::getTime()
1145
{
54 andreas 1146
tm *ltm;
8 andreas 1147
time_t t = time(NULL);
54 andreas 1148
time_t out;
8 andreas 1149
 
1150
	ltm = localtime(&t);
54 andreas 1151
	out = (time_t)(ltm->tm_hour * 3600 + ltm->tm_min * 60 + ltm->tm_sec);
1152
	return out;
8 andreas 1153
}
1154
 
3 andreas 1155
heating::HCONF* heating::appendHConf()
1156
{
1157
HCONF *akt, *p;
1158
 
1159
	akt = new HCONF;
1160
	memset(akt, 0, sizeof(HCONF));
54 andreas 1161
	akt->soll = 0.0;
1162
	akt->night = 0.0;
1163
	akt->minimal = 0.0;
1164
	akt->ist = 0.0;
3 andreas 1165
 
1166
	if (HeatConf == nullptr)
1167
		HeatConf = akt;
1168
	else
1169
	{
1170
		p = HeatConf;
1171
 
1172
		while (p->next)
1173
			p = p->next;
1174
 
1175
		p->next = akt;
1176
	}
1177
 
1178
	rm++;
1179
	akt->rnum = rm;
1180
	return akt;
1181
}
8 andreas 1182
 
1183
heating::HTABLE* heating::appendHTable(HCONF *ht)
1184
{
1185
HTABLE *akt, *p;
1186
 
1187
	akt = new HTABLE;
1188
	memset(akt, 0, sizeof(HTABLE));
1189
 
1190
	if (ht->hTable == nullptr)
1191
		ht->hTable = akt;
1192
	else
1193
	{
1194
		p = ht->hTable;
1195
 
1196
		while (p->next)
1197
			p = p->next;
1198
 
1199
		p->next = akt;
1200
	}
1201
 
1202
	return akt;
1203
}
1204
 
1205
bool heating::evaluateTemp (int room, double temp)
1206
{
1207
HCONF *akt;
9 andreas 1208
double soll, diffOut, diffIn;
52 andreas 1209
time_t loctime;
8 andreas 1210
 
1211
	akt = HeatConf;
1212
 
1213
	while (akt)
1214
	{
1215
		if (akt->rnum == room)
1216
			break;
1217
 
1218
		akt = akt->next;
1219
	}
1220
 
1221
	if (!akt)
54 andreas 1222
	{
1223
		syslog(LOG_WARNING, "evaluateTemp: Room %s not found!", room);
8 andreas 1224
		return false;
54 andreas 1225
	}
8 andreas 1226
 
52 andreas 1227
	loctime = getTime();
1228
 
9 andreas 1229
	switch(akt->status)
1230
	{
1231
		case NORMAL:
53 andreas 1232
			if (akt->wstart && akt->wstart < akt->wend && loctime >= akt->wstart && loctime <= akt->wend)
52 andreas 1233
				soll = akt->night;
1234
			else if ((loctime >= akt->start && loctime <= akt->wstart) ||
1235
				(loctime >= akt->wend && loctime <= akt->end)) 
1236
				soll = akt->soll;
1237
 
9 andreas 1238
			diffOut = trunc(soll - getOutside());
1239
			diffIn = trunc(soll - temp);
1240
		break;
1241
 
1242
		case NIGHT:
1243
			if (akt->night)
1244
				soll = akt->night;
1245
			else
1246
				soll = glb_night;
1247
 
1248
			diffOut = trunc(soll - getOutside());
1249
			diffIn = trunc(soll - temp);
1250
		break;
1251
 
1252
		case OFF:
1253
			if (akt->minimal)
1254
				soll = akt->minimal;
1255
			else
1256
				soll = glb_minimal;
1257
 
1258
			diffOut = trunc(soll - getOutside());
1259
			diffIn = trunc(soll - temp);
1260
		break;
1261
	}
1262
 
8 andreas 1263
	if (!akt->hTable)			// If we've no heating table, we've to evaluate the temperature difference
1264
	{
9 andreas 1265
		if (!akt->valve && temp <= (soll - 0.5))
8 andreas 1266
		{
1267
			HTABLE *tb;
1268
			tb = appendHTable(akt);
9 andreas 1269
			tb->tempDifferOut = trunc(soll - getOutside());
1270
			tb->tempDifferIn = trunc(soll - temp);
8 andreas 1271
			tb->start = getTime();
1272
			return true;
1273
		}
1274
 
9 andreas 1275
		if (akt->valve && temp < soll)
8 andreas 1276
			return true;
1277
		else
1278
			return false;
1279
	}
9 andreas 1280
	else if (akt->valve && temp < soll)
8 andreas 1281
		return true;
9 andreas 1282
	else if (akt->valve && temp >= soll)
8 andreas 1283
	{
1284
		HTABLE *tb = akt->hTable;
1285
 
9 andreas 1286
		while (tb)
1287
		{
1288
			if (tb->start)
1289
				break;
8 andreas 1290
 
9 andreas 1291
			if (tb->next)
1292
				tb = tb->next;
1293
			else
1294
				break;
1295
		}
1296
 
1297
		if (tb && tb->start)
8 andreas 1298
		{
53 andreas 1299
			if (loctime > tb->start)
1300
				tb->heat = loctime - tb->start;
8 andreas 1301
			else
53 andreas 1302
				tb->heat = (86400 + loctime) - tb->start;
8 andreas 1303
 
1304
			tb->start = 0;
1305
		}
1306
 
1307
		return false;
1308
	}
9 andreas 1309
	else if (!akt->valve && temp <= (soll - 0.5))		// If temperature is beyond soll, start immediately
53 andreas 1310
	{
1311
		HTABLE *tb = akt->hTable;
1312
		// Find out whether we've already a correct time in the table or not.
1313
		while (tb)
1314
		{
1315
			if (tb->tempDifferOut == diffOut && tb->tempDifferIn == diffIn)
1316
				break;
1317
 
1318
			tb = tb->next;
1319
		}
1320
 
1321
		if (!tb)
1322
		{
1323
			tb = appendHTable(akt);
1324
			tb->tempDifferOut = diffOut;
1325
			tb->tempDifferIn = diffIn;
1326
			tb->start = loctime;
1327
		}
1328
 
9 andreas 1329
		return true;
53 andreas 1330
	}
9 andreas 1331
	else
8 andreas 1332
	{
9 andreas 1333
		HTABLE *tb = akt->hTable;
1334
		time_t t = getTime();
1335
		// Check the current time and look in learned table whether we should
1336
		// start heating or not.
1337
		if (tb)											// Only if we already have a table!
1338
		{												// Yes there is one, so search through it.
1339
			bool strt = false;
1340
 
1341
			if (diffIn <= 0.0)							// Is it warmer inside than it should be?
1342
				return false;							// yes, then turn heating off
1343
 
1344
			if (akt->status == OFF && diffIn >= 0.5)	// Are we in off mode and is the temperature lower than it should be?
1345
				return true;							// yes, then start heating
1346
			else if (akt->status == OFF)				// otherwise ...
1347
				return false;							// no heating
1348
 
1349
			while (tb)									// Search through learned table
1350
			{
1351
				if (!tb->start && tb->tempDifferOut == diffOut && tb->tempDifferIn == diffIn)
1352
					break;
1353
 
1354
				tb = tb->next;
1355
			}
1356
 
1357
			if (tb)										// Have we found a known time to heat?
1358
			{											// Yes, then look if it's time to heat
1359
				if (akt->status == NORMAL)
1360
				{
1361
					if ((t + tb->heat) >= akt->start && (t + tb->heat) <= akt->end)
1362
						return true;
1363
				}
1364
				else if (akt->status == NIGHT)
1365
				{
1366
					if ((t + tb->heat) >= akt->end || t < (akt->end - tb->heat))
1367
						return true;
1368
				}
1369
			}
1370
			else										// None of the saved temperture differences match.
1371
			{											// So test if it's time to add a new one
1372
				if (akt->status == NORMAL)
1373
				{
1374
					if ((t + 600) >= akt->start && (t + 600) <= akt->end)
1375
						strt = true;
1376
				}
1377
				else if (akt->status == NIGHT)
1378
				{
1379
					if ((t + 600) >= akt->end || t < (akt->end - 600))
1380
						strt = true;
1381
				}
1382
 
1383
				if (strt)
1384
				{
1385
					bool add = true;
1386
 
1387
					// Make sure there is no open start
1388
					tb = akt->hTable;
1389
 
1390
					while (tb)
1391
					{
1392
						if (tb->start)
1393
						{
1394
							add = false;
1395
							break;
1396
						}
1397
 
1398
						tb = tb->next;
1399
					}
1400
 
1401
					if (add)
1402
						tb = appendHTable(akt);
1403
 
1404
					tb->tempDifferOut = diffOut;
1405
					tb->tempDifferIn = diffIn;
1406
					tb->start = t;
1407
					return true;
1408
				}
1409
			}
1410
		}
8 andreas 1411
	}
9 andreas 1412
 
1413
	return false;
8 andreas 1414
}
53 andreas 1415
 
1416
time_t heating::calcTime(double soll, double ist)
1417
{
1418
double pwm, len;
1419
double correct= 100;
1420
double parallel = 110;
1421
 
1422
	pwm = (log((soll - ist) + correct * 0.001) + parallel * 0.01) * 100.0;
1423
	len = (10 * 60) * pwm / 100.0;
1424
	return time_t(len * 10.0);
1425
}
1426