Moin,
leider habe ich kein Plugin für Smarthome.py zu diesem Thema gefunden, jedoch für Wiregate und OpenHAB
Wiregate https://knx-user-forum.de/forum/suppo...arregler-resol
...und auch eine Diskussion zu OpenHAB https://knx-user-forum.de/forum/supp...en/openhab/821
Daher habe ich ein Plugin "geschrieben", mit dem die Daten meiner Solarthermie Anlage ausgelesen werden.
Mein Regler der Solarthermie Anlage ist ähnlich zum "Resol Systemregler DeltaSol® E" http://www.resol.de/index/produktdet...d/8/sprache/de nämlich eine "Cosmo Multi" http://www.cosmo-info.de/fileadmin/u...OSMO-Multi.pdf
Das Skript basiert auf diesem Python2 Skript
https://github.com/herbstmensch/resol-vbus-python
Die Daten aus diesem Skript werden mittels "Pickle" in eine temporäre Datei geschrieben, die vom Smarthome-Plugin ausgelesen werden.
(Nicht schön - läuft jedoch :-)
Nun die Codeschnipsel, die Ihr gerne in Github übernehmen & optimieren dürft:
README.md
__init__.py
resol_background.py
config.py --> IP und Passwort editieren
spec.py (unverändert)
VBusSpecificationCosmoMulti2012.json
leider habe ich kein Plugin für Smarthome.py zu diesem Thema gefunden, jedoch für Wiregate und OpenHAB
Wiregate https://knx-user-forum.de/forum/suppo...arregler-resol
...und auch eine Diskussion zu OpenHAB https://knx-user-forum.de/forum/supp...en/openhab/821
Daher habe ich ein Plugin "geschrieben", mit dem die Daten meiner Solarthermie Anlage ausgelesen werden.
Mein Regler der Solarthermie Anlage ist ähnlich zum "Resol Systemregler DeltaSol® E" http://www.resol.de/index/produktdet...d/8/sprache/de nämlich eine "Cosmo Multi" http://www.cosmo-info.de/fileadmin/u...OSMO-Multi.pdf
Das Skript basiert auf diesem Python2 Skript
https://github.com/herbstmensch/resol-vbus-python
Die Daten aus diesem Skript werden mittels "Pickle" in eine temporäre Datei geschrieben, die vom Smarthome-Plugin ausgelesen werden.
(Nicht schön - läuft jedoch :-)
Nun die Codeschnipsel, die Ihr gerne in Github übernehmen & optimieren dürft:
README.md
Code:
# Resol ## Requirements/Description Description: Connects to read-only RESOL VBUS Data over LAN Requirements: Edit config.py (not yet done via Smarthome.py config) Add Resol specific *.json files with content of VBUS Python2 needed for Python-Script to read VBUS Data over LAN, source: https://github.com/herbstmensch/resol-vbus-python Writeable directory to save output of async-data (Exchange of Python2 -> Phyton3 Script) ## Supported Hardware I.e. Resol VBUS Data over LAN: http://www.resol.de/index/produktdetail/kategorie/1/id/76/sprache/en ## Configuration ### plugin.conf [resol] class_name = Resol class_path = plugins.resol host = localhost # ip of ebusd cycle = 60 # cycle of each item # port = 7053 # port of VBUS # username = 'USERNAME' # password = 'PASSWORD' ### items.conf Items need parameter "json_variable"- [resol] [[temperature_solar_outside]] type = num knx_dpt = 5 knx_send = 15/0/0 knx_reply = 15/0/0 json_variable = "Temperatur Sensor 1" [[temperature_heating_returnflow_unmixed]] type = num knx_dpt = 5 knx_send = 15/0/1 knx_reply = 15/0/1 json_variable = "Temperatur Sensor 7" [[temperature_heating_returnflow_mixed]] type = num knx_dpt = 5 knx_send = 15/0/2 knx_reply = 15/0/2 json_variable = "Temperatur Sensor 8"
Code:
#!/usr/bin/env python3 # ######################################################################### # Copyright 2015 KNX-Username : KHome # Inspired by eBus Plug-in & Git-Hub project by "Herbstmensch" # Includes parts of: https://github.com/herbstmensch/resol-vbus-python ######################################################################### # Free for non-commercial use ######################################################################### import pickle import time import subprocess import sys import logging import socket import threading logger = logging.getLogger('resol') class Resol(): _items = [] def __init__(self, smarthome, host, username=None, password=None, cycle=60): self._sh = smarthome self._host = host self._cycle = int(cycle) self._username = username self._password = password self.refresh_cycle = self._cycle #logging.warning("Test Init Phase, starting python2") self._var = subprocess.Popen(['python2', '/home/pi/smarthome/plugins/resol/resol_background.py'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) #start data receiving in while-loop and save variales via python pickle to a temp file, uses python2 def run(self): logging.warning("run function") self.alive = True self._sh.scheduler.add('resolcycle', self.refresh, prio=5, cycle=self._cycle, offset=2) # if you want to create child threads, do not make them daemon = True! # They will not shutdown properly. (It's a python bug) # def stop(self): self.alive = False def parse_item(self, item): if 'json_variable' in item.conf: self._items.append(item) return self.update_item #logger.debug("parse item: {0}".format(item)) # ##skeleton part # def parse_logic(self, logic): # if 'xxx' in logic.conf: # # self.function(logic['name']) # pass # def update_item(self, item, caller=None, source=None, dest=None): #logging.warning("update function") if caller != 'Resol': #logger.info("update item: {0}".format(item.id())) value = str(int(item())) def refresh(self): #logging.warning("refresh function") for item in self._items: time.sleep(1) resol_variable = item.conf['json_variable'] value = self.request(resol_variable) #logging.warning(resol_variable) #logging.warning(value) #if reading fails (i.e. at broadcast-commands) the value will not be updated if value is not None: item(value, 'resol', 'refresh') if not self.alive: brea def request(self, request): #logging.warning("request function") try: fp = open("/tmp/shared.pkl",'rb') #logging.warning(request) shared = pickle.load(fp) answer = shared[request].rsplit(";",2)[0] #logging.warning(answer) return answer except: logger.warning("Unexpected error: resol reading shared.pkl") #logger.warning("Unexpected error:", sys.exc_info()[0])
Code:
#!/usr/bin/env python2 # -*- coding: utf-8 -*- #Talk with Resol VBUS over LAN # https://github.com/herbstmensch/resol-vbus-python import socket import time import sys import json import pickle import codecs import sys reload(sys) sys.setdefaultencoding('Cp1252') # Load settings try: import config except: sys.exit("config.py not found!") # Load Message specification try: import spec except: sys.exit("Could not load Message Specification") # Logs in onto the DeltaSol BS Plus over LAN. Also starts (and maintains) the # actual stream of data. def login(): dat = recv() #Check if device answered if dat != "+HELLO\n": return False #Send Password send("PASS %s\n" % config.vbus_pass) dat = recv() return dat.startswith("+OK") def load_data(): #Request Data global new_data send("DATA\n") dat = recv() #Check if device is ready to send Data if not dat.startswith("+OK"): return init_first = 1 timeout = time.time() + 60*2 while len(result) < config.expected_packets and time.time() < timeout: if time.time() > timeout: break else: timeout = time.time() + 60*2 buf = readstream() msgs = splitmsg(buf) for msg in msgs: if "PV1" == get_protocolversion(msg): if init_first == 1: result2 = {} new_data = parse_payload(msg, True, result2) init_first = init_first+1 else: old_data = new_data result2 = {} new_data = parse_payload(msg, False,result2) if isinstance(new_data,dict) and isinstance(old_data,dict) : check_changes(old_data, new_data) if config.debug: print format_message_pv1(msg) elif "PV2" == get_protocolversion(msg): if config.debug: print format_message_pv2(msg) # Receive 1024 bytes from stream def recv(): dat = sock.recv(1024) return dat def check_changes(old_data, new_data): if cmp(old_data, new_data) == 0: a=0 # they are the same else: #print "not the same" # # continoues reading, write to file, uses module pickle d= DictDiffer(old_data,new_data) changedlist= list(d.changed()) #shared = unicode(new_data, 'utf-8') shared = new_data fp = codecs.open("/tmp/shared.pkl","w", 'utf-8') #fp = codecs.open("shared.pkl","w") pickle.dump(shared, fp) fp.close # #for field in (changedlist): # print field + "; " + new_data[field] # print field['name'] + ": "+ result[get_source_name(msg)][field['name'][0]] # Sends given bytes over the stram. Adds debug def send(dat): sock.send(dat) # Read Data until minimum 1 message is received def readstream(): data = recv() while data.count(chr(0xAA)) < 4: data += recv() return data #Split Messages on Sync Byte def splitmsg(buf): return buf.split(chr(0xAA))[1:-1] # Format 1 byte as String def format_byte(byte): return hex(ord(byte))[0:2] + '0' + hex(ord(byte))[2:] if len(hex(ord(byte))) < 4 else hex(ord(byte)) # Extract protocol Version from msg def get_protocolversion(msg): if hex(ord(msg[4])) == '0x10': return "PV1" if hex(ord(msg[4])) == '0x20': return "PV2" if hex(ord(msg[4])) == '0x30': return "PV3" return "UNKNOWN" # Extract Destination from msg def get_destination(msg): return format_byte(msg[1]) + format_byte(msg[0])[2:] #Extract source from msg def get_source(msg): return format_byte(msg[3]) + format_byte(msg[2])[2:] # Extract command from msg def get_command(msg): return format_byte(msg[6]) + format_byte(msg[5:6])[2:] # Get count of frames in msg def get_frame_count(msg): return gb(msg, 7, 8) # Extract payload from msg def get_payload(msg): payload = '' for i in range(get_frame_count(msg)): payload += integrate_septett(msg[9+(i*6):15+(i*6)]) return payload # parse payload and put result in result def parse_payload(msg, printall, packetdict): payload = get_payload(msg) for packet in spec.spec['packet']: if packet['source'] == get_source(msg) and packet['destination'] == get_destination(msg) and packet['command'] == get_command(msg): #print packet for field in packet['field']: # result[get_source_name(msg)][field['name']] = str(gb(payload, int(field['offset']), int(field['offset'])+((int(field['bitSize'])+1) / 8)) * (float(field['factor']) if field.has_key('factor') else 1)) + field['unit'] if 'unit' in field else '' if field.has_key('offset'): packetdict[field['name']] = str(gb(payload, int(field['offset']), int(field['offset'])+((int(field['bitSize'])+1) / 8)) * (float(field['factor']) if field.has_key('factor') else 1)) + "; " + (field['unit'] if field.has_key('unit') else '') if printall: # initial reading, write to file, uses module pickle #shared = unicode(packetdict, 'utf-8') shared = packetdict fp = codecs.open("/tmp/shared.pkl","w", 'utf-8') #fp = codecs.open("shared.pkl","w") pickle.dump(shared, fp) fp.close #print field['name'] + "; "+ packetdict[field['name']] return packetdict def format_message_pv1(msg): parsed = "PARSED: \n" parsed += " ZIEL".ljust(15,'.')+": " + get_destination(msg) + "\n" parsed += " QUELLE".ljust(15,'.')+": " + get_source(msg) + " " + get_source_name(msg) + "\n" parsed += " PROTOKOLL".ljust(15,'.')+": " + get_protocolversion(msg) + "\n" parsed += " BEFEHL".ljust(15,'.')+": " + get_command(msg) + "\n" parsed += " ANZ_FRAMES".ljust(15,'.')+": " + str(get_frame_count(msg)) + "\n" parsed += " CHECKSUM".ljust(15,'.')+": " + format_byte(msg[8]) + "\n" for i in range(get_frame_count(msg)): integrated = integrate_septett(msg[9+(i*6):15+(i*6)]) parsed += (" NB"+str(i*4+1)).ljust(15,'.')+": " + format_byte(msg[9+(i*6)]) + " - " + format_byte(integrated[0]) + "\n" parsed += (" NB"+str(i*4+2)).ljust(15,'.')+": " + format_byte(msg[10+(i*6)]) + " - " + format_byte(integrated[1]) + "\n" parsed += (" NB"+str(i*4+3)).ljust(15,'.')+": " + format_byte(msg[11+(i*6)]) + " - " + format_byte(integrated[2]) + "\n" parsed += (" NB"+str(i*4+4)).ljust(15,'.')+": " + format_byte(msg[12+(i*6)]) + " - " + format_byte(integrated[3]) + "\n" parsed += (" SEPTETT"+str(i+1)).ljust(15,'.')+": " + format_byte(msg[13+(i*6)]) + "\n" parsed += (" CHECKSUM"+str(i+1)).ljust(15,'.')+": " + format_byte(msg[14+(i*6)]) + "\n" parsed += " PAYLOAD".ljust(15,'.')+": " + (" ".join(format_byte(b) for b in get_payload(msg)))+"\n" return parsed def format_message_pv2(msg): parsed = "PARSED: \n" parsed += " ZIEL1".ljust(15,'.')+": " + format_byte(msg[0:1]) + "\n" parsed += " ZIEL2".ljust(15,'.')+": " + format_byte(msg[1:2]) + "\n" parsed += " QUELLE1".ljust(15,'.')+": " + format_byte(msg[2:3]) + "\n" parsed += " QUELLE2".ljust(15,'.')+": " + format_byte(msg[3:4]) + "\n" parsed += " PROTOKOLL".ljust(15,'.')+": " + format_byte(msg[4:5]) + "\n" parsed += " BEFEHL1".ljust(15,'.')+": " + format_byte(msg[5:6]) + "\n" parsed += " BEFEHL2".ljust(15,'.')+": " + format_byte(msg[6:7]) + "\n" parsed += " ID1".ljust(15,'.')+": " + format_byte(msg[7:8]) + "\n" parsed += " ID2".ljust(15,'.')+": " + format_byte(msg[8:9]) + "\n" parsed += " WERT1".ljust(15,'.')+": " + format_byte(msg[9:10]) + "\n" parsed += " WERT2".ljust(15,'.')+": " + format_byte(msg[10:11]) + "\n" parsed += " WERT3".ljust(15,'.')+": " + format_byte(msg[11:12]) + "\n" parsed += " WERT4".ljust(15,'.')+": " + format_byte(msg[12:13]) + "\n" parsed += " SEPTETT".ljust(15,'.')+": " + format_byte(msg[13:14]) + "\n" parsed += " CHECKSUM".ljust(15,'.')+": " + format_byte(msg[14:15]) + "\n" return parsed def get_compare_length(mask): i = 1 while i < 6 and mask[i] != '0': i += 1 return i+1 def get_source_name(msg): src = format_byte(msg[3]) + format_byte(msg[2])[2:] for device in spec.spec['device']: if src[:get_compare_length(device['mask'])] == device['address'][:get_compare_length(device['mask'])]: return device['name'] if get_compare_length(device['mask']) == 7 else str(device['name']).replace('#',device['address'][get_compare_length(device['mask'])-1:],1) return "" def integrate_septett(frame): data = '' septet = ord(frame[4]) for j in range(4): if septet & (1 /< /< j): data += chr(ord(frame[j]) | 0x80) else: data += frame[j] return data class DictDiffer(object): """ Calculate the difference between two dictionaries as: (1) items added (2) items removed (3) keys same in both but changed values (4) keys same in both and unchanged values """ def __init__(self, current_dict, past_dict): self.current_dict, self.past_dict = current_dict, past_dict self.current_keys, self.past_keys = [ set(d.keys()) for d in (current_dict, past_dict) ] self.intersect = self.current_keys.intersection(self.past_keys) def added(self): return self.current_keys - self.intersect def removed(self): return self.past_keys - self.intersect def changed(self): return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o]) def unchanged(self): return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o]) # Gets the numerical value of a set of bytes (respect Two's complement by value Range) def gb(data, begin, end): # GetBytes wbg = sum([0xff /< /< (i * 8) for i, b in enumerate(data[begin:end])]) s = sum([ord(b) /< /< (i * 8) for i, b in enumerate(data[begin:end])]) if s >= wbg/2: s = -1 * (wbg - s) return s if __name__ == '__main__': while 1: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(config.address) result = dict() login() load_data() # print json.dumps(result) try: sock.shutdown(0) except: pass sock.close() sock = None time.sleep(3)
Code:
address = ("192.168.178.x", 7053) vbus_pass = "PASSWORD" spec_file = "/home/pi/smarthome/plugins/resol/VBusSpecificationCosmoMulti2012.json" debug = False expected_packets = 2
Code:
#!/usr/bin/env python2 __author__ = 'Tim' import json import sys import config # Load given specFile. Specfile was created from original # RESOL Configuration File XML shippes with RSC (Resol Service Center) # using XML to JSON converter at http://www.utilities-online.info/xmltojson with open(config.spec_file) as json_data: data = json.load(json_data) try: spec = data['vbusSpecification'] except: sys.exit('Cannot load Spec') if config.debug: for device in spec['device']: print device for packet in spec['packet']: print packet for field in packet['field']: print " " + str(field) json_data.close()
Code:
{ "vbusSpecification": { "device": [ { "address": "0x7821", "mask": "0xFFFF", "name": "COSMO Multi", "isMaster": "true" }, { "address": "0x7822", "mask": "0xFFFF", "name": "COSMO Multi WMZ", "isMaster": "false" }, { "address": "0x7831", "mask": "0xFFFF", "name": "COSMO Multi HK 1 Estrichtrockung Modul 1", "isMaster": "false" }, { "address": "0x7832", "mask": "0xFFFF", "name": "COSMO Multi HK 2 Estrichtrockung Modul 2", "isMaster": "false" }, { "address": "0x7833", "mask": "0xFFFF", "name": "COSMO Multi HK 3 Estrichtrockung Modul 3", "isMaster": "false" }, { "address": "0x7834", "mask": "0xFFFF", "name": "COSMO Multi HK Estrichtrockung Lokal", "isMaster": "false" } ], "packet": [ { "destination": "0x0010", "source": "0x7821", "command": "0x0100", "field": [ { "-commonUsage": "collector1", "offset": "0", "name": "Temperatur Sensor 1", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "-commonUsage": "store1", "offset": "2", "name": "Temperatur Sensor 2", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "4", "name": "Temperatur Sensor 3", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "6", "name": "Temperatur Sensor 4", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "8", "name": "Temperatur Sensor 5", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "10", "name": "Temperatur Sensor 6", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "12", "name": "Temperatur Sensor 7", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "14", "name": "Temperatur Sensor 8", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "16", "name": "Temperatur Sensor 9", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "18", "name": "Temperatur Sensor 10", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "20", "name": "Einstrahlung CS", "bitSize": "15", "factor": "1", "unit": " W/m²" }, { "offset": "22", "name": "Impulse 1 V40", "bitSize": "16", "factor": "1", "unit": " " }, { "offset": "24", "name": "Digital Input", "bitSize": "16", "factor": "1", "unit": " " }, { "offset": "26", "name": "Drehzahl Relais 1", "bitSize": "7", "unit": " %" }, { "offset": "27", "name": "Drehzahl Relais 2", "bitSize": "7", "unit": " %" }, { "offset": "28", "name": "Drehzahl Relais 3", "bitSize": "7", "unit": " %" }, { "offset": "29", "name": "Drehzahl Relais 4", "bitSize": "7", "unit": " %" }, { "offset": "30", "name": "Drehzahl Relais 5", "bitSize": "7", "unit": " %" }, { "offset": "31", "name": "Drehzahl Relais 6", "bitSize": "7", "unit": " %" }, { "offset": "32", "name": "Drehzahl Relais 7", "bitSize": "7", "unit": " %" }, { "-commonUsage": "error", "offset": "36", "name": "Fehlermaske", "bitSize": "16" }, { "offset": "38", "name": "Meldungen", "bitSize": "16" }, { "offset": "40", "name": "System", "bitSize": "7" }, { "offset": "42", "name": "Schema", "bitSize": "16" }, { "offset": "44", "name": "Vorlauf Soll HK1 Modul Sensor 18", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "46", "name": "Status HK1 Modul", "bitSize": "16" }, { "offset": "48", "name": "Vorlauf Soll HK2 Modul Sensor 25", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "50", "name": "Status HK2 Modul", "bitSize": "16" }, { "offset": "52", "name": "Vorlauf Soll HK3 Modul Sensor 32", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "54", "name": "Status HK3 Modul", "bitSize": "16" }, { "offset": "56", "name": "Vorlauf Soll Heizkreis Sensor 11", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "58", "name": "Status Heizkreis", "bitSize": "16" }, { "offset": "62", "name": "Systemzeit", "bitSize": "15", "format": "t", "timeRef": "1" }, { "offset": "64", "name": "Jahr", "bitSize": "15", "factor": "1" }, { "offset": "66", "name": "Monat", "bitSize": "7", "factor": "1" }, { "offset": "67", "name": "Tag", "bitSize": "7", "factor": "1" }, { "name": "Version", "field": [ { "offset": "60", "bitSize": "7", "factor": "1" }, { "offset": "61", "bitSize": "7", "factor": "0,01" } ], "format": "F2" } ] }, { "destination": "0x0010", "source": "0x7822", "command": "0x0100", "field": [ { "offset": "0", "name": "Temperatur Vorlauf", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "2", "name": "Temperatur Rücklauf", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "4", "name": "Durchfluss Sensor 8", "bitSize": "15", "unit": " l/h" }, { "-commonUsage": "heat", "name": "Wärmemenge", "unit": " Wh", "field": [ { "offset": "6", "bitSize": "16", "factor": "1" }, { "offset": "8", "bitSize": "16", "factor": "1000" }, { "offset": "10", "bitSize": "16", "factor": "1000000" } ] } ] }, { "destination": "0x0010", "source": "0x7831", "sourceMask": "0xFFF0", "command": "0x0100", "field": [ { "offset": "0", "name": "Jahr", "bitSize": "15", "factor": "1" }, { "offset": "2", "name": "Monat", "bitSize": "7", "factor": "1" }, { "offset": "3", "name": "Tag", "bitSize": "7", "factor": "1" }, { "offset": "4", "name": "Systemzeit", "bitSize": "15", "format": "t", "timeRef": "1" }, { "offset": "6", "name": "Status", "bitSize": "7" }, { "offset": "7", "name": "Fehlermeldung", "bitSize": "7" }, { "offset": "8", "name": "Vorlauf-Soll-Temperatur", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "10", "name": "Vorlauftemperatur", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "12", "name": "Relais Pumpe", "bitSize": "7", "unit": " %" }, { "offset": "13", "name": "Relais Mischer Auf", "bitSize": "7", "unit": " %" }, { "offset": "14", "name": "Relais Mischer Zu", "bitSize": "7", "unit": " %" }, { "offset": "15", "name": "Handebetrieb Relais Pumpe", "bitSize": "7" }, { "offset": "16", "name": "Handebetrieb Relais Mischer Auf", "bitSize": "7" }, { "offset": "17", "name": "Handebetrieb Relais Mischer Zu", "bitSize": "7" }, { "offset": "18", "name": "NH-Anforderung", "bitSize": "7" }, { "offset": "19", "name": "Parameter Start", "bitSize": "7" }, { "offset": "20", "name": "Parameter TStart", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "22", "name": "Parameter TMax", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "24", "name": "Parameter Anstieg", "bitSize": "15", "factor": "0.1", "unit": " °C" }, { "offset": "26", "name": "Parameter Anstiegszeit", "bitSize": "7", "unit": " h" }, { "offset": "27", "name": "Parameter Haltezeit", "bitSize": "7", "unit": " d" } ] } ] } }
Kommentar