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
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU General Public License as published by *
#* the Free Software Foundation; either version 3 of the License, or *
#* (at your option) any later version. *
#* *
#***************************************************************************
"""
This is the main module for the heatpump Monitor. It forks into the background
and should to a polling every 60 secs. It is quit simple at this point, no
config files or almost no error handling.
Written by Robert Penz <robert@penz.name>
"""
#TODO: Create a common log system which is able to write a timestamp before the entry
#TODO: define which line is painted over which in the graphs
import time
import sys
import traceback
import protocol
import storage
import render
import deamon
import threadedExec
import config_manager
import report
import thresholdMonitor
config = None
# Print usage message and exit
def usage(*args):
sys.stdout = sys.stderr
print __doc__
print 50*"-"
for msg in args: print msg
sys.exit(2)
def logError(e):
""" prints a string which a human readable error text """
print "========="
# args can be empty
if e.args:
if len(e.args) > 1:
print str(e.args)
else:
print e.args[0]
else:
# print exception class name
print str(e.__class__)
print "---------"
print traceback.format_exc()
print "========="
sys.stdout.flush()
def doMonitor():
try:
print "Starting ..."
sys.stdout.flush()
p = protocol.Protocol(config.getSerialDevice(), config.getProtocolVersionsDirectory())
s = storage.Storage(config.getDatabaseFile())
r = render.Render(config.getDatabaseFile(), config.getRenderOutputPath())
c = None # ThreadedExec for copyCommand
aReport = report.Report(config)
t = thresholdMonitor.ThresholdMonitor(config, aReport)
print "Up and running"
sys.stdout.flush()
counter = 0
renderInterval = config.getRenderInterval()
copyCommand = config.getCopyCommand()
copyInterval = config.getCopyInterval()
while 1:
startTime = time.time()
try:
values = p.query()
except Exception, e:
# log the error and just try it again in 120 sec - sometimes the heatpump returns an error and works
# seconds later again
# If the query takes longer than 2 minutes, we get a negative value ... maybe a problem in rare contitions
logError(e)
t.gotQueryError()
time.sleep(120 - (time.time() - startTime))
continue
# store the stuff
s.add(values)
# render it if the time is right
if counter % renderInterval == 0:
r.render()
# upload it somewhere if it fits the time
if copyCommand and counter % copyInterval == 0:
if c and c.isAlive():
print "Error: External copy program still running, cannot start it again"
sys.stdout.flush()
else:
c = threadedExec.ThreadedExec(copyCommand)
c.start()
counter += 1
# at last check the values if something needs to reported
t.check(values)
# lets make sure it is aways 60 secs interval, no matter how long the last run took
sleepTime = 61 - (time.time() - startTime)
if sleepTime < 0:
print "System is too slow for 60 sec interval by %d seconds" % abs(int(sleepTime))
else:
time.sleep(sleepTime)
except Exception, e:
# make sure the error got logged
logError(e)
# Main program: parse command line and start processing
def main():
global config
config = config_manager.ConfigManager()
deamon.startstop(config.getLogFile(), pidfile=config.getPidFile())
doMonitor()
if __name__ == '__main__':
main()
|