197 lines
7.1 KiB
Python
197 lines
7.1 KiB
Python
import sys
|
|
from time import strftime, gmtime
|
|
|
|
from twisted.internet import reactor
|
|
from twisted.web.server import Site
|
|
from twisted.web.resource import Resource
|
|
from twisted.web.static import File
|
|
|
|
import paho.mqtt.client as mqtt
|
|
import json
|
|
|
|
LOGFILE_pre = '/tmp/'
|
|
APP_LOGFILE = LOGFILE_pre + 'laundry.log'
|
|
SERVER_LOGFILE = LOGFILE_pre + 'laundryServer.log'
|
|
|
|
TOPIC_RELAYBOX_STATE = "IoT/Status/RelayBox"
|
|
TOPIC_PARSEDDATA_pre = "IoT/ParsedData"
|
|
TOPIC_PARSEDDATA = TOPIC_PARSEDDATA_pre + "/#"
|
|
|
|
switchMapping = {
|
|
'oven': { 'index': 1, 'label': 'Herd' },
|
|
'laundry': { 'index': 2, 'label': 'Waschkueche' },
|
|
'kitchen': { 'index': 0, 'label': 'Kueche' },
|
|
'lightbasem': { 'index': 3, 'label': 'Licht Keller' },
|
|
'light1flr': { 'index': 4, 'label': 'Licht EG' },
|
|
'light2flr': { 'index': 5, 'label': 'Licht OG' },
|
|
}
|
|
|
|
loadedSwitchStates = ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7']
|
|
|
|
|
|
measurementValues = {}
|
|
|
|
|
|
|
|
def log(m):
|
|
t = strftime("%d %b %Y %H:%M:%S", gmtime())
|
|
with open(APP_LOGFILE, 'a') as f:
|
|
f.write("%s %s\n" % (t, m))
|
|
|
|
def on_message(client, userdata, msg):
|
|
topic = msg.topic
|
|
if (topic == TOPIC_RELAYBOX_STATE):
|
|
j = json.loads(msg.payload)
|
|
ss = j['data']['switchStates']
|
|
for s in ss:
|
|
if s['feedbackState'] == 0:
|
|
loadedSwitchStates[s['index']] = 'aus'
|
|
elif s['state'] == 1:
|
|
loadedSwitchStates[s['index']] = 'an'
|
|
else:
|
|
loadedSwitchStates[s['index']] = 'unbekannt'
|
|
elif (topic.startswith(TOPIC_PARSEDDATA_pre)):
|
|
j = json.loads(msg.payload)
|
|
data = j['data']
|
|
metadata = j['metadata']
|
|
|
|
if ('category' in metadata):
|
|
category = metadata['category']
|
|
else:
|
|
if (('device' in metadata) and ('Slave' in metadata) and
|
|
(metadata['device'] == 'ModbusHub') and (metadata['Slave'] == 'Thermometer')):
|
|
category = 'FreezeThermometer'
|
|
|
|
if (category in ['OnePhaseElectric_Finder', 'ThreePhaseElectric_Finder']):
|
|
measurementValues[metadata['name']] = [
|
|
{'label': 'Leistung', 'value': data['power']},
|
|
{'label': 'Verbrauch', 'value': data['energy']},
|
|
{'label': 'Strom', 'value': data['current']},
|
|
]
|
|
elif (category == 'Watermeter_Hyd'):
|
|
measurementValues[metadata['name']] = [
|
|
{'label': 'Durchfluss', 'value': data['flow']},
|
|
{'label': 'Verbrauch', 'value': data['volume']},
|
|
{'label': 'Temperatur', 'value': data['temperature']},
|
|
]
|
|
elif (category == 'OS'):
|
|
measurementValues[metadata['name']] = [
|
|
{'label': '1min', 'value': data['loadavg'][0]},
|
|
{'label': '5min', 'value': data['loadavg'][1]},
|
|
{'label': '15min', 'value': data['loadavg'][2]},
|
|
{'label': 'Uptime', 'value': data['uptime']},
|
|
]
|
|
elif (category == 'Thermometer_Hottis'):
|
|
measurementValues[metadata['name']] = [
|
|
{'label': 'Temperatur Aussen', 'value': data['temperature2']},
|
|
{'label': 'Temperatur Haus', 'value': data['temperature4']},
|
|
{'label': 'Temperatur Innen', 'value': data['temperature3']},
|
|
{'label': 'Uptime', 'value': data['operatingTime']},
|
|
]
|
|
elif (category == 'FreezeThermometer'):
|
|
measurementValues[metadata['name']] = [
|
|
{'label': 'Temperatur Gefrierschrank', 'value': data['t2']},
|
|
{'label': 'Temperatur Kuehlschrank', 'value': data['t1']},
|
|
]
|
|
else:
|
|
log('unexpected category')
|
|
|
|
|
|
|
|
|
|
class MyResource(Resource):
|
|
def log(self, m):
|
|
log(m)
|
|
|
|
def send_message(self, target, switchState):
|
|
try:
|
|
cs = ['off', 'on']
|
|
t = int(target)
|
|
s = int(switchState)
|
|
if s not in [0, 1]:
|
|
raise ValueError('illegal switchState ' + switchState)
|
|
if t < 0 or t >= len(loadedSwitchStates):
|
|
raise ValueError('illegal target ' + target)
|
|
command = "switch %d %s" % (t, cs[s])
|
|
mqttClient.publish('IoT/Command/RelayBox', command)
|
|
#mqttClient.publish('IoT/x', command)
|
|
self.log(command)
|
|
except ValueError, e:
|
|
self.log("ValueError in send_message: " + str(e))
|
|
|
|
|
|
|
|
class HelloWorld(MyResource):
|
|
isLeaf = True
|
|
|
|
def render_GET(self, request):
|
|
return "Hello world!"
|
|
|
|
|
|
class SwitchCommand(MyResource):
|
|
isLeaf = True
|
|
|
|
def render_GET(self, request):
|
|
res = "ERR"
|
|
try:
|
|
target = request.args['target'][0]
|
|
switchState = request.args['state'][0]
|
|
self.send_message(target, switchState)
|
|
res = "OK"
|
|
except KeyError, e:
|
|
self.log("KeyError in SwitchCommand, render_GET: " + str(e))
|
|
return res
|
|
|
|
|
|
class SwitchStatus(MyResource):
|
|
isLeaf = False
|
|
|
|
def render_GET(self, request):
|
|
state = "ERR"
|
|
try:
|
|
target = request.args['target'][0]
|
|
t = int(target)
|
|
state = loadedSwitchStates[t]
|
|
except ValueError, e:
|
|
self.log("ValueError in SwitchStatus, render_GET: " + str(e))
|
|
except KeyError, e:
|
|
self.log("KeyError in SwitchStatus, render_GET: " + str(e))
|
|
except IndexError, e:
|
|
self.log("KeyError in SwitchStatus, render_GET: " + str(e))
|
|
return state
|
|
|
|
|
|
class SwitchMapping(MyResource):
|
|
isLeaf = False
|
|
|
|
def render_GET(self, request):
|
|
return json.dumps(switchMapping,indent=2, separators=(',', ': '))
|
|
|
|
class MeasurementValues(MyResource):
|
|
isLeaf = False
|
|
|
|
def render_GET(self, request):
|
|
return json.dumps(measurementValues,indent=2, separators=(',', ': '))
|
|
|
|
|
|
mqttClient = mqtt.Client()
|
|
mqttClient.on_message = on_message
|
|
mqttClient.connect("mqttbroker", 1883, 60)
|
|
mqttClient.subscribe(TOPIC_RELAYBOX_STATE)
|
|
mqttClient.subscribe(TOPIC_PARSEDDATA)
|
|
mqttClient.loop_start()
|
|
|
|
root = Resource()
|
|
root.putChild("", File("index.html"))
|
|
root.putChild("Hello", HelloWorld())
|
|
root.putChild("switchCommand", SwitchCommand())
|
|
root.putChild("switchStatus", SwitchStatus())
|
|
root.putChild("switchMapping", SwitchMapping())
|
|
root.putChild("measurementValues", MeasurementValues())
|
|
|
|
factory = Site(root, logPath=SERVER_LOGFILE)
|
|
|
|
reactor.listenTCP(8080, factory)
|
|
reactor.run()
|
|
|