Die Fragen gehen jedoch weiter :o
Ich versuche nun gerade das Skript zu erweitern um mehr Informationen aus der KWL zu bekommen.
Wenn ich dieses Python Skript
#!/usr/bin/env python
#########################################################################
# Copyright 2014 Marcel Tiews marcel.tiews@gmail.com
#########################################################################
# Helios-Plugin for SmartHome.py. http://mknx.github.io/smarthome/
#
# This plugin 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 plugin is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this plugin. If not, see <http://www.gnu.org/licenses/>.
#########################################################################
import sys
import serial
import logging
import socket
import threading
import struct
import time
import datetime
import array
logger = logging.getLogger("")
# Some "Constants" - previous definitions (thanks to Johannes and Marcel)
#CONST_BUSMEMBER__MAINBOARD = 0x11
#CONST_BUSMEMBER__SLAVEBOARDS = 0x10
#CONST_BUSMEMBER__CONTROLBOARDS = 0x20
#CONST_BUSMEMBER__ME = 0x2F
# Broadcast addresses - no way to address slave boards in the units directly (according to Vallox)
CONST_BUS_ALL_MAINBOARDS = 0x10
CONST_BUS_ALL_REMOTES = 0x20
# Individual addresses
CONST_BUS_MAINBOARD1 = 0x11 # 1st of max 15 ventilation units (mainboards 1-F)
CONST_BUS_REMOTE1 = 0x21 # 1st of max 15 remote controls (remotes 1-F, default jumper = 1)
CONST_BUS_LON = 0x28 # default for LON bus module (just for information --> expensive)
CONST_BUS_ME = 0x2F # stealth mode - we are behaving like a regular remote control
CONST_MAP_VARIABLES_TO_ID = {
"outside_temp" : {"varid" : 0x32, 'type': 'temperature', 'bitposition': -1, 'read': True, 'write': False },
"exhaust_temp" : {"varid" : 0x33, 'type': 'temperature', 'bitposition': -1, 'read': True, 'write': False },
"inside_temp" : {"varid" : 0x34, 'type': 'temperature', 'bitposition': -1, 'read': True, 'write': False },
"incoming_temp" : {"varid" : 0x35, 'type': 'temperature', 'bitposition': -1, 'read': True, 'write': False },
"bypass_temp" : {"varid" : 0xAF, 'type': 'temperature', 'bitposition': -1, 'read': True, 'write': True },
"fanspeed" : {"varid" : 0x29, 'type': 'fanspeed', 'bitposition': -1, 'read': True, 'write': True },
"max_fanspeed" : {"varid" : 0xA5, 'type': 'fanspeed', 'bitposition': -1, 'read': True, 'write': True },
"min_fanspeed" : {"varid" : 0xA9, 'type': 'fanspeed', 'bitposition': -1, 'read': True, 'write': True },
"power_state" : {"varid" : 0xA3, 'type': 'bit', 'bitposition': 0, 'read': True, 'write': True },
"bypass_disabled" : {"varid" : 0xA3, 'type': 'bit', 'bitposition': 3, 'read': True, 'write': True },
"clean_filter" : {"varid" : 0xAB, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
"boost_setting" : {"varid" : 0xAA, 'type': 'bit', 'bitposition': 5, 'read': True, 'write': True },
"boost_on" : {"varid" : 0x71, 'type': 'bit', 'bitposition': 5, 'read': True, 'write': True },
"boost_status" : {"varid" : 0x71, 'type': 'bit', 'bitposition': 6, 'read': True, 'write': False },
"damper" : {"varid" : 0x08, 'type': 'bit', 'bitposition': 1, 'read': True, 'write': True },
"boost_remaining" : {"varid" : 0x79, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': False },
"fan_in_on_off" : {"varid" : 0x08, 'type': 'bit', 'bitposition': 3, 'read': True, 'write': True },
"fan_in_percent" : {"varid" : 0xB0, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
"fan_out_on_off" : {"varid" : 0x08, 'type': 'bit', 'bitposition': 5, 'read': True, 'write': True },
"fan_out_percent" : {"varid" : 0xB1, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
"device_error" : {"varid" : 0x36, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': False }
}
CONST_TEMPERATURE = array.array('i', [
-74,-70,-66,-62,-59,-56,-54,-52,-50,-48,-47,-46,-44,-43,-42,-41,-40,-39,-38,-37,-36,
-35,-34,-33,-33,-32,-31,-30,-30,-29,-28,-28,-27,-27,-26,-25,-25,-24,-24,-23,-23,-22,
-22,-21,-21,-20,-20,-19,-19,-19,-18,-18,-17,-17,-16,-16,-16,-15,-15,-14,-14,-14,-13,
-13,-12,-12,-12,-11,-11,-11,-10,-10,-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6,-6,-5,-5,-5,-4,
-4,-4,-3,-3,-3,-2,-2,-2,-1,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,5,6,6,6,7,7,
7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13,13,14,14,14,15,15,15,16,16,16,17,17,
18,18,18,19,19,19,20,20,21,21,21,22,22,22,23,23,24,24,24,25,25,26,26,27,27,27,28,28,
29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,40,40,41,41,42,43,43,
44,45,45,46,47,48,48,49,50,51,52,53,53,54,55,56,57,59,60,61,62,63,65,66,68,69,71,73,
75,77,79,81,82,86,90,93,97,100,100,100,100,100,100,100,100,100])
class HeliosException(Exception):
pass
class HeliosBase():
def __init__(self, tty='/dev/ttyUSB0'):
self._tty = tty
self._is_connected = False
self._port = False
self._lock = threading.Lock()
def connect(self):
if self._is_connected and self._port:
return True
try:
logger.debug("Helios: Connecting...")
self._port = serial.Serial(
self._tty,
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=1)
self._is_connected = True
return True
except:
logger.error("Helios: Could not open {0}.".format(self._tty))
return False
def disconnect(self):
if self._is_connected and self._port:
logger.debug("HeliosBase: Disconnecting...")
self._port.close()
self._is_connected = False
def _createTelegram(self, sender, receiver, function, value):
telegram = [1,sender,receiver,function,value,0]
telegram[5] = self._calculateCRC(telegram)
return telegram
def _waitForSilence(self):
# Modbus RTU only allows one master (client which controls communication).
# So lets try to wait a bit and jump in when nobody's speaking.
# Modbus defines a waittime of 3,5 Characters between telegrams:
# (1/9600baud * (1 Start bit + 8 Data bits + 1 Parity bit + 1 Stop bit)
# => about 4ms
# Lets go with 7ms! ;O)
gotSlot = False
backupTimeout = self._port.timeout
end = time.time() + 3
self._port.timeout = 0.07
while end > time.time():
chars = self._port.read(1)
# nothing received so we got a slot of silence...hopefully
if len(chars) == 0:
gotSlot = True
break
self._port.timeout = backupTimeout
return gotSlot
def _sendTelegram(self, telegram):
if not self._is_connected:
return False
logger.debug("Helios: Sending telegram '{0}'".format(self._telegramToString(telegram)))
self._port.write(bytearray(telegram))
return True
def _readTelegram(self, sender, receiver, datapoint):
# sometimes a lot of garbage is received...so lets get a bit robust
# and read a bit of this junk and see whether we are getting something
# useful out of it!
# How long does it take until something useful is received???
timeout = time.time() + 1
telegram = [0,0,0,0,0,0]
while self._is_connected and timeout > time.time():
char = self._port.read(1)
if(len(char) > 0):
byte = bytearray(char)[0]
telegram.pop(0)
telegram.append(byte)
# Telegrams always start with a 0x01, is the CRC valid?, ...
if (telegram[0] == 0x01 and
telegram[1] == sender and
telegram[2] == receiver and
telegram[3] == datapoint and
telegram[5] == self._calculateCRC(telegram)):
logger.debug("Telegram received '{0}'".format(self._telegramToString(telegram)))
return telegram[4]
return None
def _calculateCRC(self, telegram):
sum = 0
for c in telegram[:-1]:
sum = sum + c
return sum % 256
def _telegramToString(self, telegram):
str = ""
for c in telegram:
# str = str + hex(c) + " " 0x01 was showing as 0x1, 0x1A was showing as 0x1a
str = str + '0x%0*X' % (2,c) + " "
str = str[:-1] # remove trailing space
return str
def _convertFromRawValue(self, varname, rawvalue):
value = None
vardef = CONST_MAP_VARIABLES_TO_ID[varname]
if vardef["type"] == "temperature":
value = CONST_TEMPERATURE[rawvalue]
elif vardef["type"] == "fanspeed":
if rawvalue == 0x01:
value = 1
elif rawvalue == 0x03:
value = 2
elif rawvalue == 0x07:
value = 3
elif rawvalue == 0x0F:
value = 4
elif rawvalue == 0x1F:
value = 5
elif rawvalue == 0x3F:
value = 6
elif rawvalue == 0x7F:
value = 7
elif rawvalue == 0xFF:
value = 8
else:
value = None
elif vardef["type"] == "bit":
value = rawvalue >> vardef["bitposition"] & 0x01
elif vardef["type"] == "dec": # decimal value
value = rawvalue
return value
def _convertFromValue(self, varname, value, prevvalue):
rawvalue = None
vardef = CONST_MAP_VARIABLES_TO_ID[varname]
if vardef['type'] == "temperature":
rawvalue = CONST_TEMPERATURE.index(int(value))
elif vardef["type"] == "fanspeed":
value = int(value)
if value == 1:
rawvalue = 0x01
elif value == 2:
rawvalue = 0x03
elif value == 3:
rawvalue = 0x07
elif value == 4:
rawvalue = 0x0F
elif value == 5:
rawvalue = 0x1F
elif value == 6:
rawvalue = 0x3F
elif value == 7:
rawvalue = 0x7F
elif value == 8:
rawvalue = 0xFF
else:
rawvalue = None
elif vardef["type"] == "bit":
# for bits we have to keep the other bits of the byte (previous value)
if value in (True,1,"true","True","1","On","on"):
rawvalue = prevvalue | (1 << vardef["bitposition"])
else:
rawvalue = prevvalue & ~(1 << vardef["bitposition"])
elif vardef["type"] == "dec": # decimal value
rawvalue = int(value)
return rawvalue
def writeValue(self,varname, value):
if CONST_MAP_VARIABLES_TO_ID[varname]["write"] != True:
logger.error("Helios: Variable {0} may not be written!".format(varname))
return False
success = False
self._lock.acquire()
try:
# if we have got to write a single bit, we need the current (byte) value to
# reproduce the other bits...
if CONST_MAP_VARIABLES_TO_ID[varname]["type"] == "bit":
currentval = None
if self._waitForSilence():
# Send poll request
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_MAINBOARD1,
0,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
self._sendTelegram(telegram)
# Read response
currentval = self._readTelegram(
CONST_BUS_MAINBOARD1,
CONST_BUS_ME,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
if currentval == None:
logger.error("Helios: Sending value to ventilation system failed. Can not read current variable value '{0}'."
.format(varname))
return False
rawvalue = self._convertFromValue(varname, value, currentval)
else:
rawvalue = self._convertFromValue(varname, value, None)
# send the new value
if self._waitForSilence():
if rawvalue != None:
# Broadcasting value to all remote control boards
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_ALL_REMOTES,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
# Broadcasting value to all mainboards
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_ALL_MAINBOARDS,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
# Writing value to 1st mainboard
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_MAINBOARD1,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
# Send checksum a second time
self._sendTelegram([telegram[5]])
##################### Special treatment to switch the remote controls on again:
if CONST_MAP_VARIABLES_TO_ID[varname]["varid"] == 0xA3 and CONST_MAP_VARIABLES_TO_ID[varname]["bitposition"] == 0:
logger.debug("On/off command - special treatment for the remote controls")
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_ALL_REMOTES,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_REMOTE1,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
self._sendTelegram([telegram[5]])
####################
success = True
else:
logger.error("Helios: Sending value to ventilation system failed. Can not convert value '{0}' for variable '{1}'."
.format(value,varname))
success = False
else:
logger.error("Helios: Sending value to ventilation system failed. No free slot for sending telegrams available.")
success = False
except Exception as e:
logger.error("Helios: Exception in writeValue() occurred: {0}".format(e))
finally:
self._lock.release()
return success
def readValue(self,varname):
if CONST_MAP_VARIABLES_TO_ID[varname]["read"] != True:
logger.error("Variable {0} may not be read!".format(varname))
return False
value = None
self._lock.acquire()
try:
logger.debug("Helios: Reading value: {0}".format(varname))
if self._waitForSilence():
# Send poll request
telegram = self._createTelegram(
CONST_BUS_ME,
CONST_BUS_MAINBOARD1,
0,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
self._sendTelegram(telegram)
# Read response
value = self._readTelegram(
CONST_BUS_MAINBOARD1,
CONST_BUS_ME,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
if value is not None:
raw_value = value
value = self._convertFromRawValue(varname,value)
logger.debug("Value for {0} ({1}) received: {2}|{3}|{4} --> converted = {5}"
.format(varname, '0x%0*X' % (2, CONST_MAP_VARIABLES_TO_ID[varname]["varid"]),
'0x%0*X' % (2,raw_value), "{0:08b}".format(raw_value), raw_value, value)
)
else:
logger.error("Helios: No valid value for '{0}' from ventilation system received."
.format(varname)
)
else:
logger.warn("Helios: Reading value from ventilation system failed. No free slot to send poll request available.")
except Exception as e:
logger.error("Helios: Exception in readValue() occurred: {0}".format(e))
finally:
self._lock.release()
return value
class Helios(HeliosBase):
_items = {}
def __init__(self, smarthome, tty, cycle=300):
HeliosBase.__init__(self, tty)
self._sh = smarthome
self._cycle = int(cycle)
self._alive = False
def run(self):
self.connect()
self._alive = True
self._sh.scheduler.add('Helios', self._update, cycle=self._cycle)
def stop(self):
self.disconnect()
self._alive = False
def parse_item(self, item):
if 'helios_var' in item.conf:
varname = item.conf['helios_var']
if varname in CONST_MAP_VARIABLES_TO_ID.keys():
self._items[varname] = item
return self.update_item
else:
logger.warn("Helios: Ignoring unknown variable '{0}'".format(varname))
def update_item(self, item, caller=None, source=None, dest=None):
if caller != 'Helios':
self.writeValue(item.conf['helios_var'], item())
def _update(self):
logger.debug("Helios: Updating values")
for var in self._items.keys():
val = self.readValue(var)
if val != None:
self._items[var](val,"Helios")
def main():
import argparse
parser = argparse.ArgumentParser(
description="Helios ventilation system commandline interface.",
epilog="Without arguments all readable values using default tty will be retrieved.",
argument_default=argparse.SUPPRESS)
parser.add_argument("-t", "--tty", dest="port", default="/dev/ttyUSB0", help="Serial device to use")
parser.add_argument("-r", "--read", dest="read_var", help="Read variables from ventilation system")
parser.add_argument("-w", "--write", dest="write_var", help="Write variable to ventilation system")
parser.add_argument("-v", "--value", dest="value", help="Value to write (required with option -v)")
parser.add_argument("-d", "--debug", dest="enable_debug", action="store_true", help="Prints debug statements.")
args = vars(parser.parse_args())
if "write_var" in args.keys() and "value" not in args.keys():
parser.print_usage()
return
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
if "enable_debug" in args.keys():
ch.setLevel(logging.DEBUG)
else:
ch.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
logger.addHandler(ch)
try:
helios = HeliosBase(args["port"])
helios.connect()
if not helios._is_connected:
raise Exception("Not connected")
if "read_var" in args.keys():
print("{0} = {1}".format(args["read_var"],helios.readValue(args["read_var"])))
elif "write_var" in args.keys():
helios.writeValue(args["write_var"],args["value"])
else:
for var in CONST_MAP_VARIABLES_TO_ID.keys():
print("{0} = {1}".format(var,helios.readValue(var)))
except Exception as e:
print("Exception: {0}".format(e))
return 1
finally:
if helios:
helios.disconnect()
if __name__ == "__main__":
sys.exit(main())
auf meinem PI ausführe erhalte ich folgende Daten zurück:
bypass_disabled = 0
max_fanspeed = 8
inside_temp = 20
fan_out_percent = 100
incoming_temp = 15
boost_setting = 1
boost_remaining = 0
min_fanspeed = 1
fan_out_on_off = 0
outside_temp = 14
fan_in_percent = 100
clean_filter = 0
fan_in_on_off = 0
bypass_temp = 12
power_state = 1
exhaust_temp = 21
fanspeed = 1
damper = 1
device_error = 0
boost_status = 0
boost_on = 0
Ich möchte zum Beispiel den Fan In Status, den Fan Out Status und die Bypass Klappe (damper) abfragen.
Was mich wundert, dass wie im Python Skript beschrieben im Register \x08 diese Informationen sein soll, wenn ich jedoch im Debug für den Serial Port als auch für den Cutter kein Register 08 erkennen kann.
So sieht aktuell mein Skript aus:
<?
$ID_Betrieb = 57584 /*[Schnittstellen\Vallox KWL\Betrieb]*/;
$CO2_Status = 49064 /*[Schnittstellen\Vallox KWL\CO2 Status]*/;
$Luftfeuchte_Status = 26466 /*[Schnittstellen\Vallox KWL\Luftfeuchte Status]*/;
$Heizung_Status = 38671 /*[Schnittstellen\Vallox KWL\Sommer-Winterbetrieb]*/;
$Filter_Status = 54659 /*[Schnittstellen\Vallox KWL\Filterwechsel]*/;
$Heizung_Indikator = 24032 /*[Schnittstellen\Vallox KWL\Heizung indicator]*/;
$Fehler_Indikator = 15439 /*[Schnittstellen\Vallox KWL\Fehler Indicator]*/;
$Service = 26131 /*[Schnittstellen\Vallox KWL\Service]*/;
$Boost_on = 30876 /*[Schnittstellen\Vallox KWL\Boost on]*/;
$Boost_Status = 40442 /*[Schnittstellen\Vallox KWL\Boost Status]*/;
$Fan_In_On = 56190 /*[Schnittstellen\Vallox KWL\kwl test\Fan In]*/;
$Fan_Out_On = 48667 /*[Schnittstellen\Vallox KWL\kwl test\Fan Out]*/;
$Klappe = 46617 /*[Schnittstellen\Vallox KWL\kwl test\Bypass Klappe]*/;
$ID_Luefterstufe = 50869 /*[Schnittstellen\Vallox KWL\Lüfterstufe IST]*/;
$ID_Aussenluft =25558 /*[Objekt #25558 existiert nicht]*/;
$ID_Fortluft =39025 /*[Objekt #39025 existiert nicht]*/;
$ID_Abluft =26336 /*[Objekt #26336 existiert nicht]*/;
$ID_Zuluft =46208 /*[Objekt #46208 existiert nicht]*/;
$ID_Temp = 53257 /*[Schnittstellen\Vallox KWL\Speicher]*/;
// Tabelle zur Temperatur Umrechnung
$Temperatur = array(
"-74", "-70", "-66", "-62", "-59", "-56", "-54", "-52", "-50", "-48", "-47",
"-46", "-44", "-43", "-42", "-41", "-40", "-39", "-38", "-37", "-36", "-35",
"-34", "-33", "-33", "-32", "-31", "-30", "-30", "-29", "-28", "-28", "-27",
"-27", "-26", "-25", "-25", "-24", "-24", "-23", "-23", "-22", "-22", "-21",
"-21", "-20", "-20", "-19", "-19", "-19", "-18", "-18", "-17", "-17", "-16",
"-16", "-16", "-15", "-15", "-14", "-14", "-14", "-13", "-13", "-12", "-12",
"-12", "-11", "-11", "-11", "-10", "-10", "-9", "-9", "-9", "-8", "-8", "-8",
"-7", "-7", "-7", "-6", "-6", "-6", "-5", "-5", "-5", "-4", "-4", "-4", "-3",
"-3", "-3", "-2", "-2", "-2", "-1", "-1", "-1", "-1", "0", "0", "0", "1", "1",
"1", "2", "2", "2", "3", "3", "3", "4", "4", "4", "5", "5", "5", "5", "6", "6",
"6", "7", "7", "7", "8", "8", "8", "9", "9", "9", "10", "10.3", "10.6", "11", "11.3",
"11.6", "12.0", "12.3", "12.6", "13.0", "13.3", "13.6", "14.0", "14.3", "14.6", "15.0", "15.3", "15.6",
"16.0", "16.3", "16.6", "17.3", "17.6", "18.0", "18.3", "18.6", "19.0", "19.3", "19.6", "20.0", "20.5",
"21.0", "21.3", "21.6", "22.0", "22.3", "22.6", "23.0", "23.5", "24.0", "24.3", "24.6", "25.0", "25.5",
"26.0", "26.5", "27.0", "27.3", "27.6", "28.0", "28.5", "29.0", "29.5", "30.0", "30.5", "31.0", "31.5",
"32.0", "32.5", "33.0", "33.5", "34.0", "34.5", "35.0", "35.5", "36.0", "36.5", "37.0", "37.5", "38.0",
"38.5", "39", "40.0", "40.5", "41.0", "41.5", "42", "43.0", "43.5", "44", "45", "45", "46",
"47", "48", "48", "49", "50", "51", "52", "53", "53", "54", "55", "56", "57",
"59", "60", "61", "62", "63", "65", "66", "68", "69", "71", "73", "75", "77",
"79", "81", "82", "86", "90", "93", "97", "100", "100", "100", "100", "100",
"100", "100", "100", "100");
// wenn das Skript von einer RegisterVariable-Instanz aus aufgerufen worden ist
if ($_IPS['SENDER'] == "RegisterVariable")
{
// bereits im Puffer der Instanz vorhandene Daten in $data kopieren
$data = RegVar_GetBuffer($_IPS['INSTANCE']);
// neu empfangene Daten an $data anhängen
$data .= $_IPS['VALUE'];
// Lüfterstufe Status auslesen
$Funktion=substr($data,0,5);// Funktion ausfiltern
switch($Funktion)
{
case "\x01\x11\x21\x29\x01": // Lüfterstufe 1
SetValue($ID_Luefterstufe, 1);
break;
case "\x01\x11\x21\x29\x03": // Lüfterstufe 2
SetValue($ID_Luefterstufe, 2);
break;
case "\x01\x11\x21\x29\x07": // Lüfterstufe 3
SetValue($ID_Luefterstufe, 3);
break;
case "\x01\x11\x21\x29\x0F": // Lüfterstufe 4
SetValue($ID_Luefterstufe, 4);
break;
case "\x01\x11\x21\x29\x1F": // Lüfterstufe 5
SetValue($ID_Luefterstufe, 5);
break;
case "\x01\x11\x21\x29\x3F": // Lüfterstufe 6
SetValue($ID_Luefterstufe, 6);
break;
case "\x01\x11\x21\x29\x7F": // Lüfterstufe 7
SetValue($ID_Luefterstufe, 7);
break;
case "\x01\x11\x21\x29\xFF": // Lüfterstufe 8
SetValue($ID_Luefterstufe, 8);
break;
}
// Temperaturen auslesen
$Funktion1=substr($data,0,4);// Funktion ausfiltern
switch($Funktion1)
{
case "\x01\x11\x20\xAF": // Bypass Temperatur
$Bypass=substr($data,4,1);// Temperatur ausfiltern
$BypassTemp = ord($Bypass); // Chr in Dezimal umwandeln
SetValue(11639 /*[Schnittstellen\Vallox KWL\Bypass Temperatur]*/ , $Temperatur[$BypassTemp]);
break;
case "\x01\x11\x20\x35": // Zuluft Temperatur in die Wohnung
$Zuluft=substr($data,4,1);// Temperatur ausfiltern
$ZuluftTemp = ord($Zuluft); // Chr in Dezimal umwandeln
SetValue(26273 /*[Schnittstellen\Vallox KWL\Temp Zuluft in die Wohnung]*/ , $Temperatur[$ZuluftTemp]);
break;
case "\x01\x11\x20\x34": // Abluft Temperatur aus der Wohnung
$Abluft=substr($data,4,1);// Temperatur ausfiltern
$AbluftTemp = ord($Abluft); // Chr in Dezimal umwandeln
SetValue(47538 /*[Schnittstellen\Vallox KWL\Temp Abluft aus der Wohnung]*/ , $Temperatur[$AbluftTemp]);
break;
case "\x01\x11\x20\x33": // Fortluft Temperatur nach draussen
$Fortluft=substr($data,4,1);// Temperatur ausfiltern
$FortluftTemp = ord($Fortluft); // Chr in Dezimal umwandeln
SetValue(45899 /*[Schnittstellen\Vallox KWL\Temp Fortluft nach draussen]*/ , $Temperatur[$FortluftTemp]);
break;
case "\x01\x11\x20\x32": // Außenluft Temperatur zum Gerät
$Aussenluft=substr($data,4,1);// Temperatur ausfiltern
$AussenluftTemp = ord($Aussenluft); // Chr in Dezimal umwandeln
SetValue(21161 /*[Schnittstellen\Vallox KWL\Temp Aussenluft zum Gerät]*/ , $Temperatur[$AussenluftTemp]);
break;
case "\x01\x11\x21\xA3": // Anlagen Status
$Status=substr($data,4,1);// Status ausfiltern
$StatusDez = ord($Status);
if (getBitState($StatusDez, 0)) // KWL Betriebsstatus an Bit0 auslesen
SetValueBoolean($ID_Betrieb , true);
else
SetValueBoolean($ID_Betrieb , false);
if (getBitState($StatusDez, 1)) // KWL CO2 adjust state an Bit1 auslesen
SetValueBoolean($CO2_Status , true);
else
SetValueBoolean($CO2_Status , false);
if (getBitState($StatusDez, 2)) // KWL %RH adjust state an Bit2 auslesen
SetValueBoolean($Luftfeuchte_Status , true);
else
SetValueBoolean($Luftfeuchte_Status , false);
if (getBitState($StatusDez, 3)) // KWL Heating state an Bit3 auslesen
SetValueBoolean($Heizung_Status , true);
else
SetValueBoolean($Heizung_Status , false);
if (getBitState($StatusDez, 4)) // KWL Filterguard indicator an Bit4 auslesen
SetValueBoolean($Filter_Status , true);
else
SetValueBoolean($Filter_Status , false);
if (getBitState($StatusDez, 5)) // KWL Heating indicator an Bit5 auslesen
SetValueBoolean($Heizung_Indikator , true);
else
SetValueBoolean($Heizung_Indikator , false);
if (getBitState($StatusDez, 6)) // KWL Fault indicator an Bit6 auslesen
SetValueBoolean($Fehler_Indikator , true);
else
SetValueBoolean($Fehler_Indikator , false);
if (getBitState($StatusDez, 7)) // KWL Service reminder an Bit7 auslesen
SetValueBoolean($Service , true);
else
SetValueBoolean($Service , false);
break;
case "\x01\x11\x21\x71": // Anlagen Status
$Status=substr($data,4,1);// Status ausfiltern
$StatusDez = ord($Status);
if (getBitState($StatusDez, 5)) // KWL Boost On an Bit5 auslesen
SetValueBoolean($Boost_on , true);
else
SetValueBoolean($Boost_on , false);
if (getBitState($StatusDez, 6)) // KWL Boost Status an Bit6 auslesen
SetValueBoolean($Boost_Status , true);
else
SetValueBoolean($Boost_Status , false);
break;
case "\x01\x11\x21\x08": // Anlagen Status
$Status=substr($data,4,1);// Status ausfiltern
$StatusDez = ord($Status);
if (getBitState($StatusDez, 1)) // KWL Damper Position an Bit1 auslesen
SetValueBoolean($Klappe , true);
else
SetValueBoolean($Klappe , false);
if (getBitState($StatusDez, 3)) // KWL Fan In an Bit3 auslesen
SetValueBoolean($Fan_In_On , true);
else
SetValueBoolean($Fan_In_On , false);
if (getBitState($StatusDez, 5)) // KWL Fan Out an Bit5 auslesen
SetValueBoolean($Fan_Out_On , true);
else
SetValueBoolean($Fan_Out_On , false);
break;
}
}
function getBitState($Value, $BitNo)
{
return (($Value & pow(2, $BitNo)) != 0);
}
?>
Wo hab ich wieder mal den Denkfehler?