reformatted using pyCharm

master
agp8x 2015-08-30 18:22:55 +02:00
parent bb840d46cf
commit a508fb7269
8 changed files with 450 additions and 433 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ arch/
locks/ locks/
logs/ logs/
records/ records/
.idea/
bin/ bin/
bin/* bin/*
*~ *~

View File

@ -1,8 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time
import sys
import traceback import traceback
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import os import os
@ -11,6 +9,7 @@ from timeFunctions import *
from config import SensorType, setup_data_echo, setup_data_log from config import SensorType, setup_data_echo, setup_data_log
from config import settings from config import settings
class Logger(object): class Logger(object):
def __init__(self, log): def __init__(self, log):
self.temp_prev_default = settings.prev_temps_default self.temp_prev_default = settings.prev_temps_default
@ -22,63 +21,57 @@ class Logger(object):
self.datalog = setup_data_log() self.datalog = setup_data_log()
def __build_prev_temps__(self): def __build_prev_temps__(self):
prev_temps={} prev_temps = {}
hosts_name = "hosts" hosts_name = "hosts"
if hosts_name in settings: if hosts_name in settings:
for i in settings[hosts_name]: for i in settings[hosts_name]:
for j in settings[hosts_name][i]['sensors']: for j in settings[hosts_name][i]['sensors']:
if settings[hosts_name][i]['sensors'][j][1] == SensorType.temp: if settings[hosts_name][i]['sensors'][j][1] == SensorType.temp:
prev_temps[j]=self.temp_prev_default prev_temps[j] = self.temp_prev_default
return prev_temps return prev_temps
def temp_rise(self, new, sensor): def temp_rise(self, new, sensor):
old = self.prev_temps[sensor] old = self.prev_temps[sensor]
if(old == self.temp_prev_default): if old == self.temp_prev_default:
return True return True
if(((old-new) > self.temp_max_diff) or ((new-old) > self.temp_max_diff)): if ((old - new) > self.temp_max_diff) or ((new - old) > self.temp_max_diff):
self.log.error('error checking ' + sensor + ';prev(' + str(old) + ');cur(' + str(new) + ');') self.log.error('error checking ' + sensor + ';prev(' + str(old) + ');cur(' + str(new) + ');')
return False return False
else: else:
return True return True
########################################## # common function to write value to file
# common function to write value to file #
##########################################
def write_value(self, value, sensor): def write_value(self, value, sensor):
if settings.legacy_record: if settings.legacy_record:
valuename = self.records + "/" + sensor + "_" + preptime() valuename = self.records + "/" + sensor + "_" + preptime()
valuelog=open(valuename, 'a') valuelog = open(valuename, 'a')
valuelog.write(str(value) + ';' + str( int(time.time()) ) + "\n") valuelog.write(str(value) + ';' + str(int(time.time())) + "\n")
valuelog.close() valuelog.close()
self.datalog.info('%s;%s;%s',value, int(time.time()), sensor) self.datalog.info('%s;%s;%s', value, int(time.time()), sensor)
########################################## # generic callback
# generic callback # def cb_generic(self, value, sensor, type, supress=False):
##########################################
def cb_generic(self,value, sensor, type, supress = False):
if type == SensorType.temp: if type == SensorType.temp:
if self.temp_rise(value, sensor): if self.temp_rise(value, sensor):
self.write_value(value, sensor) self.write_value(value, sensor)
self.prev_temps[sensor] = value self.prev_temps[sensor] = value
elif (type == SensorType.none): elif type == SensorType.none:
return return
else: else:
self.write_value(value, sensor) self.write_value(value, sensor)
unit = settings.sensor_properties[type] unit = settings.sensor_properties[type]
if not supress: if not supress:
self.dataecho.info(sensor + ': ' + str(value/unit[1]) + ' ' + unit[2]) self.dataecho.info(sensor + ': ' + str(value / unit[1]) + ' ' + unit[2])
########################################### # exception logging
# exception logging # def print_exception(self, inst):
########################################### tree = ET.parse(os.path.join(settings.log, settings.exceptionlog))
def printException(self, inst):
tree = ET.parse(os.path.join(settings.log,settings.exceptionlog))
root = tree.getroot() root = tree.getroot()
new = ET.Element('exception', {'class':str( type(inst) ).split("'")[1], 'date':str( time.ctime() ), 'time':str( int(time.time()) ), 'type':str(inst)}) new = ET.Element('exception', {'class': str(type(inst)).split("'")[1], 'date': str(time.ctime()),
'time': str(int(time.time())), 'type': str(inst)})
new.text = traceback.format_exc() new.text = traceback.format_exc()
root.append(new) root.append(new)
tree.write(settings.exceptionlog) tree.write(settings.exceptionlog)
message = 'an Exception happend @' + time.ctime()+"\n" message = 'an Exception happend @' + time.ctime() + "\n"
self.log.error(message) self.log.error(message)
print(message) print(message)

View File

@ -49,3 +49,4 @@ Optional: Upload der Aufzeichnungen mit SFTP an einem Server (beinhaltet Archivi
# TODOS # TODOS
* TODOS ausdenken * TODOS ausdenken
* rugged approach [http://www.tinkerforge.com/en/doc/Tutorials/Tutorial_Rugged/Tutorial.html](http://www.tinkerforge.com/en/doc/Tutorials/Tutorial_Rugged/Tutorial.html)

View File

@ -18,44 +18,47 @@ except ImportError:
from config import SensorType from config import SensorType
from config import settings from config import settings
class ConnectionSetup(object): class ConnectionSetup(object):
def __init__(self, log): def __init__(self, log):
self.log = log self.log = log
def setupConnection(self, host): def setup_connection(self, host):
ipcon = IPConnection() ipcon = IPConnection()
try:
ipcon.connect(host['name'], host['port']) ipcon.connect(host['name'], host['port'])
return (ipcon) self.log.info("connection to '%s:%s' established", host['name'], host['port'])
except ConnectionError:
self.log.error("connection to '%s:%s' failed", host['name'], host['port'])
return ipcon
def setupConnectionAndSensors(self, host, sensors, cb_generic): def setup_connection_and_sensors(self, host, sensors, cb_generic):
hostname = host['name'] ipcon = self.setup_connection(host)
port = host['port'] sensor_setup = SensorSetup(ipcon, sensors, cb_generic, self.log)
ipcon = IPConnection() connected_sensors = sensor_setup.setup_sensors()
ipcon.connect(hostname, port) return ipcon, connected_sensors
sensorSetup = SensorSetup(ipcon, sensors, cb_generic, self.log)
connectedSensors = sensorSetup.setupSensors()
return (ipcon, connectedSensors)
def disconnectAny(self, connections): def disconnect_any(self, connections):
for connection in connections: for connection in connections:
if not connection.get_connection_state() is IPConnection.CONNECTION_STATE_DISCONNECTED: if not connection.get_connection_state() is IPConnection.CONNECTION_STATE_DISCONNECTED:
self.log.debug("disconnecting (%s)", connection)
connection.disconnect() connection.disconnect()
class SensorSetup(object):
class SensorSetup(object):
def __init__(self, connection, sensors, cb_generic, log): def __init__(self, connection, sensors, cb_generic, log):
self.connection = connection self.connection = connection
self.sensors = sensors self.sensors = sensors
self.cb_generic = cb_generic self.cb_generic = cb_generic
self.log = log self.log = log
self._previous_sensors={} self._previous_sensors = {}
self._configs={ self._configs = {
#SensorType.none: { # SensorType.none: {
# 'obj': , # 'obj': ,
# 'setcb': , # 'setcb': ,
# 'get': , # 'get': ,
# 'cb': # 'cb':
#}, # },
SensorType.temp: { SensorType.temp: {
'obj': Temperature, 'obj': Temperature,
'setcb': Temperature.set_temperature_callback_period, 'setcb': Temperature.set_temperature_callback_period,
@ -94,11 +97,10 @@ class SensorSetup(object):
} }
} }
def parametrizedCallback(self, name, type): def parametrized_callback(self, name, type):
return partial(self.cb_generic, sensor=name, type=type) return partial(self.cb_generic, sensor=name, type=type)
def __setupSensor__(self, callback, id, cbtime, var): def __setupSensor__(self, callback, id, cbtime, var):
obj = None
if id in self._previous_sensors: if id in self._previous_sensors:
self.log.debug("reusing instance for %s", id) self.log.debug("reusing instance for %s", id)
obj = self._previous_sensors[id] # restore instance for another callback obj = self._previous_sensors[id] # restore instance for another callback
@ -107,13 +109,13 @@ class SensorSetup(object):
obj = var['obj'](id, self.connection) # construct instance obj = var['obj'](id, self.connection) # construct instance
self._previous_sensors[id] = obj # save instance for multiple callbacks self._previous_sensors[id] = obj # save instance for multiple callbacks
var['setcb'](obj, cbtime) # set callback period var['setcb'](obj, cbtime) # set callback period
callback(var['get'](obj ), supress=True) # execute callback with raw getter as value callback(var['get'](obj), supress=True) # execute callback with raw getter as value
obj.register_callback(var['cb'], callback) # register callback obj.register_callback(var['cb'], callback) # register callback
return obj return obj
def genericSensorSetup(self, name, sensor): def generic_sensor_setup(self, name, sensor):
status = "setup device "+ sensor[0] +" ("+ name +"):" status = "setup device " + sensor[0] + " (" + name + "):"
callback = self.parametrizedCallback(name, type=sensor[1]) callback = self.parametrized_callback(name, type=sensor[1])
cbtime = settings.sensor_properties[sensor[1]][0] cbtime = settings.sensor_properties[sensor[1]][0]
obj = None obj = None
if sensor[1] is SensorType.rain: if sensor[1] is SensorType.rain:
@ -126,14 +128,13 @@ class SensorSetup(object):
obj = self.__setupSensor__(callback, sensor[0], cbtime, self._configs[sensor[1]]) obj = self.__setupSensor__(callback, sensor[0], cbtime, self._configs[sensor[1]])
self.log.info("%s OK", status) self.log.info("%s OK", status)
except Exception as e: except Exception as e:
self.log.error("%s FAIL:: %s (%s)",status, e,traceback.format_exc()) self.log.error("%s FAIL:: %s (%s)", status, e, traceback.format_exc())
return obj return obj
def setupSensors(self): def setup_sensors(self):
connected=[] connected = []
for name in self.sensors: for name in self.sensors:
sensor = self.sensors[name] sensor = self.sensors[name]
obj = self.genericSensorSetup(name, sensor) obj = self.generic_sensor_setup(name, sensor)
connected.append(obj) connected.append(obj)
return connected return connected

View File

@ -5,6 +5,7 @@ import json
import logging import logging
import os import os
class SensorType: class SensorType:
none = 0 none = 0
temp = 1 # temperature bricklet temp = 1 # temperature bricklet
@ -15,15 +16,16 @@ class SensorType:
iram = 6 # temperature ir bricklet, ambient iram = 6 # temperature ir bricklet, ambient
irob = 7 # temperature ir bricklet, object irob = 7 # temperature ir bricklet, object
DEFAULTS ={
"hosts":{ DEFAULTS = {
"HOSTDESC_i":{ "hosts": {
"host":{"name":"HOSTNAME_OR_IP","port":4223}, "HOSTDESC_i": {
"sensors":{ "host": {"name": "HOSTNAME_OR_IP", "port": 4223},
"NAME":["UID", "SensorType.TYPE"]} "sensors": {
"NAME": ["UID", "SensorType.TYPE"]}
} }
}, },
"sensor_properties":{ "sensor_properties": {
"SensorType.none": [0, 0, ""], "SensorType.none": [0, 0, ""],
"SensorType.temp": [30000, 100.0, "°C"], "SensorType.temp": [30000, 100.0, "°C"],
"SensorType.humi": [30000, 10.0, "%RH"], "SensorType.humi": [30000, 10.0, "%RH"],
@ -32,37 +34,43 @@ DEFAULTS ={
"SensorType.rain": [0, 2.5, "l/qm"], "SensorType.rain": [0, 2.5, "l/qm"],
"SensorType.iram": [1000, 10.0, "°C"], "SensorType.iram": [1000, 10.0, "°C"],
"SensorType.irob": [1000, 10.0, "°C"]}, "SensorType.irob": [1000, 10.0, "°C"]},
"tempmaxdiff":200, "tempmaxdiff": 200,
"prev_temps_default":20000, "prev_temps_default": 20000,
"logs":'logs', "logs": 'logs',
"locks":'locks', "locks": 'locks',
"records":'records', "records": 'records',
"arch":'arch', "arch": 'arch',
"lockname":"all.lock", "lockname": "all.lock",
"logname":"logging.log", "logname": "logging.log",
"exceptionlog":"exceptions.xml", "exceptionlog": "exceptions.xml",
"recordlog":"record.log", "recordlog": "record.log",
"movelog":"move.log", "movelog": "move.log",
"movelock":"last_move", "movelock": "last_move",
"waitDelay":10, "waitDelay": 10,
"tempSensors":0, "tempSensors": 0,
"loglevel": "info", "loglevel": "info",
"datalog": "info", "datalog": "info",
"dataecho": "info", "dataecho": "info",
"legacy_record": True "legacy_record": True
} }
class Settings(dict): class Settings(dict):
def __getattr__(self,name): def __getattr__(self, name):
if name in self: if name in self:
return self[name] return self[name]
return DEFAULTS[name] return DEFAULTS[name]
def __setattr__(self,name,value):
self[name]=value def __setattr__(self, name, value):
def __delattr__(self,name): self[name] = value
def __delattr__(self, name):
del self[name] del self[name]
def load_json(filename="config.json"): def load_json(filename="config.json"):
values=json.load(open(filename), object_hook=Settings) values = json.load(open(filename), object_hook=Settings)
sensors_name="hosts" sensors_name = "hosts"
if sensors_name in values: if sensors_name in values:
for host in values[sensors_name]: for host in values[sensors_name]:
for sensor in values[sensors_name][host]["sensors"]: for sensor in values[sensors_name][host]["sensors"]:
@ -70,17 +78,19 @@ def load_json(filename="config.json"):
sensor[1] = eval(sensor[1]) sensor[1] = eval(sensor[1])
sensor_props = "sensor_properties" sensor_props = "sensor_properties"
if sensor_props in values: if sensor_props in values:
new_units={} new_units = {}
for unit in values[sensor_props]: for unit in values[sensor_props]:
new_units[eval(unit)] = values[sensor_props][unit] new_units[eval(unit)] = values[sensor_props][unit]
values[sensor_props] = new_units values[sensor_props] = new_units
return values return values
def setupLogger():
def setup_logger():
level = getattr(logging, settings.loglevel.upper(), logging.INFO) level = getattr(logging, settings.loglevel.upper(), logging.INFO)
log = logging.getLogger("weatherstation") log = logging.getLogger("weatherstation")
log.setLevel(level) log.setLevel(level)
ch = logging.StreamHandler() ch = logging.StreamHandler()
#formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter = logging.Formatter('%(asctime)s:[%(levelname)s] - %(message)s') formatter = logging.Formatter('%(asctime)s:[%(levelname)s] - %(message)s')
ch.setFormatter(formatter) ch.setFormatter(formatter)
log.addHandler(ch) log.addHandler(ch)
@ -89,6 +99,7 @@ def setupLogger():
log.addHandler(fh) log.addHandler(fh)
return log return log
def setup_data_log(): def setup_data_log():
level = getattr(logging, settings.datalog.upper(), logging.INFO) level = getattr(logging, settings.datalog.upper(), logging.INFO)
log = logging.getLogger("weatherstation.datalog") log = logging.getLogger("weatherstation.datalog")
@ -100,6 +111,7 @@ def setup_data_log():
log.propagate = False log.propagate = False
return log return log
def setup_data_echo(): def setup_data_echo():
level = getattr(logging, settings.dataecho.upper(), logging.INFO) level = getattr(logging, settings.dataecho.upper(), logging.INFO)
log = logging.getLogger("weatherstation.data") log = logging.getLogger("weatherstation.data")
@ -111,7 +123,8 @@ def setup_data_echo():
log.propagate = False log.propagate = False
return log return log
settings=load_json()
settings = load_json()
""" """
0: { 0: {
"host": { "host": {
@ -129,4 +142,3 @@ settings=load_json()
"humi2": ["9V5", SensorType.humi], "humi2": ["9V5", SensorType.humi],
} }
},""" },"""

47
main.py
View File

@ -6,17 +6,18 @@ import time
from Logger import Logger from Logger import Logger
from Setup import ConnectionSetup from Setup import ConnectionSetup
from config import settings, setupLogger from config import settings, setup_logger
log = setup_logger()
lockpath = os.path.join(settings.locks, settings.lockname)
log = setupLogger()
lockpath=os.path.join(settings.locks,settings.lockname)
def check_dirs_and_files(): def check_dirs_and_files():
# log # log
if not os.path.exists(settings.logs): if not os.path.exists(settings.logs):
os.mkdir(settings.logs, 0o000755) os.mkdir(settings.logs, 0o000755)
if not os.path.exists(os.path.join(settings.logs,settings.exceptionlog)): if not os.path.exists(os.path.join(settings.logs, settings.exceptionlog)):
file=open(os.path.join(settings.logs,settings.exceptionlog), 'w') file = open(os.path.join(settings.logs, settings.exceptionlog), 'w')
file.write("<exceptions></exceptions>") file.write("<exceptions></exceptions>")
file.close() file.close()
# lock # lock
@ -26,21 +27,25 @@ def check_dirs_and_files():
if not os.path.exists(settings.records): if not os.path.exists(settings.records):
os.mkdir(settings.records, 0o000755) os.mkdir(settings.records, 0o000755)
def obtainLock():
def obtain_lock():
if not os.path.exists(lockpath): if not os.path.exists(lockpath):
lock = open(lockpath, 'w') lock = open(lockpath, 'w')
lock.write( str(time.time()) ) lock.write(str(time.time()))
lock.close() lock.close()
return True return True
return False return False
def freeLock():
def free_lock():
if os.path.exists(lockpath): if os.path.exists(lockpath):
os.remove(lockpath) os.remove(lockpath)
def formatHost(host):
def format_host(host):
return "%s:%d" % (host['name'], host['port']) return "%s:%d" % (host['name'], host['port'])
if __name__ == "__main__": if __name__ == "__main__":
try: try:
input = raw_input input = raw_input
@ -53,30 +58,30 @@ if __name__ == "__main__":
try: try:
log.info("setting up all sensors") log.info("setting up all sensors")
while True: while True:
if obtainLock(): if obtain_lock():
logger = Logger(log) logger = Logger(log)
for con in settings.hosts: for con in settings.hosts:
try: try:
log.info("connecting to host '"+str(con)+"'") log.info("connecting to host '" + str(con) + "'")
con = settings.hosts[con] con = settings.hosts[con]
connection, sensors = conSetup.setupConnectionAndSensors(con['host'], con['sensors'], logger.cb_generic) connection, sensors = conSetup.setup_connection_and_sensors(con['host'], con['sensors'], logger.cb_generic)
connections.append(connection) connections.append(connection)
connectedSensors.append(sensors) connectedSensors.append(sensors)
log.info("started logging at " + formatHost(con['host'])) log.info("started logging at " + format_host(con['host']))
except Exception as inst: except Exception as inst:
#connection failed, log and exit # connection failed, log and exit
#TODO: logger.printException(inst) # TODO: logger.print_exception(inst)
log.error("connection failed: "+str(inst)) log.error("connection failed: " + str(inst))
# noinspection PyUnboundLocalVariable
input("Press key to restart\n") input("Press key to restart\n")
log.info("stop logging... @" + time.ctime() + "\n") log.info("stop logging... @" + time.ctime() + "\n")
conSetup.disconnectAny(connections) conSetup.disconnect_any(connections)
freeLock() free_lock()
else: else:
log.critical("lock collision: lock 'all' active") log.critical("lock collision: lock 'all' active")
log.info("wait for retry (" + str(settings.waitDelay) + ")") log.info("wait for retry (" + str(settings.waitDelay) + ")")
time.sleep(settings.waitDelay) time.sleep(settings.waitDelay)
except KeyboardInterrupt: except KeyboardInterrupt:
log.info("keyboard-interrupt happened, cleaning up") log.info("keyboard-interrupt happened, cleaning up")
conSetup.disconnectAny(connections) conSetup.disconnect_any(connections)
freeLock() free_lock()

33
move.py
View File

@ -1,7 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time
import os import os
import logging import logging
from shutil import move from shutil import move
@ -9,11 +8,12 @@ from shutil import move
from timeFunctions import * from timeFunctions import *
from config import settings from config import settings
def setupLogger():
def setup_logger():
log = logging.getLogger("weatherstation.move") log = logging.getLogger("weatherstation.move")
log.setLevel(logging.INFO) log.setLevel(logging.INFO)
ch = logging.StreamHandler() ch = logging.StreamHandler()
#formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter = logging.Formatter('%(asctime)s:[%(levelname)s] - %(message)s') formatter = logging.Formatter('%(asctime)s:[%(levelname)s] - %(message)s')
ch.setFormatter(formatter) ch.setFormatter(formatter)
log.addHandler(ch) log.addHandler(ch)
@ -22,14 +22,16 @@ def setupLogger():
log.addHandler(fh) log.addHandler(fh)
return log return log
log = setupLogger()
checkfile=os.path.join(settings.locks,settings.movelock) log = setup_logger()
checkfile = os.path.join(settings.locks, settings.movelock)
if not os.path.exists(checkfile): if not os.path.exists(checkfile):
open(checkfile,'w').close() open(checkfile, 'w').close()
if not os.path.exists(settings.arch): if not os.path.exists(settings.arch):
os.mkdir(arch, 0o000755) os.mkdir(settings.arch, 0o000755)
def mycopy(keep): def mycopy(keep):
names = os.listdir(settings.records) names = os.listdir(settings.records)
@ -38,22 +40,23 @@ def mycopy(keep):
continue continue
move(os.path.join(settings.records, name), settings.arch) move(os.path.join(settings.records, name), settings.arch)
check=open(checkfile,'r')
temp=check.read() check = open(checkfile, 'r')
if len(temp)<1: temp = check.read()
if len(temp) < 1:
check.close() check.close()
check=open(checkfile,'w') check = open(checkfile, 'w')
check.write(str(time.time())) check.write(str(time.time()))
check.flush() check.flush()
log.info("updated time since file was empty") log.info("updated time since file was empty")
else: else:
last=time.gmtime(float(temp)) last = time.gmtime(float(temp))
now=time.gmtime() now = time.gmtime()
if(prevday(last,now)): if prevday(last, now):
log.info("moving records") log.info("moving records")
mycopy(preptime()) mycopy(preptime())
check.close() check.close()
check=open(checkfile,'w') check = open(checkfile, 'w')
check.write(str(time.time())) check.write(str(time.time()))
check.flush() check.flush()
else: else:

View File

@ -3,14 +3,16 @@
import time import time
def prevday(then, now): def prevday(then, now):
#ist "then" gestern (oder noch älter)? # ist "then" gestern (oder noch älter)?
greaterDay = (then.tm_yday < now.tm_yday) and (then.tm_year == now.tm_year) greater_day = (then.tm_yday < now.tm_yday) and (then.tm_year == now.tm_year)
if greaterDay: if greater_day:
newYear = False new_year = False
else: else:
newYear = then.tm_year < now.tm_year new_year = then.tm_year < now.tm_year
return greaterDay or newYear return greater_day or new_year
def preptime(): def preptime():
now = time.localtime() now = time.localtime()
@ -26,4 +28,3 @@ def preptime():
else: else:
month = str(month) month = str(month)
return month + "." + day + "." + year return month + "." + day + "." + year