diff --git a/viessmann/_pv_1_2_3/README.md b/viessmann/README.md similarity index 100% rename from viessmann/_pv_1_2_3/README.md rename to viessmann/README.md diff --git a/viessmann/__init__.py b/viessmann/__init__.py old mode 100644 new mode 100755 index 1e8f94e41..11bd79325 --- a/viessmann/__init__.py +++ b/viessmann/__init__.py @@ -1,32 +1,39 @@ #!/usr/bin/env python3 # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab + ######################################################################### -# Copyright 2020- Sebastian Helms Morg @ knx-user-forum +# Copyright 2020 Michael Wenzel +# Copyright 2020 Sebastian Helms ######################################################################### -# This file is part of SmartHomeNG -# -# Viessmann heating plugin for SmartDevicePlugin class +# Viessmann-Plugin for SmartHomeNG. https://github.com/smarthomeNG// # -# SmartHomeNG is free software: you can redistribute it and/or modify +# 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. # -# SmartHomeNG is distributed in the hope that it will be useful, +# 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 SmartHomeNG If not, see . +# along with this plugin. If not, see . ######################################################################### -import builtins -import os +import logging import sys +import time +import re +import json +import serial +import threading +from datetime import datetime +import dateutil.parser +import cherrypy if __name__ == '__main__': - builtins.SDP_standalone = True + # just needed for standalone mode class SmartPlugin(): pass @@ -34,105 +41,392 @@ class SmartPlugin(): class SmartPluginWebIf(): pass + import os BASE = os.path.sep.join(os.path.realpath(__file__).split(os.path.sep)[:-3]) sys.path.insert(0, BASE) - from protocol import SDPProtocolViessmann + import commands else: - builtins.SDP_standalone = False - from .protocol import SDPProtocolViessmann + from . import commands -from lib.model.sdp.globals import PLUGIN_ATTR_SERIAL_PORT, PLUGIN_ATTR_PROTOCOL -from lib.model.smartdeviceplugin import SmartDevicePlugin, Standalone + from lib.item import Items + from lib.model.smartplugin import SmartPlugin, SmartPluginWebIf, Modules + from bin.smarthome import VERSION -if not SDP_standalone: - from .webif import WebInterface +class Viessmann(SmartPlugin): + ''' + Main class of the plugin. Provides communication with Viessmann heating systems + via serial / USB-to-serial connections to read values and set operating parameters. -class viessmann(SmartDevicePlugin): - """ Device class for Viessmann heating systems. + Supported device types must be defined in ./commands.py. + ''' + ALLOW_MULTIINSTANCE = False - Standalone mode is automatic device type discovery - """ - PLUGIN_VERSION = '1.3.0' + PLUGIN_VERSION = '1.2.3' - def _set_device_defaults(self): +# +# public methods +# - if not SDP_standalone: - self._webif = WebInterface + def __init__(self, sh, *args, standalone='', logger=None, **kwargs): - self._parameters[PLUGIN_ATTR_PROTOCOL] = SDPProtocolViessmann + # Call init code of parent class (SmartPlugin) + super().__init__() -# -# methods for standalone mode -# + # standalone mode: just setup basic info + if standalone: + self._serialport = standalone + self._timeout = 3 + self.logger = logger + self._standalone = True + + else: + # Get plugin parameter + self._serialport = self.get_parameter_value('serialport') + self._heating_type = self.get_parameter_value('heating_type') + self._protocol = self.get_parameter_value('protocol') + self._timeout = self.get_parameter_value('timeout') + self._standalone = False + + # Set variables + self._error_count = 0 + self._params = {} # Item dict + self._init_cmds = [] # List of command codes for read at init + self._cyclic_cmds = {} # Dict of command codes with cylce-times for cyclic readings + self._application_timer = {} # Dict of application timer with command codes and values + self._timer_cmds = [] # List of command codes for timer + self._viess_timer_dict = {} + self._last_values = {} + self._balist_item = None # list of last value per command code + self._lock = threading.Lock() + self._initread = False + self._timerread = False + self._connected = False + self._initialized = False + self._lastbyte = b'' + self._lastbytetime = 0 + self._cyclic_update_active = False + self._wochentage = { + 'MO': ['mo', 'montag', 'monday'], + 'TU': ['di', 'dienstag', 'tuesday'], + 'WE': ['mi', 'mittwoch', 'wednesday'], + 'TH': ['do', 'donnerstag', 'thursday'], + 'FR': ['fr', 'freitag', 'friday'], + 'SA': ['sa', 'samstag', 'saturday'], + 'SU': ['so', 'sonntag', 'sunday']} + + # if running standalone, don't initialize command sets + if not sh: + return + + # initialize logger if necessary + if '.'.join(VERSION.split('.', 2)[:2]) <= '1.5': + self.logger = logging.getLogger(__name__) + + self._config_loaded = False - def run_standalone(self): - """ - try to identify device - """ - print(f'dev_viessmann trying to identify device at {self._parameters.get("serialport", "unknown")}...') - devs = self.get_lookup('devicetypes') - if not devs: - devs = {} + if not self._load_configuration(): + return None + + # Init web interface + self.init_webinterface() + + def run(self): + ''' + Run method for the plugin + ''' + if not self._config_loaded: + if not self._load_configuration(): + return + self.alive = True + self._connect() + self._read_initial_values() + self._read_timers() + + def stop(self): + ''' + Stop method for the plugin + ''' + self.alive = False + if self.scheduler_get('cyclic'): + self.scheduler_remove('cyclic') + self._disconnect() + # force reload of configuration on restart + self._config_loaded = False + + def parse_item(self, item): + ''' + Method for parsing items. + If the item carries any viess_* field, this item is registered to the plugin. + + :param item: The item to process. + :type item: object + + :return: The item update method to be triggered if the item is changed, or None. + :rtype: object + ''' + # Process the update config + if self.has_iattr(item.conf, 'viess_update'): + self.logger.debug(f'Item for requesting update for all items triggered: {item}') + return self.update_item + + # Process the timer config and fill timer dict + if self.has_iattr(item.conf, 'viess_timer'): + timer_app = self.get_iattr_value(item.conf, 'viess_timer') + for commandname in self._commandset: + if commandname.startswith(timer_app): + commandconf = self._commandset[commandname] + self.logger.debug(f'Process the timer config, commandname: {commandname}') + # {'addr': '2100', 'len': 8, 'unit': 'CT', 'set': True} + commandcode = (commandconf['addr']).lower() + if timer_app not in self._application_timer: + self._application_timer[timer_app] = {'item': item, 'commandcodes': []} + if commandcode not in self._application_timer[timer_app]['commandcodes']: + self._application_timer[timer_app]['commandcodes'].append(commandcode) + self._application_timer[timer_app]['commandcodes'].sort() + self.logger.info(f'Loaded Application Timer {self._application_timer}') + # self._application_timer: {'Timer_M2': {'item': Item: heizung.heizkreis_m2.schaltzeiten, 'commandcodes': ['3000', '3008', '3010', '3018', '3020', '3028', '3030']}, 'Timer_Warmwasser': {'item': Item: heizung.warmwasser.schaltzeiten, 'commandcodes': ['2100', '2108', '2110', '2118', '2120', '2128', '2130']}} + + for subdict in self._application_timer: + for commandcode in self._application_timer[subdict]['commandcodes']: + if commandcode not in self._timer_cmds: + self._timer_cmds.append(commandcode) + self._timer_cmds.sort() + self.logger.debug(f'Loaded Timer commands {self._timer_cmds}') + return self.update_item + + # Process the read config + if self.has_iattr(item.conf, 'viess_read'): + commandname = self.get_iattr_value(item.conf, 'viess_read') + if commandname is None or commandname not in self._commandset: + self.logger.error(f'Item {item} contains invalid read command {commandname}!') + return None - for proto in ('P300', 'KW'): + # Remember the read config to later update this item if the configured response comes in + self.logger.info(f'Item {item} reads by using command {commandname}') + commandconf = self._commandset[commandname] + commandcode = (commandconf['addr']).lower() - res = self.get_device_type(proto) + # Fill item dict + self._params[commandcode] = {'item': item, 'commandname': commandname} + self.logger.debug(f'Loaded params {self._params}') - if res is None: + # Allow items to be automatically initiated on startup + if self.has_iattr(item.conf, 'viess_init') and self.get_iattr_value(item.conf, 'viess_init'): + self.logger.info(f'Item {item} is initialized on startup') + if commandcode not in self._init_cmds: + self._init_cmds.append(commandcode) + self.logger.debug(f'CommandCodes should be read at init: {self._init_cmds}') - # None means no connection, no further tries - print(f'Connection could not be established to {self._parameters[PLUGIN_ATTR_SERIAL_PORT]}. Please check connection.') - break + # Allow items to be cyclically updated + if self.has_iattr(item.conf, 'viess_read_cycle'): + cycle = int(self.get_iattr_value(item.conf, 'viess_read_cycle')) + self.logger.info(f'Item {item} should read cyclic every {cycle} seconds') + nexttime = time.time() + cycle + if commandcode not in self._cyclic_cmds: + self._cyclic_cmds[commandcode] = {'cycle': cycle, 'nexttime': nexttime} + else: + # If another item requested this command already with a longer cycle, use the shorter cycle now + if self._cyclic_cmds[commandcode]['cycle'] > cycle: + self._cyclic_cmds[commandcode]['cycle'] = cycle + self.logger.debug(f'CommandCodes should be read cyclic: {self._cyclic_cmds}') - if res is False: + # Process the write config + if self.has_iattr(item.conf, 'viess_send'): + if self.get_iattr_value(item.conf, 'viess_send'): + commandname = self.get_iattr_value(item.conf, 'viess_read') + else: + commandname = self.get_iattr_value(item.conf, 'viess_send') - # False means no comm init (only P300), go on - print(f'Communication could not be established using protocol {proto}.') + if commandname is None or commandname not in self._commandset: + self.logger.error(f'Item {item} contains invalid write command {commandname}!') + return None else: + self.logger.info(f'Item {item} to be written by using command {commandname}') + return self.update_item + + # get operating modes list + if self.has_iattr(item.conf, 'viess_ba_list'): + self._balist_item = item + self.logger.info(f'Item {item} wants list of operating modes') + + def parse_logic(self, logic): + pass + + def update_item(self, item, caller=None, source=None, dest=None): + ''' + Callback method for sending values to the plugin when a registered item has changed + + :param item: item to be updated towards the plugin + :param caller: if given it represents the callers name + :param source: if given it represents the source + :param dest: if given it represents the dest + ''' + if self.alive and caller != self.get_shortname(): + self.logger.info(f'Update item: {item.id()}, item has been changed outside this plugin') + self.logger.debug(f'update_item was called with item {item} from caller {caller}, source {source} and dest {dest}') + + if self.has_iattr(item.conf, 'viess_send'): + # Send write command + if self.get_iattr_value(item.conf, 'viess_send'): + commandname = self.get_iattr_value(item.conf, 'viess_read') + else: + commandname = self.get_iattr_value(item.conf, 'viess_send') + value = item() + self.logger.debug(f'Got item value to be written: {value} on command name {commandname}') + if not self._send_command(commandname, value): + # create_write_command() liefert False, wenn das Schreiben fehlgeschlagen ist + # -> dann auch keine weitere Verarbeitung + self.logger.debug(f'Write for {commandname} with value {value} failed, reverting value, canceling followup actions') + item(item.property.last_value, self.get_shortname()) + return None + + # If a read command should be sent after write + if self.has_iattr(item.conf, 'viess_read') and self.has_iattr(item.conf, 'viess_read_afterwrite'): + readcommandname = self.get_iattr_value(item.conf, 'viess_read') + readafterwrite = self.get_iattr_value(item.conf, 'viess_read_afterwrite') + self.logger.debug(f'Attempting read after write for item {item}, command {readcommandname}, delay {readafterwrite}') + if readcommandname is not None and readafterwrite is not None: + aw = float(readafterwrite) + time.sleep(aw) + self._send_command(readcommandname) + + # If commands should be triggered after this write + if self.has_iattr(item.conf, 'viess_trigger'): + trigger = self.get_iattr_value(item.conf, 'viess_trigger') + if trigger is None: + self.logger.error(f'Item {item} contains invalid trigger command list {trigger}!') + else: + tdelay = 5 # default delay + if self.has_iattr(item.conf, 'viess_trigger_afterwrite'): + tdelay = float(self.get_iattr_value(item.conf, 'viess_trigger_afterwrite')) + if type(trigger) != list: + trigger = [trigger] + for triggername in trigger: + triggername = triggername.strip() + if triggername is not None and readafterwrite is not None: + self.logger.debug(f'Triggering command {triggername} after write for item {item}') + time.sleep(tdelay) + self._send_command(triggername) + + elif self.has_iattr(item.conf, 'viess_timer'): + timer_app = self.get_iattr_value(item.conf, 'viess_timer') + uzsu_dict = item() + self.logger.debug(f'Got changed UZSU timer: {uzsu_dict} on timer application {timer_app}') + self._uzsu_dict_to_viess_timer(timer_app, uzsu_dict) + + elif self.has_iattr(item.conf, 'viess_update'): + if item(): + self.logger.debug('Reading of all values/items has been requested') + self.update_all_read_items() - # anything else should be the devices answer, try to decode and quit - print(f'Device ID is {res}, device type is {devs.get(res.upper(), "unknown")} supporting protocol {proto}') - # break + def send_cyclic_cmds(self): + ''' + Recall function for shng scheduler. Reads all values configured to be read cyclically. + ''' + # check if another cyclic cmd run is still active + if self._cyclic_update_active: + self.logger.warning('Triggered cyclic command read, but previous cyclic run is still active. Check device and cyclic configuration (too much/too short?)') + return + else: + self.logger.info('Triggering cyclic command read') + + # set lock + self._cyclic_update_active = True + currenttime = time.time() + read_items = 0 + todo = [] + for commandcode in list(self._cyclic_cmds.keys()): + + entry = self._cyclic_cmds[commandcode] + # Is the command already due? + if entry['nexttime'] <= currenttime: + todo.append(commandcode) + + if self._protocol == 'KW': + # see if we got to do anything - maybe no items are due to be read? + if len(todo) > 0: + self._KW_send_multiple_read_commands(todo) + for addr in todo: + self._cyclic_cmds[addr]['nexttime'] = currenttime + self._cyclic_cmds[addr]['cycle'] + read_items = len(todo) + else: + for addr in todo: + # as this loop can take considerable time, repeatedly check if shng wants to stop + if not self.alive: + self.logger.info('shng issued stop command, canceling cyclic read.') + return + + commandname = self._commandname_by_commandcode(addr) + self.logger.debug(f'Triggering cyclic read command: {commandname}') + self._send_command(commandname, ) + self._cyclic_cmds[addr]['nexttime'] = currenttime + self._cyclic_cmds[addr]['cycle'] + read_items += 1 + + self._cyclic_update_active = False + if read_items: + self.logger.debug(f'cyclic command read took {(time.time() - currenttime):.1f} seconds for {read_items} items') + + def update_all_read_items(self): + ''' + Read all values preset in commands.py as readable + ''' + for commandcode in list(self._params.keys()): + commandname = self._commandname_by_commandcode(commandcode) + self.logger.debug(f'Triggering read command: {commandname} for requested value update') + self._send_command(commandname) def read_addr(self, addr): - """ + ''' Tries to read a data point indepently of item config :param addr: data point addr (2 byte hex address) :type addr: str :return: Value if read is successful, None otherwise - """ + ''' addr = addr.lower() - commandname = self._commands.get_command_from_reply(addr) + commandname = self._commandname_by_commandcode(addr) if commandname is None: self.logger.debug(f'Address {addr} not defined in commandset, aborting') return None self.logger.debug(f'Attempting to read address {addr} for command {commandname}') - return self.send_command(commandname) + (packet, responselen) = self._build_command_packet(commandname) + if packet is None: + return None + + response_packet = self._send_command_packet(packet, responselen) + if response_packet is None: + return None - def read_temp_addr(self, addr, length=1, mult=0, signed=False): - """ + res = self._parse_response(response_packet, commandname) + if res is None: + return None + + (value, commandcode) = res + + return value + + def read_temp_addr(self, addr, length, unit): + ''' Tries to read an arbitrary supplied data point indepently of device config :param addr: data point addr (2 byte hex address) :type addr: str :param len: Length (in byte) expected from address read :type len: num - :param mult: value multiplicator - :type mult: num - :param signed: specifies signed or unsigned value - :type signed: bool + :param unit: Unit code from commands.py + :type unit: str :return: Value if read is successful, None otherwise - """ + ''' # as we have no reference whatever concerning the supplied data, we do a few sanity checks... addr = addr.lower() + if len(addr) != 4: # addresses are 2 bytes self.logger.warning(f'temp address: address not 4 digits long: {addr}') return None @@ -146,103 +440,1683 @@ def read_temp_addr(self, addr, length=1, mult=0, signed=False): self.logger.warning(f'temp address: len is not > 0 and < 33: {len}') return None + if unit not in self._unitset: # units need to be predefined + self.logger.warning(f'temp address: unit {unit} not in unitset. Cannot use custom units') + return None + # addr already known? - cmd = self._commands.get_command_from_reply(addr) - if cmd: + if addr in self._commandset: + cmd = self._commandname_by_commandcode(addr) self.logger.info(f'temp address {addr} already known for command {cmd}') else: # create temp commandset cmd = 'temp_cmd' - cmdconf = {'read': True, 'write': False, 'opcode': addr, 'reply_token': addr, 'item_type': 'str', 'dev_datatype': 'H', 'params': ['value', 'mult', 'signed', 'len'], 'param_values': ['VAL', mult, signed, length]} + cmdconf = {'addr': addr, 'len': length, 'unit': unit, 'set': False} self.logger.debug(f'Adding temporary command config {cmdconf} for command temp_cmd') - self._commands._parse_commands(self.device_id, {cmd: cmdconf}, [cmd]) + self._commandset[cmd] = cmdconf - try: - res = self.read_addr(addr) - except Exception as e: - self.logger.error(f'Error on send: {e}') - res = None + res = self.read_addr(addr) - try: - del self._commands._commands['temp_cmd'] - except (KeyError, AttributeError): - pass + if cmd == 'temp_cmd': + del self._commandset['temp_cmd'] return res def write_addr(self, addr, value): - """ + ''' Tries to write a data point indepently of item config :param addr: data point addr (2 byte hex address) :type addr: str :param value: value to write :return: Value if read is successful, None otherwise - """ + ''' addr = addr.lower() - commandname = self._commands.get_command_from_reply(addr) + commandname = self._commandname_by_commandcode(addr) if commandname is None: self.logger.debug(f'Address {addr} not defined in commandset, aborting') return None self.logger.debug(f'Attempting to write address {addr} with value {value} for command {commandname}') - return self.send_command(commandname, value) + (packet, responselen) = self._build_command_packet(commandname, value) + if packet is None: + return None + + response_packet = self._send_command_packet(packet, responselen) + if response_packet is None: + return None - def get_device_type(self, protocol): + return self._parse_response(response_packet, commandname) - serialport = self._parameters.get('serialport', None) +# +# initialization methods +# - # try to connect and read device type info from 0x00f8 - self.logger.info(f'Trying protocol {protocol} on device {serialport}') + def _load_configuration(self): + ''' + Load configuration sets from commands.py + ''' - # first, initialize Viessmann object for use - self.alive = True - self._parameters['viess_proto'] = protocol - self._parameters['protocol'] = 'viessmann' - self._get_connection() - self._dispatch_callback = self._cb_standalone + # Load protocol dependent sets + if self._protocol in commands.controlset and self._protocol in commands.errorset and self._protocol in commands.unitset and self._protocol in commands.returnstatus and self._protocol in commands.setreturnstatus: + self._controlset = commands.controlset[self._protocol] + self.logger.debug(f'Loaded controlset for protocol {self._controlset}') + self._errorset = commands.errorset[self._protocol] + self.logger.debug(f'Loaded errors for protocol {self._errorset}') + self._unitset = commands.unitset[self._protocol] + self.logger.debug(f'Loaded units for protocol {self._unitset}') + self._devicetypes = commands.devicetypes + self.logger.debug(f'Loaded device types for protocol {self._devicetypes}') + self._returnstatus = commands.returnstatus[self._protocol] + self.logger.debug(f'Loaded return status for protocol {self._returnstatus}') + self._setreturnstatus = commands.setreturnstatus[self._protocol] + self.logger.debug(f'Loaded set return status for protocol {self._setreturnstatus}') + else: + self.logger.error(f'Sets for protocol {self._protocol} could not be found or incomplete!') + return False + + # Load device dependent sets + if self._heating_type in commands.commandset and self._heating_type in commands.operatingmodes and self._heating_type in commands.systemschemes: + self._commandset = commands.commandset[self._heating_type] + self.logger.debug(f'Loaded commands for heating type {self._commandset}') + self._operatingmodes = commands.operatingmodes[self._heating_type] + self.logger.debug(f'Loaded operating modes for heating type {self._operatingmodes}') + self._systemschemes = commands.systemschemes[self._heating_type] + self.logger.debug(f'Loaded system schemes for heating type {self._systemschemes}') + else: + sets = [] + if self._heating_type not in commands.commandset: + sets += 'command' + if self._heating_type not in commands.operatingmodes: + sets += 'operating modes' + if self._heating_type not in commands.systemschemes: + sets += 'system schemes' + + self.logger.error(f'Sets {", ".join(sets)} for heating type {self._heating_type} could not be found!') + return False + + self.logger.info(f'Loaded configuration for heating type {self._heating_type} with protocol {self._protocol}') + self._config_loaded = True + return True - err = None - res = None + def _connect(self): + ''' + Tries to establish a connection to the serial reading device. To prevent + multiple concurrent connection locking is used. + + :return: Returns True if connection was established, False otherwise + :rtype: bool + ''' + if not self.alive: + return False + + if self._connected and self._serial: + return True + + self._lock.acquire() try: - res = self._connection.open() + self.logger.debug(f'Connecting to {self._serialport}..') + self._serial = serial.Serial() + self._serial.baudrate = self._controlset['Baudrate'] + self._serial.parity = self._controlset['Parity'] + self._serial.bytesize = self._controlset['Bytesize'] + self._serial.stopbits = self._controlset['Stopbits'] + self._serial.port = self._serialport + + # both of the following timeout values are determined by trial and error + if self._protocol == 'KW': + # needed to "capture" the 0x05 sync bytes + self._serial.timeout = 1.0 + else: + # not too long to prevent lags in communication. + self._serial.timeout = 0.5 + self._serial.open() + self._connected = True + self.logger.info(f'Connected to {self._serialport}') + self._connection_attempts = 0 + if not self._standalone and not self.scheduler_get('cyclic'): + self._create_cyclic_scheduler() + return True except Exception as e: - err = e - if not res: - self.logger.info(f'Connection to {serialport} failed. Please check connection. {err if err else ""}') - return None + self.logger.error(f'Could not _connect to {self._serialport}; Error: {e}') + return False + finally: + self._lock.release() + + def _disconnect(self): + ''' + Disconnect any connected devices. + ''' + self._connected = False + self._initialized = False + try: + self._serial.close() + except IOError: + pass + self._serial = None + try: + self._lock.release() + except RuntimeError: + pass + self.logger.info('Disconnected') + + def _init_communication(self): + ''' + After connecting to the device, setup the communication protocol + + :return: Returns True, if communication was established successfully, False otherwise + :rtype: bool + ''' + # just try to connect anyway; if connected, this does nothing and no harm, if not, it connects + if not self._connect(): + + self.logger.error('Init communication not possible as connect failed.') + return False + + # initialization only necessary for P300 protocol... + if self._protocol == 'P300': + + # init procedure is + # interface: 0x04 (reset) + # device: 0x05 (repeated) + # interface: 0x160000 (sync) + # device: 0x06 (sync ok) + # interface: resume communication, periodically send 0x160000 as keepalive if necessary + + self.logger.debug('Init Communication....') + is_initialized = False + initstringsent = False + self.logger.debug(f'send_bytes: Send reset command {self._int2bytes(self._controlset["Reset_Command"], 1)}') + self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) + readbyte = self._read_bytes(1) + self.logger.debug(f'read_bytes: read {readbyte}, last byte is {self._lastbyte}') + + for i in range(0, 10): + if initstringsent and self._lastbyte == self._int2bytes(self._controlset['Acknowledge'], 1): + is_initialized = True + self.logger.debug('Device acknowledged initialization') + break + if self._lastbyte == self._int2bytes(self._controlset['Not_initiated'], 1): + self._send_bytes(self._int2bytes(self._controlset['Sync_Command'], 3)) + self.logger.debug(f'send_bytes: Send sync command {self._int2bytes(self._controlset["Sync_Command"], 3)}') + initstringsent = True + elif self._lastbyte == self._int2bytes(self._controlset['Init_Error'], 1): + self.logger.error(f'The interface has reported an error (\x15), loop increment {i}') + self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) + self.logger.debug(f'send_bytes: Send reset command {self._int2bytes(self._controlset["Reset_Command"], 1)}') + initstringsent = False + else: + self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) + self.logger.debug(f'send_bytes: Send reset command {self._int2bytes(self._controlset["Reset_Command"], 1)}') + initstringsent = False + readbyte = self._read_bytes(1) + self.logger.debug(f'read_bytes: read {readbyte}, last byte is {self._lastbyte}') + + self.logger.debug(f'Communication initialized: {is_initialized}') + self._initialized = is_initialized + + else: # at the moment the only other supported protocol is 'KW' which is not stateful + is_initialized = True + self._initialized = is_initialized - res = None + return is_initialized + + def _create_cyclic_scheduler(self): + ''' + Setup the scheduler to handle cyclic read commands and find the proper time for the cycle. + ''' + if not self.alive: + return + + shortestcycle = -1 + # find shortest cycle + for commandname in list(self._cyclic_cmds.keys()): + entry = self._cyclic_cmds[commandname] + if shortestcycle == -1 or entry['cycle'] < shortestcycle: + shortestcycle = entry['cycle'] + # Start the worker thread + if shortestcycle != -1: + # Balance unnecessary calls and precision + workercycle = int(shortestcycle / 2) + # just in case it already exists... + if self.scheduler_get('cyclic'): + self.scheduler_remove('cyclic') + self.scheduler_add('cyclic', self.send_cyclic_cmds, cycle=workercycle, prio=5, offset=0) + self.logger.info(f'Added cyclic worker thread ({workercycle} sec cycle). Shortest item update cycle found: {shortestcycle} sec') + + def _read_initial_values(self): + ''' + Read all values configured to be read at startup / connection + ''' + if self._balist_item is not None: + balist = list(self._operatingmodes.values()) + self._balist_item(balist, self.get_shortname()) + self.logger.info(f'writing list of operating modes ({len(balist)} entries) to item {self._balist_item}') + + if self._init_cmds != []: + self.logger.info('Starting initial read commands.') + if self._protocol == 'KW': + self._KW_send_multiple_read_commands(self._init_cmds) + else: + for commandcode in self._init_cmds: + commandname = self._commandname_by_commandcode(commandcode) + self.logger.debug(f'send_init_commands {commandname}') + self._send_command(commandname) + self._initread = True + self.logger.debug(f'self._initread = {self._initread}') + + # + # send and receive commands + # + + def _read_timers(self): + ''' + Read all configured timer values from device and create uzsu timer dict + ''' + if self._application_timer is not []: + self.logger.debug('Starting timer read commands.') + for timer_app in self._application_timer: + for commandcode in self._application_timer[timer_app]['commandcodes']: + commandname = self._commandname_by_commandcode(commandcode) + self.logger.debug(f'send_timer_commands {commandname}') + self._send_command(commandname) + self._timerread = True + self.logger.debug(f'Timer Readout done = {self._timerread}') + self._viess_dict_to_uzsu_dict() + + def _send_command(self, commandname, value=None): + ''' + Create formatted command sequence from command name and send to device + + Note: The implementation detail results in "write if value present, read if value is None". + I have not found anything wrong with this; if any use case needs a specific read/write + selection, please tell me. + + :param commandname: Command for which to create command sequence as defined in commands.py + :type commandname: str + :param value: Value to write to device, None if command is read command + ''' + if value is not None: + self.logger.debug(f'Got a new write job: Command {commandname} with value {value}') + else: + self.logger.debug(f'Got a new read job: Command {commandname}') + + # Build packet with value bytes for write commands + (packet, responselen) = self._build_command_packet(commandname, value) + + # quit if no packet (error on packet build) + if packet is None: + return False + + if value is not None and self._protocol == 'KW': + read_response = False + else: + read_response = True + + # hand over built packet to send_command_packet + response_packet = self._send_command_packet(packet, responselen) + + # process response + if response_packet is None: + return False + + result = self._process_response(response_packet, commandname, read_response) + return result + + def _KW_send_multiple_read_commands(self, commandcodes): + ''' + Takes list of commandnames, builds all command packets and tries to send them in one go. + This only works for read commands and only with KW protocol. + On error the whole remaining read process is aborted, no retries or continuation is attempted. + + :param commandnames: List of commands for which to create command sequence as defined in commands.py + :type commandname: str + ''' + if self._protocol != 'KW': + self.logger.error(f'Called _KW_send_multiple_read_commands, but protocol is {self._protocol}. This shouldn\'t happen..') + return + + self.logger.debug(f'Got a new bulk read job: Commands {commandcodes}') + + bulk = {} + + # Build packets with value bytes for write commands + for addr in commandcodes: + commandname = self._commandname_by_commandcode(addr) + (packet, responselen) = self._build_command_packet(commandname, None, True) + + if packet: + bulk[addr] = {'packet': packet, 'responselen': responselen, 'command': commandname} + + # quit if no packet (error on packet build) + if not bulk: + return + + if not self._connected: + self.logger.error('Not connected, trying to reconnect.') + if not self._connect(): + self.logger.error('Could not connect to serial device') + return + + self._lock.acquire() try: - res = self._connection._send_init_on_send() + self._init_communication() + + replies = {} + + if not self._KW_get_sync(): + return + + first_cmd = True + first_packet = bytearray(self._int2bytes(self._controlset['StartByte'], 1)) + + for addr in bulk.keys(): + + if first_cmd: + # make sure that the first sent packet has the StartByte (0x01) lead byte set + # this way the first packet actually sent has the start byte, regardless of bulk.keys() order + first_packet.extend(bulk[addr]['packet']) + bulk[addr]['packet'] = first_packet + first_cmd = False + + # send query + try: + self._send_bytes(bulk[addr]['packet']) + self.logger.debug(f'Successfully sent packet: {self._bytes2hexstring(bulk[addr]["packet"])}') + except IOError as io: + raise IOError(f'IO Error: {io}') + return + except Exception as e: + raise Exception(f'Exception while sending: {e}') + return + + # receive response + replies[addr] = bytearray() + try: + self.logger.debug(f'Trying to receive {bulk[addr]["responselen"]} bytes of the response') + chunk = self._read_bytes(bulk[addr]['responselen']) + + self.logger.debug(f'Received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') + if len(chunk) != 0: + replies[addr].extend(chunk) + else: + self.logger.error(f'Received 0 bytes chunk from {addr} - this probably is a communication error, possibly a wrong datapoint address?') + return + except IOError as io: + raise IOError(f'IO Error: {io}') + return + except Exception as e: + raise Exception(f'Error receiving response: {e}') + return + + # sent all read requests, time to parse the replies + # do this inside the _lock-block so this doesn't interfere with + # possible cyclic read data assignments + for addr in bulk.keys(): + if len(replies[addr]) > 0: + self._process_response(replies[addr], bulk[addr]['command'], True) + + except IOError as io: + self.logger.error(f'KW_send_multiple_read_commands failed with IO error: {io}') + self.logger.error('Trying to reconnect (disconnecting, connecting') + self._disconnect() + return except Exception as e: - err = e - if not res: - self.logger.info(f'Could not initialize communication using protocol {protocol}. {err if err else ""}') + self.logger.error(f'KW_send_multiple_read_commands failed with error: {e}') + return + finally: + try: + self._lock.release() + except RuntimeError: + pass + + def _KW_get_sync(self): + ''' + Try to get a sync packet (0x05) from heating system to be able to send commands + + :return: True if sync packet received, False otherwise (after retries) + :rtype: bool + ''' + if not self._connected or self._protocol != 'KW': + return False # don't even try. We only want to be called by _send_command_packet, which just before executed connect() + + retries = 5 + + # try to reset communication, especially if previous P300 comms is still open + self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) + + attempt = 0 + while attempt < retries: + self.logger.debug(f'Starting sync loop - attempt {attempt + 1}/{retries}') + + self._serial.reset_input_buffer() + chunk = self._read_bytes(1) + # enable for 'raw' debugging + # self.logger.debug(f'sync loop - got {self._bytes2hexstring(chunk)}') + if chunk == self._int2bytes(self._controlset['Not_initiated'], 1, False): + self.logger.debug('Got sync. Commencing command send') + return True + time.sleep(.8) + attempt = attempt + 1 + self.logger.error(f'Sync not acquired after {attempt} attempts') + self._disconnect() + + return False + + def _send_command_packet(self, packet, packetlen_response): + ''' + Send command sequence to device + + :param packet: Command sequence to send + :type packet: bytearray + :param packetlen_response: number of bytes expected in reply + :type packetlen_response: int + :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) + :type read_response: bool + :return: Response packet (bytearray) if no error occured, None otherwise + ''' + if not self._connected: + self.logger.error('Not connected, trying to reconnect.') + if not self._connect(): + self.logger.error('Could not connect to serial device') + return None + + self._lock.acquire() + try: + if not self._initialized or (time.time() - 500) > self._lastbytetime: + if self._protocol == 'P300': + if self._initialized: + self.logger.debug('Communication timed out, trying to reestablish communication.') + else: + self.logger.info('Communication no longer initialized, trying to reestablish.') + self._init_communication() + + if self._initialized: + # send query + try: + if self._protocol == 'KW': + # try to get sync, exit if it fails + if not self._KW_get_sync(): + return None + + self._send_bytes(packet) + self.logger.debug(f'Successfully sent packet: {self._bytes2hexstring(packet)}') + except IOError as io: + raise IOError(f'IO Error: {io}') + return None + except Exception as e: + raise Exception(f'Exception while sending: {e}') + return None + + # receive response + response_packet = bytearray() + self.logger.debug(f'Trying to receive {packetlen_response} bytes of the response') + chunk = self._read_bytes(packetlen_response) + + if self._protocol == 'P300': + self.logger.debug(f'Received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') + if len(chunk) != 0: + if chunk[:1] == self._int2bytes(self._controlset['Error'], 1): + self.logger.error(f'Interface returned error! response was: {chunk}') + elif len(chunk) == 1 and chunk[:1] == self._int2bytes(self._controlset['Not_initiated'], 1): + self.logger.error('Received invalid chunk, connection not initialized. Forcing re-initialize...') + self._initialized = False + elif chunk[:1] != self._int2bytes(self._controlset['Acknowledge'], 1): + self.logger.error(f'Received invalid chunk, not starting with ACK! response was: {chunk}') + self._error_count += 1 + if self._error_count >= 5: + self.logger.warning('Encountered 5 invalid chunks in sequence. Maybe communication was lost, re-initializing') + self._initialized = False + else: + response_packet.extend(chunk) + self._error_count = 0 + return response_packet + else: + self.logger.error(f'Received 0 bytes chunk - ignoring response_packet! chunk was: {chunk}') + elif self._protocol == 'KW': + self.logger.debug(f'Received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') + if len(chunk) != 0: + response_packet.extend(chunk) + return response_packet + else: + self.logger.error('Received 0 bytes chunk - this probably is a communication error, possibly a wrong datapoint address?') + else: + raise Exception('Interface not initialized!') + except IOError as io: + self.logger.error(f'send_command_packet failed with IO error: {io}') + self.logger.error('Trying to reconnect (disconnecting, connecting') + self._disconnect() + except Exception as e: + self.logger.error(f'send_command_packet failed with error: {e}') + finally: + try: + self._lock.release() + except RuntimeError: + pass + + # if we didn't return with data earlier, we hit an error. Act accordingly + return None + + def _send_bytes(self, packet): + ''' + Send data to device + + :param packet: Data to be sent + :type packet: bytearray + :return: Returns False, if no connection is established or write failed; True otherwise + :rtype: bool + ''' + if not self._connected: return False - self._result = None try: - self.read_temp_addr('00f8', 2, 0, False) + self._serial.write(packet) + except serial.SerialTimeoutException: + return False + + # self.logger.debug(f'send_bytes: Sent {packet}') + return True + + def _read_bytes(self, length): + ''' + Try to read bytes from device + + :param length: Number of bytes to read + :type length: int + :return: Number of bytes actually read + :rtype: int + ''' + if not self._connected: + return 0 + + totalreadbytes = bytes() + # self.logger.debug('read_bytes: Start read') + starttime = time.time() + + # don't wait for input indefinitely, stop after self._timeout seconds + while time.time() <= starttime + self._timeout: + readbyte = self._serial.read() + self._lastbyte = readbyte + # self.logger.debug(f'read_bytes: Read {readbyte}') + if readbyte != b'': + self._lastbytetime = time.time() + else: + return totalreadbytes + totalreadbytes += readbyte + if len(totalreadbytes) >= length: + return totalreadbytes + + # timeout reached, did we read anything? + if not totalreadbytes: + + # just in case, force plugin to reconnect + self._connected = False + self._initialized = False + + # return what we got so far, might be 0 + return totalreadbytes + + def _process_response(self, response, commandname='', read_response=True, update_item=True): + ''' + Process device response data, try to parse type and value and assign value to associated item + + :param response: Data received from device + :type response: bytearray + :param commandname: Commandname used for request (only needed for KW protocol) + :type commandname: str + :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) + :type read_response: bool + :param update_item: True if value should be written to corresponding item + :type update_item: bool + ''' + res = self._parse_response(response, commandname, read_response) + + # None means error on read/parse or write reponse. Errors are already logged, so no further action necessary + if res is None: + return + + # write returns True on success + if res is True: + return True + + # assign results + (value, commandcode) = res + + # get command config + commandname = self._commandname_by_commandcode(commandcode) + commandconf = self._commandset[commandname] + commandunit = commandconf['unit'] + + # update items if commandcode is in item-dict + if commandcode in self._params.keys(): + + # Find corresponding item + item = self._params[commandcode]['item'] + self.logger.debug(f'Corresponding item {item} for command {commandname}') + + # Update item + if update_item: + self.logger.debug(f'Updating item {item} with value {value}') + if commandunit == 'CT': + # Split timer list and put it the child items, which were created by struct.timer in iso time format + try: + for child in item.return_children(): + child_item = str(child.id()) + if child_item.endswith('an1'): + child(value[0]['An'], self.get_shortname()) + # child(datetime.strptime(value[0]['An'], '%H:%M').time().isoformat()) + elif child_item.endswith('aus1'): + child(value[0]['Aus'], self.get_shortname()) + elif child_item.endswith('an2'): + child(value[1]['An'], self.get_shortname()) + elif child_item.endswith('aus2'): + child(value[1]['Aus'], self.get_shortname()) + elif child_item.endswith('an3'): + child(value[2]['An'], self.get_shortname()) + elif child_item.endswith('aus3'): + child(value[2]['Aus'], self.get_shortname()) + elif child_item.endswith('an4'): + child(value[3]['An'], self.get_shortname()) + elif child_item.endswith('aus4'): + child(value[3]['Aus'], self.get_shortname()) + except KeyError: + self.logger.debug('No child items for timer found (use timer.structs) or value no valid') + + # save value to item + item(value, self.get_shortname()) + else: + self.logger.debug(f'Not updating item {item} as not requested') + else: + if (commandcode not in self._timer_cmds) and update_item: + self.logger.error(f'Should update item with response to a command not in item config: {commandcode}. This shouldn''t happen..') + + # Process response for timers in timer-dict using the commandcode + if commandcode in self._timer_cmds: + self.logger.debug(f'process_response_timer: {commandcode}') + + # Find timer application + for timer in self._application_timer: + if commandcode in self._application_timer[timer]['commandcodes']: + timer_app = timer + + # Fill timer dict + if timer_app not in self._viess_timer_dict: + self._viess_timer_dict[timer_app] = {} + + self._viess_timer_dict[timer_app][commandname] = value + self.logger.debug(f'Viessmann timer dict: {self._viess_timer_dict}') + +# +# convert data types +# + + def _build_valuebytes_from_value(self, value, commandconf): + ''' + Convert value to formatted bytearray for write commands + :param value: Value to send + :param commandconf: configuration set for requested command + :type commandconf: dict + :return: bytearray with value if successful, None if error + ''' + try: + commandvaluebytes = commandconf['len'] + commandunit = commandconf['unit'] + set_allowed = bool(commandconf['set']) + if 'min_value' in commandconf: + min_allowed_value = commandconf['min_value'] + else: + min_allowed_value = None + if 'max_value' in commandconf: + max_allowed_value = commandconf['max_value'] + else: + max_allowed_value = None + except KeyError: + self.logger.error(f'Error in command configuration {commandconf}, aborting') + return None + + # unit HEX = hex values as string is only for read requests (debugging). Don't even try... + if commandunit == 'HEX': + + self.logger.error(f'Error in command configuration {commandconf}: unit HEX is not writable, aborting') + return None + + if commandunit == 'BA': + + # try to convert BA string to byte value, setting str values will fail + # this will not work properly if multiple entries have the same value! + try: + value = int(dict(map(reversed, self._operatingmodes.items()))[value]) + commandunit = 'IUNON' + except KeyError: + # value doesn't exist in operatingmodes. don't know what to do + self.logger.error(f'Value {value} not defined in operating modes for device {self._heating_type}') + return None + + try: + unitconf = self._unitset[commandunit] + except KeyError: + self.logger.error(f'Error: unit {commandunit} not found in unit set {self._unitset}') + return None + + try: + valuetype = unitconf['type'] + valuereadtransform = unitconf['read_value_transform'] + except KeyError: + self.logger.error(f'Error in unit configuration {unitconf} for unit {commandunit}, aborting') + return None + + self.logger.debug(f'Unit defined to {commandunit} with config{unitconf}') + + # check if writing is allowed for this address + if not set_allowed: + self.logger.error(f'Command {self._commandname_by_commandcode(commandconf["addr"])} is not configured for writing') + return None + + # check if value is empty + if value is None or value == '': + self.logger.error(f'Command value for command {self._commandname_by_commandcode(commandconf["addr"])} is empty, not possible to send (check item, command and unit configuration') + return None + + # check if value to be written is in allowed range + if (min_allowed_value is not None and min_allowed_value > value) or (max_allowed_value is not None and max_allowed_value < value): + self.logger.error(f'Invalid range - value {value} not in range [{min_allowed_value}, {max_allowed_value}]') + return None + + try: + # Create valuebytes + if valuetype == 'datetime' or valuetype == 'date': + try: + datestring = dateutil.parser.isoparse(value).strftime('%Y%m%d%w%H%M%S') + # Viessmann erwartet 2 digits für Wochentag, daher wird hier noch eine 0 eingefügt + datestring = datestring[:8] + '0' + datestring[8:] + valuebytes = bytes.fromhex(datestring) + self.logger.debug(f'Created value bytes for type {valuetype} as bytes: {valuebytes}') + except Exception as e: + self.logger.error(f'Incorrect data format, YYYY-MM-DD expected; Error: {e}') + return None + elif valuetype == 'timer': + try: + times = '' + for switching_time in value: + an = self._encode_timer(switching_time['An']) + aus = self._encode_timer(switching_time['Aus']) + times += f'{an:02x}{aus:02x}' + valuebytes = bytes.fromhex(times) + self.logger.debug(f'Created value bytes for type {valuetype} as hexstring: {self._bytes2hexstring(valuebytes)} and as bytes: {valuebytes}') + except Exception as e: + self.logger.error(f'Incorrect data format, (An: hh:mm Aus: hh:mm) expected; Error: {e}') + return None + # valuetype 'list' is transformed to listentry via index on read, but written directly as int, so numerical transform could apply + elif valuetype == 'integer' or valuetype == 'list': + # transform value is numerical -> multiply value with it + if self._isfloat(valuereadtransform): + value = self._value_transform_write(value, valuereadtransform) + self.logger.debug(f'Transformed value using method "* {valuereadtransform}" to {value}') + elif valuereadtransform == 'bool': + value = bool(value) + else: + value = int(value) + valuebytes = self._int2bytes(value, commandvaluebytes, byteorder='little') + self.logger.debug(f'Created value bytes for type {valuetype} as hexstring: {self._bytes2hexstring(valuebytes)} and as bytes: {valuebytes}') + else: + self.logger.error(f'Type {valuetype} not definied for creating write command bytes') + return None except Exception as e: - err = e + self.logger.debug(f'_build_valuebytes_from_value failed with unexpected error: {e}') + return None + + return valuebytes - if self._result is None: - raise ValueError(f'Error on communicating with the device, no response received. {err if err else ""}') + def _build_command_packet(self, commandname, value=None, KWFollowUp=False): + ''' + Create formatted command sequence from command name. + If value is None, a read packet will be built, a write packet otherwise - # let it go... - self._connection.close() + :param commandname: Command for which to create command sequence as defined in commands.py + :type commandname: str + :param value: Write value if command is to be written + :param KWFollowUp: create read sequence for KW protocol if multiple read commands will be sent without individual sync + :type KWFollowUp: bool + :return: tuple of (command sequence, expected response len), (None, 0) if error occured + :rtype: tuple (bytearray, int) + ''' - if self._result is not None: - return self._result + # A read_request telegram looks like this: + # P300: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of value bytes expected in answer (1 byte), checksum (1 byte) + # KW: startbyte (1 byte), read/write (1 byte), addr (2 bytes), amount of value bytes expected in answer (1 byte) + # A write_request telegram looks like this: + # P300: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of bytes to be written (1 byte), value (bytes as per last byte), checksum (1 byte) + # KW: startbyte (1 byte), read/write (1 byte), addr (2 bytes), length of value (1 byte), value bytes (1-4 bytes) + + write = value is not None + self.logger.debug(f'Build {"write" if write else "read"} packet for command {commandname}') + + # Get command config + commandconf = self._commandset[commandname] + commandcode = (commandconf['addr']).lower() + commandvaluebytes = commandconf['len'] + + if write: + valuebytes = self._build_valuebytes_from_value(value, commandconf) + # can't write 'no value'... + if not valuebytes: + return (None, 0) + + # Calculate length of payload (only needed for P300) + payloadlength = int(self._controlset.get('Command_bytes_write', 0)) + int(commandvaluebytes) + self.logger.debug(f'Payload length is: {payloadlength} bytes') + + # Build packet for read commands + # + # at the moment this only has to differentiate between protocols P300 and KW + # these are basically similar, only P300 is an evolution of KW adding + # stateful connections, command length and checksum + # + # so for the time being the easy way is one code path for both protocols which + # omits P300 elements from the built byte string. + # Later additions of other protocols (like GWG) might have to bring a second + # code path for proper processing + packet = bytearray() + if not KWFollowUp: + packet.extend(self._int2bytes(self._controlset['StartByte'], 1)) + if self._protocol == 'P300': + if write: + packet.extend(self._int2bytes(payloadlength, 1)) + else: + packet.extend(self._int2bytes(self._controlset['Command_bytes_read'], 1)) + packet.extend(self._int2bytes(self._controlset['Request'], 1)) + + if write: + packet.extend(self._int2bytes(self._controlset['Write'], 1)) + else: + packet.extend(self._int2bytes(self._controlset['Read'], 1)) + packet.extend(bytes.fromhex(commandcode)) + packet.extend(self._int2bytes(commandvaluebytes, 1)) + if write: + packet.extend(valuebytes) + if self._protocol == 'P300': + packet.extend(self._int2bytes(self._calc_checksum(packet), 1)) + + if self._protocol == 'P300': + responselen = int(self._controlset['Command_bytes_read']) + 4 + (0 if write else int(commandvaluebytes)) else: + responselen = 1 if write else int(commandvaluebytes) + + if write: + self.logger.debug(f'Created command {commandname} to be sent as hexstring: {self._bytes2hexstring(packet)} and as bytes: {packet} with value {value} (transformed to value byte {self._bytes2hexstring(valuebytes)})') + else: + self.logger.debug(f'Created command {commandname} to be sent as hexstring: {self._bytes2hexstring(packet)} and as bytes: {packet}') + + return (packet, responselen) + + def _parse_response(self, response, commandname='', read_response=True): + ''' + Process device response data, try to parse type and value + + :param response: Data received from device + :type response: bytearray + :param commandname: Commandname used for request (only needed for KW protocol) + :type commandname: str + :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) + :type read_response: bool + :return: tuple of (parsed response value, commandcode) or None if error + ''' + if self._protocol == 'P300': + + # A read_response telegram looks like this: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of valuebytes (1 byte), value (bytes as per last byte), checksum (1 byte) + # A write_response telegram looks like this: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of bytes written (1 byte), checksum (1 byte) + + # Validate checksum + checksum = self._calc_checksum(response[1:len(response) - 1]) # first, cut first byte (ACK) and last byte (checksum) and then calculate checksum + received_checksum = response[len(response) - 1] + if received_checksum != checksum: + self.logger.error(f'Calculated checksum {checksum} does not match received checksum of {received_checksum}! Ignoring reponse') + return None + + # Extract command/address, valuebytes and valuebytecount out of response + commandcode = response[5:7].hex() + responsetypecode = response[3] # 0x00 = query, 0x01 = reply, 0x03 = error + responsedatacode = response[4] # 0x01 = ReadData, 0x02 = WriteData, 0x07 = Function Call + valuebytecount = response[7] + + # Extract databytes out of response + rawdatabytes = bytearray() + rawdatabytes.extend(response[8:8 + (valuebytecount)]) + elif self._protocol == 'KW': + + # imitate P300 response code data for easier combined handling afterwards + # a read_response telegram consists only of the value bytes + # a write_response telegram is 0x00 for OK, 0xXX for error + if commandname == '': + self.logger.error('trying to parse KW protocol response, but commandname not set in _parse_response. This should not happen...') + return None + + responsetypecode = 1 + commandcode = self._commandset[commandname]['addr'].lower() + valuebytecount = len(response) + rawdatabytes = response + + if read_response: + # value response to read request, error detection by empty = no response + responsedatacode = 1 + if len(rawdatabytes) == 0: + # error, no answer means wrong address (?) + responsetypecode = 3 + else: + # status response to write request + responsedatacode = 2 + if (len(rawdatabytes) == 1 and rawdatabytes[0] != 0) or len(rawdatabytes) == 0: + # error if status reply is not 0x00 + responsetypecode = 3 + + self.logger.debug(f'Response decoded to: commandcode: {commandcode}, responsedatacode: {responsedatacode}, valuebytecount: {valuebytecount}, responsetypecode: {responsetypecode}') + self.logger.debug(f'Rawdatabytes formatted: {self._bytes2hexstring(rawdatabytes)} and unformatted: {rawdatabytes}') + + # Process response for items if response and not error + # added: only in P300 or if read_response is set, do not try if KW replies with 0x00 (OK) + if responsedatacode == 1 and responsetypecode != 3 and (self._protocol == 'P300' or read_response): + + # parse response if command config is available + commandname = self._commandname_by_commandcode(commandcode) + if commandname is None: + self.logger.error(f'Received response for unknown address point {commandcode}') + return None + + # Get command and respective unit config + commandconf = self._commandset[commandname] + commandvaluebytes = commandconf['len'] + commandunit = commandconf['unit'] + unitconf = self._unitset.get(commandunit) + if not unitconf: + self.logger.error(f'Unit configuration not found for unit {commandunit} in protocol {self._protocol}. This is a configuration error in commands.py, please fix') + return None + commandsigned = unitconf['signed'] + valuetransform = unitconf['read_value_transform'] + + # start value decode + if commandunit == 'CT': + timer = self._decode_timer(rawdatabytes.hex()) + # fill list + timer = [{'An': on_time, 'Aus': off_time} + for on_time, off_time in zip(timer, timer)] + value = timer + self.logger.debug(f'Matched command {commandname} and read transformed timer {value} and byte length {commandvaluebytes}') + elif commandunit == 'TI': + # decode datetime + value = datetime.strptime(rawdatabytes.hex(), '%Y%m%d%W%H%M%S').isoformat() + self.logger.debug(f'Matched command {commandname} and read transformed datetime {value} and byte length {commandvaluebytes}') + elif commandunit == 'DA': + # decode date + value = datetime.strptime(rawdatabytes.hex(), '%Y%m%d%W%H%M%S').date().isoformat() + self.logger.debug(f'Matched command {commandname} and read transformed datetime {value} and byte length {commandvaluebytes}') + elif commandunit == 'ES': + # erstes Byte = Fehlercode; folgenden 8 Byte = Systemzeit + errorcode = (rawdatabytes[:1]).hex() + # errorquerytime = (rawdatabytes[1:8]).hex() + value = self._error_decode(errorcode) + self.logger.debug(f'Matched command {commandname} and read transformed errorcode {value} (raw value was {errorcode}) and byte length {commandvaluebytes}') + elif commandunit == 'SC': + # erstes Byte = Anlagenschema + systemschemescode = (rawdatabytes[:1]).hex() + value = self._systemscheme_decode(systemschemescode) + self.logger.debug(f'Matched command {commandname} and read transformed system scheme {value} (raw value was {systemschemescode}) and byte length {commandvaluebytes}') + elif commandunit == 'BA': + operatingmodecode = (rawdatabytes[:1]).hex() + value = self._operatingmode_decode(operatingmodecode) + self.logger.debug(f'Matched command {commandname} and read transformed operating mode {value} (raw value was {operatingmodecode}) and byte length {commandvaluebytes}') + elif commandunit == 'DT': + # device type has 8 bytes, but first 4 bytes are device type indicator + devicetypebytes = rawdatabytes[:2].hex() + value = self._devicetype_decode(devicetypebytes).upper() + self.logger.debug(f'Matched command {commandname} and read transformed device type {value} (raw value was {devicetypebytes}) and byte length {commandvaluebytes}') + elif commandunit == 'SN': + # serial number has 7 bytes, + serialnumberbytes = rawdatabytes[:7] + value = self._serialnumber_decode(serialnumberbytes) + self.logger.debug(f'Matched command {commandname} and read transformed device type {value} (raw value was {serialnumberbytes}) and byte length {commandvaluebytes}') + elif commandunit == 'HEX': + # hex string for debugging purposes + hexstr = rawdatabytes.hex() + value = ' '.join([hexstr[i:i + 2] for i in range(0, len(hexstr), 2)]) + self.logger.debug(f'Read hex bytes {value}') + else: + rawvalue = self._bytes2int(rawdatabytes, commandsigned) + value = self._value_transform_read(rawvalue, valuetransform) + self.logger.debug(f'Matched command {commandname} and read transformed value {value} (integer raw value was {rawvalue}) and byte length {commandvaluebytes}') + + # assign to dict for use by other functions + self._last_values[commandcode] = value + + return (value, commandcode) + + # Handling of write command response if not error + elif responsedatacode == 2 and responsetypecode != 3: + self.logger.debug(f'Write request of adress {commandcode} successfull writing {valuebytecount} bytes') + return True + else: + self.logger.error(f'Write request of adress {commandcode} NOT successfull writing {valuebytecount} bytes') return None - def _cb_standalone(self, command, value, by): - self._result = value + def _viess_dict_to_uzsu_dict(self): + ''' + Convert data read from device to UZSU compatible struct. + Input is taken from self._viess_timer_dict, output is written to + self._uzsu_dict + ''' + dict_timer = {} + empty_time = '00:00' + shitems = Items.get_instance() + + try: + sunset = shitems.return_item('env.location.sunset')().strftime('%H:%M') + sunrise = shitems.return_item('env.location.sunrise')().strftime('%H:%M') + except (AttributeError, ValueError): + sunset = '21:00' + sunrise = '06:00' + + # convert all switching times with corresponding app and days to timer-dict + for application in self._viess_timer_dict: + if application not in dict_timer: + dict_timer[application] = {} + for application_day in self._viess_timer_dict[application]: + timer = self._viess_timer_dict[application][application_day] + day = application_day[(application_day.rfind('_') + 1):len(application_day)].lower() + + # normalize days + for element in self._wochentage: + if day in self._wochentage[element]: + weekday = element + + for entry in timer: + for event, sw_time in entry.items(): + if sw_time != empty_time: + value = 1 if event == 'An' else 0 + if sw_time not in dict_timer[application]: + dict_timer[application][sw_time] = {} + if value not in dict_timer[application][sw_time]: + dict_timer[application][sw_time][value] = [] + dict_timer[application][sw_time][value].append(weekday) + + self.logger.debug(f'Viessmann timer dict for UZSU: {dict_timer}') + + # find items, read UZSU-dict, convert to list of switching times, update item + for application in dict_timer: + item = self._application_timer[application]['item'] + + # read UZSU-dict (or use preset if empty) + uzsu_dict = item() + if not item(): + uzsu_dict = {'lastvalue': '0', 'sunset': sunset, 'list': [], 'active': True, 'interpolation': {'initage': '', 'initialized': True, 'itemtype': 'bool', 'interval': '', 'type': 'none'}, 'sunrise': sunrise} + + # create empty list + uzsu_dict['list'] = [] + + # fill list with switching times + for sw_time in sorted(dict_timer[application].keys()): + for key in dict_timer[application][sw_time]: + rrule = 'FREQ=WEEKLY;BYDAY=' + ','.join(dict_timer[application][sw_time][key]) + uzsu_dict['list'].append({'time': sw_time, 'rrule': rrule, 'value': str(key), 'active': True}) + + # update item + item(uzsu_dict, self.get_shortname()) + + def _uzsu_dict_to_viess_timer(self, timer_app, uzsu_dict): + ''' + Convert UZSU dict from item/visu for selected application into separate + on/off time events and write all timers to the device + + :param timer_app: Application for which the timer should be written, as in commands.py + :type timer_app: str + :param uzsu_dict: UZSU-compatible dict with timer data + :type uzsu_dict: dict + ''' + if self._timerread: + + # set variables + commandnames = set() + timer_dict = {} + an = {} + aus = {} + + # quit if timer_app not defined + if timer_app not in self._application_timer: + return + + commandnames.update([self._commandname_by_commandcode(code) for code in self._application_timer[timer_app]['commandcodes']]) + self.logger.debug(f'Commandnames: {commandnames}') + + # find switching times and create lists for on and off operations + for sw_time in uzsu_dict['list']: + myDays = sw_time['rrule'].split(';')[1].split('=')[1].split(',') + for day in myDays: + if sw_time['value'] == '1' and sw_time['active']: + if day not in an: + an[day] = [] + an[day].append(sw_time['time']) + for day in myDays: + if sw_time['value'] == '0' and sw_time['active']: + if day not in aus: + aus[day] = [] + aus[day].append(sw_time['time']) + + # sort daily lists + for day in an: + an[day].sort() + self.logger.debug(f'An: {an}') + for day in aus: + aus[day].sort() + self.logger.debug(f'Aus: {aus}') + + # create timer dict in Viessmann format for all weekdays + for commandname in commandnames: + self.logger.debug(f'Commandname in process: {commandname}') + # create empty dict + timer_dict[commandname] = [{'An': '00:00', 'Aus': '00:00'}, {'An': '00:00', 'Aus': '00:00'}, {'An': '00:00', 'Aus': '00:00'}, {'An': '00:00', 'Aus': '00:00'}] + # get current day + wday = commandname[(commandname.rfind('_') + 1):len(commandname)].lower() + # normalize day + for element in self._wochentage: + if wday in self._wochentage[element]: + wday = element + # transfer switching times + for idx, val in enumerate(an[wday]): + timer_dict[commandname][idx]['An'] = val + for idx, val in enumerate(aus[wday]): + timer_dict[commandname][idx]['Aus'] = val + self.logger.debug(f'Timer-dict for update of items: {timer_dict}') + + # write all timer dicts to device + for commandname in timer_dict: + value = timer_dict[commandname] + self.logger.debug(f'Got item value to be written: {value} on command name {commandname}') + self._send_command(commandname, value) + + def _calc_checksum(self, packet): + ''' + Calculate checksum for P300 protocol packets + + :parameter packet: Data packet for which to calculate checksum + :type packet: bytearray + :return: Calculated checksum + :rtype: int + ''' + checksum = 0 + if len(packet) > 0: + if packet[:1] == b'\x41': + packet = packet[1:] + checksum = sum(packet) + checksum = checksum - int(checksum / 256) * 256 + else: + self.logger.error('bytes to calculate checksum from not starting with start byte') + else: + self.logger.error('No bytes received to calculate checksum') + return checksum + + def _int2bytes(self, value, length, signed=False, byteorder='big'): + ''' + Convert value to bytearray with respect to defined length and sign format. + Value exceeding limit set by length and sign will be truncated + + :parameter value: Value to convert + :type value: int + :parameter length: number of bytes to create + :type length: int + :parameter signed: True if result should be a signed int, False for unsigned + :type signed: bool + :return: Converted value + :rtype: bytearray + ''' + value = value % (2 ** (length * 8)) + return value.to_bytes(length, byteorder=byteorder, signed=signed) + + def _bytes2int(self, rawbytes, signed): + ''' + Convert bytearray to value with respect to sign format + + :parameter rawbytes: Bytes to convert + :type value: bytearray + :parameter signed: True if result should be a signed int, False for unsigned + :type signed: bool + :return: Converted value + :rtype: int + ''' + return int.from_bytes(rawbytes, byteorder='little', signed=signed) + + def _bytes2hexstring(self, bytesvalue): + ''' + Create hex-formatted string from bytearray + :param bytesvalue: Bytes to convert + :type bytesvalue: bytearray + :return: Converted hex string + :rtype: str + ''' + return ''.join(f'{c:02x}' for c in bytesvalue) + + def _decode_rawvalue(self, rawdatabytes, commandsigned): + ''' + Convert little-endian byte sequence to int value + + :param rawdatabytes: Bytes to convert + :type rawdatabytes: bytearray + :param commandsigned: 'signed' if value should be interpreted as signed + :type commandsigned: str + :return: Converted value + :rtype: int + ''' + rawvalue = 0 + for i in range(len(rawdatabytes)): + leftbyte = rawdatabytes[0] + value = int(leftbyte * pow(256, i)) + rawvalue += value + rawdatabytes = rawdatabytes[1:] + # Signed/Unsigned berücksichtigen + if commandsigned == 'signed' and rawvalue > int(pow(256, i) / 2 - 1): + rawvalue = (pow(256, i) - rawvalue) * (-1) + return rawvalue + + def _decode_timer(self, rawdatabytes): + ''' + Generator to convert byte sequence to a number of time strings hh:mm + + :param rawdatabytes: Bytes to convert + :type rawdatabytes: bytearray + ''' + while rawdatabytes: + hours, minutes = divmod(int(rawdatabytes[:2], 16), 8) + if minutes >= 6 or hours >= 24: + # not a valid time + yield '00:00' + else: + yield f'{hours:02d}:{(minutes * 10):02d}' + rawdatabytes = rawdatabytes[2:] + return None + + def _encode_timer(self, switching_time): + ''' + Convert time string to encoded time value for timer application + + :param switching_time: time value in 'hh:mm' format + :type switching_time: str + :return: Encoded time value + :rtype: int + ''' + if switching_time == '00:00': + return 0xff + clocktime = re.compile(r'(\d\d):(\d\d)') + mo = clocktime.search(switching_time) + number = int(mo.group(1)) * 8 + int(mo.group(2)) // 10 + return number + + def _value_transform_read(self, value, transform): + ''' + Transform value according to protocol specification for writing to device + + :param value: Value to transform + :param transform: Specification for transforming + :return: Transformed value + ''' + if transform == 'bool': + return bool(value) + elif self._isfloat(transform): + return round(value / float(transform), 2) + else: + return int(value) + + def _value_transform_write(self, value, transform): + ''' + Transform value according to protocol requirement after reading from device + + :param value: Value to transform + :type value: int + :param transform: Specification for transforming + :type transform: int + :return: Transformed value + :rtype: int + ''' + # as transform and value can be float and by error possibly str, we try to float both + return int(float(value) * float(transform)) + + def _error_decode(self, value): + ''' + Decode error value from device if defined, else return error as string + ''' + value = str(value).upper() + if value in self._errorset: + errorstring = str(self._errorset[value]) + else: + errorstring = str(value) + return errorstring + + def _systemscheme_decode(self, value): + ''' + Decode schema value from device if possible, else return schema as string + ''' + if value in self._systemschemes: + systemscheme = str(self._systemschemes[value]) + else: + systemscheme = str(value) + return systemscheme + + def _operatingmode_decode(self, value): + ''' + Decode operating mode value from device if possible, else return mode as string + ''' + if value in self._operatingmodes: + operatingmode = str(self._operatingmodes[value]) + else: + operatingmode = str(value) + return operatingmode + + def _devicetype_decode(self, value): + ''' + Decode device type value if possible, else return device type as string + ''' + if value in self._devicetypes: + devicetypes = str(self._devicetypes[value]) + else: + devicetypes = str(value) + return devicetypes + + def _serialnumber_decode(self, serialnumberbytes): + ''' + Decode serial number from device response + ''' + serialnumber = 0 + serialnumberbytes.reverse() + for byte in range(0, len(serialnumberbytes)): + serialnumber += (serialnumberbytes[byte] - 48) * 10 ** byte + return hex(serialnumber).upper() + + def _commandname_by_commandcode(self, commandcode): + ''' + Find matching command name from commands.py for given command address + + :param commandcode: address of command + :type commandcode: str + :return: name of matching command or None if not found + ''' + for commandname in self._commandset.keys(): + if self._commandset[commandname]['addr'].lower() == commandcode.lower(): + return commandname + return None + + def _isfloat(self, value): + ''' + Test if string is decimal number + + :param value: expression to test + :type value: str + :return: True if value can be converted to a float, False otherwise + ''' + try: + float(value) + return True + except ValueError: + return False + +# +# webinterface +# + + def init_webinterface(self): + ''' + Initialize the web interface for this plugin + + This method is only needed if the plugin is implementing a web interface + ''' + try: + self.mod_http = Modules.get_instance().get_module('http') # try/except to handle running in a core version that does not support modules + except NameError: + self.mod_http = None + if self.mod_http is None: + self.logger.warning('Not initializing the web interface') + return False + + if 'SmartPluginWebIf' not in list(sys.modules['lib.model.smartplugin'].__dict__): + self.logger.warning('Web interface needs SmartHomeNG v1.5 or later. Not initializing the web interface') + return False + + # set application configuration for cherrypy + webif_dir = self.path_join(self.get_plugin_dir(), 'webif') + config = { + '/': { + 'tools.staticdir.root': webif_dir, + }, + '/static': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': 'static' + } + } + + # Register the web interface as a cherrypy app + self.mod_http.register_webif(WebInterface(webif_dir, self, self._commandset), + self.get_shortname(), + config, + self.get_classname(), self.get_instance_name(), + description='') + + return True + + +# ------------------------------------------ +# Webinterface of the plugin +# ------------------------------------------ + +class WebInterface(SmartPluginWebIf): + + def __init__(self, webif_dir, plugin, cmdset): + ''' + Initialization of instance of class WebInterface + + :param webif_dir: directory where the webinterface of the plugin resides + :param plugin: instance of the plugin + :type webif_dir: str + :type plugin: object + ''' + self.logger = logging.getLogger(__name__) + self.webif_dir = webif_dir + self.plugin = plugin + self.tplenv = self.init_template_environment() + + self.items = Items.get_instance() + + self.cmdset = cmdset + + self._last_read = {} + self._last_read['last'] = {'addr': None, 'val': '', 'cmd': ''} + + self._read_addr = None + self._read_cmd = '' + self._read_val = '' + + @cherrypy.expose + def index(self, reload=None): + ''' + Build index.html for cherrypy + + Render the template and return the html file to be delivered to the browser + + :return: contents of the template after beeing rendered + ''' + tmpl = self.tplenv.get_template('index.html') + # add values to be passed to the Jinja2 template eg: tmpl.render(p=self.plugin, interface=interface, ...) + + return tmpl.render(p=self.plugin, + items=sorted(self.items.return_items(), key=lambda k: str.lower(k['_path'])), + cmds=self.cmdset, + units=sorted(list(self.plugin._unitset.keys())), + last_read_addr=self._last_read['last']['addr'], + last_read_value=self._last_read['last']['val'], + last_read_cmd=self._last_read['last']['cmd'] + ) + + @cherrypy.expose + def submit(self, button=None, addr=None, length=0, unit=None, clear=False): + ''' + Submit handler for Ajax + ''' + if button is not None: + + read_val = self.plugin.read_addr(button) + if read_val is None: + self.logger.debug(f'Error trying to read addr {button} submitted by WebIf') + read_val = 'Fehler beim Lesen' + else: + read_cmd = self.plugin._commandname_by_commandcode(button) + if read_cmd is not None: + self._last_read[button] = {'addr': button, 'cmd': read_cmd, 'val': read_val} + self._last_read['last'] = self._last_read[button] + + elif addr is not None and unit is not None and length.isnumeric(): + + read_val = self.plugin.read_temp_addr(addr, int(length), unit) + if read_val is None: + self.logger.debug(f'Error trying to read custom addr {button} submitted by WebIf') + read_val = 'Fehler beim Lesen' + else: + self._last_read[addr] = {'addr': addr, 'cmd': f'custom ({addr})', 'val': read_val} + self._last_read['last'] = self._last_read[addr] + + elif clear: + for addr in self._last_read: + self._last_read[addr]['val'] = '' + self._last_read['last'] = {'addr': None, 'val': '', 'cmd': ''} + + cherrypy.response.headers['Content-Type'] = 'application/json' + return json.dumps(self._last_read).encode('utf-8') + + +# ------------------------------------------ +# The following code is for standalone use of the plugin to identify the device +# ------------------------------------------ + +def get_device_type(v, protocol): + + # try to connect and read device type info from 0x00f8 + print(f'Trying protocol {protocol} on device {serialport}') + + # first, initialize Viessmann object for use + v.alive = True + v._protocol = protocol + + # setup protocol controlset + v._controlset = commands.controlset[protocol] + res = v._connect() + if not res: + logger.info(f'Connection to {serialport} failed. Please check connection.') + return None + + res = v._init_communication() + if not res: + logger.info(f'Could not initialize communication using protocol {protocol}.') + return False + + # we are connected to the IR head + + # set needed unit + v._unitset = { + 'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'} + } + + # set needed command. DeviceType command is (hopefully) the same in all devices... + v._commandset = { + 'DT': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, + } + + # we leave this empty so we get the DT code back + v._devicetypes = {} + + # this is protocol dependent, so easier to let the Class work this out... + (packet, responselen) = v._build_command_packet('DT') + if packet is None: + raise ValueError('No command packet received for address 00f8. This shouldn\'t happen...') + + # send it + response_packet = v._send_command_packet(packet, responselen) + if response_packet is None: + raise ValueError('Error on communicating with the device, no response received. Unknown error.') + + # let it go... + v._disconnect() + + (val, code) = v._parse_response(response_packet, 'DT') + + if val is not None: + return val + else: + return None if __name__ == '__main__': - s = Standalone(viessmann, sys.argv[0]) + + usage = ''' + Usage: + ---------------------------------------------------------------------------------- + + This plugin is meant to be used inside SmartHomeNG. + + For diagnostic purposes, you can run it as a standalone Python program from the + command line. It will try to communicate with a connected Viessmann heating system + and return the device type and the necessary protocol for setting up your plugin + in SmartHomeNG. + + You need to call this plugin with the serial interface as the first parameter, e.g. + + ./__init__.py /dev/ttyUSB0 + + If you call it with -v as a second parameter, you get additional debug information: + + ./__init__.py /dev/ttyUSB0 -v + + ''' + + logger = logging.getLogger(__name__) + logger.setLevel(logging.CRITICAL) + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(message)s @ %(lineno)d') + ch.setFormatter(formatter) + + # add the handlers to the logger + logger.addHandler(ch) + + serialport = "" + + if len(sys.argv) == 2: + serialport = sys.argv[1] + elif len(sys.argv) == 3 and sys.argv[2] == '-v': + serialport = sys.argv[1] + logger.setLevel(logging.DEBUG) + else: + print(usage) + exit() + + print("This is Viessmann plugin running in standalone mode") + print("===================================================") + + v = Viessmann(None, standalone=serialport, logger=logger) + + for proto in ('P300', 'KW'): + + res = get_device_type(v, proto) + if res is None: + + # None means no connection, no further tries + print(f'Connection could not be established to {serialport}. Please check connection.') + break + + if res is False: + + # False means no comm init (only P300), go on + print(f'Communication could not be established using protocol {proto}.') + else: + + # anything else should be the devices answer, try to decode and quit + print(f'Device ID is {res}, device type is {commands.devicetypes.get(res, "unknown")} using protocol {proto}') + # break + + print('Done.') diff --git a/viessmann/_pv_1_2_3/__init__.py b/viessmann/_pv_1_2_3/__init__.py deleted file mode 100755 index 11bd79325..000000000 --- a/viessmann/_pv_1_2_3/__init__.py +++ /dev/null @@ -1,2122 +0,0 @@ -#!/usr/bin/env python3 -# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab - -######################################################################### -# Copyright 2020 Michael Wenzel -# Copyright 2020 Sebastian Helms -######################################################################### -# Viessmann-Plugin for SmartHomeNG. https://github.com/smarthomeNG// -# -# 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 . -######################################################################### - -import logging -import sys -import time -import re -import json -import serial -import threading -from datetime import datetime -import dateutil.parser -import cherrypy - -if __name__ == '__main__': - # just needed for standalone mode - - class SmartPlugin(): - pass - - class SmartPluginWebIf(): - pass - - import os - BASE = os.path.sep.join(os.path.realpath(__file__).split(os.path.sep)[:-3]) - sys.path.insert(0, BASE) - import commands - -else: - from . import commands - - from lib.item import Items - from lib.model.smartplugin import SmartPlugin, SmartPluginWebIf, Modules - - from bin.smarthome import VERSION - - -class Viessmann(SmartPlugin): - ''' - Main class of the plugin. Provides communication with Viessmann heating systems - via serial / USB-to-serial connections to read values and set operating parameters. - - Supported device types must be defined in ./commands.py. - ''' - ALLOW_MULTIINSTANCE = False - - PLUGIN_VERSION = '1.2.3' - -# -# public methods -# - - def __init__(self, sh, *args, standalone='', logger=None, **kwargs): - - # Call init code of parent class (SmartPlugin) - super().__init__() - - # standalone mode: just setup basic info - if standalone: - self._serialport = standalone - self._timeout = 3 - self.logger = logger - self._standalone = True - - else: - # Get plugin parameter - self._serialport = self.get_parameter_value('serialport') - self._heating_type = self.get_parameter_value('heating_type') - self._protocol = self.get_parameter_value('protocol') - self._timeout = self.get_parameter_value('timeout') - self._standalone = False - - # Set variables - self._error_count = 0 - self._params = {} # Item dict - self._init_cmds = [] # List of command codes for read at init - self._cyclic_cmds = {} # Dict of command codes with cylce-times for cyclic readings - self._application_timer = {} # Dict of application timer with command codes and values - self._timer_cmds = [] # List of command codes for timer - self._viess_timer_dict = {} - self._last_values = {} - self._balist_item = None # list of last value per command code - self._lock = threading.Lock() - self._initread = False - self._timerread = False - self._connected = False - self._initialized = False - self._lastbyte = b'' - self._lastbytetime = 0 - self._cyclic_update_active = False - self._wochentage = { - 'MO': ['mo', 'montag', 'monday'], - 'TU': ['di', 'dienstag', 'tuesday'], - 'WE': ['mi', 'mittwoch', 'wednesday'], - 'TH': ['do', 'donnerstag', 'thursday'], - 'FR': ['fr', 'freitag', 'friday'], - 'SA': ['sa', 'samstag', 'saturday'], - 'SU': ['so', 'sonntag', 'sunday']} - - # if running standalone, don't initialize command sets - if not sh: - return - - # initialize logger if necessary - if '.'.join(VERSION.split('.', 2)[:2]) <= '1.5': - self.logger = logging.getLogger(__name__) - - self._config_loaded = False - - if not self._load_configuration(): - return None - - # Init web interface - self.init_webinterface() - - def run(self): - ''' - Run method for the plugin - ''' - if not self._config_loaded: - if not self._load_configuration(): - return - self.alive = True - self._connect() - self._read_initial_values() - self._read_timers() - - def stop(self): - ''' - Stop method for the plugin - ''' - self.alive = False - if self.scheduler_get('cyclic'): - self.scheduler_remove('cyclic') - self._disconnect() - # force reload of configuration on restart - self._config_loaded = False - - def parse_item(self, item): - ''' - Method for parsing items. - If the item carries any viess_* field, this item is registered to the plugin. - - :param item: The item to process. - :type item: object - - :return: The item update method to be triggered if the item is changed, or None. - :rtype: object - ''' - # Process the update config - if self.has_iattr(item.conf, 'viess_update'): - self.logger.debug(f'Item for requesting update for all items triggered: {item}') - return self.update_item - - # Process the timer config and fill timer dict - if self.has_iattr(item.conf, 'viess_timer'): - timer_app = self.get_iattr_value(item.conf, 'viess_timer') - for commandname in self._commandset: - if commandname.startswith(timer_app): - commandconf = self._commandset[commandname] - self.logger.debug(f'Process the timer config, commandname: {commandname}') - # {'addr': '2100', 'len': 8, 'unit': 'CT', 'set': True} - commandcode = (commandconf['addr']).lower() - if timer_app not in self._application_timer: - self._application_timer[timer_app] = {'item': item, 'commandcodes': []} - if commandcode not in self._application_timer[timer_app]['commandcodes']: - self._application_timer[timer_app]['commandcodes'].append(commandcode) - self._application_timer[timer_app]['commandcodes'].sort() - self.logger.info(f'Loaded Application Timer {self._application_timer}') - # self._application_timer: {'Timer_M2': {'item': Item: heizung.heizkreis_m2.schaltzeiten, 'commandcodes': ['3000', '3008', '3010', '3018', '3020', '3028', '3030']}, 'Timer_Warmwasser': {'item': Item: heizung.warmwasser.schaltzeiten, 'commandcodes': ['2100', '2108', '2110', '2118', '2120', '2128', '2130']}} - - for subdict in self._application_timer: - for commandcode in self._application_timer[subdict]['commandcodes']: - if commandcode not in self._timer_cmds: - self._timer_cmds.append(commandcode) - self._timer_cmds.sort() - self.logger.debug(f'Loaded Timer commands {self._timer_cmds}') - return self.update_item - - # Process the read config - if self.has_iattr(item.conf, 'viess_read'): - commandname = self.get_iattr_value(item.conf, 'viess_read') - if commandname is None or commandname not in self._commandset: - self.logger.error(f'Item {item} contains invalid read command {commandname}!') - return None - - # Remember the read config to later update this item if the configured response comes in - self.logger.info(f'Item {item} reads by using command {commandname}') - commandconf = self._commandset[commandname] - commandcode = (commandconf['addr']).lower() - - # Fill item dict - self._params[commandcode] = {'item': item, 'commandname': commandname} - self.logger.debug(f'Loaded params {self._params}') - - # Allow items to be automatically initiated on startup - if self.has_iattr(item.conf, 'viess_init') and self.get_iattr_value(item.conf, 'viess_init'): - self.logger.info(f'Item {item} is initialized on startup') - if commandcode not in self._init_cmds: - self._init_cmds.append(commandcode) - self.logger.debug(f'CommandCodes should be read at init: {self._init_cmds}') - - # Allow items to be cyclically updated - if self.has_iattr(item.conf, 'viess_read_cycle'): - cycle = int(self.get_iattr_value(item.conf, 'viess_read_cycle')) - self.logger.info(f'Item {item} should read cyclic every {cycle} seconds') - nexttime = time.time() + cycle - if commandcode not in self._cyclic_cmds: - self._cyclic_cmds[commandcode] = {'cycle': cycle, 'nexttime': nexttime} - else: - # If another item requested this command already with a longer cycle, use the shorter cycle now - if self._cyclic_cmds[commandcode]['cycle'] > cycle: - self._cyclic_cmds[commandcode]['cycle'] = cycle - self.logger.debug(f'CommandCodes should be read cyclic: {self._cyclic_cmds}') - - # Process the write config - if self.has_iattr(item.conf, 'viess_send'): - if self.get_iattr_value(item.conf, 'viess_send'): - commandname = self.get_iattr_value(item.conf, 'viess_read') - else: - commandname = self.get_iattr_value(item.conf, 'viess_send') - - if commandname is None or commandname not in self._commandset: - self.logger.error(f'Item {item} contains invalid write command {commandname}!') - return None - else: - self.logger.info(f'Item {item} to be written by using command {commandname}') - return self.update_item - - # get operating modes list - if self.has_iattr(item.conf, 'viess_ba_list'): - self._balist_item = item - self.logger.info(f'Item {item} wants list of operating modes') - - def parse_logic(self, logic): - pass - - def update_item(self, item, caller=None, source=None, dest=None): - ''' - Callback method for sending values to the plugin when a registered item has changed - - :param item: item to be updated towards the plugin - :param caller: if given it represents the callers name - :param source: if given it represents the source - :param dest: if given it represents the dest - ''' - if self.alive and caller != self.get_shortname(): - self.logger.info(f'Update item: {item.id()}, item has been changed outside this plugin') - self.logger.debug(f'update_item was called with item {item} from caller {caller}, source {source} and dest {dest}') - - if self.has_iattr(item.conf, 'viess_send'): - # Send write command - if self.get_iattr_value(item.conf, 'viess_send'): - commandname = self.get_iattr_value(item.conf, 'viess_read') - else: - commandname = self.get_iattr_value(item.conf, 'viess_send') - value = item() - self.logger.debug(f'Got item value to be written: {value} on command name {commandname}') - if not self._send_command(commandname, value): - # create_write_command() liefert False, wenn das Schreiben fehlgeschlagen ist - # -> dann auch keine weitere Verarbeitung - self.logger.debug(f'Write for {commandname} with value {value} failed, reverting value, canceling followup actions') - item(item.property.last_value, self.get_shortname()) - return None - - # If a read command should be sent after write - if self.has_iattr(item.conf, 'viess_read') and self.has_iattr(item.conf, 'viess_read_afterwrite'): - readcommandname = self.get_iattr_value(item.conf, 'viess_read') - readafterwrite = self.get_iattr_value(item.conf, 'viess_read_afterwrite') - self.logger.debug(f'Attempting read after write for item {item}, command {readcommandname}, delay {readafterwrite}') - if readcommandname is not None and readafterwrite is not None: - aw = float(readafterwrite) - time.sleep(aw) - self._send_command(readcommandname) - - # If commands should be triggered after this write - if self.has_iattr(item.conf, 'viess_trigger'): - trigger = self.get_iattr_value(item.conf, 'viess_trigger') - if trigger is None: - self.logger.error(f'Item {item} contains invalid trigger command list {trigger}!') - else: - tdelay = 5 # default delay - if self.has_iattr(item.conf, 'viess_trigger_afterwrite'): - tdelay = float(self.get_iattr_value(item.conf, 'viess_trigger_afterwrite')) - if type(trigger) != list: - trigger = [trigger] - for triggername in trigger: - triggername = triggername.strip() - if triggername is not None and readafterwrite is not None: - self.logger.debug(f'Triggering command {triggername} after write for item {item}') - time.sleep(tdelay) - self._send_command(triggername) - - elif self.has_iattr(item.conf, 'viess_timer'): - timer_app = self.get_iattr_value(item.conf, 'viess_timer') - uzsu_dict = item() - self.logger.debug(f'Got changed UZSU timer: {uzsu_dict} on timer application {timer_app}') - self._uzsu_dict_to_viess_timer(timer_app, uzsu_dict) - - elif self.has_iattr(item.conf, 'viess_update'): - if item(): - self.logger.debug('Reading of all values/items has been requested') - self.update_all_read_items() - - def send_cyclic_cmds(self): - ''' - Recall function for shng scheduler. Reads all values configured to be read cyclically. - ''' - # check if another cyclic cmd run is still active - if self._cyclic_update_active: - self.logger.warning('Triggered cyclic command read, but previous cyclic run is still active. Check device and cyclic configuration (too much/too short?)') - return - else: - self.logger.info('Triggering cyclic command read') - - # set lock - self._cyclic_update_active = True - currenttime = time.time() - read_items = 0 - todo = [] - for commandcode in list(self._cyclic_cmds.keys()): - - entry = self._cyclic_cmds[commandcode] - # Is the command already due? - if entry['nexttime'] <= currenttime: - todo.append(commandcode) - - if self._protocol == 'KW': - # see if we got to do anything - maybe no items are due to be read? - if len(todo) > 0: - self._KW_send_multiple_read_commands(todo) - for addr in todo: - self._cyclic_cmds[addr]['nexttime'] = currenttime + self._cyclic_cmds[addr]['cycle'] - read_items = len(todo) - else: - for addr in todo: - # as this loop can take considerable time, repeatedly check if shng wants to stop - if not self.alive: - self.logger.info('shng issued stop command, canceling cyclic read.') - return - - commandname = self._commandname_by_commandcode(addr) - self.logger.debug(f'Triggering cyclic read command: {commandname}') - self._send_command(commandname, ) - self._cyclic_cmds[addr]['nexttime'] = currenttime + self._cyclic_cmds[addr]['cycle'] - read_items += 1 - - self._cyclic_update_active = False - if read_items: - self.logger.debug(f'cyclic command read took {(time.time() - currenttime):.1f} seconds for {read_items} items') - - def update_all_read_items(self): - ''' - Read all values preset in commands.py as readable - ''' - for commandcode in list(self._params.keys()): - commandname = self._commandname_by_commandcode(commandcode) - self.logger.debug(f'Triggering read command: {commandname} for requested value update') - self._send_command(commandname) - - def read_addr(self, addr): - ''' - Tries to read a data point indepently of item config - - :param addr: data point addr (2 byte hex address) - :type addr: str - :return: Value if read is successful, None otherwise - ''' - addr = addr.lower() - - commandname = self._commandname_by_commandcode(addr) - if commandname is None: - self.logger.debug(f'Address {addr} not defined in commandset, aborting') - return None - - self.logger.debug(f'Attempting to read address {addr} for command {commandname}') - - (packet, responselen) = self._build_command_packet(commandname) - if packet is None: - return None - - response_packet = self._send_command_packet(packet, responselen) - if response_packet is None: - return None - - res = self._parse_response(response_packet, commandname) - if res is None: - return None - - (value, commandcode) = res - - return value - - def read_temp_addr(self, addr, length, unit): - ''' - Tries to read an arbitrary supplied data point indepently of device config - - :param addr: data point addr (2 byte hex address) - :type addr: str - :param len: Length (in byte) expected from address read - :type len: num - :param unit: Unit code from commands.py - :type unit: str - :return: Value if read is successful, None otherwise - ''' - # as we have no reference whatever concerning the supplied data, we do a few sanity checks... - - addr = addr.lower() - - if len(addr) != 4: # addresses are 2 bytes - self.logger.warning(f'temp address: address not 4 digits long: {addr}') - return None - - for c in addr: # addresses are hex strings - if c not in '0123456789abcdef': - self.logger.warning(f'temp address: address digit "{c}" is not hex char') - return None - - if length < 1 or length > 32: # empiritistical choice - self.logger.warning(f'temp address: len is not > 0 and < 33: {len}') - return None - - if unit not in self._unitset: # units need to be predefined - self.logger.warning(f'temp address: unit {unit} not in unitset. Cannot use custom units') - return None - - # addr already known? - if addr in self._commandset: - cmd = self._commandname_by_commandcode(addr) - self.logger.info(f'temp address {addr} already known for command {cmd}') - else: - # create temp commandset - cmd = 'temp_cmd' - cmdconf = {'addr': addr, 'len': length, 'unit': unit, 'set': False} - self.logger.debug(f'Adding temporary command config {cmdconf} for command temp_cmd') - self._commandset[cmd] = cmdconf - - res = self.read_addr(addr) - - if cmd == 'temp_cmd': - del self._commandset['temp_cmd'] - - return res - - def write_addr(self, addr, value): - ''' - Tries to write a data point indepently of item config - - :param addr: data point addr (2 byte hex address) - :type addr: str - :param value: value to write - :return: Value if read is successful, None otherwise - ''' - addr = addr.lower() - - commandname = self._commandname_by_commandcode(addr) - if commandname is None: - self.logger.debug(f'Address {addr} not defined in commandset, aborting') - return None - - self.logger.debug(f'Attempting to write address {addr} with value {value} for command {commandname}') - - (packet, responselen) = self._build_command_packet(commandname, value) - if packet is None: - return None - - response_packet = self._send_command_packet(packet, responselen) - if response_packet is None: - return None - - return self._parse_response(response_packet, commandname) - -# -# initialization methods -# - - def _load_configuration(self): - ''' - Load configuration sets from commands.py - ''' - - # Load protocol dependent sets - if self._protocol in commands.controlset and self._protocol in commands.errorset and self._protocol in commands.unitset and self._protocol in commands.returnstatus and self._protocol in commands.setreturnstatus: - self._controlset = commands.controlset[self._protocol] - self.logger.debug(f'Loaded controlset for protocol {self._controlset}') - self._errorset = commands.errorset[self._protocol] - self.logger.debug(f'Loaded errors for protocol {self._errorset}') - self._unitset = commands.unitset[self._protocol] - self.logger.debug(f'Loaded units for protocol {self._unitset}') - self._devicetypes = commands.devicetypes - self.logger.debug(f'Loaded device types for protocol {self._devicetypes}') - self._returnstatus = commands.returnstatus[self._protocol] - self.logger.debug(f'Loaded return status for protocol {self._returnstatus}') - self._setreturnstatus = commands.setreturnstatus[self._protocol] - self.logger.debug(f'Loaded set return status for protocol {self._setreturnstatus}') - else: - self.logger.error(f'Sets for protocol {self._protocol} could not be found or incomplete!') - return False - - # Load device dependent sets - if self._heating_type in commands.commandset and self._heating_type in commands.operatingmodes and self._heating_type in commands.systemschemes: - self._commandset = commands.commandset[self._heating_type] - self.logger.debug(f'Loaded commands for heating type {self._commandset}') - self._operatingmodes = commands.operatingmodes[self._heating_type] - self.logger.debug(f'Loaded operating modes for heating type {self._operatingmodes}') - self._systemschemes = commands.systemschemes[self._heating_type] - self.logger.debug(f'Loaded system schemes for heating type {self._systemschemes}') - else: - sets = [] - if self._heating_type not in commands.commandset: - sets += 'command' - if self._heating_type not in commands.operatingmodes: - sets += 'operating modes' - if self._heating_type not in commands.systemschemes: - sets += 'system schemes' - - self.logger.error(f'Sets {", ".join(sets)} for heating type {self._heating_type} could not be found!') - return False - - self.logger.info(f'Loaded configuration for heating type {self._heating_type} with protocol {self._protocol}') - self._config_loaded = True - return True - - def _connect(self): - ''' - Tries to establish a connection to the serial reading device. To prevent - multiple concurrent connection locking is used. - - :return: Returns True if connection was established, False otherwise - :rtype: bool - ''' - if not self.alive: - return False - - if self._connected and self._serial: - return True - - self._lock.acquire() - try: - self.logger.debug(f'Connecting to {self._serialport}..') - self._serial = serial.Serial() - self._serial.baudrate = self._controlset['Baudrate'] - self._serial.parity = self._controlset['Parity'] - self._serial.bytesize = self._controlset['Bytesize'] - self._serial.stopbits = self._controlset['Stopbits'] - self._serial.port = self._serialport - - # both of the following timeout values are determined by trial and error - if self._protocol == 'KW': - # needed to "capture" the 0x05 sync bytes - self._serial.timeout = 1.0 - else: - # not too long to prevent lags in communication. - self._serial.timeout = 0.5 - self._serial.open() - self._connected = True - self.logger.info(f'Connected to {self._serialport}') - self._connection_attempts = 0 - if not self._standalone and not self.scheduler_get('cyclic'): - self._create_cyclic_scheduler() - return True - except Exception as e: - self.logger.error(f'Could not _connect to {self._serialport}; Error: {e}') - return False - finally: - self._lock.release() - - def _disconnect(self): - ''' - Disconnect any connected devices. - ''' - self._connected = False - self._initialized = False - try: - self._serial.close() - except IOError: - pass - self._serial = None - try: - self._lock.release() - except RuntimeError: - pass - self.logger.info('Disconnected') - - def _init_communication(self): - ''' - After connecting to the device, setup the communication protocol - - :return: Returns True, if communication was established successfully, False otherwise - :rtype: bool - ''' - # just try to connect anyway; if connected, this does nothing and no harm, if not, it connects - if not self._connect(): - - self.logger.error('Init communication not possible as connect failed.') - return False - - # initialization only necessary for P300 protocol... - if self._protocol == 'P300': - - # init procedure is - # interface: 0x04 (reset) - # device: 0x05 (repeated) - # interface: 0x160000 (sync) - # device: 0x06 (sync ok) - # interface: resume communication, periodically send 0x160000 as keepalive if necessary - - self.logger.debug('Init Communication....') - is_initialized = False - initstringsent = False - self.logger.debug(f'send_bytes: Send reset command {self._int2bytes(self._controlset["Reset_Command"], 1)}') - self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) - readbyte = self._read_bytes(1) - self.logger.debug(f'read_bytes: read {readbyte}, last byte is {self._lastbyte}') - - for i in range(0, 10): - if initstringsent and self._lastbyte == self._int2bytes(self._controlset['Acknowledge'], 1): - is_initialized = True - self.logger.debug('Device acknowledged initialization') - break - if self._lastbyte == self._int2bytes(self._controlset['Not_initiated'], 1): - self._send_bytes(self._int2bytes(self._controlset['Sync_Command'], 3)) - self.logger.debug(f'send_bytes: Send sync command {self._int2bytes(self._controlset["Sync_Command"], 3)}') - initstringsent = True - elif self._lastbyte == self._int2bytes(self._controlset['Init_Error'], 1): - self.logger.error(f'The interface has reported an error (\x15), loop increment {i}') - self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) - self.logger.debug(f'send_bytes: Send reset command {self._int2bytes(self._controlset["Reset_Command"], 1)}') - initstringsent = False - else: - self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) - self.logger.debug(f'send_bytes: Send reset command {self._int2bytes(self._controlset["Reset_Command"], 1)}') - initstringsent = False - readbyte = self._read_bytes(1) - self.logger.debug(f'read_bytes: read {readbyte}, last byte is {self._lastbyte}') - - self.logger.debug(f'Communication initialized: {is_initialized}') - self._initialized = is_initialized - - else: # at the moment the only other supported protocol is 'KW' which is not stateful - is_initialized = True - self._initialized = is_initialized - - return is_initialized - - def _create_cyclic_scheduler(self): - ''' - Setup the scheduler to handle cyclic read commands and find the proper time for the cycle. - ''' - if not self.alive: - return - - shortestcycle = -1 - # find shortest cycle - for commandname in list(self._cyclic_cmds.keys()): - entry = self._cyclic_cmds[commandname] - if shortestcycle == -1 or entry['cycle'] < shortestcycle: - shortestcycle = entry['cycle'] - # Start the worker thread - if shortestcycle != -1: - # Balance unnecessary calls and precision - workercycle = int(shortestcycle / 2) - # just in case it already exists... - if self.scheduler_get('cyclic'): - self.scheduler_remove('cyclic') - self.scheduler_add('cyclic', self.send_cyclic_cmds, cycle=workercycle, prio=5, offset=0) - self.logger.info(f'Added cyclic worker thread ({workercycle} sec cycle). Shortest item update cycle found: {shortestcycle} sec') - - def _read_initial_values(self): - ''' - Read all values configured to be read at startup / connection - ''' - if self._balist_item is not None: - balist = list(self._operatingmodes.values()) - self._balist_item(balist, self.get_shortname()) - self.logger.info(f'writing list of operating modes ({len(balist)} entries) to item {self._balist_item}') - - if self._init_cmds != []: - self.logger.info('Starting initial read commands.') - if self._protocol == 'KW': - self._KW_send_multiple_read_commands(self._init_cmds) - else: - for commandcode in self._init_cmds: - commandname = self._commandname_by_commandcode(commandcode) - self.logger.debug(f'send_init_commands {commandname}') - self._send_command(commandname) - self._initread = True - self.logger.debug(f'self._initread = {self._initread}') - - # - # send and receive commands - # - - def _read_timers(self): - ''' - Read all configured timer values from device and create uzsu timer dict - ''' - if self._application_timer is not []: - self.logger.debug('Starting timer read commands.') - for timer_app in self._application_timer: - for commandcode in self._application_timer[timer_app]['commandcodes']: - commandname = self._commandname_by_commandcode(commandcode) - self.logger.debug(f'send_timer_commands {commandname}') - self._send_command(commandname) - self._timerread = True - self.logger.debug(f'Timer Readout done = {self._timerread}') - self._viess_dict_to_uzsu_dict() - - def _send_command(self, commandname, value=None): - ''' - Create formatted command sequence from command name and send to device - - Note: The implementation detail results in "write if value present, read if value is None". - I have not found anything wrong with this; if any use case needs a specific read/write - selection, please tell me. - - :param commandname: Command for which to create command sequence as defined in commands.py - :type commandname: str - :param value: Value to write to device, None if command is read command - ''' - if value is not None: - self.logger.debug(f'Got a new write job: Command {commandname} with value {value}') - else: - self.logger.debug(f'Got a new read job: Command {commandname}') - - # Build packet with value bytes for write commands - (packet, responselen) = self._build_command_packet(commandname, value) - - # quit if no packet (error on packet build) - if packet is None: - return False - - if value is not None and self._protocol == 'KW': - read_response = False - else: - read_response = True - - # hand over built packet to send_command_packet - response_packet = self._send_command_packet(packet, responselen) - - # process response - if response_packet is None: - return False - - result = self._process_response(response_packet, commandname, read_response) - return result - - def _KW_send_multiple_read_commands(self, commandcodes): - ''' - Takes list of commandnames, builds all command packets and tries to send them in one go. - This only works for read commands and only with KW protocol. - On error the whole remaining read process is aborted, no retries or continuation is attempted. - - :param commandnames: List of commands for which to create command sequence as defined in commands.py - :type commandname: str - ''' - if self._protocol != 'KW': - self.logger.error(f'Called _KW_send_multiple_read_commands, but protocol is {self._protocol}. This shouldn\'t happen..') - return - - self.logger.debug(f'Got a new bulk read job: Commands {commandcodes}') - - bulk = {} - - # Build packets with value bytes for write commands - for addr in commandcodes: - commandname = self._commandname_by_commandcode(addr) - (packet, responselen) = self._build_command_packet(commandname, None, True) - - if packet: - bulk[addr] = {'packet': packet, 'responselen': responselen, 'command': commandname} - - # quit if no packet (error on packet build) - if not bulk: - return - - if not self._connected: - self.logger.error('Not connected, trying to reconnect.') - if not self._connect(): - self.logger.error('Could not connect to serial device') - return - - self._lock.acquire() - try: - self._init_communication() - - replies = {} - - if not self._KW_get_sync(): - return - - first_cmd = True - first_packet = bytearray(self._int2bytes(self._controlset['StartByte'], 1)) - - for addr in bulk.keys(): - - if first_cmd: - # make sure that the first sent packet has the StartByte (0x01) lead byte set - # this way the first packet actually sent has the start byte, regardless of bulk.keys() order - first_packet.extend(bulk[addr]['packet']) - bulk[addr]['packet'] = first_packet - first_cmd = False - - # send query - try: - self._send_bytes(bulk[addr]['packet']) - self.logger.debug(f'Successfully sent packet: {self._bytes2hexstring(bulk[addr]["packet"])}') - except IOError as io: - raise IOError(f'IO Error: {io}') - return - except Exception as e: - raise Exception(f'Exception while sending: {e}') - return - - # receive response - replies[addr] = bytearray() - try: - self.logger.debug(f'Trying to receive {bulk[addr]["responselen"]} bytes of the response') - chunk = self._read_bytes(bulk[addr]['responselen']) - - self.logger.debug(f'Received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') - if len(chunk) != 0: - replies[addr].extend(chunk) - else: - self.logger.error(f'Received 0 bytes chunk from {addr} - this probably is a communication error, possibly a wrong datapoint address?') - return - except IOError as io: - raise IOError(f'IO Error: {io}') - return - except Exception as e: - raise Exception(f'Error receiving response: {e}') - return - - # sent all read requests, time to parse the replies - # do this inside the _lock-block so this doesn't interfere with - # possible cyclic read data assignments - for addr in bulk.keys(): - if len(replies[addr]) > 0: - self._process_response(replies[addr], bulk[addr]['command'], True) - - except IOError as io: - self.logger.error(f'KW_send_multiple_read_commands failed with IO error: {io}') - self.logger.error('Trying to reconnect (disconnecting, connecting') - self._disconnect() - return - except Exception as e: - self.logger.error(f'KW_send_multiple_read_commands failed with error: {e}') - return - finally: - try: - self._lock.release() - except RuntimeError: - pass - - def _KW_get_sync(self): - ''' - Try to get a sync packet (0x05) from heating system to be able to send commands - - :return: True if sync packet received, False otherwise (after retries) - :rtype: bool - ''' - if not self._connected or self._protocol != 'KW': - return False # don't even try. We only want to be called by _send_command_packet, which just before executed connect() - - retries = 5 - - # try to reset communication, especially if previous P300 comms is still open - self._send_bytes(self._int2bytes(self._controlset['Reset_Command'], 1)) - - attempt = 0 - while attempt < retries: - self.logger.debug(f'Starting sync loop - attempt {attempt + 1}/{retries}') - - self._serial.reset_input_buffer() - chunk = self._read_bytes(1) - # enable for 'raw' debugging - # self.logger.debug(f'sync loop - got {self._bytes2hexstring(chunk)}') - if chunk == self._int2bytes(self._controlset['Not_initiated'], 1, False): - self.logger.debug('Got sync. Commencing command send') - return True - time.sleep(.8) - attempt = attempt + 1 - self.logger.error(f'Sync not acquired after {attempt} attempts') - self._disconnect() - - return False - - def _send_command_packet(self, packet, packetlen_response): - ''' - Send command sequence to device - - :param packet: Command sequence to send - :type packet: bytearray - :param packetlen_response: number of bytes expected in reply - :type packetlen_response: int - :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) - :type read_response: bool - :return: Response packet (bytearray) if no error occured, None otherwise - ''' - if not self._connected: - self.logger.error('Not connected, trying to reconnect.') - if not self._connect(): - self.logger.error('Could not connect to serial device') - return None - - self._lock.acquire() - try: - if not self._initialized or (time.time() - 500) > self._lastbytetime: - if self._protocol == 'P300': - if self._initialized: - self.logger.debug('Communication timed out, trying to reestablish communication.') - else: - self.logger.info('Communication no longer initialized, trying to reestablish.') - self._init_communication() - - if self._initialized: - # send query - try: - if self._protocol == 'KW': - # try to get sync, exit if it fails - if not self._KW_get_sync(): - return None - - self._send_bytes(packet) - self.logger.debug(f'Successfully sent packet: {self._bytes2hexstring(packet)}') - except IOError as io: - raise IOError(f'IO Error: {io}') - return None - except Exception as e: - raise Exception(f'Exception while sending: {e}') - return None - - # receive response - response_packet = bytearray() - self.logger.debug(f'Trying to receive {packetlen_response} bytes of the response') - chunk = self._read_bytes(packetlen_response) - - if self._protocol == 'P300': - self.logger.debug(f'Received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') - if len(chunk) != 0: - if chunk[:1] == self._int2bytes(self._controlset['Error'], 1): - self.logger.error(f'Interface returned error! response was: {chunk}') - elif len(chunk) == 1 and chunk[:1] == self._int2bytes(self._controlset['Not_initiated'], 1): - self.logger.error('Received invalid chunk, connection not initialized. Forcing re-initialize...') - self._initialized = False - elif chunk[:1] != self._int2bytes(self._controlset['Acknowledge'], 1): - self.logger.error(f'Received invalid chunk, not starting with ACK! response was: {chunk}') - self._error_count += 1 - if self._error_count >= 5: - self.logger.warning('Encountered 5 invalid chunks in sequence. Maybe communication was lost, re-initializing') - self._initialized = False - else: - response_packet.extend(chunk) - self._error_count = 0 - return response_packet - else: - self.logger.error(f'Received 0 bytes chunk - ignoring response_packet! chunk was: {chunk}') - elif self._protocol == 'KW': - self.logger.debug(f'Received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') - if len(chunk) != 0: - response_packet.extend(chunk) - return response_packet - else: - self.logger.error('Received 0 bytes chunk - this probably is a communication error, possibly a wrong datapoint address?') - else: - raise Exception('Interface not initialized!') - except IOError as io: - self.logger.error(f'send_command_packet failed with IO error: {io}') - self.logger.error('Trying to reconnect (disconnecting, connecting') - self._disconnect() - except Exception as e: - self.logger.error(f'send_command_packet failed with error: {e}') - finally: - try: - self._lock.release() - except RuntimeError: - pass - - # if we didn't return with data earlier, we hit an error. Act accordingly - return None - - def _send_bytes(self, packet): - ''' - Send data to device - - :param packet: Data to be sent - :type packet: bytearray - :return: Returns False, if no connection is established or write failed; True otherwise - :rtype: bool - ''' - if not self._connected: - return False - - try: - self._serial.write(packet) - except serial.SerialTimeoutException: - return False - - # self.logger.debug(f'send_bytes: Sent {packet}') - return True - - def _read_bytes(self, length): - ''' - Try to read bytes from device - - :param length: Number of bytes to read - :type length: int - :return: Number of bytes actually read - :rtype: int - ''' - if not self._connected: - return 0 - - totalreadbytes = bytes() - # self.logger.debug('read_bytes: Start read') - starttime = time.time() - - # don't wait for input indefinitely, stop after self._timeout seconds - while time.time() <= starttime + self._timeout: - readbyte = self._serial.read() - self._lastbyte = readbyte - # self.logger.debug(f'read_bytes: Read {readbyte}') - if readbyte != b'': - self._lastbytetime = time.time() - else: - return totalreadbytes - totalreadbytes += readbyte - if len(totalreadbytes) >= length: - return totalreadbytes - - # timeout reached, did we read anything? - if not totalreadbytes: - - # just in case, force plugin to reconnect - self._connected = False - self._initialized = False - - # return what we got so far, might be 0 - return totalreadbytes - - def _process_response(self, response, commandname='', read_response=True, update_item=True): - ''' - Process device response data, try to parse type and value and assign value to associated item - - :param response: Data received from device - :type response: bytearray - :param commandname: Commandname used for request (only needed for KW protocol) - :type commandname: str - :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) - :type read_response: bool - :param update_item: True if value should be written to corresponding item - :type update_item: bool - ''' - res = self._parse_response(response, commandname, read_response) - - # None means error on read/parse or write reponse. Errors are already logged, so no further action necessary - if res is None: - return - - # write returns True on success - if res is True: - return True - - # assign results - (value, commandcode) = res - - # get command config - commandname = self._commandname_by_commandcode(commandcode) - commandconf = self._commandset[commandname] - commandunit = commandconf['unit'] - - # update items if commandcode is in item-dict - if commandcode in self._params.keys(): - - # Find corresponding item - item = self._params[commandcode]['item'] - self.logger.debug(f'Corresponding item {item} for command {commandname}') - - # Update item - if update_item: - self.logger.debug(f'Updating item {item} with value {value}') - if commandunit == 'CT': - # Split timer list and put it the child items, which were created by struct.timer in iso time format - try: - for child in item.return_children(): - child_item = str(child.id()) - if child_item.endswith('an1'): - child(value[0]['An'], self.get_shortname()) - # child(datetime.strptime(value[0]['An'], '%H:%M').time().isoformat()) - elif child_item.endswith('aus1'): - child(value[0]['Aus'], self.get_shortname()) - elif child_item.endswith('an2'): - child(value[1]['An'], self.get_shortname()) - elif child_item.endswith('aus2'): - child(value[1]['Aus'], self.get_shortname()) - elif child_item.endswith('an3'): - child(value[2]['An'], self.get_shortname()) - elif child_item.endswith('aus3'): - child(value[2]['Aus'], self.get_shortname()) - elif child_item.endswith('an4'): - child(value[3]['An'], self.get_shortname()) - elif child_item.endswith('aus4'): - child(value[3]['Aus'], self.get_shortname()) - except KeyError: - self.logger.debug('No child items for timer found (use timer.structs) or value no valid') - - # save value to item - item(value, self.get_shortname()) - else: - self.logger.debug(f'Not updating item {item} as not requested') - else: - if (commandcode not in self._timer_cmds) and update_item: - self.logger.error(f'Should update item with response to a command not in item config: {commandcode}. This shouldn''t happen..') - - # Process response for timers in timer-dict using the commandcode - if commandcode in self._timer_cmds: - self.logger.debug(f'process_response_timer: {commandcode}') - - # Find timer application - for timer in self._application_timer: - if commandcode in self._application_timer[timer]['commandcodes']: - timer_app = timer - - # Fill timer dict - if timer_app not in self._viess_timer_dict: - self._viess_timer_dict[timer_app] = {} - - self._viess_timer_dict[timer_app][commandname] = value - self.logger.debug(f'Viessmann timer dict: {self._viess_timer_dict}') - -# -# convert data types -# - - def _build_valuebytes_from_value(self, value, commandconf): - ''' - Convert value to formatted bytearray for write commands - :param value: Value to send - :param commandconf: configuration set for requested command - :type commandconf: dict - :return: bytearray with value if successful, None if error - ''' - try: - commandvaluebytes = commandconf['len'] - commandunit = commandconf['unit'] - set_allowed = bool(commandconf['set']) - if 'min_value' in commandconf: - min_allowed_value = commandconf['min_value'] - else: - min_allowed_value = None - if 'max_value' in commandconf: - max_allowed_value = commandconf['max_value'] - else: - max_allowed_value = None - except KeyError: - self.logger.error(f'Error in command configuration {commandconf}, aborting') - return None - - # unit HEX = hex values as string is only for read requests (debugging). Don't even try... - if commandunit == 'HEX': - - self.logger.error(f'Error in command configuration {commandconf}: unit HEX is not writable, aborting') - return None - - if commandunit == 'BA': - - # try to convert BA string to byte value, setting str values will fail - # this will not work properly if multiple entries have the same value! - try: - value = int(dict(map(reversed, self._operatingmodes.items()))[value]) - commandunit = 'IUNON' - except KeyError: - # value doesn't exist in operatingmodes. don't know what to do - self.logger.error(f'Value {value} not defined in operating modes for device {self._heating_type}') - return None - - try: - unitconf = self._unitset[commandunit] - except KeyError: - self.logger.error(f'Error: unit {commandunit} not found in unit set {self._unitset}') - return None - - try: - valuetype = unitconf['type'] - valuereadtransform = unitconf['read_value_transform'] - except KeyError: - self.logger.error(f'Error in unit configuration {unitconf} for unit {commandunit}, aborting') - return None - - self.logger.debug(f'Unit defined to {commandunit} with config{unitconf}') - - # check if writing is allowed for this address - if not set_allowed: - self.logger.error(f'Command {self._commandname_by_commandcode(commandconf["addr"])} is not configured for writing') - return None - - # check if value is empty - if value is None or value == '': - self.logger.error(f'Command value for command {self._commandname_by_commandcode(commandconf["addr"])} is empty, not possible to send (check item, command and unit configuration') - return None - - # check if value to be written is in allowed range - if (min_allowed_value is not None and min_allowed_value > value) or (max_allowed_value is not None and max_allowed_value < value): - self.logger.error(f'Invalid range - value {value} not in range [{min_allowed_value}, {max_allowed_value}]') - return None - - try: - # Create valuebytes - if valuetype == 'datetime' or valuetype == 'date': - try: - datestring = dateutil.parser.isoparse(value).strftime('%Y%m%d%w%H%M%S') - # Viessmann erwartet 2 digits für Wochentag, daher wird hier noch eine 0 eingefügt - datestring = datestring[:8] + '0' + datestring[8:] - valuebytes = bytes.fromhex(datestring) - self.logger.debug(f'Created value bytes for type {valuetype} as bytes: {valuebytes}') - except Exception as e: - self.logger.error(f'Incorrect data format, YYYY-MM-DD expected; Error: {e}') - return None - elif valuetype == 'timer': - try: - times = '' - for switching_time in value: - an = self._encode_timer(switching_time['An']) - aus = self._encode_timer(switching_time['Aus']) - times += f'{an:02x}{aus:02x}' - valuebytes = bytes.fromhex(times) - self.logger.debug(f'Created value bytes for type {valuetype} as hexstring: {self._bytes2hexstring(valuebytes)} and as bytes: {valuebytes}') - except Exception as e: - self.logger.error(f'Incorrect data format, (An: hh:mm Aus: hh:mm) expected; Error: {e}') - return None - # valuetype 'list' is transformed to listentry via index on read, but written directly as int, so numerical transform could apply - elif valuetype == 'integer' or valuetype == 'list': - # transform value is numerical -> multiply value with it - if self._isfloat(valuereadtransform): - value = self._value_transform_write(value, valuereadtransform) - self.logger.debug(f'Transformed value using method "* {valuereadtransform}" to {value}') - elif valuereadtransform == 'bool': - value = bool(value) - else: - value = int(value) - valuebytes = self._int2bytes(value, commandvaluebytes, byteorder='little') - self.logger.debug(f'Created value bytes for type {valuetype} as hexstring: {self._bytes2hexstring(valuebytes)} and as bytes: {valuebytes}') - else: - self.logger.error(f'Type {valuetype} not definied for creating write command bytes') - return None - except Exception as e: - self.logger.debug(f'_build_valuebytes_from_value failed with unexpected error: {e}') - return None - - return valuebytes - - def _build_command_packet(self, commandname, value=None, KWFollowUp=False): - ''' - Create formatted command sequence from command name. - If value is None, a read packet will be built, a write packet otherwise - - :param commandname: Command for which to create command sequence as defined in commands.py - :type commandname: str - :param value: Write value if command is to be written - :param KWFollowUp: create read sequence for KW protocol if multiple read commands will be sent without individual sync - :type KWFollowUp: bool - :return: tuple of (command sequence, expected response len), (None, 0) if error occured - :rtype: tuple (bytearray, int) - ''' - - # A read_request telegram looks like this: - # P300: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of value bytes expected in answer (1 byte), checksum (1 byte) - # KW: startbyte (1 byte), read/write (1 byte), addr (2 bytes), amount of value bytes expected in answer (1 byte) - # A write_request telegram looks like this: - # P300: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of bytes to be written (1 byte), value (bytes as per last byte), checksum (1 byte) - # KW: startbyte (1 byte), read/write (1 byte), addr (2 bytes), length of value (1 byte), value bytes (1-4 bytes) - - write = value is not None - self.logger.debug(f'Build {"write" if write else "read"} packet for command {commandname}') - - # Get command config - commandconf = self._commandset[commandname] - commandcode = (commandconf['addr']).lower() - commandvaluebytes = commandconf['len'] - - if write: - valuebytes = self._build_valuebytes_from_value(value, commandconf) - # can't write 'no value'... - if not valuebytes: - return (None, 0) - - # Calculate length of payload (only needed for P300) - payloadlength = int(self._controlset.get('Command_bytes_write', 0)) + int(commandvaluebytes) - self.logger.debug(f'Payload length is: {payloadlength} bytes') - - # Build packet for read commands - # - # at the moment this only has to differentiate between protocols P300 and KW - # these are basically similar, only P300 is an evolution of KW adding - # stateful connections, command length and checksum - # - # so for the time being the easy way is one code path for both protocols which - # omits P300 elements from the built byte string. - # Later additions of other protocols (like GWG) might have to bring a second - # code path for proper processing - packet = bytearray() - if not KWFollowUp: - packet.extend(self._int2bytes(self._controlset['StartByte'], 1)) - if self._protocol == 'P300': - if write: - packet.extend(self._int2bytes(payloadlength, 1)) - else: - packet.extend(self._int2bytes(self._controlset['Command_bytes_read'], 1)) - packet.extend(self._int2bytes(self._controlset['Request'], 1)) - - if write: - packet.extend(self._int2bytes(self._controlset['Write'], 1)) - else: - packet.extend(self._int2bytes(self._controlset['Read'], 1)) - packet.extend(bytes.fromhex(commandcode)) - packet.extend(self._int2bytes(commandvaluebytes, 1)) - if write: - packet.extend(valuebytes) - if self._protocol == 'P300': - packet.extend(self._int2bytes(self._calc_checksum(packet), 1)) - - if self._protocol == 'P300': - responselen = int(self._controlset['Command_bytes_read']) + 4 + (0 if write else int(commandvaluebytes)) - else: - responselen = 1 if write else int(commandvaluebytes) - - if write: - self.logger.debug(f'Created command {commandname} to be sent as hexstring: {self._bytes2hexstring(packet)} and as bytes: {packet} with value {value} (transformed to value byte {self._bytes2hexstring(valuebytes)})') - else: - self.logger.debug(f'Created command {commandname} to be sent as hexstring: {self._bytes2hexstring(packet)} and as bytes: {packet}') - - return (packet, responselen) - - def _parse_response(self, response, commandname='', read_response=True): - ''' - Process device response data, try to parse type and value - - :param response: Data received from device - :type response: bytearray - :param commandname: Commandname used for request (only needed for KW protocol) - :type commandname: str - :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) - :type read_response: bool - :return: tuple of (parsed response value, commandcode) or None if error - ''' - if self._protocol == 'P300': - - # A read_response telegram looks like this: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of valuebytes (1 byte), value (bytes as per last byte), checksum (1 byte) - # A write_response telegram looks like this: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of bytes written (1 byte), checksum (1 byte) - - # Validate checksum - checksum = self._calc_checksum(response[1:len(response) - 1]) # first, cut first byte (ACK) and last byte (checksum) and then calculate checksum - received_checksum = response[len(response) - 1] - if received_checksum != checksum: - self.logger.error(f'Calculated checksum {checksum} does not match received checksum of {received_checksum}! Ignoring reponse') - return None - - # Extract command/address, valuebytes and valuebytecount out of response - commandcode = response[5:7].hex() - responsetypecode = response[3] # 0x00 = query, 0x01 = reply, 0x03 = error - responsedatacode = response[4] # 0x01 = ReadData, 0x02 = WriteData, 0x07 = Function Call - valuebytecount = response[7] - - # Extract databytes out of response - rawdatabytes = bytearray() - rawdatabytes.extend(response[8:8 + (valuebytecount)]) - elif self._protocol == 'KW': - - # imitate P300 response code data for easier combined handling afterwards - # a read_response telegram consists only of the value bytes - # a write_response telegram is 0x00 for OK, 0xXX for error - if commandname == '': - self.logger.error('trying to parse KW protocol response, but commandname not set in _parse_response. This should not happen...') - return None - - responsetypecode = 1 - commandcode = self._commandset[commandname]['addr'].lower() - valuebytecount = len(response) - rawdatabytes = response - - if read_response: - # value response to read request, error detection by empty = no response - responsedatacode = 1 - if len(rawdatabytes) == 0: - # error, no answer means wrong address (?) - responsetypecode = 3 - else: - # status response to write request - responsedatacode = 2 - if (len(rawdatabytes) == 1 and rawdatabytes[0] != 0) or len(rawdatabytes) == 0: - # error if status reply is not 0x00 - responsetypecode = 3 - - self.logger.debug(f'Response decoded to: commandcode: {commandcode}, responsedatacode: {responsedatacode}, valuebytecount: {valuebytecount}, responsetypecode: {responsetypecode}') - self.logger.debug(f'Rawdatabytes formatted: {self._bytes2hexstring(rawdatabytes)} and unformatted: {rawdatabytes}') - - # Process response for items if response and not error - # added: only in P300 or if read_response is set, do not try if KW replies with 0x00 (OK) - if responsedatacode == 1 and responsetypecode != 3 and (self._protocol == 'P300' or read_response): - - # parse response if command config is available - commandname = self._commandname_by_commandcode(commandcode) - if commandname is None: - self.logger.error(f'Received response for unknown address point {commandcode}') - return None - - # Get command and respective unit config - commandconf = self._commandset[commandname] - commandvaluebytes = commandconf['len'] - commandunit = commandconf['unit'] - unitconf = self._unitset.get(commandunit) - if not unitconf: - self.logger.error(f'Unit configuration not found for unit {commandunit} in protocol {self._protocol}. This is a configuration error in commands.py, please fix') - return None - commandsigned = unitconf['signed'] - valuetransform = unitconf['read_value_transform'] - - # start value decode - if commandunit == 'CT': - timer = self._decode_timer(rawdatabytes.hex()) - # fill list - timer = [{'An': on_time, 'Aus': off_time} - for on_time, off_time in zip(timer, timer)] - value = timer - self.logger.debug(f'Matched command {commandname} and read transformed timer {value} and byte length {commandvaluebytes}') - elif commandunit == 'TI': - # decode datetime - value = datetime.strptime(rawdatabytes.hex(), '%Y%m%d%W%H%M%S').isoformat() - self.logger.debug(f'Matched command {commandname} and read transformed datetime {value} and byte length {commandvaluebytes}') - elif commandunit == 'DA': - # decode date - value = datetime.strptime(rawdatabytes.hex(), '%Y%m%d%W%H%M%S').date().isoformat() - self.logger.debug(f'Matched command {commandname} and read transformed datetime {value} and byte length {commandvaluebytes}') - elif commandunit == 'ES': - # erstes Byte = Fehlercode; folgenden 8 Byte = Systemzeit - errorcode = (rawdatabytes[:1]).hex() - # errorquerytime = (rawdatabytes[1:8]).hex() - value = self._error_decode(errorcode) - self.logger.debug(f'Matched command {commandname} and read transformed errorcode {value} (raw value was {errorcode}) and byte length {commandvaluebytes}') - elif commandunit == 'SC': - # erstes Byte = Anlagenschema - systemschemescode = (rawdatabytes[:1]).hex() - value = self._systemscheme_decode(systemschemescode) - self.logger.debug(f'Matched command {commandname} and read transformed system scheme {value} (raw value was {systemschemescode}) and byte length {commandvaluebytes}') - elif commandunit == 'BA': - operatingmodecode = (rawdatabytes[:1]).hex() - value = self._operatingmode_decode(operatingmodecode) - self.logger.debug(f'Matched command {commandname} and read transformed operating mode {value} (raw value was {operatingmodecode}) and byte length {commandvaluebytes}') - elif commandunit == 'DT': - # device type has 8 bytes, but first 4 bytes are device type indicator - devicetypebytes = rawdatabytes[:2].hex() - value = self._devicetype_decode(devicetypebytes).upper() - self.logger.debug(f'Matched command {commandname} and read transformed device type {value} (raw value was {devicetypebytes}) and byte length {commandvaluebytes}') - elif commandunit == 'SN': - # serial number has 7 bytes, - serialnumberbytes = rawdatabytes[:7] - value = self._serialnumber_decode(serialnumberbytes) - self.logger.debug(f'Matched command {commandname} and read transformed device type {value} (raw value was {serialnumberbytes}) and byte length {commandvaluebytes}') - elif commandunit == 'HEX': - # hex string for debugging purposes - hexstr = rawdatabytes.hex() - value = ' '.join([hexstr[i:i + 2] for i in range(0, len(hexstr), 2)]) - self.logger.debug(f'Read hex bytes {value}') - else: - rawvalue = self._bytes2int(rawdatabytes, commandsigned) - value = self._value_transform_read(rawvalue, valuetransform) - self.logger.debug(f'Matched command {commandname} and read transformed value {value} (integer raw value was {rawvalue}) and byte length {commandvaluebytes}') - - # assign to dict for use by other functions - self._last_values[commandcode] = value - - return (value, commandcode) - - # Handling of write command response if not error - elif responsedatacode == 2 and responsetypecode != 3: - self.logger.debug(f'Write request of adress {commandcode} successfull writing {valuebytecount} bytes') - return True - else: - self.logger.error(f'Write request of adress {commandcode} NOT successfull writing {valuebytecount} bytes') - return None - - def _viess_dict_to_uzsu_dict(self): - ''' - Convert data read from device to UZSU compatible struct. - Input is taken from self._viess_timer_dict, output is written to - self._uzsu_dict - ''' - dict_timer = {} - empty_time = '00:00' - shitems = Items.get_instance() - - try: - sunset = shitems.return_item('env.location.sunset')().strftime('%H:%M') - sunrise = shitems.return_item('env.location.sunrise')().strftime('%H:%M') - except (AttributeError, ValueError): - sunset = '21:00' - sunrise = '06:00' - - # convert all switching times with corresponding app and days to timer-dict - for application in self._viess_timer_dict: - if application not in dict_timer: - dict_timer[application] = {} - for application_day in self._viess_timer_dict[application]: - timer = self._viess_timer_dict[application][application_day] - day = application_day[(application_day.rfind('_') + 1):len(application_day)].lower() - - # normalize days - for element in self._wochentage: - if day in self._wochentage[element]: - weekday = element - - for entry in timer: - for event, sw_time in entry.items(): - if sw_time != empty_time: - value = 1 if event == 'An' else 0 - if sw_time not in dict_timer[application]: - dict_timer[application][sw_time] = {} - if value not in dict_timer[application][sw_time]: - dict_timer[application][sw_time][value] = [] - dict_timer[application][sw_time][value].append(weekday) - - self.logger.debug(f'Viessmann timer dict for UZSU: {dict_timer}') - - # find items, read UZSU-dict, convert to list of switching times, update item - for application in dict_timer: - item = self._application_timer[application]['item'] - - # read UZSU-dict (or use preset if empty) - uzsu_dict = item() - if not item(): - uzsu_dict = {'lastvalue': '0', 'sunset': sunset, 'list': [], 'active': True, 'interpolation': {'initage': '', 'initialized': True, 'itemtype': 'bool', 'interval': '', 'type': 'none'}, 'sunrise': sunrise} - - # create empty list - uzsu_dict['list'] = [] - - # fill list with switching times - for sw_time in sorted(dict_timer[application].keys()): - for key in dict_timer[application][sw_time]: - rrule = 'FREQ=WEEKLY;BYDAY=' + ','.join(dict_timer[application][sw_time][key]) - uzsu_dict['list'].append({'time': sw_time, 'rrule': rrule, 'value': str(key), 'active': True}) - - # update item - item(uzsu_dict, self.get_shortname()) - - def _uzsu_dict_to_viess_timer(self, timer_app, uzsu_dict): - ''' - Convert UZSU dict from item/visu for selected application into separate - on/off time events and write all timers to the device - - :param timer_app: Application for which the timer should be written, as in commands.py - :type timer_app: str - :param uzsu_dict: UZSU-compatible dict with timer data - :type uzsu_dict: dict - ''' - if self._timerread: - - # set variables - commandnames = set() - timer_dict = {} - an = {} - aus = {} - - # quit if timer_app not defined - if timer_app not in self._application_timer: - return - - commandnames.update([self._commandname_by_commandcode(code) for code in self._application_timer[timer_app]['commandcodes']]) - self.logger.debug(f'Commandnames: {commandnames}') - - # find switching times and create lists for on and off operations - for sw_time in uzsu_dict['list']: - myDays = sw_time['rrule'].split(';')[1].split('=')[1].split(',') - for day in myDays: - if sw_time['value'] == '1' and sw_time['active']: - if day not in an: - an[day] = [] - an[day].append(sw_time['time']) - for day in myDays: - if sw_time['value'] == '0' and sw_time['active']: - if day not in aus: - aus[day] = [] - aus[day].append(sw_time['time']) - - # sort daily lists - for day in an: - an[day].sort() - self.logger.debug(f'An: {an}') - for day in aus: - aus[day].sort() - self.logger.debug(f'Aus: {aus}') - - # create timer dict in Viessmann format for all weekdays - for commandname in commandnames: - self.logger.debug(f'Commandname in process: {commandname}') - # create empty dict - timer_dict[commandname] = [{'An': '00:00', 'Aus': '00:00'}, {'An': '00:00', 'Aus': '00:00'}, {'An': '00:00', 'Aus': '00:00'}, {'An': '00:00', 'Aus': '00:00'}] - # get current day - wday = commandname[(commandname.rfind('_') + 1):len(commandname)].lower() - # normalize day - for element in self._wochentage: - if wday in self._wochentage[element]: - wday = element - # transfer switching times - for idx, val in enumerate(an[wday]): - timer_dict[commandname][idx]['An'] = val - for idx, val in enumerate(aus[wday]): - timer_dict[commandname][idx]['Aus'] = val - self.logger.debug(f'Timer-dict for update of items: {timer_dict}') - - # write all timer dicts to device - for commandname in timer_dict: - value = timer_dict[commandname] - self.logger.debug(f'Got item value to be written: {value} on command name {commandname}') - self._send_command(commandname, value) - - def _calc_checksum(self, packet): - ''' - Calculate checksum for P300 protocol packets - - :parameter packet: Data packet for which to calculate checksum - :type packet: bytearray - :return: Calculated checksum - :rtype: int - ''' - checksum = 0 - if len(packet) > 0: - if packet[:1] == b'\x41': - packet = packet[1:] - checksum = sum(packet) - checksum = checksum - int(checksum / 256) * 256 - else: - self.logger.error('bytes to calculate checksum from not starting with start byte') - else: - self.logger.error('No bytes received to calculate checksum') - return checksum - - def _int2bytes(self, value, length, signed=False, byteorder='big'): - ''' - Convert value to bytearray with respect to defined length and sign format. - Value exceeding limit set by length and sign will be truncated - - :parameter value: Value to convert - :type value: int - :parameter length: number of bytes to create - :type length: int - :parameter signed: True if result should be a signed int, False for unsigned - :type signed: bool - :return: Converted value - :rtype: bytearray - ''' - value = value % (2 ** (length * 8)) - return value.to_bytes(length, byteorder=byteorder, signed=signed) - - def _bytes2int(self, rawbytes, signed): - ''' - Convert bytearray to value with respect to sign format - - :parameter rawbytes: Bytes to convert - :type value: bytearray - :parameter signed: True if result should be a signed int, False for unsigned - :type signed: bool - :return: Converted value - :rtype: int - ''' - return int.from_bytes(rawbytes, byteorder='little', signed=signed) - - def _bytes2hexstring(self, bytesvalue): - ''' - Create hex-formatted string from bytearray - :param bytesvalue: Bytes to convert - :type bytesvalue: bytearray - :return: Converted hex string - :rtype: str - ''' - return ''.join(f'{c:02x}' for c in bytesvalue) - - def _decode_rawvalue(self, rawdatabytes, commandsigned): - ''' - Convert little-endian byte sequence to int value - - :param rawdatabytes: Bytes to convert - :type rawdatabytes: bytearray - :param commandsigned: 'signed' if value should be interpreted as signed - :type commandsigned: str - :return: Converted value - :rtype: int - ''' - rawvalue = 0 - for i in range(len(rawdatabytes)): - leftbyte = rawdatabytes[0] - value = int(leftbyte * pow(256, i)) - rawvalue += value - rawdatabytes = rawdatabytes[1:] - # Signed/Unsigned berücksichtigen - if commandsigned == 'signed' and rawvalue > int(pow(256, i) / 2 - 1): - rawvalue = (pow(256, i) - rawvalue) * (-1) - return rawvalue - - def _decode_timer(self, rawdatabytes): - ''' - Generator to convert byte sequence to a number of time strings hh:mm - - :param rawdatabytes: Bytes to convert - :type rawdatabytes: bytearray - ''' - while rawdatabytes: - hours, minutes = divmod(int(rawdatabytes[:2], 16), 8) - if minutes >= 6 or hours >= 24: - # not a valid time - yield '00:00' - else: - yield f'{hours:02d}:{(minutes * 10):02d}' - rawdatabytes = rawdatabytes[2:] - return None - - def _encode_timer(self, switching_time): - ''' - Convert time string to encoded time value for timer application - - :param switching_time: time value in 'hh:mm' format - :type switching_time: str - :return: Encoded time value - :rtype: int - ''' - if switching_time == '00:00': - return 0xff - clocktime = re.compile(r'(\d\d):(\d\d)') - mo = clocktime.search(switching_time) - number = int(mo.group(1)) * 8 + int(mo.group(2)) // 10 - return number - - def _value_transform_read(self, value, transform): - ''' - Transform value according to protocol specification for writing to device - - :param value: Value to transform - :param transform: Specification for transforming - :return: Transformed value - ''' - if transform == 'bool': - return bool(value) - elif self._isfloat(transform): - return round(value / float(transform), 2) - else: - return int(value) - - def _value_transform_write(self, value, transform): - ''' - Transform value according to protocol requirement after reading from device - - :param value: Value to transform - :type value: int - :param transform: Specification for transforming - :type transform: int - :return: Transformed value - :rtype: int - ''' - # as transform and value can be float and by error possibly str, we try to float both - return int(float(value) * float(transform)) - - def _error_decode(self, value): - ''' - Decode error value from device if defined, else return error as string - ''' - value = str(value).upper() - if value in self._errorset: - errorstring = str(self._errorset[value]) - else: - errorstring = str(value) - return errorstring - - def _systemscheme_decode(self, value): - ''' - Decode schema value from device if possible, else return schema as string - ''' - if value in self._systemschemes: - systemscheme = str(self._systemschemes[value]) - else: - systemscheme = str(value) - return systemscheme - - def _operatingmode_decode(self, value): - ''' - Decode operating mode value from device if possible, else return mode as string - ''' - if value in self._operatingmodes: - operatingmode = str(self._operatingmodes[value]) - else: - operatingmode = str(value) - return operatingmode - - def _devicetype_decode(self, value): - ''' - Decode device type value if possible, else return device type as string - ''' - if value in self._devicetypes: - devicetypes = str(self._devicetypes[value]) - else: - devicetypes = str(value) - return devicetypes - - def _serialnumber_decode(self, serialnumberbytes): - ''' - Decode serial number from device response - ''' - serialnumber = 0 - serialnumberbytes.reverse() - for byte in range(0, len(serialnumberbytes)): - serialnumber += (serialnumberbytes[byte] - 48) * 10 ** byte - return hex(serialnumber).upper() - - def _commandname_by_commandcode(self, commandcode): - ''' - Find matching command name from commands.py for given command address - - :param commandcode: address of command - :type commandcode: str - :return: name of matching command or None if not found - ''' - for commandname in self._commandset.keys(): - if self._commandset[commandname]['addr'].lower() == commandcode.lower(): - return commandname - return None - - def _isfloat(self, value): - ''' - Test if string is decimal number - - :param value: expression to test - :type value: str - :return: True if value can be converted to a float, False otherwise - ''' - try: - float(value) - return True - except ValueError: - return False - -# -# webinterface -# - - def init_webinterface(self): - ''' - Initialize the web interface for this plugin - - This method is only needed if the plugin is implementing a web interface - ''' - try: - self.mod_http = Modules.get_instance().get_module('http') # try/except to handle running in a core version that does not support modules - except NameError: - self.mod_http = None - if self.mod_http is None: - self.logger.warning('Not initializing the web interface') - return False - - if 'SmartPluginWebIf' not in list(sys.modules['lib.model.smartplugin'].__dict__): - self.logger.warning('Web interface needs SmartHomeNG v1.5 or later. Not initializing the web interface') - return False - - # set application configuration for cherrypy - webif_dir = self.path_join(self.get_plugin_dir(), 'webif') - config = { - '/': { - 'tools.staticdir.root': webif_dir, - }, - '/static': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': 'static' - } - } - - # Register the web interface as a cherrypy app - self.mod_http.register_webif(WebInterface(webif_dir, self, self._commandset), - self.get_shortname(), - config, - self.get_classname(), self.get_instance_name(), - description='') - - return True - - -# ------------------------------------------ -# Webinterface of the plugin -# ------------------------------------------ - -class WebInterface(SmartPluginWebIf): - - def __init__(self, webif_dir, plugin, cmdset): - ''' - Initialization of instance of class WebInterface - - :param webif_dir: directory where the webinterface of the plugin resides - :param plugin: instance of the plugin - :type webif_dir: str - :type plugin: object - ''' - self.logger = logging.getLogger(__name__) - self.webif_dir = webif_dir - self.plugin = plugin - self.tplenv = self.init_template_environment() - - self.items = Items.get_instance() - - self.cmdset = cmdset - - self._last_read = {} - self._last_read['last'] = {'addr': None, 'val': '', 'cmd': ''} - - self._read_addr = None - self._read_cmd = '' - self._read_val = '' - - @cherrypy.expose - def index(self, reload=None): - ''' - Build index.html for cherrypy - - Render the template and return the html file to be delivered to the browser - - :return: contents of the template after beeing rendered - ''' - tmpl = self.tplenv.get_template('index.html') - # add values to be passed to the Jinja2 template eg: tmpl.render(p=self.plugin, interface=interface, ...) - - return tmpl.render(p=self.plugin, - items=sorted(self.items.return_items(), key=lambda k: str.lower(k['_path'])), - cmds=self.cmdset, - units=sorted(list(self.plugin._unitset.keys())), - last_read_addr=self._last_read['last']['addr'], - last_read_value=self._last_read['last']['val'], - last_read_cmd=self._last_read['last']['cmd'] - ) - - @cherrypy.expose - def submit(self, button=None, addr=None, length=0, unit=None, clear=False): - ''' - Submit handler for Ajax - ''' - if button is not None: - - read_val = self.plugin.read_addr(button) - if read_val is None: - self.logger.debug(f'Error trying to read addr {button} submitted by WebIf') - read_val = 'Fehler beim Lesen' - else: - read_cmd = self.plugin._commandname_by_commandcode(button) - if read_cmd is not None: - self._last_read[button] = {'addr': button, 'cmd': read_cmd, 'val': read_val} - self._last_read['last'] = self._last_read[button] - - elif addr is not None and unit is not None and length.isnumeric(): - - read_val = self.plugin.read_temp_addr(addr, int(length), unit) - if read_val is None: - self.logger.debug(f'Error trying to read custom addr {button} submitted by WebIf') - read_val = 'Fehler beim Lesen' - else: - self._last_read[addr] = {'addr': addr, 'cmd': f'custom ({addr})', 'val': read_val} - self._last_read['last'] = self._last_read[addr] - - elif clear: - for addr in self._last_read: - self._last_read[addr]['val'] = '' - self._last_read['last'] = {'addr': None, 'val': '', 'cmd': ''} - - cherrypy.response.headers['Content-Type'] = 'application/json' - return json.dumps(self._last_read).encode('utf-8') - - -# ------------------------------------------ -# The following code is for standalone use of the plugin to identify the device -# ------------------------------------------ - -def get_device_type(v, protocol): - - # try to connect and read device type info from 0x00f8 - print(f'Trying protocol {protocol} on device {serialport}') - - # first, initialize Viessmann object for use - v.alive = True - v._protocol = protocol - - # setup protocol controlset - v._controlset = commands.controlset[protocol] - res = v._connect() - if not res: - logger.info(f'Connection to {serialport} failed. Please check connection.') - return None - - res = v._init_communication() - if not res: - logger.info(f'Could not initialize communication using protocol {protocol}.') - return False - - # we are connected to the IR head - - # set needed unit - v._unitset = { - 'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'} - } - - # set needed command. DeviceType command is (hopefully) the same in all devices... - v._commandset = { - 'DT': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, - } - - # we leave this empty so we get the DT code back - v._devicetypes = {} - - # this is protocol dependent, so easier to let the Class work this out... - (packet, responselen) = v._build_command_packet('DT') - if packet is None: - raise ValueError('No command packet received for address 00f8. This shouldn\'t happen...') - - # send it - response_packet = v._send_command_packet(packet, responselen) - if response_packet is None: - raise ValueError('Error on communicating with the device, no response received. Unknown error.') - - # let it go... - v._disconnect() - - (val, code) = v._parse_response(response_packet, 'DT') - - if val is not None: - return val - else: - return None - - -if __name__ == '__main__': - - usage = ''' - Usage: - ---------------------------------------------------------------------------------- - - This plugin is meant to be used inside SmartHomeNG. - - For diagnostic purposes, you can run it as a standalone Python program from the - command line. It will try to communicate with a connected Viessmann heating system - and return the device type and the necessary protocol for setting up your plugin - in SmartHomeNG. - - You need to call this plugin with the serial interface as the first parameter, e.g. - - ./__init__.py /dev/ttyUSB0 - - If you call it with -v as a second parameter, you get additional debug information: - - ./__init__.py /dev/ttyUSB0 -v - - ''' - - logger = logging.getLogger(__name__) - logger.setLevel(logging.CRITICAL) - ch = logging.StreamHandler() - ch.setLevel(logging.DEBUG) - - # create formatter and add it to the handlers - formatter = logging.Formatter('%(asctime)s - %(message)s @ %(lineno)d') - ch.setFormatter(formatter) - - # add the handlers to the logger - logger.addHandler(ch) - - serialport = "" - - if len(sys.argv) == 2: - serialport = sys.argv[1] - elif len(sys.argv) == 3 and sys.argv[2] == '-v': - serialport = sys.argv[1] - logger.setLevel(logging.DEBUG) - else: - print(usage) - exit() - - print("This is Viessmann plugin running in standalone mode") - print("===================================================") - - v = Viessmann(None, standalone=serialport, logger=logger) - - for proto in ('P300', 'KW'): - - res = get_device_type(v, proto) - if res is None: - - # None means no connection, no further tries - print(f'Connection could not be established to {serialport}. Please check connection.') - break - - if res is False: - - # False means no comm init (only P300), go on - print(f'Communication could not be established using protocol {proto}.') - else: - - # anything else should be the devices answer, try to decode and quit - print(f'Device ID is {res}, device type is {commands.devicetypes.get(res, "unknown")} using protocol {proto}') - # break - - print('Done.') diff --git a/viessmann/_pv_1_2_3/commands.py b/viessmann/_pv_1_2_3/commands.py deleted file mode 100755 index 34d97e67e..000000000 --- a/viessmann/_pv_1_2_3/commands.py +++ /dev/null @@ -1,900 +0,0 @@ -# !/usr/bin/env python -# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Copyright 2020 Michael Wenzel -# Copyright 2020 Sebastian Helms -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# Viessmann-Plugin for SmartHomeNG. https://github.com/smarthomeNG// -# -# 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 . -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -controlset = { - 'P300': { - 'Baudrate': 4800, - 'Bytesize': 8, # 'EIGHTBITS' - 'Parity': 'E', # 'PARITY_EVEN', - 'Stopbits': 2, # 'STOPBITS_TWO', - 'StartByte': 0x41, - 'Request': 0x00, - 'Response': 0x01, - 'Error': 0x03, - 'Read': 0x01, - 'Write': 0x02, - 'Function_Call': 0x7, - 'Acknowledge': 0x06, - 'Not_initiated': 0x05, - 'Init_Error': 0x15, - 'Reset_Command': 0x04, - 'Reset_Command_Response': 0x05, - 'Sync_Command': 0x160000, - 'Sync_Command_Response': 0x06, - 'Command_bytes_read': 5, - 'Command_bytes_write': 5, - # init: send'Reset_Command' receive'Reset_Command_Response' send'Sync_Command' - # request: send('StartByte' 'Länge der Nutzdaten als Anzahl der Bytes zwischen diesem Byte und der Prüfsumme' 'Request' 'Read' 'addr' 'checksum') - # request_response: receive('Acknowledge' 'StartByte' 'Länge der Nutzdaten als Anzahl der Bytes zwischen diesem Byte und der Prüfsumme' 'Response' 'Read' 'addr' 'Anzahl der Bytes des Wertes' 'Wert' 'checksum') - }, - 'KW': { - 'Baudrate': 4800, - 'Bytesize': 8, # 'EIGHTBITS' - 'Parity': 'E', # 'PARITY_EVEN', - 'Stopbits': 2, # 'STOPBITS_TWO', - 'StartByte': 0x01, - 'Read': 0xF7, - 'Write': 0xF4, - 'Acknowledge': 0x01, - 'Reset_Command': 0x04, - 'Not_initiated': 0x05, - 'Write_Ack': 0x00, - }, -} - -commandset = { - 'V200KO1B': { - # Kessel - 'Aussentemperatur': {'addr': '0800', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur - 'Aussentemperatur_TP': {'addr': '5525', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur_tiefpass - 'Aussentemperatur_Dp': {'addr': '5527', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur in Grad C (Gedaempft) - 'Kesseltemperatur': {'addr': '0802', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur - 'Kesseltemperatur_TP': {'addr': '0810', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur_tiefpass - 'Kesselsolltemperatur': {'addr': '555a', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesselsolltemperatur - 'Temp_Speicher_Ladesensor': {'addr': '0812', 'len': 2, 'unit': 'IU10', 'set': False}, # Temperatur Speicher Ladesensor Komfortsensor - 'Auslauftemperatur': {'addr': '0814', 'len': 2, 'unit': 'IU10', 'set': False}, # Auslauftemperatur - 'Abgastemperatur': {'addr': '0816', 'len': 2, 'unit': 'IU10', 'set': False}, # Abgastemperatur - 'Gem_Vorlauftemperatur': {'addr': '081a', 'len': 2, 'unit': 'IU10', 'set': False}, # Gem. Vorlauftemperatur - 'Relais_K12': {'addr': '0842', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Relais K12 Interne Anschlußerweiterung - 'Eingang_0-10_V': {'addr': '0a86', 'len': 1, 'unit': 'IUINT', 'set': False}, # Eingang 0-10 V - 'EA1_Kontakt_0': {'addr': '0a90', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Kontakt 0 - 'EA1_Kontakt_1': {'addr': '0a91', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Kontakt 1 - 'EA1_Kontakt_2': {'addr': '0a92', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Kontakt 2 - 'EA1_Externer_Soll_0-10V': {'addr': '0a93', 'len': 1, 'unit': 'IUINT', 'set': False}, # EA1: Externer Sollwert 0-10V - 'EA1_Relais_0': {'addr': '0a95', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Relais 0 - 'AM1_Ausgang_1': {'addr': '0aa0', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # AM1 Ausgang 1 - 'AM1_Ausgang_2': {'addr': '0aa1', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # AM1 Ausgang 2 - 'TempKOffset': {'addr': '6760', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Kesseloffset KT ueber WWsoll in Grad C - 'Systemtime': {'addr': '088e', 'len': 8, 'unit': 'TI', 'set': True}, # Systemzeit - 'Anlagenschema': {'addr': '7700', 'len': 2, 'unit': 'SC', 'set': False}, # Anlagenschema - 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # Heizungstyp - 'Inventory': {'addr': '08e0', 'len': 7, 'unit': 'SN', 'set': False}, # Sachnummer - 'CtrlId': {'addr': '08e0', 'len': 7, 'unit': 'DT', 'set': False}, # Reglerkennung - # Fehler - 'Sammelstoerung': {'addr': '0a82', 'len': 1, 'unit': 'RT', 'set': False}, # Sammelstörung - 'Error0': {'addr': '7507', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 1 - 'Error1': {'addr': '7510', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 2 - 'Error2': {'addr': '7519', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 3 - 'Error3': {'addr': '7522', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 4 - 'Error4': {'addr': '752b', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 5 - 'Error5': {'addr': '7534', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 6 - 'Error6': {'addr': '753d', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 7 - 'Error7': {'addr': '7546', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 8 - 'Error8': {'addr': '754f', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 9 - 'Error9': {'addr': '7558', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 10 - # Pumpen - 'Speicherladepumpe': {'addr': '6513', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Speicherladepumpe - 'Zirkulationspumpe': {'addr': '6515', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Zirkulationspumpe - 'Interne_Pumpe': {'addr': '7660', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Interne Pumpe - 'Heizkreispumpe_A1M1': {'addr': '2906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe A1 - 'Heizkreispumpe_A1M1_RPM': {'addr': '7663', 'len': 1, 'unit': 'IUNON', 'set': False}, # Heizkreispumpe A1M1 Drehzahl - 'Heizkreispumpe_M2': {'addr': '3906', 'len': 1, 'unit': 'IUINT', 'set': False}, # Heizkreispumpe M2 - 'Heizkreispumpe_M2_RPM': {'addr': '7665', 'len': 1, 'unit': 'IUNON', 'set': False}, # Heizkreispumpe M2 Drehzahl - 'Relais_Status_Pumpe_A1M1': {'addr': 'a152', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Relais-Status Heizkreispumpe 1 - # Brenner - 'Brennerstarts': {'addr': '088a', 'len': 4, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brennerstarts - 'Brenner_Betriebsstunden': {'addr': '08a7', 'len': 4, 'unit': 'IU3600', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brenner-Betriebsstunden - 'Brennerstatus_1': {'addr': '0842', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe1 - 'Brennerstatus_2': {'addr': '0849', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe2 - 'Oeldurchsatz': {'addr': '5726', 'len': 4, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Oeldurchsatz Brenner in Dezi-Liter pro Stunde - 'Oelverbrauch': {'addr': '7574', 'len': 4, 'unit': 'IS1000', 'set': True}, # Oelverbrauch kumuliert - # Solar - 'Nachladeunterdrueckung': {'addr': '6551', 'len': 1, 'unit': 'IUBOOL', 'set': False}, - 'SolarPumpe': {'addr': '6552', 'len': 1, 'unit': 'IUBOOL', 'set': False}, - 'Kollektortemperatur': {'addr': '6564', 'len': 2, 'unit': 'IS10', 'set': False}, - 'Speichertemperatur': {'addr': '6566', 'len': 2, 'unit': 'IU10', 'set': False}, - 'Solar_Betriebsstunden': {'addr': '6568', 'len': 4, 'unit': 'IU100', 'set': False}, - 'Solarsteuerung': {'addr': '7754', 'len': 2, 'unit': 'IUINT', 'set': False}, - # Heizkreis A1M1 - 'Raumtemperatur_A1M1': {'addr': '0896', 'len': 1, 'unit': 'ISNON', 'set': False}, # Raumtemperatur A1M1 - 'Raumtemperatur_Soll_Normalbetrieb_A1M1': {'addr': '2306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb A1M1 - 'Raumtemperatur_Soll_Red_Betrieb_A1M1': {'addr': '2307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb A1M1 - 'Raumtemperatur_Soll_Party_Betrieb_A1M1': {'addr': '2308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb A1M1 - 'Aktuelle_Betriebsart_A1M1': {'addr': '2301', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart A1M1 - 'Betriebsart_A1M1': {'addr': '2323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Betriebsart A1M1 - 'Sparbetrieb_A1M1': {'addr': '2302', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Sparbetrieb A1M1 - 'Zustand_Sparbetrieb_A1M1': {'addr': '2331', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Sparbetrieb A1M1 - 'Partybetrieb_A1M1': {'addr': '2303', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Partybetrieb A1M1 - 'Zustand_Partybetrieb_A1M1': {'addr': '2330', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Partybetrieb A1M1 - 'Vorlauftemperatur_A1M1': {'addr': '2900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur A1M1 - 'Vorlauftemperatur_Soll_A1M1': {'addr': '2544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll A1M1 - 'StatusFrost_A1M1': {'addr': '2500', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Status Frostwarnung A1M1 - 'Externe_Raumsolltemperatur_Normal_A1M1': {'addr': '2321', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 37}, # Externe Raumsolltemperatur Normal A1M1 - 'Externe_Betriebsartenumschaltung_A1M1': {'addr': '2549', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Externe Betriebsartenumschaltung A1M1 - 'Speichervorrang_A1M1': {'addr': '27a2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Speichervorrang auf Heizkreispumpe und Mischer - 'Frostschutzgrenze_A1M1': {'addr': '27a3', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -9, 'max_value': 15}, # Frostschutzgrenze - 'Frostschutz_A1M1': {'addr': '27a4', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Frostschutzgrenze - 'Heizkreispumpenlogik_A1M1': {'addr': '27a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # HeizkreispumpenlogikFunktion - 'Sparschaltung_A1M1': {'addr': '27a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 35}, # AbsolutSommersparschaltung - 'Mischersparfunktion_A1M1': {'addr': '27a7', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Mischersparfunktion - 'Pumpenstillstandzeit_A1M1': {'addr': '27a9', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Pumpenstillstandzeit - 'Vorlauftemperatur_min_A1M1': {'addr': '27c5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Minimalbegrenzung der Vorlauftemperatur - 'Vorlauftemperatur_max_A1M1': {'addr': '27c6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 127}, # Maximalbegrenzung der Vorlauftemperatur - 'Neigung_Heizkennlinie_A1M1': {'addr': '27d3', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie A1M1 - 'Niveau_Heizkennlinie_A1M1': {'addr': '27d4', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie A1M1 - 'Partybetrieb_Zeitbegrenzung_A1M1': {'addr': '27f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Zeitliche Begrenzung für Partybetrieb oder externe BetriebsprogrammUmschaltung mit Taster - 'Temperaturgrenze_red_Betrieb_A1M1': {'addr': '27f8', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -61, 'max_value': 10}, # Temperaturgrenze für Aufhebung des reduzierten Betriebs -5 ºC - 'Temperaturgrenze_red_Raumtemp_A1M1': {'addr': '27f9', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -60, 'max_value': 10}, # Temperaturgrenze für Anhebung des reduzierten RaumtemperaturSollwertes - 'Vorlauftemperatur_Erhoehung_Soll_A1M1': {'addr': '27fa', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 50}, # Erhöhung des Kesselwasser- bzw. Vorlauftemperatur-Sollwertes beim Übergang von Betrieb mit reduzierter Raumtemperatur in den Betrieb mit normaler Raumtemperatur um 20 % - 'Vorlauftemperatur_Erhoehung_Zeit_A1M1': {'addr': '27fa', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 150}, # Zeitdauer für die Erhöhung des Kesselwasser bzw.VorlauftemperaturSollwertes (siehe Codieradresse „FA“) 60 min. - # Heizkreis M2 - 'Raumtemperatur_M2': {'addr': '0898', 'len': 1, 'unit': 'ISNON', 'set': False}, # Raumtemperatur - 'Raumtemperatur_Soll_Normalbetrieb_M2': {'addr': '3306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb - 'Raumtemperatur_Soll_Red_Betrieb_M2': {'addr': '3307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb - 'Raumtemperatur_Soll_Party_Betrieb_M2': {'addr': '3308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb - 'Aktuelle_Betriebsart_M2': {'addr': '3301', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart - 'Betriebsart_M2': {'addr': '3323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Betriebsart - 'Sparbetrieb_M2': {'addr': '3302', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Sparbetrieb - 'Zustand_Sparbetrieb_M2': {'addr': '3331', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Sparbetrieb - 'Partybetrieb_M2': {'addr': '3303', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Partybetrieb - 'Zustand_Partybetrieb_M2': {'addr': '3330', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Partybetrieb - 'Vorlauftemperatur_M2': {'addr': '3900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur - 'Vorlauftemperatur_Soll_M2': {'addr': '3544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll - 'StatusFrost_M2': {'addr': '3500', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Status Frostwarnung - 'Externe_Raumsolltemperatur_Normal_M2': {'addr': '3321', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 37}, # Externe Raumsolltemperatur Normal - 'Externe_Betriebsartenumschaltung_M2': {'addr': '3549', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Externe Betriebsartenumschaltung - 'Speichervorrang_M2': {'addr': '37a2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Speichervorrang auf Heizkreispumpe und Mischer - 'Frostschutzgrenze_M2': {'addr': '37a3', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -9, 'max_value': 15}, # Frostschutzgrenze - 'Frostschutz_M2': {'addr': '37a4', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Frostschutzgrenze - 'Heizkreispumpenlogik_M2': {'addr': '37a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # HeizkreispumpenlogikFunktion - 'Sparschaltung_M2': {'addr': '37a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 35}, # AbsolutSommersparschaltung - 'Mischersparfunktion_M2': {'addr': '37a7', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Mischersparfunktion - 'Pumpenstillstandzeit_M2': {'addr': '37a9', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Pumpenstillstandzeit - 'Vorlauftemperatur_min_M2': {'addr': '37c5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Minimalbegrenzung der Vorlauftemperatur - 'Vorlauftemperatur_max_M2': {'addr': '37c6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 127}, # Maximalbegrenzung der Vorlauftemperatur - 'Neigung_Heizkennlinie_M2': {'addr': '37d3', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie - 'Niveau_Heizkennlinie_M2': {'addr': '37d4', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie - 'Partybetrieb_Zeitbegrenzung_M2': {'addr': '37f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Zeitliche Begrenzung für Partybetrieb oder externe BetriebsprogrammUmschaltung mit Taster - 'Temperaturgrenze_red_Betrieb_M2': {'addr': '37f8', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -61, 'max_value': 10}, # Temperaturgrenze für Aufhebung des reduzierten Betriebs -5 ºC - 'Temperaturgrenze_red_Raumtemp_M2': {'addr': '37f9', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -60, 'max_value': 10}, # Temperaturgrenze für Anhebung des reduzierten RaumtemperaturSollwertes - 'Vorlauftemperatur_Erhoehung_Soll_M2': {'addr': '37fa', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 50}, # Erhöhung des Kesselwasser- bzw. Vorlauftemperatur-Sollwertes beim Übergang von Betrieb mit reduzierter Raumtemperatur in den Betrieb mit normaler Raumtemperatur um 20 % - 'Vorlauftemperatur_Erhoehung_Zeit_M2': {'addr': '37fb', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 150}, # Zeitdauer für die Erhöhung des Kesselwasser bzw.VorlauftemperaturSollwertes (siehe Codieradresse „FA“) 60 min. - # Warmwasser - 'Warmwasser_Temperatur': {'addr': '0804', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwassertemperatur in Grad C - 'Warmwasser_Solltemperatur': {'addr': '6300', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 95}, # Warmwasser-Solltemperatur - 'Status_Warmwasserbereitung': {'addr': '650a', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Satus Warmwasserbereitung - 'WarmwasserPumpenNachlauf': {'addr': '6762', 'len': 2, 'unit': 'ISNON' , 'set': True, 'min_value': 0, 'max_value': 1}, # Warmwasserpumpennachlauf - # Ferienprogramm HK_A1M1 - 'Ferienprogramm_A1M1': {'addr': '2535', 'len': 1, 'unit': 'IUINT', 'set': False}, # Ferienprogramm A1M1 - 'Ferien_Abreisetag_A1M1': {'addr': '2309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag A1M1 - 'Ferien_Rückreisetag_A1M1': {'addr': '2311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag A1M1 - # Ferienprogramm HK_M2 - 'Ferienprogramm_M2': {'addr': '3535', 'len': 1, 'unit': 'IUINT', 'set': False}, # Ferienprogramm M2 - 'Ferien_Abreisetag_M2': {'addr': '3309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag M2 - 'Ferien_Rückreisetag_M2': {'addr': '3311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag M2 - # Schaltzeiten Warmwasser - 'Timer_Warmwasser_Mo': {'addr': '2100', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Montag - 'Timer_Warmwasser_Di': {'addr': '2108', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Dienstag - 'Timer_Warmwasser_Mi': {'addr': '2110', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Mittwoch - 'Timer_Warmwasser_Do': {'addr': '2118', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Donnerstag - 'Timer_Warmwasser_Fr': {'addr': '2120', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Freitag - 'Timer_Warmwasser_Sa': {'addr': '2128', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Samstag - 'Timer_Warmwasser_So': {'addr': '2130', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Sonntag - # Schaltzeiten HK_A1M1 - 'Timer_A1M1_Mo': {'addr': '2000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag - 'Timer_A1M1_Di': {'addr': '2008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag - 'Timer_A1M1_Mi': {'addr': '2010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch - 'Timer_A1M1_Do': {'addr': '2018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag - 'Timer_A1M1_Fr': {'addr': '2020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag - 'Timer_A1M1_Sa': {'addr': '2028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag - 'Timer_A1M1_So': {'addr': '2030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag - # Schaltzeiten HK_M2 - 'Timer_M2_Mo': {'addr': '3000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag - 'Timer_M2_Di': {'addr': '3008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag - 'Timer_M2_Mi': {'addr': '3010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch - 'Timer_M2_Do': {'addr': '3018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag - 'Timer_M2_Fr': {'addr': '3020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag - 'Timer_M2_Sa': {'addr': '3028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag - 'Timer_M2_So': {'addr': '3030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag - # Schaltzeiten Zirkulation - 'Timer_Zirku_Mo': {'addr': '2200', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Montag - 'Timer_Zirku_Di': {'addr': '2208', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Dienstag - 'Timer_Zirku_Mi': {'addr': '2210', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Mittwoch - 'Timer_Zirku_Do': {'addr': '2218', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Donnerstag - 'Timer_Zirku_Fr': {'addr': '2220', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Freitag - 'Timer_Zirku_Sa': {'addr': '2228', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Samstag - 'Timer_Zirku_So': {'addr': '2230', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Sonntag - }, - 'V200HO1C': { - # Allgemein - 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # Heizungstyp - 'Anlagenschema': {'addr': '7700', 'len': 2, 'unit': 'SC', 'set': False}, # Anlagenschema - 'Frostgefahr': {'addr': '2510', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Frostgefahr - 'Aussentemperatur_TP': {'addr': '5525', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur_tiefpass - 'Aussentemperatur_Dp': {'addr': '5527', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur in Grad C (Gedaempft) - 'Anlagenleistung': {'addr': 'a38f', 'len': 2, 'unit': 'IS10', 'set': False}, # Anlagenleistung - # Kessel - 'Kesseltemperatur_TP': {'addr': '0810', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur_tiefpass - 'Kesselsolltemperatur': {'addr': '555a', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesselsolltemperatur - 'Abgastemperatur': {'addr': '0816', 'len': 2, 'unit': 'IU10', 'set': False}, # Abgastemperatur - # Fehler - 'Sammelstoerung': {'addr': '0a82', 'len': 1, 'unit': 'RT', 'set': False}, # Sammelstörung - 'Error0': {'addr': '7507', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 1 - 'Error1': {'addr': '7510', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 2 - 'Error2': {'addr': '7519', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 3 - 'Error3': {'addr': '7522', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 4 - 'Error4': {'addr': '752b', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 5 - 'Error5': {'addr': '7534', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 6 - 'Error6': {'addr': '753d', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 7 - 'Error7': {'addr': '7546', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 8 - 'Error8': {'addr': '754f', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 9 - 'Error9': {'addr': '7558', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 10 - # Pumpen - 'Speicherladepumpe': {'addr': '6513', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Speicherladepumpe für Warmwasser - 'Zirkulationspumpe': {'addr': '6515', 'len': 1, 'unit': 'IUBOOL', 'set': True}, # Zirkulationspumpe - 'Interne_Pumpe': {'addr': '7660', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Interne Pumpe - 'Heizkreispumpe_HK1': {'addr': '2906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe A1 - 'Heizkreispumpe_HK2': {'addr': '3906', 'len': 1, 'unit': 'IUINT', 'set': False}, # Heizkreispumpe M2 - # Brenner - 'Brennerstarts': {'addr': '088a', 'len': 4, 'unit': 'ISNON', 'set': False}, # Brennerstarts - 'Brennerleistung': {'addr': 'a305', 'len': 2, 'unit': 'IS10', 'set': False}, # Brennerleistung - 'Brenner_Betriebsstunden': {'addr': '08a7', 'len': 4, 'unit': 'IU3600', 'set': False}, # Brenner-Betriebsstunden - # Solar - 'SolarPumpe': {'addr': '6552', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Solarpumpe - 'Kollektortemperatur': {'addr': '6564', 'len': 2, 'unit': 'IS10', 'set': False}, # Kollektortemperatur - 'Speichertemperatur': {'addr': '6566', 'len': 2, 'unit': 'IU10', 'set': False}, # Spichertemperatur - 'Solar_Betriebsstunden': {'addr': '6568', 'len': 4, 'unit': 'IU100', 'set': False}, # Solar Betriebsstunden - 'Solar_Waermemenge': {'addr': '6560', 'len': 2, 'unit': 'IUINT', 'set': False}, # Solar Waermemenge - 'Solar_Ausbeute': {'addr': 'cf30', 'len': 4, 'unit': 'IUINT', 'set': False}, # Solar Ausbeute - # Heizkreis 1 - 'Betriebsart_HK1': {'addr': '2500', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 3}, # Betriebsart (0=Abschaltbetrieb, 1=Red. Betrieb, 2=Normalbetrieb (Schaltuhr), 3=Normalbetrieb (Dauernd)) - 'Heizart_HK1': {'addr': '2323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Heizart (0=Abschaltbetrieb, 1=Nur Warmwasser, 2=Heizen und Warmwasser, 3=Normalbetrieb (Reduziert), 4=Normalbetrieb (Dauernd)) - 'Vorlauftemperatur_Soll_HK1': {'addr': '2544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll - 'Vorlauftemperatur_HK1': {'addr': '2900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Ist - # Heizkreis 2 - 'Betriebsart_HK2': {'addr': '3500', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 3}, # Betriebsart (0=Abschaltbetrieb, 1=Red. Betrieb, 2=Normalbetrieb (Schaltuhr), 3=Normalbetrieb (Dauernd)) - 'Heizart_HK2': {'addr': '3323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Heizart (0=Abschaltbetrieb, 1=Nur Warmwasser, 2=Heizen und Warmwasser, 3=Normalbetrieb (Reduziert), 4=Normalbetrieb (Dauernd)) - 'Vorlauftemperatur_Soll_HK2': {'addr': '3544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll - 'Vorlauftemperatur_HK2': {'addr': '3900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Ist - # Warmwasser - 'Warmwasser_Temperatur': {'addr': '0812', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwassertemperatur in Grad C - 'Warmwasser_Solltemperatur': {'addr': '6300', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 80}, # Warmwasser-Solltemperatur - 'Warmwasser_Austrittstemperatur': {'addr': '0814', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwasseraustrittstemperatur in Grad C - }, - 'V200KW2': { - # Allgemein - 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # Ermittle Device Typ der Anlage - 'Anlagenschema': {'addr': '7700', 'len': 2, 'unit': 'SC', 'set': False}, # Anlagenschema - 'AnlagenSoftwareIndex': {'addr': '7330', 'len': 1, 'unit': 'IUNON', 'set': False}, # Bedienteil SoftwareIndex - 'Aussentemperatur': {'addr': '0800', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur_tiefpass - 'Aussentemperatur_Dp': {'addr': '5527', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur in Grad C (Gedaempft) - 'Systemtime': {'addr': '088e', 'len': 8, 'unit': 'TI', 'set': True}, # Systemzeit - # Kessel - 'TempKOffset': {'addr': '6760', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 10, 'max_value': 50}, # Kesseloffset KT ueber WWsoll in Grad C - 'Kesseltemperatur': {'addr': '0802', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur - 'Kesselsolltemperatur': {'addr': '5502', 'len': 2, 'unit': 'IU10', 'set': True}, # Kesselsolltemperatur - # Fehler - 'Sammelstoerung': {'addr': '0847', 'len': 1, 'unit': 'RT', 'set': False}, # Sammelstörung - 'Brennerstoerung': {'addr': '0883', 'len': 1, 'unit': 'RT', 'set': False}, - 'Error0': {'addr': '7507', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 1 - 'Error1': {'addr': '7510', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 2 - 'Error2': {'addr': '7519', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 3 - 'Error3': {'addr': '7522', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 4 - 'Error4': {'addr': '752b', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 5 - 'Error5': {'addr': '7534', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 6 - 'Error6': {'addr': '753d', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 7 - 'Error7': {'addr': '7546', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 8 - 'Error8': {'addr': '754f', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 9 - 'Error9': {'addr': '7558', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 10 - # Pumpen - 'Speicherladepumpe': {'addr': '0845', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Speicherladepumpe für Warmwasser - 'Zirkulationspumpe': {'addr': '0846', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Zirkulationspumpe - 'Heizkreispumpe_A1M1': {'addr': '2906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe A1M1 - 'Heizkreispumpe_M2': {'addr': '3906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe M2 - # Brenner - 'Brennertyp': {'addr': 'a30b', 'len': 1, 'unit': 'IUNON', 'set': False}, # Brennertyp 0=einstufig 1=zweistufig 2=modulierend - 'Brennerstufe': {'addr': '551e', 'len': 1, 'unit': 'RT', 'set': False}, # Ermittle die aktuelle Brennerstufe - 'Brennerstarts': {'addr': '088a', 'len': 2, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brennerstarts - 'Brennerstatus_1': {'addr': '55d3', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe1 - 'Brennerstatus_2': {'addr': '0849', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe2 - 'Brenner_BetriebsstundenStufe1': {'addr': '0886', 'len': 4, 'unit': 'IU3600', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brenner-Betriebsstunden Stufe 1 - 'Brenner_BetriebsstundenStufe2': {'addr': '08a3', 'len': 4, 'unit': 'IU3600', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brenner-Betriebsstunden Stufe 2 - # Heizkreis A1M1 - 'Betriebsart_A1M1': {'addr': '2301', 'len': 1, 'unit': 'BA', 'set': True}, # Betriebsart A1M1 - 'Aktuelle_Betriebsart_A1M1': {'addr': '2500', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart A1M1 - 'Sparbetrieb_A1M1': {'addr': '2302', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Sparbetrieb A1M1 - 'Partybetrieb_A1M1_Zeit': {'addr': '27f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Partyzeit M2 - 'Partybetrieb_A1M1': {'addr': '2303', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Partybetrieb A1M1 - 'Vorlauftemperatur_A1M1': {'addr': '2900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur A1M1 - 'Vorlauftemperatur_Soll_A1M1': {'addr': '2544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll A1M1 - 'Raumtemperatur_Soll_Normalbetrieb_A1M1': {'addr': '2306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb A1M1 - 'Raumtemperatur_Soll_Red_Betrieb_A1M1': {'addr': '2307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb A1M1 - 'Raumtemperatur_Soll_Party_Betrieb_A1M1': {'addr': '2308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb A1M1 - 'Neigung_Heizkennlinie_A1M1': {'addr': '2305', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie A1M1 - 'Niveau_Heizkennlinie_A1M1': {'addr': '2304', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie A1M1 - 'MischerM1': {'addr': '254c', 'len': 1, 'unit': 'IUPR', 'set': False}, # Ermittle Mischerposition M1 - 'Heizkreispumpenlogik_A1M1': {'addr': '27a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # 0=ohne HPL-Funktion, 1=AT > RTsoll + 5 K, 2=AT > RTsoll + 4 K, 3=AT > RTsoll + 3 K, 4=AT > RTsoll + 2 K, 5=AT > RTsoll + 1 K, 6=AT > RTsoll, 7=AT > RTsoll - 1 K, 8=AT > RTsoll - 2 K, 9=AT > RTsoll - 3 K, 10=AT > RTsoll - 4 K, 11=AT > RTsoll - 5 K, 12=AT > RTsoll - 6 K, 13=AT > RTsoll - 7 K, 14=AT > RTsoll - 8 K, 15=AT > RTsoll - 9 K - 'Sparschaltung_A1M1': {'addr': '27a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 36}, # AbsolutSommersparschaltung - # Heizkreis M2 - 'Betriebsart_M2': {'addr': '3301', 'len': 1, 'unit': 'BA', 'set': True}, # Betriebsart M2 - 'Aktuelle_Betriebsart_M2': {'addr': '3500', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart M2 - 'Sparbetrieb_M2': {'addr': '3302', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Sparbetrieb - 'Partybetrieb_M2': {'addr': '3303', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Partybetrieb A1M1 - 'Partybetrieb_M2_Zeit': {'addr': '37f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Partyzeit M2 - 'Raumtemperatur_Soll_Normalbetrieb_M2': {'addr': '3306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb - 'Raumtemperatur_Soll_Red_Betrieb_M2': {'addr': '3307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb - 'Raumtemperatur_Soll_Party_Betrieb_M2': {'addr': '3308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb - 'Neigung_Heizkennlinie_M2': {'addr': '3305', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie M2 - 'Niveau_Heizkennlinie_M2': {'addr': '3304', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie M2 - 'MischerM2': {'addr': '354c', 'len': 1, 'unit': 'IUPR', 'set': False}, # Ermittle Mischerposition M2 - 'MischerM2Auf': {'addr': '084d', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # MischerM2 Auf 0=AUS;1=EIN - 'MischerM2Zu': {'addr': '084c', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # MischerM2 Zu 0=AUS;1=EIN - 'Vorlauftemperatur_Soll_M2': {'addr': '37c6', 'len': 2, 'unit': 'IU10', 'set': True, 'min_value': 10, 'max_value': 80}, # Vorlauftemperatur Soll - 'Vorlauftemperatur_M2': {'addr': '080c', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Ist - 'Vorlauftemperatur_min_M2': {'addr': '37c5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Minimalbegrenzung der Vorlauftemperatur - 'Vorlauftemperatur_max_M2': {'addr': '37c6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Maximalbegrenzung der Vorlauftemperatur - 'Heizkreispumpenlogik_M2': {'addr': '37a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # 0=ohne HPL-Funktion, 1=AT > RTsoll + 5 K, 2=AT > RTsoll + 4 K, 3=AT > RTsoll + 3 K, 4=AT > RTsoll + 2 K, 5=AT > RTsoll + 1 K, 6=AT > RTsoll, 7=AT > RTsoll - 1 K, 8=AT > RTsoll - 2 K, 9=AT > RTsoll - 3 K, 10=AT > RTsoll - 4 K, 11=AT > RTsoll - 5 K, 12=AT > RTsoll - 6 K, 13=AT > RTsoll - 7 K, 14=AT > RTsoll - 8 K, 15=AT > RTsoll - 9 K - 'Sparschaltung_M2': {'addr': '37a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 36}, # AbsolutSommersparschaltung - 'StatusKlemme2': {'addr': '3904', 'len': 1, 'unit': 'IUINT', 'set': False}, # 0=OK, 1=Kurzschluss, 2=nicht vorhanden, 3-5=Referenzfehler, 6=nicht vorhanden - 'StatusKlemme17': {'addr': '3905', 'len': 1, 'unit': 'IUINT', 'set': False}, # 0=OK, 1=Kurzschluss, 2=nicht vorhanden, 3-5=Referenzfehler, 6=nicht vorhanden - # Warmwasser - 'Warmwasser_Status': {'addr': '650A', 'len': 1, 'unit': 'IUNON', 'set': False}, # 0=Ladung inaktiv, 1=in Ladung, 2=im Nachlauf - 'Warmwasser_KesselOffset': {'addr': '6760', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 10, 'max_value': 50}, # Warmwasser Kessel Offset in K - 'Warmwasser_BeiPartyDNormal': {'addr': '6764', 'len': 1, 'unit': 'IUNON', 'set': True, 'min_value': 0, 'max_value': 2}, # WW Heizen bei Party 0=AUS, 1=nach Schaltuhr, 2=EIN - 'Warmwasser_Temperatur': {'addr': '0804', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwassertemperatur in Grad C - 'Warmwasser_Solltemperatur': {'addr': '6300', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 80}, # Warmwasser-Solltemperatur - 'Warmwasser_SolltemperaturAktuell': {'addr': '6500', 'len': 1, 'unit': 'IU10' , 'set': False}, # Warmwasser-Solltemperatur aktuell - 'Warmwasser_SollwertMax': {'addr': '675a', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # 0=inaktiv, 1=aktiv - # Ferienprogramm HK_A1M1 - 'Ferienprogramm_A1M1': {'addr': '2535', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Ferienprogramm A1M1 0=inaktiv 1=aktiv - 'Ferien_Abreisetag_A1M1': {'addr': '2309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag A1M1 - 'Ferien_Rückreisetag_A1M1': {'addr': '2311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag A1M1 - # Ferienprogramm HK_M2 - 'Ferienprogramm_M2': {'addr': '3535', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Ferienprogramm M2 0=inaktiv 1=aktiv - 'Ferien_Abreisetag_M2': {'addr': '3309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag M2 - 'Ferien_Rückreisetag_M2': {'addr': '3311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag M2 - # Schaltzeiten Warmwasser - 'Timer_Warmwasser_Mo': {'addr': '2100', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Montag - 'Timer_Warmwasser_Di': {'addr': '2108', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Dienstag - 'Timer_Warmwasser_Mi': {'addr': '2110', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Mittwoch - 'Timer_Warmwasser_Do': {'addr': '2118', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Donnerstag - 'Timer_Warmwasser_Fr': {'addr': '2120', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Freitag - 'Timer_Warmwasser_Sa': {'addr': '2128', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Samstag - 'Timer_Warmwasser_So': {'addr': '2130', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Sonntag - # Schaltzeiten HK_A1M1 - 'Timer_A1M1_Mo': {'addr': '2000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag - 'Timer_A1M1_Di': {'addr': '2008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag - 'Timer_A1M1_Mi': {'addr': '2010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch - 'Timer_A1M1_Do': {'addr': '2018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag - 'Timer_A1M1_Fr': {'addr': '2020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag - 'Timer_A1M1_Sa': {'addr': '2028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag - 'Timer_A1M1_So': {'addr': '2030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag - # Schaltzeiten HK_M2 - 'Timer_M2_Mo': {'addr': '3000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag - 'Timer_M2_Di': {'addr': '3008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag - 'Timer_M2_Mi': {'addr': '3010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch - 'Timer_M2_Do': {'addr': '3018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag - 'Timer_M2_Fr': {'addr': '3020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag - 'Timer_M2_Sa': {'addr': '3028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag - 'Timer_M2_So': {'addr': '3030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag - }, - 'V200WO1C': { - # generelle Infos - 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # getAnlTyp -- Information - Allgemein: Anlagentyp (204D) - 'Aussentemperatur': {'addr': '0101', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempA -- Information - Allgemein: Aussentemperatur (-40..70) - # Anlagenstatus - 'Betriebsart': {'addr': 'b000', 'len': 1, 'unit': 'BA', 'set': True}, # getBetriebsart -- Bedienung HK1 - Heizkreis 1: Betriebsart (Textstring) - 'Manuell': {'addr': 'b020', 'len': 1, 'unit': 'IUNON', 'set': True, 'min_value': 0, 'max_value': 2}, # getManuell / setManuell -- 0 = normal, 1 = manueller Heizbetrieb, 2 = 1x Warmwasser auf Temp2 - 'Sekundaerpumpe': {'addr': '0484', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusSekP -- Diagnose - Anlagenuebersicht: Sekundaerpumpe 1 (0..1) - 'Heizkreispumpe': {'addr': '048d', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusPumpe -- Information - Heizkreis HK1: Heizkreispumpe (0..1) - 'Zirkulationspumpe': {'addr': '0490', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusPumpeZirk -- Information - Warmwasser: Zirkulationspumpe (0..1) - 'VentilHeizenWW': {'addr': '0494', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusVentilWW -- Diagnose - Waermepumpe: 3-W-Ventil Heizen WW1 (0 (Heizen)..1 (WW)) - 'Vorlaufsolltemp': {'addr': '1800', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempVLSoll -- Diagnose - Heizkreis HK1: Vorlaufsolltemperatur HK1 (0..95) - 'Outdoor_Fanspeed': {'addr': '1a52', 'len': 1, 'unit': 'IUNON', 'set': False}, # getSpdFanOut -- Outdoor Fanspeed - 'Status_Fanspeed': {'addr': '1a53', 'len': 1, 'unit': 'IUNON', 'set': False}, # getSpdFan -- Geschwindigkeit Luefter - 'Kompressor_Freq': {'addr': '1a54', 'len': 1, 'unit': 'IUNON', 'set': False}, # getSpdKomp -- Compressor Frequency - # Temperaturen - 'SolltempWarmwasser': {'addr': '6000', 'len': 2, 'unit': 'IS10', 'set': True, 'min_value': 10, 'max_value': 60}, # getTempWWSoll -- Bedienung WW - Betriebsdaten WW: Warmwassersolltemperatur (10..60 (95)) - 'VorlauftempSek': {'addr': '0105', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekVL -- Information - Heizkreis HK1: Vorlauftemperatur Sekundaer 1 (0..95) - 'RuecklauftempSek': {'addr': '0106', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekRL -- Diagnose - Anlagenuebersicht: Ruecklauftemperatur Sekundaer 1 (0..95) - 'Warmwassertemperatur': {'addr': '010d', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempWWIstOben -- Information - Warmwasser: Warmwassertemperatur oben (0..95) - # Stellwerte - 'Raumsolltemp': {'addr': '2000', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempRaumSollNormal -- Bedienung HK1 - Heizkreis 1: Raumsolltemperatur normal (10..30) - 'RaumsolltempReduziert': {'addr': '2001', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempRaumSollRed -- Bedienung HK1 - Heizkreis 1: Raumsolltemperatur reduzierter Betrieb (10..30) - 'HeizkennlinieNiveau': {'addr': '2006', 'len': 2, 'unit': 'IS10', 'set': False}, # getHKLNiveau -- Bedienung HK1 - Heizkreis 1: Niveau der Heizkennlinie (-15..40) - 'HeizkennlinieNeigung': {'addr': '2007', 'len': 2, 'unit': 'IS10', 'set': False}, # getHKLNeigung -- Bedienung HK1 - Heizkreis 1: Neigung der Heizkennlinie (0..35) - 'RaumsolltempParty': {'addr': '2022', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempRaumSollParty -- Bedienung HK1 - Heizkreis 1: Party Solltemperatur (10..30) - # Statistiken / Laufzeiten - 'EinschaltungenSekundaer': {'addr': '0504', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzQuelleSek -- Statistik - Schaltzyklen Anlage: Einschaltungen Sekundaerquelle (?) - 'EinschaltungenHeizstab1': {'addr': '0508', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzHeizstabSt1 -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizstab Stufe 1 (?) - 'EinschaltungenHeizstab2': {'addr': '0509', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzHeizstabSt2 -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizstab Stufe 2 (?) - 'EinschaltungenHK': {'addr': '050d', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzHK -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizkreis (?) - 'LZSekundaerpumpe': {'addr': '0584', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZPumpeSek -- Statistik - Betriebsstunden Anlage: Betriebsstunden Sekundaerpumpe (?) - 'LZHeizstab1': {'addr': '0588', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZHeizstabSt1 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Heizstab Stufe 1 (?) - 'LZHeizstab2': {'addr': '0589', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZHeizstabSt2 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Heizstab Stufe 2 (?) - 'LZPumpeHK': {'addr': '058d', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZPumpe -- Statistik - Betriebsstunden Anlage: Betriebsstunden Pumpe HK1 (0..1150000) - 'LZWWVentil': {'addr': '0594', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZVentilWW -- Statistik - Betriebsstunden Anlage: Betriebsstunden Warmwasserventil (?) - 'LZVerdichterStufe1': {'addr': '1620', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt1 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 1 (?) - 'LZVerdichterStufe2': {'addr': '1622', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt2 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 2 (?) - 'LZVerdichterStufe3': {'addr': '1624', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt3 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 3 (?) - 'LZVerdichterStufe4': {'addr': '1626', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt4 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 4 (?) - 'LZVerdichterStufe5': {'addr': '1628', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt5 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 5 (?) - 'VorlauftempSekMittel': {'addr': '16b2', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekVLMittel -- Statistik - Energiebilanz: mittlere sek. Vorlauftemperatur (0..95) - 'RuecklauftempSekMittel': {'addr': '16b3', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekRLMittel -- Statistik - Energiebilanz: mittlere sek.Temperatur RL1 (0..95) - 'OAT_Temperature': {'addr': '1a5c', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempOAT -- OAT Temperature - 'ICT_Temperature': {'addr': '1a5d', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempICT -- OCT Temperature - 'CCT_Temperature': {'addr': '1a5e', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempCCT -- CCT Temperature - 'HST_Temperature': {'addr': '1a5f', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempHST -- HST Temperature - 'OMT_Temperature': {'addr': '1a60', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempOMT -- OMT Temperature - 'LZVerdichterWP': {'addr': '5005', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZWP -- Statistik - Betriebsstunden Anlage: Betriebsstunden Waermepumpe (0..1150000) - 'SollLeistungVerdichter': {'addr': '5030', 'len': 1, 'unit': 'IUNON', 'set': False}, # getPwrSollVerdichter -- Diagnose - Anlagenuebersicht: Soll-Leistung Verdichter 1 (0..100) - 'WaermeWW12M': {'addr': '1660', 'len': 4, 'unit': 'IU10', 'set': False}, # Wärmeenergie für WW-Bereitung der letzten 12 Monate (kWh) - 'ElektroWW12M': {'addr': '1670', 'len': 4, 'unit': 'IU10', 'set': False}, # elektr. Energie für WW-Bereitung der letzten 12 Monate (kWh) - }, -} - -unitset = { - 'P300': { - 'BA': {'unit_de': 'Betriebsart', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: BA - 'CT': {'unit_de': 'CycleTime', 'type': 'timer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: CT - 'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: DT - 'ES': {'unit_de': 'ErrorState', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ES - 'IU2': {'unit_de': 'INT unsigned 2', 'type': 'integer', 'signed': False, 'read_value_transform': '2'}, # vito unit: UT1U, PR1 - 'IU10': {'unit_de': 'INT unsigned 10', 'type': 'integer', 'signed': False, 'read_value_transform': '10'}, # vito unit: - 'IU100': {'unit_de': 'INT unsigned 100', 'type': 'integer', 'signed': False, 'read_value_transform': '100'}, # vito unit: - 'IU3600': {'unit_de': 'INT unsigned 3600', 'type': 'integer', 'signed': False, 'read_value_transform': '3600'}, # vito unit: CS - 'IUBOOL': {'unit_de': 'INT unsigned bool', 'type': 'integer', 'signed': False, 'read_value_transform': 'bool'}, # vito unit: - 'IUINT': {'unit_de': 'INT unsigned int', 'type': 'integer', 'signed': False, 'read_value_transform': '1'}, # vito unit: - 'IUNON': {'unit_de': 'INT unsigned non', 'type': 'integer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: UTI, CO - 'IS2': {'unit_de': 'INT signed 2', 'type': 'integer', 'signed': True, 'read_value_transform': '2'}, # vito unit: UT1, PR - 'IS10': {'unit_de': 'INT signed 10', 'type': 'integer', 'signed': True, 'read_value_transform': '10'}, # vito unit: UT, UN - 'IS100': {'unit_de': 'INT signed 100', 'type': 'integer', 'signed': True, 'read_value_transform': '100'}, # vito unit: - 'IS1000': {'unit_de': 'INT signed 1000', 'type': 'integer', 'signed': True, 'read_value_transform': '1000'}, # vito unit: - 'ISNON': {'unit_de': 'INT signed non', 'type': 'integer', 'signed': True, 'read_value_transform': 'non'}, # vito unit: - 'RT': {'unit_de': 'ReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ST, RT - 'SC': {'unit_de': 'SystemScheme', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'SN': {'unit_de': 'Sachnummer', 'type': 'serial', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'SR': {'unit_de': 'SetReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'TI': {'unit_de': 'SystemTime', 'type': 'datetime', 'signed': False, 'read_value_transform': 'non'}, # vito unit: TI - 'DA': {'unit_de': 'Date', 'type': 'date', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'HEX': {'unit_de': 'HexString', 'type': 'string', 'signed': False, 'read_value_transform': 'hex'}, # vito unit: - }, - 'KW': { - 'BA': {'unit_de': 'Betriebsart', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: BA - 'CT': {'unit_de': 'CycleTime', 'type': 'timer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: CT - 'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: DT - 'ES': {'unit_de': 'ErrorState', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ES - 'IU2': {'unit_de': 'INT unsigned 2', 'type': 'integer', 'signed': False, 'read_value_transform': '2'}, # vito unit: UT1U, PR1 - 'IU10': {'unit_de': 'INT unsigned 10', 'type': 'integer', 'signed': False, 'read_value_transform': '10'}, # vito unit: - 'IU100': {'unit_de': 'INT unsigned 100', 'type': 'integer', 'signed': False, 'read_value_transform': '100'}, # vito unit: - 'IU1000': {'unit_de': 'INT unsigned 1000', 'type': 'integer', 'signed': False, 'read_value_transform': '1000'}, # vito unit: - 'IU3600': {'unit_de': 'INT unsigned 3600', 'type': 'integer', 'signed': False, 'read_value_transform': '3600'}, # vito unit: CS - 'IUPR': {'unit_de': 'INT unsigned 2.55', 'type': 'integer', 'signed': False, 'read_value_transform': '2.55'}, # vito unit: PP - 'IUBOOL': {'unit_de': 'INT unsigned bool', 'type': 'integer', 'signed': False, 'read_value_transform': 'bool'}, # vito unit: - 'IUINT': {'unit_de': 'INT unsigned int', 'type': 'integer', 'signed': False, 'read_value_transform': '1'}, # vito unit: - 'IUNON': {'unit_de': 'INT unsigned non', 'type': 'integer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: UTI, CO - 'IS2': {'unit_de': 'INT signed 2', 'type': 'integer', 'signed': True, 'read_value_transform': '2'}, # vito unit: UT1, PR - 'IS10': {'unit_de': 'INT signed 10', 'type': 'integer', 'signed': True, 'read_value_transform': '10'}, # vito unit: UT, UN - 'IS100': {'unit_de': 'INT signed 100', 'type': 'integer', 'signed': True, 'read_value_transform': '100'}, # vito unit: - 'IS1000': {'unit_de': 'INT signed 1000', 'type': 'integer', 'signed': True, 'read_value_transform': '1000'}, # vito unit: - 'ISNON': {'unit_de': 'INT signed non', 'type': 'integer', 'signed': True, 'read_value_transform': 'non'}, # vito unit: - 'RT': {'unit_de': 'ReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ST, RT - 'BT': {'unit_de': 'Brennertyp', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'SC': {'unit_de': 'SystemScheme', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'SN': {'unit_de': 'Sachnummer', 'type': 'serial', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'SR': {'unit_de': 'SetReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'TI': {'unit_de': 'SystemTime', 'type': 'datetime', 'signed': False, 'read_value_transform': 'non'}, # vito unit: TI - 'DA': {'unit_de': 'Date', 'type': 'date', 'signed': False, 'read_value_transform': 'non'}, # vito unit: - 'HEX': {'unit_de': 'HexString', 'type': 'string', 'signed': False, 'read_value_transform': 'hex'}, # vito unit: - } -} - -errorset = { - 'P300': { - '00': 'Regelbetrieb (kein Fehler)', - '0F': 'Wartung (fuer Reset Codieradresse 24 auf 0 stellen)', - '10': 'Kurzschluss Aussentemperatursensor', - '18': 'Unterbrechung Aussentemperatursensor', - '19': 'Unterbrechung Kommunikation Außentemperatursensor RF', - '1D': 'Keine Kommunikation mit Sensor', - '1E': 'Strömungssensor defekt', - '1F': 'Strömungssensor defekt', - '20': 'Kurzschluss Vorlauftemperatursensor', - '21': 'Kurzschluss Ruecklauftemperatursensor', - '28': 'Unterbrechung Aussentemperatursensor / Vorlauftemperatursensor Anlage', - '29': 'Unterbrechung Ruecklauftemperatursensor', - '30': 'Kurzschluss Kesseltemperatursensor', - '38': 'Unterbrechung Kesseltemperatursensor', - '40': 'Kurzschluss Vorlauftemperatursensor M2', - '42': 'Unterbrechung Vorlauftemperatursensor M2', - '44': 'Kurzschluss Vorlauftemperatursensor Heizkreis 3', - '48': 'Unterbrechung Vorlauftemperatursensor Heizkreis 3', - '50': 'Kurzschluss Speichertemperatursensor', - '51': 'Kurzschluss Auslauftemperatursensor', - '58': 'Unterbrechung Speichertemperatursensor', - '59': 'Unterbrechung Auslauftemperatursensor', - '92': 'Solar: Kurzschluss Kollektortemperatursensor', - '93': 'Solar: Kurzschluss Sensor S3', - '94': 'Solar: Kurzschluss Speichertemperatursensor', - '9A': 'Solar: Unterbrechung Kollektortemperatursensor', - '9B': 'Solar: Unterbrechung Sensor S3', - '9C': 'Solar: Unterbrechung Speichertemperatursensor', - '9E': 'Solar: Zu geringer bzw. kein Volumenstrom oder Temperaturwächter ausgeloest', - '9F': 'Solar: Fehlermeldung Solarteil (siehe Solarregler)', - 'A4': 'Amx. Anlagendruck überschritten', - 'A7': 'Bedienteil defekt', - 'A8': 'Luft in der internen Umwaelzpumpe oder Mindest-Volumenstrom nicht erreicht', - 'B0': 'Kurzschluss Abgastemperatursensor', - 'B1': 'Kommunikationsfehler Bedieneinheit', - 'B4': 'Interner Fehler (Elektronik)', - 'B5': 'Interner Fehler (Elektronik)', - 'B6': 'Ungueltige Hardwarekennung (Elektronik)', - 'B7': 'Interner Fehler (Kesselkodierstecker)', - 'B8': 'Unterbrechung Abgastemperatursensor', - 'B9': 'Interner Fehler (Dateneingabe wiederholen)', - 'BA': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2', - 'BB': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis 3', - 'BC': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1', - 'BD': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2', - 'BE': 'Falsche Codierung Fernbedienung Vitorol', - 'BF': 'Falsches Kommunikationsmodul LON', - 'C1': 'Externe Sicherheitseinrichtung (Kessel kuehlt aus)', - 'C2': 'Kommunikationsfehler Solarregelung', - 'C3': 'Kommunikationsfehler Erweiterung AM1', - 'C4': 'Kommunikationsfehler Erweiterumg Open Therm', - 'C5': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1', - 'C6': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2', - 'C7': 'Falsche Codierung der Heizkreispumpe', - 'C8': 'Kommunikationsfehler drehzahlgeregelte, externe Heizkreispumpe 3', - 'C9': 'Stoermeldeeingang am Schaltmodul-V aktiv', - 'CD': 'Kommunikationsfehler Vitocom 100 (KM-BUS)', - 'CE': 'Kommunikationsfehler Schaltmodul-V', - 'CF': 'Kommunikationsfehler LON Modul', - 'D1': 'Brennerstoerung', - 'D4': 'Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt', - 'D6': 'Eingang DE1 an Erweiterung EA1 meldet eine Stoerung', - 'D7': 'Eingang DE2 an Erweiterung EA1 meldet eine Stoerung', - 'D8': 'Eingang DE3 an Erweiterung EA1 meldet eine Stoerung', - 'DA': 'Kurzschluss Raumtemperatursensor, Heizkreis M1', - 'DB': 'Kurzschluss Raumtemperatursensor, Heizkreis M2', - 'DC': 'Kurzschluss Raumtemperatursensor, Heizkreis 3', - 'DD': 'Unterbrechung Raumtemperatursensor, Heizkreis M1', - 'DE': 'Unterbrechung Raumtemperatursensor, Heizkreis M2', - 'DF': 'Unterbrechung Raumtemperatursensor, Heizkreis 3', - 'E0': 'Fehler externer LON Teilnehmer', - 'E1': 'Isolationsstrom waehrend des Kalibrierens zu hoch', - 'E3': 'Zu geringe Wärmeabnahme während des Kalibrierens, Temperaturwächter hat ausgeschaltet', - 'E4': 'Fehler Versorgungsspannung', - 'E5': 'Interner Fehler, Flammenverstärker(Ionisationselektrode)', - 'E6': 'Abgas- / Zuluftsystem verstopft, Anlagendruck zu niedrig', - 'E7': 'Ionisationsstrom waehrend des Kalibrierens zu gering', - 'E8': 'Ionisationsstrom nicht im gültigen Bereich', - 'EA': 'Ionisationsstrom waehrend des Kalibrierens nicht im gueltigen Bereich', - 'EB': 'Wiederholter Flammenverlust waehrend des Kalibrierens', - 'EC': 'Parameterfehler waehrend des Kalibrierens', - 'ED': 'Interner Fehler', - 'EE': 'Flammensignal ist bei Brennerstart nicht vorhanden oder zu gering', - 'EF': 'Flammenverlust direkt nach Flammenbildung (waehrend der Sicherheitszeit)', - 'F0': 'Interner Fehler (Regelung tauschen)', - 'F1': 'Abgastemperaturbegrenzer ausgeloest', - 'F2': 'Temperaturbegrenzer ausgeloest', - 'F3': 'Flammensigal beim Brennerstart bereits vorhanden', - 'F4': 'Flammensigal nicht vorhanden', - 'F7': 'Differenzdrucksensor defekt, Kurzschluss ider Wasserdrucksensor', - 'F8': 'Brennstoffventil schliesst zu spaet', - 'F9': 'Geblaesedrehzahl beim Brennerstart zu niedrig', - 'FA': 'Geblaesestillstand nicht erreicht', - 'FC': 'Gaskombiregler defekt oder fehlerhafte Ansteuerung Modulationsventil oder Abgasweg versperrt', - 'FD': 'Fehler Gasfeuerungsautomat, Kesselkodierstecker fehlt(in Verbindung mit B7)', - 'FE': 'Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt', - 'FF': 'Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler' - }, - 'KW': { - '00': 'Regelbetrieb (kein Fehler)', - '0F': 'Wartung (fuer Reset Codieradresse 24 auf 0 stellen)', - '10': 'Kurzschluss Aussentemperatursensor', - '18': 'Unterbrechung Aussentemperatursensor', - '19': 'Unterbrechung Kommunikation Außentemperatursensor RF', - '1D': 'Keine Kommunikation mit Sensor', - '1E': 'Strömungssensor defekt', - '1F': 'Strömungssensor defekt', - '20': 'Kurzschluss Vorlauftemperatursensor', - '21': 'Kurzschluss Ruecklauftemperatursensor', - '28': 'Unterbrechung Aussentemperatursensor / Vorlauftemperatursensor Anlage', - '29': 'Unterbrechung Ruecklauftemperatursensor', - '30': 'Kurzschluss Kesseltemperatursensor', - '38': 'Unterbrechung Kesseltemperatursensor', - '40': 'Kurzschluss Vorlauftemperatursensor M2', - '42': 'Unterbrechung Vorlauftemperatursensor M2', - '44': 'Kurzschluss Vorlauftemperatursensor Heizkreis 3', - '48': 'Unterbrechung Vorlauftemperatursensor Heizkreis 3', - '50': 'Kurzschluss Speichertemperatursensor', - '51': 'Kurzschluss Auslauftemperatursensor', - '58': 'Unterbrechung Speichertemperatursensor', - '59': 'Unterbrechung Auslauftemperatursensor', - '92': 'Solar: Kurzschluss Kollektortemperatursensor', - '93': 'Solar: Kurzschluss Sensor S3', - '94': 'Solar: Kurzschluss Speichertemperatursensor', - '9A': 'Solar: Unterbrechung Kollektortemperatursensor', - '9B': 'Solar: Unterbrechung Sensor S3', - '9C': 'Solar: Unterbrechung Speichertemperatursensor', - '9E': 'Solar: Zu geringer bzw. kein Volumenstrom oder Temperaturwächter ausgeloest', - '9F': 'Solar: Fehlermeldung Solarteil (siehe Solarregler)', - 'A4': 'Amx. Anlagendruck überschritten', - 'A7': 'Bedienteil defekt', - 'A8': 'Luft in der internen Umwaelzpumpe oder Mindest-Volumenstrom nicht erreicht', - 'B0': 'Kurzschluss Abgastemperatursensor', - 'B1': 'Kommunikationsfehler Bedieneinheit', - 'B4': 'Interner Fehler (Elektronik)', - 'B5': 'Interner Fehler (Elektronik)', - 'B6': 'Ungueltige Hardwarekennung (Elektronik)', - 'B7': 'Interner Fehler (Kesselkodierstecker)', - 'B8': 'Unterbrechung Abgastemperatursensor', - 'B9': 'Interner Fehler (Dateneingabe wiederholen)', - 'BA': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2', - 'BB': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis 3', - 'BC': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1', - 'BD': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2', - 'BE': 'Falsche Codierung Fernbedienung Vitorol', - 'BF': 'Falsches Kommunikationsmodul LON', - 'C1': 'Externe Sicherheitseinrichtung (Kessel kuehlt aus)', - 'C2': 'Kommunikationsfehler Solarregelung', - 'C3': 'Kommunikationsfehler Erweiterung AM1', - 'C4': 'Kommunikationsfehler Erweiterumg Open Therm', - 'C5': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1', - 'C6': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2', - 'C7': 'Falsche Codierung der Heizkreispumpe', - 'C8': 'Kommunikationsfehler drehzahlgeregelte, externe Heizkreispumpe 3', - 'C9': 'Stoermeldeeingang am Schaltmodul-V aktiv', - 'CD': 'Kommunikationsfehler Vitocom 100 (KM-BUS)', - 'CE': 'Kommunikationsfehler Schaltmodul-V', - 'CF': 'Kommunikationsfehler LON Modul', - 'D1': 'Brennerstoerung', - 'D4': 'Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt', - 'D6': 'Eingang DE1 an Erweiterung EA1 meldet eine Stoerung', - 'D7': 'Eingang DE2 an Erweiterung EA1 meldet eine Stoerung', - 'D8': 'Eingang DE3 an Erweiterung EA1 meldet eine Stoerung', - 'DA': 'Kurzschluss Raumtemperatursensor, Heizkreis M1', - 'DB': 'Kurzschluss Raumtemperatursensor, Heizkreis M2', - 'DC': 'Kurzschluss Raumtemperatursensor, Heizkreis 3', - 'DD': 'Unterbrechung Raumtemperatursensor, Heizkreis M1', - 'DE': 'Unterbrechung Raumtemperatursensor, Heizkreis M2', - 'DF': 'Unterbrechung Raumtemperatursensor, Heizkreis 3', - 'E0': 'Fehler externer LON Teilnehmer', - 'E1': 'Isolationsstrom waehrend des Kalibrierens zu hoch', - 'E3': 'Zu geringe Wärmeabnahme während des Kalibrierens, Temperaturwächter hat ausgeschaltet', - 'E4': 'Fehler Versorgungsspannung', - 'E5': 'Interner Fehler, Flammenverstärker(Ionisationselektrode)', - 'E6': 'Abgas- / Zuluftsystem verstopft, Anlagendruck zu niedrig', - 'E7': 'Ionisationsstrom waehrend des Kalibrierens zu gering', - 'E8': 'Ionisationsstrom nicht im gültigen Bereich', - 'EA': 'Ionisationsstrom waehrend des Kalibrierens nicht im gueltigen Bereich', - 'EB': 'Wiederholter Flammenverlust waehrend des Kalibrierens', - 'EC': 'Parameterfehler waehrend des Kalibrierens', - 'ED': 'Interner Fehler', - 'EE': 'Flammensignal ist bei Brennerstart nicht vorhanden oder zu gering', - 'EF': 'Flammenverlust direkt nach Flammenbildung (waehrend der Sicherheitszeit)', - 'F0': 'Interner Fehler (Regelung tauschen)', - 'F1': 'Abgastemperaturbegrenzer ausgeloest', - 'F2': 'Temperaturbegrenzer ausgeloest', - 'F3': 'Flammensigal beim Brennerstart bereits vorhanden', - 'F4': 'Flammensigal nicht vorhanden', - 'F7': 'Differenzdrucksensor defekt, Kurzschluss ider Wasserdrucksensor', - 'F8': 'Brennstoffventil schliesst zu spaet', - 'F9': 'Geblaesedrehzahl beim Brennerstart zu niedrig', - 'FA': 'Geblaesestillstand nicht erreicht', - 'FC': 'Gaskombiregler defekt oder fehlerhafte Ansteuerung Modulationsventil oder Abgasweg versperrt', - 'FD': 'Fehler Gasfeuerungsautomat, Kesselkodierstecker fehlt(in Verbindung mit B7)', - 'FE': 'Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt', - 'FF': 'Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler' - }, -} - -operatingmodes = { - 'V200KW2': { - '00': 'Warmwasser (Schaltzeiten)', - '01': 'reduziert Heizen (dauernd)', - '02': 'normal Heizen (dauernd)', - '04': 'Heizen und Warmwasser (FS)', - '03': 'Heizen und Warmwasser (Schaltzeiten)', - '05': 'Standby', - }, - 'V200KO1B': { - '00': 'Warmwasser (Schaltzeiten)', - '01': 'reduziert Heizen (dauernd)', - '02': 'normal Heizen (dauernd)', - '04': 'Heizen und Warmwasser (FS)', - '03': 'Heizen und Warmwasser (Schaltzeiten)', - '05': 'Standby', - }, - 'aktuelle_Betriebsart': { - '00': 'Abschaltbetrieb', - '01': 'Reduzierter Betrieb', - '02': 'Normalbetrieb', - '03': 'Dauernd Normalbetrieb', - }, - 'V200WO1C': { - '00': 'Abschaltbetrieb', - '01': 'Warmwasser', - '02': 'Heizen und Warmwasser', - '03': 'undefiniert', - '04': 'dauernd reduziert', - '05': 'dauernd normal', - '06': 'normal Abschalt', - '07': 'nur kühlen', - }, - 'V200HO1C': { - '00': 'Abschaltbetrieb', - '01': 'Warmwasser', - '02': 'Heizen und Warmwasser', - '03': 'Normal reduziert', - '04': 'Normal dauernd' - } -} - -systemschemes = { - 'V200KW2': { - '00': '-', - '01': 'A1', - '02': 'A1 + WW', - '03': 'M2', - '04': 'M2 + WW', - '05': 'A1 + M2', - '06': 'A1 + M2 + WW', - '07': 'M2 + M3', - '08': 'M2 + M3 + WW', - '09': 'M2 + M3 + WW', - '10': 'A1 + M2 + M3 + WW' - }, - 'V200KO1B': { - '01': 'A1', - '02': 'A1 + WW', - '04': 'M2', - '03': 'M2 + WW', - '05': 'A1 + M2', - '06': 'A1 + M2 + WW' - }, - 'V200WO1C': { - '01': 'WW', - '02': 'HK + WW', - '04': 'HK + WW', - '05': 'HK + WW' - }, - 'V200HO1C': { - '01': 'WW', - '02': 'HK + WW', - '04': 'HK + WW', - '05': 'HK + WW' - } -} - -devicetypes = { - '2098': 'V200KW2', # Protokoll: KW - '2053': 'GWG_VBEM', # Protokoll: GWG - '20CB': 'VScotHO1', # Protokoll: P300 - '2094': 'V200KW1', # Protokoll: KW - '209F': 'V200KO1B', # Protokoll: P300 - '204D': 'V200WO1C', # Protokoll: P300 - '20B8': 'V333MW1', - '20A0': 'V100GC1', - '20C2': 'VDensHO1', - '20A4': 'V200GW1', - '20C8': 'VPlusHO1', - '2046': 'V200WO1', - '2047': 'V200WO1', - '2049': 'V200WO1', - '2032': 'VBC550', - '2033': 'VBC550' -} - -returnstatus = { - 'P300': { - '00': '0', - '01': '1', - '03': '2', - 'AA': 'NOT OK', - # At least for device 20CB the heating circuit pump returns status 03 when it's on and the heating runs in in night mode - }, - 'KW': { - '00': '0', - '01': '1', - '03': '2', - 'AA': 'NOT OK', - }, -} - -setreturnstatus = { - 'P300': { - '00': 'OK', - '05': 'SYNC (NOT OK)', - }, - 'KW': { - '00': 'OK', - '05': 'SYNC (NOT OK)', - }, -} - - -# P300 Protokoll -# -# Beispiel -# -# Senden 41 5 0 1 55 25 2 82 -# Read Request -- - - - ----- - -- -# | | | | | | +------- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex -# | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden -# | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur -# | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call -# | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler -# | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) -# +------------------------ Telegramm-Start-Byte -# -# Empfangen : 6 ----------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) -# 5 ----------------------- Schnittstelle ist aktiv und wartet auf eine Initialisierung -# 15 ----------------------- Schnittstelle meldet einen Fehler zurück -# -# 41 7 1 1 55 25 2 EF 0 74 -# -- - - - ----- - ---- -- -# | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) -# | | | | | | +------ Wert -# | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden -# | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur -# | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call -# | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler -# | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) -# +------------------------ Telegramm-Start-Byte -# Kommunikationsbeispiele -# Information Kessel Außentemperatur read 2-Byte -60..60 0x5525 -# DATA TX: 41 5 0 1 55 25 2 82 -# DATA RX: 41 7 1 1 55 25 2 EF 0 74 --> 00EF = 239 --> 23.9°C (Faktor 0.1) -# --> Senden 41 5 0 1 55 25 2 82 -# -- - - - ----- - -- -# | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex -# | | | | | +----- XX Anzahl der Bytes, die in der Antwort erwartet werden -# | | | | +--------- XX XX 2 byte Adresse der Daten oder Prozedur -# | | | +------------- XX 01 = ReadData, 02 = WriteData, 07 = Function Call -# | | +--------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler -# | +----------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) -# +------------------- Telegramm-Start-Byte -# -# --> Empfangen 6 41 7 1 1 55 25 2 EF 0 74 -# - -- - - - ----- - ---- -- -# | | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) -# | | | | | | | +------ Wert -# | | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden -# | | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur -# | | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call -# | | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler -# | | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) -# | +------------------------ Telegramm-Start-Byte -# +--------------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) -# -# --> Antwort: 0x00EF = 239 = 23.9° diff --git a/viessmann/_pv_1_2_3/plugin.yaml b/viessmann/_pv_1_2_3/plugin.yaml deleted file mode 100755 index a77d0a8ed..000000000 --- a/viessmann/_pv_1_2_3/plugin.yaml +++ /dev/null @@ -1,231 +0,0 @@ -%YAML 1.1 -# vim: set et ts=4 sts=4 sw=4 ai ff=unix nu wrap : ---- - -# Metadata for the Smart-Plugin -plugin: - # Global plugin attributes - type: interface # plugin type (gateway, interface, protocol, system, web) - description: - de: 'Lesen und Schreiben von Werten einer Viessmann Heizung' - en: 'Read and write data of a Viessmann heating system' - maintainer: Morg - tester: sisamiwe, tcr82 - keywords: viessmann heating optolink - state: ready # change to ready when done with development - version: 1.2.3 # Plugin version - sh_minversion: 1.6.0 # minimum shNG version to use this plugin - py_minversion: 3.6 - multi_instance: false # plugin supports multi instance - restartable: true - classname: Viessmann # class containing the plugin - support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1455991-viessmann-plugin-neuentwicklung-python-hilfe/ - -parameters: - # Definition of parameters to be configured in etc/plugin.yaml - serialport: - type: str - default: '' - description: - de: 'Serieller Port, an dem der Lesekopf angeschlossen ist' - en: 'Serial port the device is connected to' - - heating_type: - type: str - default: '' - description: - de: 'Gerätetype der Heizung' - en: 'Device type of heating system' - - protocol: - type: str - default: 'P300' - valid list: - - 'P300' - - 'KW' - description: - de: 'Protokoll der Heizung' - en: 'Protocol of heating system' - - timeout: - type: num - default: 1.5 - description: - de: 'Zeitbegrenzung für das Lesen vom seriellen Port in Sekunden' - en: 'Timeout for serial read operations in seconds' - -item_attributes: - # Definition of item attributes defined by this plugin - viess_send: - type: str - description: - de: 'Änderung des Items wird mit konfiguriertem Kommando an die Heizung geschickt' - en: 'Changes to this item result in sending the configured command to the heating system' - - viess_read: - type: str - description: - de: 'Liest Wert mit konfiguriertem Kommando aus der Heizung aus' - en: 'The item value should be read by using the configured command' - - viess_read_afterwrite: - type: num - description: - de: 'Konfiguriert eine Verzögerung in Sekunden nachdem ein Lesekommando nach einem Schreibkommando an die Heizung geschickt wird' - en: 'Configures delay in seconds to issue a read command after write command' - - viess_read_cycle: - type: num - description: - de: 'Konfiguriert ein Intervall in Sekunden für das Lesekommando' - en: 'Configures a interval in seconds for the read command' - - viess_init: - type: bool - description: - de: 'Konfiguriert, ob der Wert aus der Heizung initialisiert werden soll' - en: 'Configures to initialize the item value with the value from the KWL system' - - viess_trigger: - type: list(str) - description: - de: 'Konfiguriert Lesekommandos, die nach einem Schreibvorgang auf das Item aufgerufen werden' - en: 'Configures read commands after an update to the item' - - viess_trigger_afterwrite: - type: num - description: - de: 'Konfiguriert eine Verzögerung in Sekunden, bis ein Trigger ausgeführt werden soll, nachdem ein Wert gesetzt wurde' - en: 'Configures delay in seconds to run trigger commands after item update' - - viess_update: - type: bool - description: - de: 'Liest alle konfigurierten Items neu, wenn es auf True gesetzt wird' - en: 'Triggers reading of all configured items if set to True' - - viess_timer: - type: str - description: - de: 'Liest alle Timer zur übergebenen Anwendung (z.B. Heizkreis_A1M1) und stellt diese für die Nutzung mit UZSU zur Verfügung' - en: 'Provides an UZSU-compatible dict with all timers for the given application (e.g. Heizkreis_A1M1)' - - viess_ba_list: - type: bool - description: - de: 'Gibt nach der Initialisierung eine Liste aller für die konfigurierte Heizung gültigen Betriebsarten zurück' - en: 'Returns a list of valid operating modes for the configured device type after initialization' - -item_structs: - timer: - name: Schaltzeiten in Einzelzeiten fuer An und Aus - - an1: - name: erste Anschaltzeit - type: str - visu_acl: rw - - aus1: - name: erste Ausschaltzeit - type: str - visu_acl: rw - - an2: - name: zweite Anschaltzeit - type: str - visu_acl: rw - - aus2: - name: zweite Ausschaltzeit - type: str - visu_acl: rw - - an3: - name: dritte Anschaltzeit - type: str - visu_acl: rw - - aus3: - name: dritte Ausschaltzeit - type: str - visu_acl: rw - - an4: - name: vierte Anschaltzeit - type: str - visu_acl: rw - - aus4: - name: vierte Ausschaltzeit - type: str - visu_acl: rw - - betriebsart: - name: Betriebsart in string wandeln - - betriebsart_str: - type: str - eval: "'Neustart' if value == '' else ['Standby', 'Warmwasser (Schaltzeiten)', 'Heizen und Warmwasser (Schaltzeiten)', 'reduziert Heizen (dauernd)', 'normal Heizen (dauernd)'][int(value)]" - eval_trigger: .. - -logic_parameters: NONE -# Definition of logic parameters defined by this plugin - -plugin_functions: - update_all_read_items: - type: NONE - description: - de: 'Stößt das Lesen aller konfigurierten Items an' - en: 'Triggers reading of all configured items' - read_addr: - type: foo - description: - de: 'Stößt das Lesen des angegebenen Datenpunkts an, der nicht an ein Item gebunden sein muss. Es erfolgt keine Zuweisung an ein Item. Rückgabewert ist der gelesene Wert, oder NONE bei Fehler' - en: 'Triggers reading of the supplied data point, which doesn''t have to be bound to an item. Result will not be assigned to an item. Return value is the read value, or NONE if an error occurred' - parameters: - addr: - type: str - description: - de: 'Vierstellige Hex-Adresse des Datenpunktes' - en: 'Four-digit hex address of the data point' - read_temp_addr: - type: foo - description: - de: 'Stößt das Lesen eines beliebigen Datenpunkts an, der nicht konfiguriert oder bekannt sein muss. Es erfolgt keine Zuweisung an ein Item. Rückgabewert ist der gelesene Wert, oder NONE bei Fehler' - en: 'Triggers reading of an arbitrary data point, which doesn''t have to be configured or known. Result will not be assigned to an item. Return value is the read value, or NONE if an error occurred' - parameters: - addr: - type: str - mandatory: yes - description: - de: 'Vierstellige Hex-Adresse des Datenpunktes' - en: 'Four-digit hex address of the data point' - length: - type: int - mandatory: yes - description: - de: 'Länge der Geräteantwort in Bytes (1-8)' - en: 'Lengh of device response in bytes (1-8)' - valid_min: 1 - valid_max: 8 - unit: - type: str - mandatory: yes - description: - de: 'Einheitencode für die Konvertierung der Antwort. Muss in der Protokollkonfiguration ``unitset`` in commands.py definiert sein' - en: 'Unit code for converting the response value. Needs to be defined in the protocol configuration ``unitset`` in commands.py' - write_addr: - type: foo - description: - de: 'Stößt das Schreiben des angegebenen Datenpunkts an, der nicht an ein Item gebunden sein muss. Der übergebene Wert muss zum konfigurierten Datentyp passen' - en: 'Triggers writing of the supplied data point, which doesn''t have to be bound to an item. The submitted value must match the configured data type' - parameters: - addr: - type: str - description: - de: 'Vierstellige Hex-Adresse des Datenpunktes' - en: 'Four-digit hex address of the data point' - value: - description: - de: 'Zu schreibender Wert' - en: 'Value to be written' diff --git a/viessmann/_pv_1_2_3/user_doc.rst b/viessmann/_pv_1_2_3/user_doc.rst deleted file mode 100755 index c9147d140..000000000 --- a/viessmann/_pv_1_2_3/user_doc.rst +++ /dev/null @@ -1,443 +0,0 @@ -.. index:: Plugins; viessmann -.. index:: viessmann - -========= -viessmann -========= - -.. image:: webif/static/img/plugin_logo.svg - :alt: plugin logo - :width: 300px - :height: 300px - :scale: 50 % - :align: left - -Das Viessmann-Plugin ermöglicht die Verbindung zu einer Viessmann-Heizung über einen IR-Adapter (z.B. Optolink oder Nachbauten, wie im OpenV-Wiki beschrieben) und das Lesen und Schreiben von Parametern der Heizung. -Derzeit sind das P300- und das KW-Protokoll unterstützt. Weitere Gerätetypen, die diese Protokolle unterstützen, können einfach hinzugefügt werden. Für weitere Protokolle (z.B. GWG) wird zusätzliche Entwicklungsarbeit notwendig sein. - -Details zu den betroffenen Geräten und Protokollen finden sich im -.. _OpenV-Wiki: https://github.com/openv/openv/wiki/vcontrold - -Dieses Plugin nutzt eine separate Datei ``commands.py``, in der die Definitionen für Protokolle, Gerätetypen und Befehlssätze enthalten sind. Neue Geräte können hinzugefügt werden, indem die entsprechenden Informationen in der ``commands.py`` ergänzt werden. - -Das Plugin unterstützt die serielle Kommunikation mit dem Lesekopf (ggf. über einen USB-Seriell-Adapter). - -Zur Identifizierung des Heizungstyps kann das Plugin auch im Standalone-Modus betrieben werden (s.u.) - -Changelog ---------- - -1.2.2 -~~~~~ - -- Funktion zum manuellen Schreiben von Werten hinzugefügt - -1.2.0 -~~~~~ - -- Komplette Überarbeitung von Code und Webinterface (AJAX) -- Code refaktorisiert und besser strukturiert -- Funktion zum Lesen mehrerer Werte gleichzeitig im KW-Protokoll -- Verbesserte Fehler- und Locking-Behandlung -- Funktionen zum manuellen Auslesen von konfigurierten und unbekannten Adressen, z.B. zum Testen von Adressen -- Webinterface mit der Möglichkeit, Adressen manuell auszulesen - -1.1.0 -~~~~~ - -- Unterstützung für das KW-Protokoll - -1.0.0 -~~~~~ - -- Erste Version - -Anforderungen -============= - -Das Plugin benötigt die ``pyserial``-Bibliothek und einen seriellen IR-Adapter. - -Unterstützte Geräte -------------------- - -Jede Viessmann-Heizung mit Optolink-Anschluss wird grundsätzlich unterstützt. - -Derzeit sind Gerätekonfigurationen (Befehlssätze) für die folgenden Type verfügbar: - -- V200KO1B -- V200HO1C -- V200KW2 -- V200WO1C - -Weitere Gerätetypen können problemlos hinzugefügt werden, wenn die entsprechenden Befehlsadressen bekannt sind. - -Konfiguration -============= - -Diese Plugin Parameter und die Informationen zur Item-spezifischen Konfiguration des Plugins sind -unter :doc:`/plugins_doc/config/viessmann` beschrieben. - - -plugin.yaml ------------ - -.. code:: yaml - - viessmann: - protocol: P300 - plugin_name: viessmann - heating_type: V200KO1B - serialport: /dev/ttyUSB_optolink - - -items.yaml ----------- - -Die Verknüfpung von SmartHomeNG-Items und Heizungsparametern ist vollständig flexibel und konfigurierbar. Mit den Item-Attributen kann das Verhalten des Plugins festgelegt werden. - -Die folgenden Attribute werden unterstützt: - - -viess\_read -~~~~~~~~~~~ - -Der Wert des angegebenen Parameters wird gelesen und dem Item zugewiesen. - -.. code:: yaml - - item: - viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 - - -viess\_send -~~~~~~~~~~~ - -Der angegebene Parameter wird bei Änderungen an diesem Item an die Heizung gesendet. - -.. code:: yaml - - item: - viess_send: Raumtemperatur_Soll_Normalbetrieb_A1M1 - -Sofern das Item sowohl zum Lesen als auch zum Schreiben eines Parameters konfiguriert wird, kann die vereinfachte Konfiguration mit ``true`` erfolgen: - -.. code:: yaml - - item: - viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 - viess_send: true - - -viess\_read\_afterwrite -~~~~~~~~~~~~~~~~~~~~~~~ - -Wenn dieses Attribut mit einer Dauer in Sekunden angegeben ist, wird nach eine Schreibvorgang die angegebene Anzahl an Sekunden gewartet und ein erneuter Lesevorgang ausgelöst. - -Damit dieses Attribut verwendet werden kann, muss das Item sowohl die Attribute ``viess_read`` als auch ``viess_send`` enthalten. - -.. code:: yaml - - item: - viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 - viess_send: true - viess_read_afterwrite: 1 # seconds - - -viess\_read\_cycle -~~~~~~~~~~~~~~~~~~ - -Mit einer Angabe in Sekunden wird ein periodisches Lesen angefordert. ``viess_read`` muss zusätzlich konfiguriert sein. - -.. code:: yaml - - item: - viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 - viess_read_cycle: 3600 # every hour - - -viess\_init -~~~~~~~~~~~ - -Wenn dieses Attribut vorhanden und auf ``true`` gesetzt ist, wird das Item nach dem Start von SmartHomeNG einmalig gelesen. -``viess_read`` muss zusätzlich konfiguriert sein. - -.. code:: yaml - - item: - viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 - viess_init: true - - -viess\_trigger -~~~~~~~~~~~~~~ - -Enthält eine Liste von Parametern. Wenn dieses Item aktualisiert wird, wird ein Lesevorgang für jeden Eintrag in der Liste angestoßen. ``viess_send`` muss zusätzlich konfiguriert sein. - -Zwischen dem Schreibvorgang und den folgenden Lesevorgängen ist standardmäßig eine Verzögerung von 5 Sekunden eingestellt. Diese kann mit ``viess_trigger_afterwrite`` verändert werden. - -Beispiel: wenn der Betriebsmodus geändert wird, können neue Sollwerte für Raum- und Wassertemperaturen gelesen werden. - -.. code:: yaml - - item: - viess_send: Betriebsart_A1M1 - viess_trigger: - - Raumtemperatur_Soll - - Wassertemperatur_Soll - - -viess\_trigger\_afterwrite -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Wenn ein ``viess_trigger`` konfiguriert ist, kann mit diesem Attribut die Verzögerung zwischen Schreib- und Lesevorgang verändert werden. - -Standardmäßig beträgt diese Verzögerung 5 Sekunden. - -.. code:: yaml - - item: - viess_send: Betriebsart_A1M1 - viess_trigger: - - Raumtemperatur_Soll - - Wassertemperatur_Soll - viess_trigger_afterwrite: 10 # seconds - - -viess\_update -~~~~~~~~~~~~~ -Das Zuweisen von ``true`` an ein Item mit diesem Attribut löst den Lesevorgang aller konfigurierter Items mit ``viess_read`` aus. - -Der in der Itemkonfiguration angegebene Wert wird nicht ausgewertet. - -.. code:: yaml - - item: - viess_update: 'egal' - - -viess\_timer -~~~~~~~~~~~~ -Das Item mit diesem Attribut übergibt als Attributwert den Namen einer Anwendung, z.B. Heizkreis_A1M1, und das Plugin gibt ein UZSU-formatiertes dict mit allen zugehörigen Timern der Heizung zurück -Beim Schreiben wird das UZSU-dict in die einzelnen Tagestimer aufgeteilt und an die Heizung gesendet. - -.. code:: yaml - - item: - viess_timer: 'Heizkreis_A1M1' - - -viess\_ba\_list -~~~~~~~~~~~~~~~ -Das Item mit diesem Attribut erhält einmalig beim Start des Plugins die Liste der für den konfigurierten Heizungstyp gültigen Betriebsarten. - -Diese kann z.B. in SmartVISU wie folgt eingebunden werden: - -.. code:: yaml - - item: - viess_ba_list: 'egal' - -.. code:: - - {{ basic.select('heizen_ba_item', 'heizung.betriebsart', 'menu', '', '', '', '', '', 'heizung.ba_list') }} - -Dies erzeugt eine ("Menü"-) Auswahlliste, aus der die Betriebsart ausgewählt werden kann, die dann vom Plugin an die Heizung übergeben wird. - - -Beispiel --------- - -Here you can find a configuration sample using the commands for -V200KO1B: - -.. code:: yaml - - viessmann: - viessmann_update: - name: Update aller Items mit 'viess_read' - type: bool - visu_acl: rw - viess_update: 1 - enforce_updates: true - autotimer: 1 = false = latest - - allgemein: - aussentemp: - name: Aussentemperatur - type: num - viess_read: Aussentemperatur - viess_read_cycle: 300 - viess_init: true - database: true - - aussentemp_gedaempft: - name: Aussentemperatur - type: num - viess_read: Aussentemperatur_TP - viess_read_cycle: 300 - viess_init: true - database: true - - kessel: - kesseltemperatur_ist: - name: Kesseltemperatur_Ist - type: num - viess_read: Kesseltemperatur - viess_read_cycle: 180 - viess_init: true - database: init - kesseltemperatur_soll: - name: Kesselsolltemperatur_Soll - type: num - viess_read: Kesselsolltemperatur - viess_read_cycle: 180 - viess_init: true - abgastemperatur: - name: Abgastemperatur - type: num - viess_read: Abgastemperatur - viess_read_cycle: 180 - viess_init: true - database: init - heizkreis_a1m1: - betriebsart: - betriebsart_aktuell: - name: Aktuelle_Betriebsart_A1M1 - type: str - viess_read: Aktuelle_Betriebsart_A1M1 - viess_read_cycle: 3600 - viess_init: true - betriebsart: - name: Betriebsart_A1M1 - type: num - viess_read: Betriebsart_A1M1 - viess_send: true - viess_read_afterwrite: 5 - viess_init: true - cache: true - enforce_updates: true - viess_trigger: - - Aktuelle_Betriebsart_A1M1 - struct: viessmann.betriebsart - visu_acl: rw - sparbetrieb: - name: Sparbetrieb_A1M1 - type: bool - viess_read: Sparbetrieb_A1M1 - viess_send: true - viess_read_afterwrite: 5 - viess_trigger: - - Betriebsart_A1M1 - - Aktuelle_Betriebsart_A1M1 - viess_init: true - visu_acl: rw - schaltzeiten: - montag: - name: Timer_A1M1_Mo - type: list - viess_read: Timer_A1M1_Mo - viess_send: true - viess_read_afterwrite: 5 - viess_init: true - struct: viessmann.timer - visu_acl: rw - dienstag: - name: Timer_A1M1_Di - type: list - viess_read: Timer_A1M1_Di - viess_send: true - viess_read_afterwrite: 5 - viess_init: true - struct: viessmann.timer - visu_acl: rw - ferienprogramm: - status: - name: Ferienprogramm_A1M1 - type: num - viess_read: Ferienprogramm_A1M1 - viess_read_cycle: 3600 - viess_init: true - starttag: - name: Ferien_Abreisetag_A1M1 - type: str - viess_read: Ferien_Abreisetag_A1M1 - viess_send: true - viess_read_afterwrite: 5 - viess_init: true - visu_acl: rw - eval: value[:10] - endtag: - name: Ferien_Rückreisetag_A1M1 - type: str - viess_read: Ferien_Rückreisetag_A1M1 - viess_send: true - viess_read_afterwrite: 5 - viess_init: true - visu_acl: rw - - -Funktionen -========== - -update\_all\_read\_items() --------------------------- - -Diese Funktion stößt den Lesevorgang aller konfigurierten Items mit ``viess_read``-Attribut an. - - -read\_addr(addr) ----------------- - -Diese Funktion löst das Lesen des Parameters mit der übergebenen Adresse ``addr`` aus. Die Adresse muss als vierstellige Hex-Zahl im String-Format übergeben werden. Es können nur Adressen ausgelesen werden, die im Befehlssatz für den aktiven Heizungstyp enthalten sind. Unabhängig von der Itemkonfiguration werden durch ``read_addr()`` keine Werte an Items zugewiesen. -Der Rückgabewert ist das Ergebnis des Lesevorgangs oder None, wenn ein Fehler aufgetreten ist. - - -read\_temp\_addr(addr, length, unit) ------------------------------------- - -Diese Funktion versucht, den Parameter an der Adresse ``addr`` zu lesen und einen Wert von ``length`` Bytes in die Einheit ``unit`` zu konvertieren. Die Adresse muss als vierstellige Hex-Zahl im String-Format übergeben werden, im Gegensatz zu ``read_addr()`` aber nicht im Befehlssatz definiert sein. ``length`` ist auf Werte zwischen 1 und 8 (Bytes) beschränkt. ``unit`` muss im aktuellen Befehlssatz definiert sein. -Der Rückgabewert ist das Ergebnis des Lesevorgangs oder None, wenn ein Fehler aufgetreten ist. - - -write\_addr(addr, value) ------------------------- - -Diese Funktion versucht, den Wert ``value`` an die angegebene Adresse zu schreiben. Die Adresse muss als vierstellige Hex-Zahl im String-Format übergeben werden. Es können nur Adressen beschrieben werden, die im Befehlssatz für den aktiven Heizungstyp enthalten sind. Durch ``write_addr`` werden Itemwerte nicht direkt geändert; wenn die geschriebenen Werte von der Heizung wieder ausgelesen werden (z.B. durch zyklisches Lesen), werden die geänderten Werte in die entsprechenden Items übernommen. - - -:Warning: Das Schreiben von beliebigen Werten oder Werten, deren Bedeutung nicht klar ist, kann im Heizungsgerät möglicherweise unerwartete Folgen haben. Auch eine Beschädigung der Heizung ist nicht auszuschließen. - - -:Note: Wenn eine der Plugin-Funktionen in einer Logik verwendet werden sollen, kann dies in der folgenden Form erfolgen: - -.. code::yaml - - result = sh.plugins.return_plugin('viessmann').read_temp_addr('00f8', 2, 'DT') - - -Web Interface -============= - -Im Web-Interface gibt es neben den allgemeinen Statusinformationen zum Plugin zwei Seiten. - -Auf einer Seite werden die Items aufgelistet, die Plugin-Attributen konfiguriert haben. Damit kann eine schnelle Übersicht über die Konfiguration und die aktuellen Werte geboten werden. - -Auf der zweiten Seite werden alle im aktuellen Befehlssatz enthaltenen Parameter aufgelistet. Dabei besteht für jeden Wert einzeln die Möglichkeit, einen Lesevorgang auszulösen. Die Rückgabewerte werden in die jeweilige Tabellenzeile eingetragen. Dieser entspricht der Funktion ``read_addr()``, d.h. es werden keine Item-Werte aktualisiert. - -Weiterhin kann in der Zeile für den Parameter "_Custom" eine freie Adresse angegeben werden, die analog zur Funktion ``read_temp_addr()`` einen Lesevorgang auf beliebigen Adressen erlaubt. Auch hier wird der Rückgabewert in die jeweilige Tabellenzeile eingetragen. Damit wird ermöglicht, ohne großen Aufwand Datenpunkte und deren Konfiguration (Einheit und Datenlänge) zu testen. - - -Standalone-Modus -================ - -Wenn der Heizungstyp nicht bekannt ist, kann das Plugin im Standalone-Modus (also ohne SmartHomeNG zu starten) genutzt werden. Es versucht dann, mit der Heizung zu kommunizieren und den Gerätetyp zu identizifieren. - -Dazu muss das Plugin im Plugin-Ordner direkt aufgerufen werden: - -``./__init__.py [-v]`` - -Der serielle Port ist dabei die Gerätedatei bzw. der entsprechende Port, an dem der Lesekopf angeschlossen ist, z.B. ``/dev/ttyUSB0``. Dieses Argument ist verpflichtend. - -Das optionale zweite Argument `-v` weist das Plugin an, zusätzliche Debug-Ausgaben zu erzeugen. Solange keine Probleme beim Aufruf auftreten, ist das nicht erforderlich. - -Sollte die Datei sich nicht starten lassen, muss ggf. der Dateimodus angepasst werden. Mit ``chmod u+x __init__.py`` kann die z.B. unter Linux erfolgen. \ No newline at end of file diff --git a/viessmann/_pv_1_2_3/webif/static/img/plugin_logo.svg b/viessmann/_pv_1_2_3/webif/static/img/plugin_logo.svg deleted file mode 100755 index 16c50e23d..000000000 --- a/viessmann/_pv_1_2_3/webif/static/img/plugin_logo.svg +++ /dev/null @@ -1 +0,0 @@ -Element 1 \ No newline at end of file diff --git a/viessmann/_pv_1_2_3/webif/templates/index.html b/viessmann/_pv_1_2_3/webif/templates/index.html deleted file mode 100755 index d522eeefb..000000000 --- a/viessmann/_pv_1_2_3/webif/templates/index.html +++ /dev/null @@ -1,264 +0,0 @@ - -{% extends "base_plugin.html" %} -{% set tabcount = 2 %} -{% set tab1title = _('Viessmann Items') %} -{% set tab2title = _('Alle Datenpunkte') %} -{% set language = p.get_sh().get_defaultlanguage() %} -{% if last_read_cmd != "" %} -{% set start_tab = 3 %} -{% endif %} -{% if language not in ['en','de'] %} -{% set language = 'en' %} -{% endif %} - -{% block pluginscripts %} -/* - * The combined file was created by the DataTables downloader builder: - * https://datatables.net/download - * - * To rebuild or modify this file with the latest versions of the included - * software please visit: - * https://datatables.net/download/#dt/dt-1.10.21/fh-3.1.7/r-2.2.5 - * - * Included libraries: - * DataTables 1.10.21, FixedHeader 3.1.7, Responsive 2.2.5 - */ - - - - -{% endblock pluginscripts %} - - -{% block headtable %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ _('Serieller Port') }}{{ p._serialport }}{{ _('Anzahl Items') }}{{ p._params|length }}
{{ _('Heizungstyp') }}{{ p._heating_type }}{{ _('Verbunden') }}{{ p._connected }}
{{ _('Protokoll') }}{{ p._protocol }}{{ _('Verbindung aktiv') }}{{ p._initialized }}
{{ _('Letzter manuell gelesener Wert') }}{{ last_read_cmd + ": " if last_read_cmd else '---' }} {{ last_read_value }}
-{% endblock headtable %} - -{% block buttons %} - -{% endblock %} - -{% block bodytab1 %} -
-
- {% if p._params|length %} - - - - - - - - - - - - - {% for commandcode in p._params %} - - - - - - - - - {% endfor %} - -
{{ _('Item') }}{{ _('Datenpunkt') }}{{ _('Befehlsname') }}{{ _('Typ') }}{{ _('Wert') }}{{ _('Letzte Aktualisierung') }}
{{ p._params[commandcode]['item'].path() }}{{ commandcode }}{{ p._params[commandcode]['commandname'] }}{{ p._params[commandcode]['item'].type() }}{{ p._params[commandcode]['item']() }}{{ p._params[commandcode]['item'].last_update() }}
- {% endif %} -
-
-{% endblock bodytab1 %} - -{% block bodytab2 %} -
-
- {% if cmds|length %} -
- - - - - - - - - - - - - - - - - - - - - - - - - {% for cmd in cmds.keys() %} - - - - - - - - - - {% endfor %} - -
{{ _('Befehlsname') }}{{ _('Datenpunkt') }}{{ _('Länge') }}{{ _('Einheit') }}{{ _('Lesen/Schreiben') }}{{ _('Datenpunkt lesen') }}{{ _('gelesener Wert') }}
{{ _('_Custom') }} - - False 
{{ cmd }}{{ cmds[cmd]['addr'] }}{{ cmds[cmd]['len'] }}{{ cmds[cmd]['unit'] }}{{ cmds[cmd]['set'] }} 
-
- {% endif %} -
-
-{% endblock bodytab2 %} diff --git a/viessmann/commands.py b/viessmann/commands.py old mode 100644 new mode 100755 index 84a247190..34d97e67e --- a/viessmann/commands.py +++ b/viessmann/commands.py @@ -1,782 +1,900 @@ -#!/usr/bin/env python3 +# !/usr/bin/env python # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab - -""" commands for dev viessmann """ - -# models defined: +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Copyright 2020 Michael Wenzel +# Copyright 2020 Sebastian Helms +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Viessmann-Plugin for SmartHomeNG. https://github.com/smarthomeNG// # -# V200KW2 -# V200KO1B -# V200WO1C -# V200HO1C - - -commands = { - 'ALL': { - 'Anlagentyp': {'read': True, 'write': False, 'opcode': '00f8', 'reply_pattern': '*', 'item_type': 'str', 'dev_datatype': 'H', 'params': {'value': 'VAL', 'len': 2}, 'lookup': 'devicetypes', 'item_attrs': {'no_read_groups': True, 'initial': True}}, # getAnlTyp -- Information - Allgemein: Anlagentyp (204D) +# 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 . +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +controlset = { + 'P300': { + 'Baudrate': 4800, + 'Bytesize': 8, # 'EIGHTBITS' + 'Parity': 'E', # 'PARITY_EVEN', + 'Stopbits': 2, # 'STOPBITS_TWO', + 'StartByte': 0x41, + 'Request': 0x00, + 'Response': 0x01, + 'Error': 0x03, + 'Read': 0x01, + 'Write': 0x02, + 'Function_Call': 0x7, + 'Acknowledge': 0x06, + 'Not_initiated': 0x05, + 'Init_Error': 0x15, + 'Reset_Command': 0x04, + 'Reset_Command_Response': 0x05, + 'Sync_Command': 0x160000, + 'Sync_Command_Response': 0x06, + 'Command_bytes_read': 5, + 'Command_bytes_write': 5, + # init: send'Reset_Command' receive'Reset_Command_Response' send'Sync_Command' + # request: send('StartByte' 'Länge der Nutzdaten als Anzahl der Bytes zwischen diesem Byte und der Prüfsumme' 'Request' 'Read' 'addr' 'checksum') + # request_response: receive('Acknowledge' 'StartByte' 'Länge der Nutzdaten als Anzahl der Bytes zwischen diesem Byte und der Prüfsumme' 'Response' 'Read' 'addr' 'Anzahl der Bytes des Wertes' 'Wert' 'checksum') }, + 'KW': { + 'Baudrate': 4800, + 'Bytesize': 8, # 'EIGHTBITS' + 'Parity': 'E', # 'PARITY_EVEN', + 'Stopbits': 2, # 'STOPBITS_TWO', + 'StartByte': 0x01, + 'Read': 0xF7, + 'Write': 0xF4, + 'Acknowledge': 0x01, + 'Reset_Command': 0x04, + 'Not_initiated': 0x05, + 'Write_Ack': 0x00, + }, +} + +commandset = { 'V200KO1B': { - 'Allgemein': { - 'Temperatur': { - 'Aussen': {'read': True, 'write': False, 'opcode': '0800', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur - 'Aussen_TP': {'read': True, 'write': False, 'opcode': '5525', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur_tiefpass - 'Aussen_Dp': {'read': True, 'write': False, 'opcode': '5527', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur in Grad C (Gedaempft) - 'Speicher_Ladesensor': {'read': True, 'write': False, 'opcode': '0812', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Temperatur Speicher Ladesensor Komfortsensor - 'Auslauf': {'read': True, 'write': False, 'opcode': '0814', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Auslauftemperatur - 'Abgas': {'read': True, 'write': False, 'opcode': '0816', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Abgastemperatur - 'Gem_Vorlauf': {'read': True, 'write': False, 'opcode': '081a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Gem. Vorlauftemperatur - }, - 'Relais_K12': {'read': True, 'write': False, 'opcode': '0842', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Relais K12 Interne Anschlußerweiterung - 'Eingang_0-10_V': {'read': True, 'write': False, 'opcode': '0a86', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Eingang 0-10 V - 'EA1_Kontakt_0': {'read': True, 'write': False, 'opcode': '0a90', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # EA1: Kontakt 0 - 'EA1_Kontakt_1': {'read': True, 'write': False, 'opcode': '0a91', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # EA1: Kontakt 1 - 'EA1_Kontakt_2': {'read': True, 'write': False, 'opcode': '0a92', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # EA1: Kontakt 2 - 'EA1_Externer_Soll_0-10V': {'read': True, 'write': False, 'opcode': '0a93', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # EA1: Externer Sollwert 0-10V - 'EA1_Relais_0': {'read': True, 'write': False, 'opcode': '0a95', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # EA1: Relais 0 - 'AM1_Ausgang_1': {'read': True, 'write': False, 'opcode': '0aa0', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # AM1 Ausgang 1 - 'AM1_Ausgang_2': {'read': True, 'write': False, 'opcode': '0aa1', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # AM1 Ausgang 2 - 'TempKOffset': {'read': True, 'write': True, 'opcode': '6760', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Kesseloffset KT ueber WWsoll in Grad C - 'Systemtime': {'read': True, 'write': True, 'opcode': '088e', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'T', 'params': {'value': 'VAL', 'len': 8}}, # Systemzeit - 'Anlagenschema': {'read': True, 'write': False, 'opcode': '7700', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 2}, 'lookup': 'systemschemes'}, # Anlagenschema - 'Inventory': {'read': True, 'write': False, 'opcode': '08e0', 'reply_pattern': '*', 'item_type': 'str', 'dev_datatype': 'S', 'params': {'value': 'VAL', 'len': 7}}, # Sachnummer - 'CtrlId': {'read': True, 'write': False, 'opcode': '08e0', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 7}, 'lookup': 'devicetypes'}, # Reglerkennung - }, - 'Kessel': { - # Kessel - 'Ist': {'read': True, 'write': False, 'opcode': '0802', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesseltemperatur - 'TP': {'read': True, 'write': False, 'opcode': '0810', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesseltemperatur_tiefpass - 'Soll': {'read': True, 'write': False, 'opcode': '555a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesselsolltemperatur - }, - 'Fehler': { - # Fehler - 'Sammelstoerung': {'read': True, 'write': False, 'opcode': '0a82', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # Sammelstörung - 'Error0': {'read': True, 'write': False, 'opcode': '7507', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 1 - 'Error1': {'read': True, 'write': False, 'opcode': '7510', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 2 - 'Error2': {'read': True, 'write': False, 'opcode': '7519', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 3 - 'Error3': {'read': True, 'write': False, 'opcode': '7522', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 4 - 'Error4': {'read': True, 'write': False, 'opcode': '752b', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 5 - 'Error5': {'read': True, 'write': False, 'opcode': '7534', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 6 - 'Error6': {'read': True, 'write': False, 'opcode': '753d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 7 - 'Error7': {'read': True, 'write': False, 'opcode': '7546', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 8 - 'Error8': {'read': True, 'write': False, 'opcode': '754f', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 9 - 'Error9': {'read': True, 'write': False, 'opcode': '7558', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 10 - }, - 'Pumpen': { - # Pumpen - 'Speicherlade': {'read': True, 'write': False, 'opcode': '6513', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Speicherladepumpe - 'Zirkulation': {'read': True, 'write': False, 'opcode': '6515', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Zirkulationspumpe - 'Intern': {'read': True, 'write': False, 'opcode': '7660', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Interne Pumpe - 'Heizkreis_A1M1': {'read': True, 'write': False, 'opcode': '2906', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe A1 - 'Heizkreis_A1M1_RPM': {'read': True, 'write': False, 'opcode': '7663', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe A1M1 Drehzahl - 'Heizkreis_M2': {'read': True, 'write': False, 'opcode': '3906', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe M2 - 'Heizkreis_M2_RPM': {'read': True, 'write': False, 'opcode': '7665', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe M2 Drehzahl - 'Relais_Status': {'read': True, 'write': False, 'opcode': 'a152', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Relais-Status Heizkreispumpe 1 - }, - 'Brenner': { - # Brenner - 'Starts': {'read': True, 'write': True, 'opcode': '088a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 4}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Brennerstarts - 'Betriebsstunden': {'read': True, 'write': True, 'opcode': '08a7', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Brenner-Betriebsstunden - 'Status_1': {'read': True, 'write': False, 'opcode': '0842', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Brennerstatus Stufe1 - 'Status_2': {'read': True, 'write': False, 'opcode': '0849', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Brennerstatus Stufe2 - 'Oeldurchsatz': {'read': True, 'write': True, 'opcode': '5726', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 4}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Oeldurchsatz Brenner in Dezi-Liter pro Stunde - 'Oelverbrauch': {'read': True, 'write': True, 'opcode': '7574', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 1000, 'signed': True, 'len': 4}}, # Oelverbrauch kumuliert - }, - 'Solar': { - # Solar - 'Nachladeunterdrueckung': {'read': True, 'write': False, 'opcode': '6551', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, - 'Pumpe': {'read': True, 'write': False, 'opcode': '6552', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, - 'Kollektortemperatur': {'read': True, 'write': False, 'opcode': '6564', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, - 'Speichertemperatur': {'read': True, 'write': False, 'opcode': '6566', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, - 'Betriebsstunden': {'read': True, 'write': False, 'opcode': '6568', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 100, 'len': 4}}, - 'Steuerung': {'read': True, 'write': False, 'opcode': '7754', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 2}}, - }, - 'Heizkreis': { - 'A1M1': { - # Heizkreis A1M1 - 'Temperatur': { - 'Raum': { - 'Ist': {'read': True, 'write': False, 'opcode': '0896', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}}, # Raumtemperatur A1M1 - 'Soll_Normalbetrieb': {'read': True, 'write': True, 'opcode': '2306', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 3, 'force_max': 37}}, # Raumtemperatur Soll Normalbetrieb A1M1 - 'Soll_Red_Betrieb': {'read': True, 'write': True, 'opcode': '2307', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 3, 'force_max': 37}}, # Raumtemperatur Soll Reduzierter Betrieb A1M1 - 'Soll_Party_Betrieb': {'read': True, 'write': True, 'opcode': '2308', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 3, 'force_max': 37}}, # Raumtemperatur Soll Party Betrieb A1M1 - }, - 'Vorlauf': { - 'Ist': {'read': True, 'write': False, 'opcode': '2900', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur A1M1 - 'Soll': {'read': True, 'write': False, 'opcode': '2544', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Soll A1M1 - 'Min': {'read': True, 'write': True, 'opcode': '27c5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 1, 'force_max': 127}}, # Minimalbegrenzung der Vorlauftemperatur - 'Max': {'read': True, 'write': True, 'opcode': '27c6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 127}}, # Maximalbegrenzung der Vorlauftemperatur - 'Erhoehung_Soll': {'read': True, 'write': True, 'opcode': '27fa', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 50}}, # Erhöhung des Kesselwasser- bzw. Vorlauftemperatur-Sollwertes beim Übergang von Betrieb mit reduzierter Raumtemperatur in den Betrieb mit normaler Raumtemperatur um 20 % - 'Erhoehung_Zeit': {'read': True, 'write': True, 'opcode': '27fa', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 150}}, # Zeitdauer für die Erhöhung des Kesselwasser bzw.VorlauftemperaturSollwertes (siehe Codieradresse „FA“) 60 min. - }, - 'Grenze_red_Betrieb': {'read': True, 'write': True, 'opcode': '27f8', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -61, 'force_max': 10}}, # Temperaturgrenze für Aufhebung des reduzierten Betriebs -5 ºC - 'Grenze_red_Raumtemp': {'read': True, 'write': True, 'opcode': '27f9', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -60, 'force_max': 10}}, # Temperaturgrenze für Anhebung des reduzierten RaumtemperaturSollwertes - }, - 'Status': { - 'Aktuelle_Betriebsart': {'read': True, 'write': False, 'opcode': '2301', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes'}, # Aktuelle Betriebsart A1M1 - 'Betriebsart': {'read': True, 'write': True, 'opcode': '2323', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 4}}, # Betriebsart A1M1 - 'Sparbetrieb': {'read': True, 'write': False, 'opcode': '2302', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Sparbetrieb A1M1 - 'Zustand_Sparbetrieb': {'read': True, 'write': True, 'opcode': '2331', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Zustand Sparbetrieb A1M1 - 'Partybetrieb': {'read': True, 'write': False, 'opcode': '2303', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Partybetrieb A1M1 - 'Zustand_Partybetrieb': {'read': True, 'write': True, 'opcode': '2330', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Zustand Partybetrieb A1M1 - 'StatusFrost': {'read': True, 'write': False, 'opcode': '2500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Status Frostwarnung A1M1 - 'Externe_Raumsolltemperatur_Normal': {'read': True, 'write': True, 'opcode': '2321', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 37}}, # Externe Raumsolltemperatur Normal A1M1 - 'Externe_Betriebsartenumschaltung': {'read': True, 'write': True, 'opcode': '2549', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 4}}, # Externe Betriebsartenumschaltung A1M1 - 'Speichervorrang': {'read': True, 'write': True, 'opcode': '27a2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # Speichervorrang auf Heizkreispumpe und Mischer - 'Frostschutzgrenze': {'read': True, 'write': True, 'opcode': '27a3', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -9, 'force_max': 15}}, # Frostschutzgrenze - 'Frostschutz': {'read': True, 'write': True, 'opcode': '27a4', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Frostschutzgrenze - 'Heizkreispumpenlogik': {'read': True, 'write': True, 'opcode': '27a5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # HeizkreispumpenlogikFunktion - 'Sparschaltung': {'read': True, 'write': True, 'opcode': '27a6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 5, 'force_max': 35}}, # AbsolutSommersparschaltung - 'Mischersparfunktion': {'read': True, 'write': True, 'opcode': '27a7', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Mischersparfunktion - 'Pumpenstillstandzeit': {'read': True, 'write': True, 'opcode': '27a9', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # Pumpenstillstandzeit - }, - 'Heizkennlinie': { - 'Neigung': {'read': True, 'write': True, 'opcode': '27d3', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 1}, 'cmd_settings': {'force_min': 0.2, 'force_max': 3.5}}, # Neigung Heizkennlinie A1M1 - 'Niveau': {'read': True, 'write': True, 'opcode': '27d4', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -13, 'force_max': 40}}, # Niveau Heizkennlinie A1M1 - }, - 'Partybetrieb_Zeitbegrenzung': {'read': True, 'write': True, 'opcode': '27f2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 12}}, # Zeitliche Begrenzung für Partybetrieb oder externe BetriebsprogrammUmschaltung mit Taster - }, - 'M2': { - # Heizkreis M2 - 'Temperatur': { - 'Raum': { - 'Ist': {'read': True, 'write': False, 'opcode': '0898', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}}, # Raumtemperatur - 'Soll_Normalbetrieb': {'read': True, 'write': True, 'opcode': '3306', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 3, 'force_max': 37}}, # Raumtemperatur Soll Normalbetrieb - 'Soll_Red_Betrieb': {'read': True, 'write': True, 'opcode': '3307', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 3, 'force_max': 37}}, # Raumtemperatur Soll Reduzierter Betrieb - 'Soll_Party_Betrieb': {'read': True, 'write': True, 'opcode': '3308', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 3, 'force_max': 37}}, # Raumtemperatur Soll Party Betrieb - }, - 'Vorlauf': { - 'Ist': {'read': True, 'write': False, 'opcode': '3900', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur - 'Soll': {'read': True, 'write': False, 'opcode': '3544', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Soll - 'Min': {'read': True, 'write': True, 'opcode': '37c5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 1, 'force_max': 127}}, # Minimalbegrenzung der Vorlauftemperatur - 'Max': {'read': True, 'write': True, 'opcode': '37c6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 127}}, # Maximalbegrenzung der Vorlauftemperatur - 'Erhoehung_Soll': {'read': True, 'write': True, 'opcode': '37fa', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 50}}, # Erhöhung des Kesselwasser- bzw. Vorlauftemperatur-Sollwertes beim Übergang von Betrieb mit reduzierter Raumtemperatur in den Betrieb mit normaler Raumtemperatur um 20 % - 'Erhoehung_Zeit': {'read': True, 'write': True, 'opcode': '37fb', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 150}}, # Zeitdauer für die Erhöhung des Kesselwasser bzw.VorlauftemperaturSollwertes (siehe Codieradresse „FA“) 60 min. - }, - 'Grenze_red_Betrieb': {'read': True, 'write': True, 'opcode': '37f8', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -61, 'force_max': 10}}, # Temperaturgrenze für Aufhebung des reduzierten Betriebs -5 ºC - 'Grenze_red_Raumtemp': {'read': True, 'write': True, 'opcode': '37f9', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -60, 'force_max': 10}}, # Temperaturgrenze für Anhebung des reduzierten RaumtemperaturSollwertes - }, - 'Status': { - 'Aktuelle_Betriebsart': {'read': True, 'write': False, 'opcode': '3301', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes'}, # Aktuelle Betriebsart - 'Betriebsart': {'read': True, 'write': True, 'opcode': '3323', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 4}}, # Betriebsart - 'Sparbetrieb': {'read': True, 'write': False, 'opcode': '3302', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Sparbetrieb - 'Zustand_Sparbetrieb': {'read': True, 'write': True, 'opcode': '3331', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Zustand Sparbetrieb - 'Partybetrieb': {'read': True, 'write': False, 'opcode': '3303', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Partybetrieb - 'Zustand_Partybetrieb': {'read': True, 'write': True, 'opcode': '3330', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Zustand Partybetrieb - 'StatusFrost': {'read': True, 'write': False, 'opcode': '3500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Status Frostwarnung - 'Externe_Raumsolltemperatur_Normal': {'read': True, 'write': True, 'opcode': '3321', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 37}}, # Externe Raumsolltemperatur Normal - 'Externe_Betriebsartenumschaltung': {'read': True, 'write': True, 'opcode': '3549', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 4}}, # Externe Betriebsartenumschaltung - 'Speichervorrang': {'read': True, 'write': True, 'opcode': '37a2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # Speichervorrang auf Heizkreispumpe und Mischer - 'Frostschutzgrenze': {'read': True, 'write': True, 'opcode': '37a3', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -9, 'force_max': 15}}, # Frostschutzgrenze - 'Frostschutz': {'read': True, 'write': True, 'opcode': '37a4', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Frostschutzgrenze - 'Heizkreispumpenlogik': {'read': True, 'write': True, 'opcode': '37a5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # HeizkreispumpenlogikFunktion - 'Sparschaltung': {'read': True, 'write': True, 'opcode': '37a6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 5, 'force_max': 35}}, # AbsolutSommersparschaltung - 'Mischersparfunktion': {'read': True, 'write': True, 'opcode': '37a7', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Mischersparfunktion - 'Pumpenstillstandzeit': {'read': True, 'write': True, 'opcode': '37a9', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # Pumpenstillstandzeit - }, - 'Heizkennlinie': { - 'Neigung': {'read': True, 'write': True, 'opcode': '37d3', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 1}, 'cmd_settings': {'force_min': 0.2, 'force_max': 3.5}}, # Neigung Heizkennlinie - 'Niveau': {'read': True, 'write': True, 'opcode': '37d4', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -13, 'force_max': 40}}, # Niveau Heizkennlinie - }, - 'Partybetrieb_Zeitbegrenzung': {'read': True, 'write': True, 'opcode': '37f2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 12}}, # Zeitliche Begrenzung für Partybetrieb oder externe BetriebsprogrammUmschaltung mit Taster - }, - }, - 'Warmwasser': { - # Warmwasser - 'Ist': {'read': True, 'write': False, 'opcode': '0804', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Warmwassertemperatur in Grad C - 'Soll': {'read': True, 'write': True, 'opcode': '6300', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 95}}, # Warmwasser-Solltemperatur - 'Status': {'read': True, 'write': True, 'opcode': '650a', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Satus Warmwasserbereitung - 'PumpenNachlauf': {'read': True, 'write': True, 'opcode': '6762', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 2}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Warmwasserpumpennachlauf - }, - 'Ferienprogramm': { - 'A1M1': { - # Ferienprogramm HK - 'Status': {'read': True, 'write': False, 'opcode': '2535', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Ferienprogramm A1M1 - 'Abreisetag': {'read': True, 'write': True, 'opcode': '2309', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Abreisetag A1M1 - 'Rückreisetag': {'read': True, 'write': True, 'opcode': '2311', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Rückreisetag A1M1 - }, - 'M2': { - # Ferienprogramm HK - 'Status': {'read': True, 'write': False, 'opcode': '3535', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Ferienprogramm M2 - 'Abreisetag': {'read': True, 'write': True, 'opcode': '3309', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Abreisetag M2 - 'Rückreisetag': {'read': True, 'write': True, 'opcode': '3311', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Rückreisetag M2 - }, - }, - 'Timer': { - 'Warmwasser': { - # Schaltzeiten Warmwasser - 'Mo': {'read': True, 'write': True, 'opcode': '2100', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Montag - 'Di': {'read': True, 'write': True, 'opcode': '2108', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '2110', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '2118', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '2120', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '2128', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Samstag - 'So': {'read': True, 'write': True, 'opcode': '2130', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Sonntag - }, - 'A1M1': { - # Schaltzeiten HK - 'Mo': {'read': True, 'write': True, 'opcode': '2000', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Montag - 'Di': {'read': True, 'write': True, 'opcode': '2008', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '2010', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '2018', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '2020', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '2028', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Samstag - 'So': {'read': True, 'write': True, 'opcode': '2030', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Sonntag - }, - 'M2': { - # Schaltzeiten HK - 'Mo': {'read': True, 'write': True, 'opcode': '3000', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Montag - 'Di': {'read': True, 'write': True, 'opcode': '3008', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '3010', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '3018', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '3020', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '3028', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Samstag - 'So': {'read': True, 'write': True, 'opcode': '3030', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Sonntag - }, - 'Zirkulation': { - # Schaltzeiten Zirkulation - 'Mo': {'read': True, 'write': True, 'opcode': '2200', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Montag - 'Di': {'read': True, 'write': True, 'opcode': '2208', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '2210', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '2218', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '2220', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '2228', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Samstag - 'So': {'read': True, 'write': True, 'opcode': '2230', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Zirkulationspumpe Sonntag - } - } + # Kessel + 'Aussentemperatur': {'addr': '0800', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur + 'Aussentemperatur_TP': {'addr': '5525', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur_tiefpass + 'Aussentemperatur_Dp': {'addr': '5527', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur in Grad C (Gedaempft) + 'Kesseltemperatur': {'addr': '0802', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur + 'Kesseltemperatur_TP': {'addr': '0810', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur_tiefpass + 'Kesselsolltemperatur': {'addr': '555a', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesselsolltemperatur + 'Temp_Speicher_Ladesensor': {'addr': '0812', 'len': 2, 'unit': 'IU10', 'set': False}, # Temperatur Speicher Ladesensor Komfortsensor + 'Auslauftemperatur': {'addr': '0814', 'len': 2, 'unit': 'IU10', 'set': False}, # Auslauftemperatur + 'Abgastemperatur': {'addr': '0816', 'len': 2, 'unit': 'IU10', 'set': False}, # Abgastemperatur + 'Gem_Vorlauftemperatur': {'addr': '081a', 'len': 2, 'unit': 'IU10', 'set': False}, # Gem. Vorlauftemperatur + 'Relais_K12': {'addr': '0842', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Relais K12 Interne Anschlußerweiterung + 'Eingang_0-10_V': {'addr': '0a86', 'len': 1, 'unit': 'IUINT', 'set': False}, # Eingang 0-10 V + 'EA1_Kontakt_0': {'addr': '0a90', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Kontakt 0 + 'EA1_Kontakt_1': {'addr': '0a91', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Kontakt 1 + 'EA1_Kontakt_2': {'addr': '0a92', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Kontakt 2 + 'EA1_Externer_Soll_0-10V': {'addr': '0a93', 'len': 1, 'unit': 'IUINT', 'set': False}, # EA1: Externer Sollwert 0-10V + 'EA1_Relais_0': {'addr': '0a95', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # EA1: Relais 0 + 'AM1_Ausgang_1': {'addr': '0aa0', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # AM1 Ausgang 1 + 'AM1_Ausgang_2': {'addr': '0aa1', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # AM1 Ausgang 2 + 'TempKOffset': {'addr': '6760', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Kesseloffset KT ueber WWsoll in Grad C + 'Systemtime': {'addr': '088e', 'len': 8, 'unit': 'TI', 'set': True}, # Systemzeit + 'Anlagenschema': {'addr': '7700', 'len': 2, 'unit': 'SC', 'set': False}, # Anlagenschema + 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # Heizungstyp + 'Inventory': {'addr': '08e0', 'len': 7, 'unit': 'SN', 'set': False}, # Sachnummer + 'CtrlId': {'addr': '08e0', 'len': 7, 'unit': 'DT', 'set': False}, # Reglerkennung + # Fehler + 'Sammelstoerung': {'addr': '0a82', 'len': 1, 'unit': 'RT', 'set': False}, # Sammelstörung + 'Error0': {'addr': '7507', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 1 + 'Error1': {'addr': '7510', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 2 + 'Error2': {'addr': '7519', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 3 + 'Error3': {'addr': '7522', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 4 + 'Error4': {'addr': '752b', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 5 + 'Error5': {'addr': '7534', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 6 + 'Error6': {'addr': '753d', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 7 + 'Error7': {'addr': '7546', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 8 + 'Error8': {'addr': '754f', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 9 + 'Error9': {'addr': '7558', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 10 + # Pumpen + 'Speicherladepumpe': {'addr': '6513', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Speicherladepumpe + 'Zirkulationspumpe': {'addr': '6515', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Zirkulationspumpe + 'Interne_Pumpe': {'addr': '7660', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Interne Pumpe + 'Heizkreispumpe_A1M1': {'addr': '2906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe A1 + 'Heizkreispumpe_A1M1_RPM': {'addr': '7663', 'len': 1, 'unit': 'IUNON', 'set': False}, # Heizkreispumpe A1M1 Drehzahl + 'Heizkreispumpe_M2': {'addr': '3906', 'len': 1, 'unit': 'IUINT', 'set': False}, # Heizkreispumpe M2 + 'Heizkreispumpe_M2_RPM': {'addr': '7665', 'len': 1, 'unit': 'IUNON', 'set': False}, # Heizkreispumpe M2 Drehzahl + 'Relais_Status_Pumpe_A1M1': {'addr': 'a152', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Relais-Status Heizkreispumpe 1 + # Brenner + 'Brennerstarts': {'addr': '088a', 'len': 4, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brennerstarts + 'Brenner_Betriebsstunden': {'addr': '08a7', 'len': 4, 'unit': 'IU3600', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brenner-Betriebsstunden + 'Brennerstatus_1': {'addr': '0842', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe1 + 'Brennerstatus_2': {'addr': '0849', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe2 + 'Oeldurchsatz': {'addr': '5726', 'len': 4, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Oeldurchsatz Brenner in Dezi-Liter pro Stunde + 'Oelverbrauch': {'addr': '7574', 'len': 4, 'unit': 'IS1000', 'set': True}, # Oelverbrauch kumuliert + # Solar + 'Nachladeunterdrueckung': {'addr': '6551', 'len': 1, 'unit': 'IUBOOL', 'set': False}, + 'SolarPumpe': {'addr': '6552', 'len': 1, 'unit': 'IUBOOL', 'set': False}, + 'Kollektortemperatur': {'addr': '6564', 'len': 2, 'unit': 'IS10', 'set': False}, + 'Speichertemperatur': {'addr': '6566', 'len': 2, 'unit': 'IU10', 'set': False}, + 'Solar_Betriebsstunden': {'addr': '6568', 'len': 4, 'unit': 'IU100', 'set': False}, + 'Solarsteuerung': {'addr': '7754', 'len': 2, 'unit': 'IUINT', 'set': False}, + # Heizkreis A1M1 + 'Raumtemperatur_A1M1': {'addr': '0896', 'len': 1, 'unit': 'ISNON', 'set': False}, # Raumtemperatur A1M1 + 'Raumtemperatur_Soll_Normalbetrieb_A1M1': {'addr': '2306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb A1M1 + 'Raumtemperatur_Soll_Red_Betrieb_A1M1': {'addr': '2307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb A1M1 + 'Raumtemperatur_Soll_Party_Betrieb_A1M1': {'addr': '2308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb A1M1 + 'Aktuelle_Betriebsart_A1M1': {'addr': '2301', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart A1M1 + 'Betriebsart_A1M1': {'addr': '2323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Betriebsart A1M1 + 'Sparbetrieb_A1M1': {'addr': '2302', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Sparbetrieb A1M1 + 'Zustand_Sparbetrieb_A1M1': {'addr': '2331', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Sparbetrieb A1M1 + 'Partybetrieb_A1M1': {'addr': '2303', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Partybetrieb A1M1 + 'Zustand_Partybetrieb_A1M1': {'addr': '2330', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Partybetrieb A1M1 + 'Vorlauftemperatur_A1M1': {'addr': '2900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur A1M1 + 'Vorlauftemperatur_Soll_A1M1': {'addr': '2544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll A1M1 + 'StatusFrost_A1M1': {'addr': '2500', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Status Frostwarnung A1M1 + 'Externe_Raumsolltemperatur_Normal_A1M1': {'addr': '2321', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 37}, # Externe Raumsolltemperatur Normal A1M1 + 'Externe_Betriebsartenumschaltung_A1M1': {'addr': '2549', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Externe Betriebsartenumschaltung A1M1 + 'Speichervorrang_A1M1': {'addr': '27a2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Speichervorrang auf Heizkreispumpe und Mischer + 'Frostschutzgrenze_A1M1': {'addr': '27a3', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -9, 'max_value': 15}, # Frostschutzgrenze + 'Frostschutz_A1M1': {'addr': '27a4', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Frostschutzgrenze + 'Heizkreispumpenlogik_A1M1': {'addr': '27a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # HeizkreispumpenlogikFunktion + 'Sparschaltung_A1M1': {'addr': '27a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 35}, # AbsolutSommersparschaltung + 'Mischersparfunktion_A1M1': {'addr': '27a7', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Mischersparfunktion + 'Pumpenstillstandzeit_A1M1': {'addr': '27a9', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Pumpenstillstandzeit + 'Vorlauftemperatur_min_A1M1': {'addr': '27c5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Minimalbegrenzung der Vorlauftemperatur + 'Vorlauftemperatur_max_A1M1': {'addr': '27c6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 127}, # Maximalbegrenzung der Vorlauftemperatur + 'Neigung_Heizkennlinie_A1M1': {'addr': '27d3', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie A1M1 + 'Niveau_Heizkennlinie_A1M1': {'addr': '27d4', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie A1M1 + 'Partybetrieb_Zeitbegrenzung_A1M1': {'addr': '27f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Zeitliche Begrenzung für Partybetrieb oder externe BetriebsprogrammUmschaltung mit Taster + 'Temperaturgrenze_red_Betrieb_A1M1': {'addr': '27f8', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -61, 'max_value': 10}, # Temperaturgrenze für Aufhebung des reduzierten Betriebs -5 ºC + 'Temperaturgrenze_red_Raumtemp_A1M1': {'addr': '27f9', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -60, 'max_value': 10}, # Temperaturgrenze für Anhebung des reduzierten RaumtemperaturSollwertes + 'Vorlauftemperatur_Erhoehung_Soll_A1M1': {'addr': '27fa', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 50}, # Erhöhung des Kesselwasser- bzw. Vorlauftemperatur-Sollwertes beim Übergang von Betrieb mit reduzierter Raumtemperatur in den Betrieb mit normaler Raumtemperatur um 20 % + 'Vorlauftemperatur_Erhoehung_Zeit_A1M1': {'addr': '27fa', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 150}, # Zeitdauer für die Erhöhung des Kesselwasser bzw.VorlauftemperaturSollwertes (siehe Codieradresse „FA“) 60 min. + # Heizkreis M2 + 'Raumtemperatur_M2': {'addr': '0898', 'len': 1, 'unit': 'ISNON', 'set': False}, # Raumtemperatur + 'Raumtemperatur_Soll_Normalbetrieb_M2': {'addr': '3306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb + 'Raumtemperatur_Soll_Red_Betrieb_M2': {'addr': '3307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb + 'Raumtemperatur_Soll_Party_Betrieb_M2': {'addr': '3308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 3, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb + 'Aktuelle_Betriebsart_M2': {'addr': '3301', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart + 'Betriebsart_M2': {'addr': '3323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Betriebsart + 'Sparbetrieb_M2': {'addr': '3302', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Sparbetrieb + 'Zustand_Sparbetrieb_M2': {'addr': '3331', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Sparbetrieb + 'Partybetrieb_M2': {'addr': '3303', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Partybetrieb + 'Zustand_Partybetrieb_M2': {'addr': '3330', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Zustand Partybetrieb + 'Vorlauftemperatur_M2': {'addr': '3900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur + 'Vorlauftemperatur_Soll_M2': {'addr': '3544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll + 'StatusFrost_M2': {'addr': '3500', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Status Frostwarnung + 'Externe_Raumsolltemperatur_Normal_M2': {'addr': '3321', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 37}, # Externe Raumsolltemperatur Normal + 'Externe_Betriebsartenumschaltung_M2': {'addr': '3549', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Externe Betriebsartenumschaltung + 'Speichervorrang_M2': {'addr': '37a2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Speichervorrang auf Heizkreispumpe und Mischer + 'Frostschutzgrenze_M2': {'addr': '37a3', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -9, 'max_value': 15}, # Frostschutzgrenze + 'Frostschutz_M2': {'addr': '37a4', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Frostschutzgrenze + 'Heizkreispumpenlogik_M2': {'addr': '37a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # HeizkreispumpenlogikFunktion + 'Sparschaltung_M2': {'addr': '37a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 35}, # AbsolutSommersparschaltung + 'Mischersparfunktion_M2': {'addr': '37a7', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Mischersparfunktion + 'Pumpenstillstandzeit_M2': {'addr': '37a9', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 15}, # Pumpenstillstandzeit + 'Vorlauftemperatur_min_M2': {'addr': '37c5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Minimalbegrenzung der Vorlauftemperatur + 'Vorlauftemperatur_max_M2': {'addr': '37c6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 127}, # Maximalbegrenzung der Vorlauftemperatur + 'Neigung_Heizkennlinie_M2': {'addr': '37d3', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie + 'Niveau_Heizkennlinie_M2': {'addr': '37d4', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie + 'Partybetrieb_Zeitbegrenzung_M2': {'addr': '37f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Zeitliche Begrenzung für Partybetrieb oder externe BetriebsprogrammUmschaltung mit Taster + 'Temperaturgrenze_red_Betrieb_M2': {'addr': '37f8', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -61, 'max_value': 10}, # Temperaturgrenze für Aufhebung des reduzierten Betriebs -5 ºC + 'Temperaturgrenze_red_Raumtemp_M2': {'addr': '37f9', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -60, 'max_value': 10}, # Temperaturgrenze für Anhebung des reduzierten RaumtemperaturSollwertes + 'Vorlauftemperatur_Erhoehung_Soll_M2': {'addr': '37fa', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 50}, # Erhöhung des Kesselwasser- bzw. Vorlauftemperatur-Sollwertes beim Übergang von Betrieb mit reduzierter Raumtemperatur in den Betrieb mit normaler Raumtemperatur um 20 % + 'Vorlauftemperatur_Erhoehung_Zeit_M2': {'addr': '37fb', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 150}, # Zeitdauer für die Erhöhung des Kesselwasser bzw.VorlauftemperaturSollwertes (siehe Codieradresse „FA“) 60 min. + # Warmwasser + 'Warmwasser_Temperatur': {'addr': '0804', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwassertemperatur in Grad C + 'Warmwasser_Solltemperatur': {'addr': '6300', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 95}, # Warmwasser-Solltemperatur + 'Status_Warmwasserbereitung': {'addr': '650a', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Satus Warmwasserbereitung + 'WarmwasserPumpenNachlauf': {'addr': '6762', 'len': 2, 'unit': 'ISNON' , 'set': True, 'min_value': 0, 'max_value': 1}, # Warmwasserpumpennachlauf + # Ferienprogramm HK_A1M1 + 'Ferienprogramm_A1M1': {'addr': '2535', 'len': 1, 'unit': 'IUINT', 'set': False}, # Ferienprogramm A1M1 + 'Ferien_Abreisetag_A1M1': {'addr': '2309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag A1M1 + 'Ferien_Rückreisetag_A1M1': {'addr': '2311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag A1M1 + # Ferienprogramm HK_M2 + 'Ferienprogramm_M2': {'addr': '3535', 'len': 1, 'unit': 'IUINT', 'set': False}, # Ferienprogramm M2 + 'Ferien_Abreisetag_M2': {'addr': '3309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag M2 + 'Ferien_Rückreisetag_M2': {'addr': '3311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag M2 + # Schaltzeiten Warmwasser + 'Timer_Warmwasser_Mo': {'addr': '2100', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Montag + 'Timer_Warmwasser_Di': {'addr': '2108', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Dienstag + 'Timer_Warmwasser_Mi': {'addr': '2110', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Mittwoch + 'Timer_Warmwasser_Do': {'addr': '2118', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Donnerstag + 'Timer_Warmwasser_Fr': {'addr': '2120', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Freitag + 'Timer_Warmwasser_Sa': {'addr': '2128', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Samstag + 'Timer_Warmwasser_So': {'addr': '2130', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Sonntag + # Schaltzeiten HK_A1M1 + 'Timer_A1M1_Mo': {'addr': '2000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag + 'Timer_A1M1_Di': {'addr': '2008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag + 'Timer_A1M1_Mi': {'addr': '2010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch + 'Timer_A1M1_Do': {'addr': '2018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag + 'Timer_A1M1_Fr': {'addr': '2020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag + 'Timer_A1M1_Sa': {'addr': '2028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag + 'Timer_A1M1_So': {'addr': '2030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag + # Schaltzeiten HK_M2 + 'Timer_M2_Mo': {'addr': '3000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag + 'Timer_M2_Di': {'addr': '3008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag + 'Timer_M2_Mi': {'addr': '3010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch + 'Timer_M2_Do': {'addr': '3018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag + 'Timer_M2_Fr': {'addr': '3020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag + 'Timer_M2_Sa': {'addr': '3028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag + 'Timer_M2_So': {'addr': '3030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag + # Schaltzeiten Zirkulation + 'Timer_Zirku_Mo': {'addr': '2200', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Montag + 'Timer_Zirku_Di': {'addr': '2208', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Dienstag + 'Timer_Zirku_Mi': {'addr': '2210', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Mittwoch + 'Timer_Zirku_Do': {'addr': '2218', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Donnerstag + 'Timer_Zirku_Fr': {'addr': '2220', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Freitag + 'Timer_Zirku_Sa': {'addr': '2228', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Samstag + 'Timer_Zirku_So': {'addr': '2230', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Zirkulationspumpe Sonntag }, 'V200HO1C': { - 'Allgemein': { - # Allgemein - 'Anlagenschema': {'read': True, 'write': False, 'opcode': '7700', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 2}, 'lookup': 'systemschemes'}, # Anlagenschema - 'Frostgefahr': {'read': True, 'write': False, 'opcode': '2510', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Frostgefahr - 'Anlagenleistung': {'read': True, 'write': False, 'opcode': 'a38f', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Anlagenleistung - 'Temperatur': { - 'Aussen_TP': {'read': True, 'write': False, 'opcode': '5525', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur_tiefpass - 'Aussen_Dp': {'read': True, 'write': False, 'opcode': '5527', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur in Grad C (Gedaempft) - }, - }, - 'Kessel': { - # Kessel - 'TP': {'read': True, 'write': False, 'opcode': '0810', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesseltemperatur_tiefpass - 'Soll': {'read': True, 'write': False, 'opcode': '555a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesselsolltemperatur - 'Abgastemperatur': {'read': True, 'write': False, 'opcode': '0816', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Abgastemperatur - }, - 'Fehler': { - # Fehler - 'Sammelstoerung': {'read': True, 'write': False, 'opcode': '0a82', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # Sammelstörung - 'Error0': {'read': True, 'write': False, 'opcode': '7507', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 1 - 'Error1': {'read': True, 'write': False, 'opcode': '7510', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 2 - 'Error2': {'read': True, 'write': False, 'opcode': '7519', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 3 - 'Error3': {'read': True, 'write': False, 'opcode': '7522', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 4 - 'Error4': {'read': True, 'write': False, 'opcode': '752b', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 5 - 'Error5': {'read': True, 'write': False, 'opcode': '7534', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 6 - 'Error6': {'read': True, 'write': False, 'opcode': '753d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 7 - 'Error7': {'read': True, 'write': False, 'opcode': '7546', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 8 - 'Error8': {'read': True, 'write': False, 'opcode': '754f', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 9 - 'Error9': {'read': True, 'write': False, 'opcode': '7558', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 10 - }, - 'Pumpen': { - # Pumpen - 'Speicherlade': {'read': True, 'write': False, 'opcode': '6513', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Speicherladepumpe für Warmwasser - 'Zirkulation': {'read': True, 'write': True, 'opcode': '6515', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Zirkulationspumpe - 'Intern': {'read': True, 'write': False, 'opcode': '7660', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Interne Pumpe - 'Heizkreis_1': {'read': True, 'write': False, 'opcode': '2906', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe A1 - 'Heizkreis_2': {'read': True, 'write': False, 'opcode': '3906', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe M2 - }, - 'Brenner': { - # Brenner - 'Starts': {'read': True, 'write': False, 'opcode': '088a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 4}}, # Brennerstarts - 'Leistung': {'read': True, 'write': False, 'opcode': 'a305', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Brennerleistung - 'Betriebsstunden': {'read': True, 'write': False, 'opcode': '08a7', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # Brenner-Betriebsstunden - }, - 'Solar': { - # Solar - 'Pumpe': {'read': True, 'write': False, 'opcode': '6552', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Solarpumpe - 'Kollektortemperatur': {'read': True, 'write': False, 'opcode': '6564', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Kollektortemperatur - 'Speichertemperatur': {'read': True, 'write': False, 'opcode': '6566', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Spichertemperatur - 'Betriebsstunden': {'read': True, 'write': False, 'opcode': '6568', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 100, 'len': 4}}, # Solar Betriebsstunden - 'Waermemenge': {'read': True, 'write': False, 'opcode': '6560', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 2}}, # Solar Waermemenge - 'Ausbeute': {'read': True, 'write': False, 'opcode': 'cf30', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # Solar Ausbeute - }, - 'Heizkreis': { - '1': { - # Heizkreis 1 - 'Betriebsart': {'read': True, 'write': True, 'opcode': '2500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 3}}, # Betriebsart (0=Abschaltbetrieb, 1=Red. Betrieb, 2=Normalbetrieb (Schaltuhr), 3=Normalbetrieb (Dauernd)) - 'Heizart': {'read': True, 'write': True, 'opcode': '2323', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 4}}, # Heizart (0=Abschaltbetrieb, 1=Nur Warmwasser, 2=Heizen und Warmwasser, 3=Normalbetrieb (Reduziert), 4=Normalbetrieb (Dauernd)) - 'Temperatur': { - 'Vorlauf_Soll': {'read': True, 'write': False, 'opcode': '2544', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Soll - 'Vorlauf_Ist': {'read': True, 'write': False, 'opcode': '2900', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Ist - }, - }, - '2': { - # Heizkreis 2 - 'Betriebsart': {'read': True, 'write': True, 'opcode': '3500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 3}}, # Betriebsart (0=Abschaltbetrieb, 1=Red. Betrieb, 2=Normalbetrieb (Schaltuhr), 3=Normalbetrieb (Dauernd)) - 'Heizart': {'read': True, 'write': True, 'opcode': '3323', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 4}}, # Heizart (0=Abschaltbetrieb, 1=Nur Warmwasser, 2=Heizen und Warmwasser, 3=Normalbetrieb (Reduziert), 4=Normalbetrieb (Dauernd)) - 'Temperatur': { - 'Vorlauf_Soll': {'read': True, 'write': False, 'opcode': '3544', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Soll - 'Vorlauf_Ist': {'read': True, 'write': False, 'opcode': '3900', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Ist - }, - }, - }, - 'Warmwasser': { - # Warmwasser - 'Ist': {'read': True, 'write': False, 'opcode': '0812', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Warmwassertemperatur in Grad C - 'Soll': {'read': True, 'write': True, 'opcode': '6300', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 80}}, # Warmwasser-Solltemperatur - 'Austritt': {'read': True, 'write': False, 'opcode': '0814', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Warmwasseraustrittstemperatur in Grad C - }, + # Allgemein + 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # Heizungstyp + 'Anlagenschema': {'addr': '7700', 'len': 2, 'unit': 'SC', 'set': False}, # Anlagenschema + 'Frostgefahr': {'addr': '2510', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Frostgefahr + 'Aussentemperatur_TP': {'addr': '5525', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur_tiefpass + 'Aussentemperatur_Dp': {'addr': '5527', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur in Grad C (Gedaempft) + 'Anlagenleistung': {'addr': 'a38f', 'len': 2, 'unit': 'IS10', 'set': False}, # Anlagenleistung + # Kessel + 'Kesseltemperatur_TP': {'addr': '0810', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur_tiefpass + 'Kesselsolltemperatur': {'addr': '555a', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesselsolltemperatur + 'Abgastemperatur': {'addr': '0816', 'len': 2, 'unit': 'IU10', 'set': False}, # Abgastemperatur + # Fehler + 'Sammelstoerung': {'addr': '0a82', 'len': 1, 'unit': 'RT', 'set': False}, # Sammelstörung + 'Error0': {'addr': '7507', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 1 + 'Error1': {'addr': '7510', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 2 + 'Error2': {'addr': '7519', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 3 + 'Error3': {'addr': '7522', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 4 + 'Error4': {'addr': '752b', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 5 + 'Error5': {'addr': '7534', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 6 + 'Error6': {'addr': '753d', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 7 + 'Error7': {'addr': '7546', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 8 + 'Error8': {'addr': '754f', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 9 + 'Error9': {'addr': '7558', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 10 + # Pumpen + 'Speicherladepumpe': {'addr': '6513', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Speicherladepumpe für Warmwasser + 'Zirkulationspumpe': {'addr': '6515', 'len': 1, 'unit': 'IUBOOL', 'set': True}, # Zirkulationspumpe + 'Interne_Pumpe': {'addr': '7660', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Interne Pumpe + 'Heizkreispumpe_HK1': {'addr': '2906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe A1 + 'Heizkreispumpe_HK2': {'addr': '3906', 'len': 1, 'unit': 'IUINT', 'set': False}, # Heizkreispumpe M2 + # Brenner + 'Brennerstarts': {'addr': '088a', 'len': 4, 'unit': 'ISNON', 'set': False}, # Brennerstarts + 'Brennerleistung': {'addr': 'a305', 'len': 2, 'unit': 'IS10', 'set': False}, # Brennerleistung + 'Brenner_Betriebsstunden': {'addr': '08a7', 'len': 4, 'unit': 'IU3600', 'set': False}, # Brenner-Betriebsstunden + # Solar + 'SolarPumpe': {'addr': '6552', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Solarpumpe + 'Kollektortemperatur': {'addr': '6564', 'len': 2, 'unit': 'IS10', 'set': False}, # Kollektortemperatur + 'Speichertemperatur': {'addr': '6566', 'len': 2, 'unit': 'IU10', 'set': False}, # Spichertemperatur + 'Solar_Betriebsstunden': {'addr': '6568', 'len': 4, 'unit': 'IU100', 'set': False}, # Solar Betriebsstunden + 'Solar_Waermemenge': {'addr': '6560', 'len': 2, 'unit': 'IUINT', 'set': False}, # Solar Waermemenge + 'Solar_Ausbeute': {'addr': 'cf30', 'len': 4, 'unit': 'IUINT', 'set': False}, # Solar Ausbeute + # Heizkreis 1 + 'Betriebsart_HK1': {'addr': '2500', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 3}, # Betriebsart (0=Abschaltbetrieb, 1=Red. Betrieb, 2=Normalbetrieb (Schaltuhr), 3=Normalbetrieb (Dauernd)) + 'Heizart_HK1': {'addr': '2323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Heizart (0=Abschaltbetrieb, 1=Nur Warmwasser, 2=Heizen und Warmwasser, 3=Normalbetrieb (Reduziert), 4=Normalbetrieb (Dauernd)) + 'Vorlauftemperatur_Soll_HK1': {'addr': '2544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll + 'Vorlauftemperatur_HK1': {'addr': '2900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Ist + # Heizkreis 2 + 'Betriebsart_HK2': {'addr': '3500', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 3}, # Betriebsart (0=Abschaltbetrieb, 1=Red. Betrieb, 2=Normalbetrieb (Schaltuhr), 3=Normalbetrieb (Dauernd)) + 'Heizart_HK2': {'addr': '3323', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 4}, # Heizart (0=Abschaltbetrieb, 1=Nur Warmwasser, 2=Heizen und Warmwasser, 3=Normalbetrieb (Reduziert), 4=Normalbetrieb (Dauernd)) + 'Vorlauftemperatur_Soll_HK2': {'addr': '3544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll + 'Vorlauftemperatur_HK2': {'addr': '3900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Ist + # Warmwasser + 'Warmwasser_Temperatur': {'addr': '0812', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwassertemperatur in Grad C + 'Warmwasser_Solltemperatur': {'addr': '6300', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 80}, # Warmwasser-Solltemperatur + 'Warmwasser_Austrittstemperatur': {'addr': '0814', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwasseraustrittstemperatur in Grad C }, 'V200KW2': { - 'Allgemein': { - # Allgemein - 'Temperatur': { - 'Aussen': {'read': True, 'write': False, 'opcode': '0800', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur_tiefpass - 'Aussen_Dp': {'read': True, 'write': False, 'opcode': '5527', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # Aussentemperatur in Grad C (Gedaempft) - }, - 'Anlagenschema': {'read': True, 'write': False, 'opcode': '7700', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 2}, 'lookup': 'systemschemes'}, # Anlagenschema - 'AnlagenSoftwareIndex': {'read': True, 'write': False, 'opcode': '7330', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Bedienteil SoftwareIndex - 'Systemtime': {'read': True, 'write': True, 'opcode': '088e', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'T', 'params': {'value': 'VAL', 'len': 8}}, # Systemzeit - }, - 'Kessel': { - # Kessel - 'TempKOffset': {'read': True, 'write': True, 'opcode': '6760', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 50}}, # Kesseloffset KT ueber WWsoll in Grad C - 'Ist': {'read': True, 'write': False, 'opcode': '0802', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesseltemperatur - 'Soll': {'read': True, 'write': True, 'opcode': '5502', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Kesselsolltemperatur - }, - 'Fehler': { - # Fehler - 'Sammelstoerung': {'read': True, 'write': False, 'opcode': '0847', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # Sammelstörung - 'Brennerstoerung': {'read': True, 'write': False, 'opcode': '0883', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, - 'Error0': {'read': True, 'write': False, 'opcode': '7507', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 1 - 'Error1': {'read': True, 'write': False, 'opcode': '7510', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 2 - 'Error2': {'read': True, 'write': False, 'opcode': '7519', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 3 - 'Error3': {'read': True, 'write': False, 'opcode': '7522', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 4 - 'Error4': {'read': True, 'write': False, 'opcode': '752b', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 5 - 'Error5': {'read': True, 'write': False, 'opcode': '7534', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 6 - 'Error6': {'read': True, 'write': False, 'opcode': '753d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 7 - 'Error7': {'read': True, 'write': False, 'opcode': '7546', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 8 - 'Error8': {'read': True, 'write': False, 'opcode': '754f', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 9 - 'Error9': {'read': True, 'write': False, 'opcode': '7558', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 9}, 'lookup': 'errors'}, # Fehlerhistory Eintrag 10 - }, - 'Pumpen': { - # Pumpen - 'Speicherlade': {'read': True, 'write': False, 'opcode': '0845', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Speicherladepumpe für Warmwasser - 'Zirkulation': {'read': True, 'write': False, 'opcode': '0846', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Zirkulationspumpe - 'Heizkreis_A1M1': {'read': True, 'write': False, 'opcode': '2906', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe A1M1 - 'Heizkreis_M2': {'read': True, 'write': False, 'opcode': '3906', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Heizkreispumpe M2 - }, - 'Brenner': { - # Brenner - 'Typ': {'read': True, 'write': False, 'opcode': 'a30b', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Brennertyp 0=einstufig 1=zweistufig 2=modulierend - 'Stufe': {'read': True, 'write': False, 'opcode': '551e', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # Ermittle die aktuelle Brennerstufe - 'Starts': {'read': True, 'write': True, 'opcode': '088a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 2}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Brennerstarts - 'Status_1': {'read': True, 'write': False, 'opcode': '55d3', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Brennerstatus Stufe1 - 'Status_2': {'read': True, 'write': False, 'opcode': '0849', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Brennerstatus Stufe2 - 'BetriebsstundenStufe1': {'read': True, 'write': True, 'opcode': '0886', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Brenner-Betriebsstunden Stufe 1 - 'BetriebsstundenStufe2': {'read': True, 'write': True, 'opcode': '08a3', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}, 'cmd_settings': {'force_min': 0, 'force_max': 1193045}}, # Brenner-Betriebsstunden Stufe 2 - }, - 'Heizkreis': { - 'A1M1': { - # Heizkreis A1M1 - 'Temperatur': { - 'Raum': { - 'Soll_Normal': {'read': True, 'write': True, 'opcode': '2306', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 4, 'force_max': 37}}, # Raumtemperatur Soll Normalbetrieb A1M1 - 'Soll_Reduziert': {'read': True, 'write': True, 'opcode': '2307', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 4, 'force_max': 37}}, # Raumtemperatur Soll Reduzierter Betrieb A1M1 - 'Soll_Party': {'read': True, 'write': True, 'opcode': '2308', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 4, 'force_max': 37}}, # Raumtemperatur Soll Party Betrieb A1M1 - }, - 'Vorlauf': { - 'Ist': {'read': True, 'write': False, 'opcode': '2900', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur A1M1 - 'Soll': {'read': True, 'write': False, 'opcode': '2544', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Soll A1M1 - }, - }, - 'Betriebsart': {'read': True, 'write': True, 'opcode': '2301', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes'}, # Betriebsart A1M1 - 'Aktuelle_Betriebsart': {'read': True, 'write': False, 'opcode': '2500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes'}, # Aktuelle Betriebsart A1M1 - 'Sparbetrieb': {'read': True, 'write': True, 'opcode': '2302', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Sparbetrieb A1M1 - 'Partybetrieb_Zeit': {'read': True, 'write': True, 'opcode': '27f2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 12}}, # Partyzeit M2 - 'Partybetrieb': {'read': True, 'write': True, 'opcode': '2303', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Partybetrieb A1M1 - 'MischerM1': {'read': True, 'write': False, 'opcode': '254c', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 2.55, 'len': 1}}, # Ermittle Mischerposition M1 - 'Heizkreispumpenlogik': {'read': True, 'write': True, 'opcode': '27a5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # 0=ohne HPL-Funktion, 1=AT > RTsoll + 5 K, 2=AT > RTsoll + 4 K, 3=AT > RTsoll + 3 K, 4=AT > RTsoll + 2 K, 5=AT > RTsoll + 1 K, 6=AT > RTsoll, 7=AT > RTsoll - 1 K, 8=AT > RTsoll - 2 K, 9=AT > RTsoll - 3 K, 10=AT > RTsoll - 4 K, 11=AT > RTsoll - 5 K, 12=AT > RTsoll - 6 K, 13=AT > RTsoll - 7 K, 14=AT > RTsoll - 8 K, 15=AT > RTsoll - 9 K - 'Sparschaltung': {'read': True, 'write': True, 'opcode': '27a6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 5, 'force_max': 36}}, # AbsolutSommersparschaltung - 'Heizkennlinie': { - 'Neigung': {'read': True, 'write': True, 'opcode': '2305', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 1}, 'cmd_settings': {'force_min': 0.2, 'force_max': 3.5}}, # Neigung Heizkennlinie A1M1 - 'Niveau': {'read': True, 'write': True, 'opcode': '2304', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -13, 'force_max': 40}}, # Niveau Heizkennlinie A1M1 - }, - }, - 'M2': { - # Heizkreis M2 - 'Temperatur': { - 'Raum': { - 'Soll_Normal': {'read': True, 'write': True, 'opcode': '3306', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 4, 'force_max': 37}}, # Raumtemperatur Soll Normalbetrieb - 'Soll_Reduziert': {'read': True, 'write': True, 'opcode': '3307', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 4, 'force_max': 37}}, # Raumtemperatur Soll Reduzierter Betrieb - 'Soll_Party': {'read': True, 'write': True, 'opcode': '3308', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 4, 'force_max': 37}}, # Raumtemperatur Soll Party Betrieb - }, - 'Vorlauf': { - 'Soll': {'read': True, 'write': True, 'opcode': '37c6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}, 'cmd_settings': {'force_min': 10, 'force_max': 80}}, # Vorlauftemperatur Soll - 'Ist': {'read': True, 'write': False, 'opcode': '080c', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Vorlauftemperatur Ist - 'Min': {'read': True, 'write': True, 'opcode': '37c5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 1, 'force_max': 127}}, # Minimalbegrenzung der Vorlauftemperatur - 'Max': {'read': True, 'write': True, 'opcode': '37c6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 1, 'force_max': 127}}, # Maximalbegrenzung der Vorlauftemperatur - }, - }, - 'Betriebsart': {'read': True, 'write': True, 'opcode': '3301', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes'}, # Betriebsart M2 - 'Aktuelle_Betriebsart': {'read': True, 'write': False, 'opcode': '3500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes'}, # Aktuelle Betriebsart M2 - 'Sparbetrieb': {'read': True, 'write': True, 'opcode': '3302', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Sparbetrieb - 'Partybetrieb': {'read': True, 'write': True, 'opcode': '3303', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # Partybetrieb A1M1 - 'Partybetrieb_Zeit': {'read': True, 'write': True, 'opcode': '37f2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 12}}, # Partyzeit M2 - 'MischerM2': {'read': True, 'write': False, 'opcode': '354c', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 2.55, 'len': 1}}, # Ermittle Mischerposition M2 - 'MischerM2Auf': {'read': True, 'write': True, 'opcode': '084d', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # MischerM2 Auf 0=AUS;1=EIN - 'MischerM2Zu': {'read': True, 'write': True, 'opcode': '084c', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 1}}, # MischerM2 Zu 0=AUS;1=EIN - 'Heizkreispumpenlogik': {'read': True, 'write': True, 'opcode': '37a5', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 15}}, # 0=ohne HPL-Funktion, 1=AT > RTsoll + 5 K, 2=AT > RTsoll + 4 K, 3=AT > RTsoll + 3 K, 4=AT > RTsoll + 2 K, 5=AT > RTsoll + 1 K, 6=AT > RTsoll, 7=AT > RTsoll - 1 K, 8=AT > RTsoll - 2 K, 9=AT > RTsoll - 3 K, 10=AT > RTsoll - 4 K, 11=AT > RTsoll - 5 K, 12=AT > RTsoll - 6 K, 13=AT > RTsoll - 7 K, 14=AT > RTsoll - 8 K, 15=AT > RTsoll - 9 K - 'Sparschaltung': {'read': True, 'write': True, 'opcode': '37a6', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 5, 'force_max': 36}}, # AbsolutSommersparschaltung - 'StatusKlemme2': {'read': True, 'write': False, 'opcode': '3904', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # 0=OK, 1=Kurzschluss, 2=nicht vorhanden, 3-5=Referenzfehler, 6=nicht vorhanden - 'StatusKlemme17': {'read': True, 'write': False, 'opcode': '3905', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # 0=OK, 1=Kurzschluss, 2=nicht vorhanden, 3-5=Referenzfehler, 6=nicht vorhanden - 'Heizkennlinie': { - 'Neigung': {'read': True, 'write': True, 'opcode': '3305', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 1}, 'cmd_settings': {'force_min': 0.2, 'force_max': 3.5}}, # Neigung Heizkennlinie M2 - 'Niveau': {'read': True, 'write': True, 'opcode': '3304', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': -13, 'force_max': 40}}, # Niveau Heizkennlinie M2 - }, - }, - }, - 'Warmwasser': { - # Warmwasser - 'Status': {'read': True, 'write': False, 'opcode': '650A', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # 0=Ladung inaktiv, 1=in Ladung, 2=im Nachlauf - 'KesselOffset': {'read': True, 'write': True, 'opcode': '6760', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 50}}, # Warmwasser Kessel Offset in K - 'BeiPartyDNormal': {'read': True, 'write': True, 'opcode': '6764', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 2}}, # WW Heizen bei Party 0=AUS, 1=nach Schaltuhr, 2=EIN - 'Ist': {'read': True, 'write': False, 'opcode': '0804', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 2}}, # Warmwassertemperatur in Grad C - 'Soll': {'read': True, 'write': True, 'opcode': '6300', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'signed': True, 'len': 1}, 'cmd_settings': {'force_min': 10, 'force_max': 80}}, # Warmwasser-Solltemperatur - 'SollAktuell': {'read': True, 'write': False, 'opcode': '6500', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 1}}, # Warmwasser-Solltemperatur aktuell - 'SollMax': {'read': True, 'write': False, 'opcode': '675a', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # 0=inaktiv, 1=aktiv - }, - 'Ferienprogramm': { - 'A1M1': { - # Ferienprogramm HK - 'Status': {'read': True, 'write': False, 'opcode': '2535', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Ferienprogramm A1M1 0=inaktiv 1=aktiv - 'Abreisetag': {'read': True, 'write': True, 'opcode': '2309', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Abreisetag A1M1 - 'Rückreisetag': {'read': True, 'write': True, 'opcode': '2311', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Rückreisetag A1M1 - }, - 'M2': { - # Ferienprogramm HK - 'Status': {'read': True, 'write': False, 'opcode': '3535', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # Ferienprogramm M2 0=inaktiv 1=aktiv - 'Abreisetag': {'read': True, 'write': True, 'opcode': '3309', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Abreisetag M2 - 'Rückreisetag': {'read': True, 'write': True, 'opcode': '3311', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'D', 'params': {'value': 'VAL', 'len': 8}}, # Ferien Rückreisetag M2 - }, - }, - 'Timer': { - 'Warmwasser': { - # Schaltzeiten Warmwasser - 'Mo': {'read': True, 'write': True, 'opcode': '2100', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Montag - 'Di': {'read': True, 'write': True, 'opcode': '2108', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '2110', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '2118', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '2120', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '2128', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Samstag - 'So': {'read': True, 'write': True, 'opcode': '2130', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Warmwasserbereitung Sonntag - }, - 'A1M1': { - # Schaltzeiten HK - 'Mo': {'read': True, 'write': True, 'opcode': '2000', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Montag - 'Di': {'read': True, 'write': True, 'opcode': '2008', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '2010', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '2018', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '2020', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '2028', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Samstag - 'So': {'read': True, 'write': True, 'opcode': '2030', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Sonntag - }, - 'M2': { - # Schaltzeiten HK - 'Mo': {'read': True, 'write': True, 'opcode': '3000', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Montag - 'Di': {'read': True, 'write': True, 'opcode': '3008', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Dienstag - 'Mi': {'read': True, 'write': True, 'opcode': '3010', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Mittwoch - 'Do': {'read': True, 'write': True, 'opcode': '3018', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Donnerstag - 'Fr': {'read': True, 'write': True, 'opcode': '3020', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Freitag - 'Sa': {'read': True, 'write': True, 'opcode': '3028', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Samstag - 'So': {'read': True, 'write': True, 'opcode': '3030', 'reply_pattern': '*', 'item_type': 'list', 'dev_datatype': 'C', 'params': {'value': 'VAL', 'len': 8}}, # Timer Heizkreis Sonntag - }, - }, + # Allgemein + 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # Ermittle Device Typ der Anlage + 'Anlagenschema': {'addr': '7700', 'len': 2, 'unit': 'SC', 'set': False}, # Anlagenschema + 'AnlagenSoftwareIndex': {'addr': '7330', 'len': 1, 'unit': 'IUNON', 'set': False}, # Bedienteil SoftwareIndex + 'Aussentemperatur': {'addr': '0800', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur_tiefpass + 'Aussentemperatur_Dp': {'addr': '5527', 'len': 2, 'unit': 'IS10', 'set': False}, # Aussentemperatur in Grad C (Gedaempft) + 'Systemtime': {'addr': '088e', 'len': 8, 'unit': 'TI', 'set': True}, # Systemzeit + # Kessel + 'TempKOffset': {'addr': '6760', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 10, 'max_value': 50}, # Kesseloffset KT ueber WWsoll in Grad C + 'Kesseltemperatur': {'addr': '0802', 'len': 2, 'unit': 'IU10', 'set': False}, # Kesseltemperatur + 'Kesselsolltemperatur': {'addr': '5502', 'len': 2, 'unit': 'IU10', 'set': True}, # Kesselsolltemperatur + # Fehler + 'Sammelstoerung': {'addr': '0847', 'len': 1, 'unit': 'RT', 'set': False}, # Sammelstörung + 'Brennerstoerung': {'addr': '0883', 'len': 1, 'unit': 'RT', 'set': False}, + 'Error0': {'addr': '7507', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 1 + 'Error1': {'addr': '7510', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 2 + 'Error2': {'addr': '7519', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 3 + 'Error3': {'addr': '7522', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 4 + 'Error4': {'addr': '752b', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 5 + 'Error5': {'addr': '7534', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 6 + 'Error6': {'addr': '753d', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 7 + 'Error7': {'addr': '7546', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 8 + 'Error8': {'addr': '754f', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 9 + 'Error9': {'addr': '7558', 'len': 9, 'unit': 'ES', 'set': False}, # Fehlerhistory Eintrag 10 + # Pumpen + 'Speicherladepumpe': {'addr': '0845', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Speicherladepumpe für Warmwasser + 'Zirkulationspumpe': {'addr': '0846', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Zirkulationspumpe + 'Heizkreispumpe_A1M1': {'addr': '2906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe A1M1 + 'Heizkreispumpe_M2': {'addr': '3906', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Heizkreispumpe M2 + # Brenner + 'Brennertyp': {'addr': 'a30b', 'len': 1, 'unit': 'IUNON', 'set': False}, # Brennertyp 0=einstufig 1=zweistufig 2=modulierend + 'Brennerstufe': {'addr': '551e', 'len': 1, 'unit': 'RT', 'set': False}, # Ermittle die aktuelle Brennerstufe + 'Brennerstarts': {'addr': '088a', 'len': 2, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brennerstarts + 'Brennerstatus_1': {'addr': '55d3', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe1 + 'Brennerstatus_2': {'addr': '0849', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Brennerstatus Stufe2 + 'Brenner_BetriebsstundenStufe1': {'addr': '0886', 'len': 4, 'unit': 'IU3600', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brenner-Betriebsstunden Stufe 1 + 'Brenner_BetriebsstundenStufe2': {'addr': '08a3', 'len': 4, 'unit': 'IU3600', 'set': True, 'min_value': 0, 'max_value': 1193045}, # Brenner-Betriebsstunden Stufe 2 + # Heizkreis A1M1 + 'Betriebsart_A1M1': {'addr': '2301', 'len': 1, 'unit': 'BA', 'set': True}, # Betriebsart A1M1 + 'Aktuelle_Betriebsart_A1M1': {'addr': '2500', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart A1M1 + 'Sparbetrieb_A1M1': {'addr': '2302', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Sparbetrieb A1M1 + 'Partybetrieb_A1M1_Zeit': {'addr': '27f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Partyzeit M2 + 'Partybetrieb_A1M1': {'addr': '2303', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Partybetrieb A1M1 + 'Vorlauftemperatur_A1M1': {'addr': '2900', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur A1M1 + 'Vorlauftemperatur_Soll_A1M1': {'addr': '2544', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Soll A1M1 + 'Raumtemperatur_Soll_Normalbetrieb_A1M1': {'addr': '2306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb A1M1 + 'Raumtemperatur_Soll_Red_Betrieb_A1M1': {'addr': '2307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb A1M1 + 'Raumtemperatur_Soll_Party_Betrieb_A1M1': {'addr': '2308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb A1M1 + 'Neigung_Heizkennlinie_A1M1': {'addr': '2305', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie A1M1 + 'Niveau_Heizkennlinie_A1M1': {'addr': '2304', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie A1M1 + 'MischerM1': {'addr': '254c', 'len': 1, 'unit': 'IUPR', 'set': False}, # Ermittle Mischerposition M1 + 'Heizkreispumpenlogik_A1M1': {'addr': '27a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # 0=ohne HPL-Funktion, 1=AT > RTsoll + 5 K, 2=AT > RTsoll + 4 K, 3=AT > RTsoll + 3 K, 4=AT > RTsoll + 2 K, 5=AT > RTsoll + 1 K, 6=AT > RTsoll, 7=AT > RTsoll - 1 K, 8=AT > RTsoll - 2 K, 9=AT > RTsoll - 3 K, 10=AT > RTsoll - 4 K, 11=AT > RTsoll - 5 K, 12=AT > RTsoll - 6 K, 13=AT > RTsoll - 7 K, 14=AT > RTsoll - 8 K, 15=AT > RTsoll - 9 K + 'Sparschaltung_A1M1': {'addr': '27a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 36}, # AbsolutSommersparschaltung + # Heizkreis M2 + 'Betriebsart_M2': {'addr': '3301', 'len': 1, 'unit': 'BA', 'set': True}, # Betriebsart M2 + 'Aktuelle_Betriebsart_M2': {'addr': '3500', 'len': 1, 'unit': 'BA', 'set': False}, # Aktuelle Betriebsart M2 + 'Sparbetrieb_M2': {'addr': '3302', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Sparbetrieb + 'Partybetrieb_M2': {'addr': '3303', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # Partybetrieb A1M1 + 'Partybetrieb_M2_Zeit': {'addr': '37f2', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 0, 'max_value': 12}, # Partyzeit M2 + 'Raumtemperatur_Soll_Normalbetrieb_M2': {'addr': '3306', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Normalbetrieb + 'Raumtemperatur_Soll_Red_Betrieb_M2': {'addr': '3307', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Reduzierter Betrieb + 'Raumtemperatur_Soll_Party_Betrieb_M2': {'addr': '3308', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 4, 'max_value': 37}, # Raumtemperatur Soll Party Betrieb + 'Neigung_Heizkennlinie_M2': {'addr': '3305', 'len': 1, 'unit': 'IU10', 'set': True, 'min_value': 0.2, 'max_value': 3.5}, # Neigung Heizkennlinie M2 + 'Niveau_Heizkennlinie_M2': {'addr': '3304', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': -13, 'max_value': 40}, # Niveau Heizkennlinie M2 + 'MischerM2': {'addr': '354c', 'len': 1, 'unit': 'IUPR', 'set': False}, # Ermittle Mischerposition M2 + 'MischerM2Auf': {'addr': '084d', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # MischerM2 Auf 0=AUS;1=EIN + 'MischerM2Zu': {'addr': '084c', 'len': 1, 'unit': 'IUBOOL', 'set': True, 'min_value': 0, 'max_value': 1}, # MischerM2 Zu 0=AUS;1=EIN + 'Vorlauftemperatur_Soll_M2': {'addr': '37c6', 'len': 2, 'unit': 'IU10', 'set': True, 'min_value': 10, 'max_value': 80}, # Vorlauftemperatur Soll + 'Vorlauftemperatur_M2': {'addr': '080c', 'len': 2, 'unit': 'IU10', 'set': False}, # Vorlauftemperatur Ist + 'Vorlauftemperatur_min_M2': {'addr': '37c5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Minimalbegrenzung der Vorlauftemperatur + 'Vorlauftemperatur_max_M2': {'addr': '37c6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 1, 'max_value': 127}, # Maximalbegrenzung der Vorlauftemperatur + 'Heizkreispumpenlogik_M2': {'addr': '37a5', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 0, 'max_value': 15}, # 0=ohne HPL-Funktion, 1=AT > RTsoll + 5 K, 2=AT > RTsoll + 4 K, 3=AT > RTsoll + 3 K, 4=AT > RTsoll + 2 K, 5=AT > RTsoll + 1 K, 6=AT > RTsoll, 7=AT > RTsoll - 1 K, 8=AT > RTsoll - 2 K, 9=AT > RTsoll - 3 K, 10=AT > RTsoll - 4 K, 11=AT > RTsoll - 5 K, 12=AT > RTsoll - 6 K, 13=AT > RTsoll - 7 K, 14=AT > RTsoll - 8 K, 15=AT > RTsoll - 9 K + 'Sparschaltung_M2': {'addr': '37a6', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 5, 'max_value': 36}, # AbsolutSommersparschaltung + 'StatusKlemme2': {'addr': '3904', 'len': 1, 'unit': 'IUINT', 'set': False}, # 0=OK, 1=Kurzschluss, 2=nicht vorhanden, 3-5=Referenzfehler, 6=nicht vorhanden + 'StatusKlemme17': {'addr': '3905', 'len': 1, 'unit': 'IUINT', 'set': False}, # 0=OK, 1=Kurzschluss, 2=nicht vorhanden, 3-5=Referenzfehler, 6=nicht vorhanden + # Warmwasser + 'Warmwasser_Status': {'addr': '650A', 'len': 1, 'unit': 'IUNON', 'set': False}, # 0=Ladung inaktiv, 1=in Ladung, 2=im Nachlauf + 'Warmwasser_KesselOffset': {'addr': '6760', 'len': 1, 'unit': 'IUINT', 'set': True, 'min_value': 10, 'max_value': 50}, # Warmwasser Kessel Offset in K + 'Warmwasser_BeiPartyDNormal': {'addr': '6764', 'len': 1, 'unit': 'IUNON', 'set': True, 'min_value': 0, 'max_value': 2}, # WW Heizen bei Party 0=AUS, 1=nach Schaltuhr, 2=EIN + 'Warmwasser_Temperatur': {'addr': '0804', 'len': 2, 'unit': 'IU10', 'set': False}, # Warmwassertemperatur in Grad C + 'Warmwasser_Solltemperatur': {'addr': '6300', 'len': 1, 'unit': 'ISNON', 'set': True, 'min_value': 10, 'max_value': 80}, # Warmwasser-Solltemperatur + 'Warmwasser_SolltemperaturAktuell': {'addr': '6500', 'len': 1, 'unit': 'IU10' , 'set': False}, # Warmwasser-Solltemperatur aktuell + 'Warmwasser_SollwertMax': {'addr': '675a', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # 0=inaktiv, 1=aktiv + # Ferienprogramm HK_A1M1 + 'Ferienprogramm_A1M1': {'addr': '2535', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Ferienprogramm A1M1 0=inaktiv 1=aktiv + 'Ferien_Abreisetag_A1M1': {'addr': '2309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag A1M1 + 'Ferien_Rückreisetag_A1M1': {'addr': '2311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag A1M1 + # Ferienprogramm HK_M2 + 'Ferienprogramm_M2': {'addr': '3535', 'len': 1, 'unit': 'IUBOOL', 'set': False}, # Ferienprogramm M2 0=inaktiv 1=aktiv + 'Ferien_Abreisetag_M2': {'addr': '3309', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Abreisetag M2 + 'Ferien_Rückreisetag_M2': {'addr': '3311', 'len': 8, 'unit': 'DA', 'set': True}, # Ferien Rückreisetag M2 + # Schaltzeiten Warmwasser + 'Timer_Warmwasser_Mo': {'addr': '2100', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Montag + 'Timer_Warmwasser_Di': {'addr': '2108', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Dienstag + 'Timer_Warmwasser_Mi': {'addr': '2110', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Mittwoch + 'Timer_Warmwasser_Do': {'addr': '2118', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Donnerstag + 'Timer_Warmwasser_Fr': {'addr': '2120', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Freitag + 'Timer_Warmwasser_Sa': {'addr': '2128', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Samstag + 'Timer_Warmwasser_So': {'addr': '2130', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Warmwasserbereitung Sonntag + # Schaltzeiten HK_A1M1 + 'Timer_A1M1_Mo': {'addr': '2000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag + 'Timer_A1M1_Di': {'addr': '2008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag + 'Timer_A1M1_Mi': {'addr': '2010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch + 'Timer_A1M1_Do': {'addr': '2018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag + 'Timer_A1M1_Fr': {'addr': '2020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag + 'Timer_A1M1_Sa': {'addr': '2028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag + 'Timer_A1M1_So': {'addr': '2030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag + # Schaltzeiten HK_M2 + 'Timer_M2_Mo': {'addr': '3000', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Montag + 'Timer_M2_Di': {'addr': '3008', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Dienstag + 'Timer_M2_Mi': {'addr': '3010', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Mittwoch + 'Timer_M2_Do': {'addr': '3018', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Donnerstag + 'Timer_M2_Fr': {'addr': '3020', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Freitag + 'Timer_M2_Sa': {'addr': '3028', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Samstag + 'Timer_M2_So': {'addr': '3030', 'len': 8, 'unit': 'CT', 'set': True}, # Timer Heizkreis_A1M1 Sonntag }, 'V200WO1C': { - 'Allgemein': {'item_attrs': {'cycle': 45}, - 'Temperatur': { - 'Aussen': {'read': True, 'write': False, 'opcode': '0101', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempA -- Information - Allgemein: Aussentemperatur (-40..70) - }, - # Anlagenstatus - 'Betriebsart': {'read': True, 'write': True, 'opcode': 'b000', 'reply_pattern': '*', 'item_type': 'str', 'dev_datatype': 'H', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'operatingmodes', 'item_attrs': {'initial': True, 'lookup_item': True}}, # getBetriebsart -- Bedienung HK1 - Heizkreis 1: Betriebsart (Textstring) - 'Manuell': {'read': True, 'write': True, 'opcode': 'b020', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'cmd_settings': {'force_min': 0, 'force_max': 2}}, # getManuell / setManuell -- 0 = normal, 1 = manueller Heizbetrieb, 2 = 1x Warmwasser auf Temp2 - # Allgemein - 'Outdoor_Fanspeed': {'read': True, 'write': False, 'opcode': '1a52', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getSpdFanOut -- Outdoor Fanspeed - 'Status_Fanspeed': {'read': True, 'write': False, 'opcode': '1a53', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getSpdFan -- Geschwindigkeit Luefter - 'Kompressor_Freq': {'read': True, 'write': False, 'opcode': '1a54', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getSpdKomp -- Compressor Frequency - 'SollLeistungVerdichter': {'read': True, 'write': False, 'opcode': '5030', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getPwrSollVerdichter -- Diagnose - Anlagenuebersicht: Soll-Leistung Verdichter 1 (0..100) - }, - 'Pumpen': { - 'Sekundaer': {'read': True, 'write': False, 'opcode': '0484', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # getStatusSekP -- Diagnose - Anlagenuebersicht: Sekundaerpumpe 1 (0..1) - 'Heizkreis': {'read': True, 'write': False, 'opcode': '048d', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # getStatusPumpe -- Information - Heizkreis HK1: Heizkreispumpe (0..1) - 'Zirkulation': {'read': True, 'write': False, 'opcode': '0490', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # getStatusPumpeZirk -- Information - Warmwasser: Zirkulationspumpe (0..1) - }, - 'Heizkreis': { - 'Temperatur': { - 'Raum': { - 'Soll': {'read': True, 'write': False, 'opcode': '2000', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempRaumSollNormal -- Bedienung HK1 - Heizkreis 1: Raumsolltemperatur normal (10..30) - 'Soll_Reduziert': {'read': True, 'write': False, 'opcode': '2001', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempRaumSollRed -- Bedienung HK1 - Heizkreis 1: Raumsolltemperatur reduzierter Betrieb (10..30) - 'Soll_Party': {'read': True, 'write': False, 'opcode': '2022', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempRaumSollParty -- Bedienung HK1 - Heizkreis 1: Party Solltemperatur (10..30) - }, - 'Vorlauf': { - 'Ist': {'read': True, 'write': False, 'opcode': '0105', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempSekVL -- Information - Heizkreis HK1: Vorlauftemperatur Sekundaer 1 (0..95) - 'Soll': {'read': True, 'write': False, 'opcode': '1800', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempVLSoll -- Diagnose - Heizkreis HK1: Vorlaufsolltemperatur HK1 (0..95) - 'Mittel': {'read': True, 'write': False, 'opcode': '16b2', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempSekVLMittel -- Statistik - Energiebilanz: mittlere sek. Vorlauftemperatur (0..95) - }, - 'Ruecklauf': { - 'Ist': {'read': True, 'write': False, 'opcode': '0106', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempSekRL -- Diagnose - Anlagenuebersicht: Ruecklauftemperatur Sekundaer 1 (0..95) - 'Mittel': {'read': True, 'write': False, 'opcode': '16b3', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempSekRLMittel -- Statistik - Energiebilanz: mittlere sek.Temperatur RL1 (0..95) - }, - }, - 'Heizkennlinie': { - 'Niveau': {'read': True, 'write': False, 'opcode': '2006', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getHKLNiveau -- Bedienung HK1 - Heizkreis 1: Niveau der Heizkennlinie (-15..40) - 'Neigung': {'read': True, 'write': False, 'opcode': '2007', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getHKLNeigung -- Bedienung HK1 - Heizkreis 1: Neigung der Heizkennlinie (0..35) - }, - }, - 'Warmwasser': { - 'Ist': {'read': True, 'write': False, 'opcode': '010d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}}, # getTempWWIstOben -- Information - Warmwasser: Warmwassertemperatur oben (0..95) - 'Soll': {'read': True, 'write': True, 'opcode': '6000', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'signed': True, 'len': 2}, 'cmd_settings': {'force_min': 10, 'force_max': 60}}, # getTempWWSoll -- Bedienung WW - Betriebsdaten WW: Warmwassersolltemperatur (10..60 (95)) - 'Ventil': {'read': True, 'write': False, 'opcode': '0494', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}, 'lookup': 'returnstatus'}, # getStatusVentilWW -- Diagnose - Waermepumpe: 3-W-Ventil Heizen WW1 (0 (Heizen)..1 (WW)) - }, - 'Statistik': { - # Statistiken / Laufzeiten - 'Einschaltungen': { - 'Sekundaer': {'read': True, 'write': False, 'opcode': '0504', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getAnzQuelleSek -- Statistik - Schaltzyklen Anlage: Einschaltungen Sekundaerquelle (?) - 'Heizstab1': {'read': True, 'write': False, 'opcode': '0508', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getAnzHeizstabSt1 -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizstab Stufe 1 (?) - 'Heizstab2': {'read': True, 'write': False, 'opcode': '0509', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getAnzHeizstabSt2 -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizstab Stufe 2 (?) - 'HK': {'read': True, 'write': False, 'opcode': '050d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getAnzHK -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizkreis (?) - }, - 'Laufzeiten': { - 'Sekundaerpumpe': {'read': True, 'write': False, 'opcode': '0584', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # getLZPumpeSek -- Statistik - Betriebsstunden Anlage: Betriebsstunden Sekundaerpumpe (?) - 'Heizstab1': {'read': True, 'write': False, 'opcode': '0588', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # getLZHeizstabSt1 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Heizstab Stufe 1 (?) - 'Heizstab2': {'read': True, 'write': False, 'opcode': '0589', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # getLZHeizstabSt2 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Heizstab Stufe 2 (?) - 'PumpeHK': {'read': True, 'write': False, 'opcode': '058d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # getLZPumpe -- Statistik - Betriebsstunden Anlage: Betriebsstunden Pumpe HK1 (0..1150000) - 'WWVentil': {'read': True, 'write': False, 'opcode': '0594', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # getLZVentilWW -- Statistik - Betriebsstunden Anlage: Betriebsstunden Warmwasserventil (?) - 'VerdichterStufe1': {'read': True, 'write': False, 'opcode': '1620', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getLZVerdSt1 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 1 (?) - 'VerdichterStufe2': {'read': True, 'write': False, 'opcode': '1622', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getLZVerdSt2 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 2 (?) - 'VerdichterStufe3': {'read': True, 'write': False, 'opcode': '1624', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getLZVerdSt3 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 3 (?) - 'VerdichterStufe4': {'read': True, 'write': False, 'opcode': '1626', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getLZVerdSt4 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 4 (?) - 'VerdichterStufe5': {'read': True, 'write': False, 'opcode': '1628', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 4}}, # getLZVerdSt5 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 5 (?) - 'VerdichterWP': {'read': True, 'write': False, 'opcode': '5005', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 3600, 'len': 4}}, # getLZWP -- Statistik - Betriebsstunden Anlage: Betriebsstunden Waermepumpe (0..1150000) - }, - 'OAT_Temperature': {'read': True, 'write': False, 'opcode': '1a5c', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getTempOAT -- OAT Temperature - 'ICT_Temperature': {'read': True, 'write': False, 'opcode': '1a5d', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getTempICT -- OCT Temperature - 'CCT_Temperature': {'read': True, 'write': False, 'opcode': '1a5e', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getTempCCT -- CCT Temperature - 'HST_Temperature': {'read': True, 'write': False, 'opcode': '1a5f', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getTempHST -- HST Temperature - 'OMT_Temperature': {'read': True, 'write': False, 'opcode': '1a60', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'len': 1}}, # getTempOMT -- OMT Temperature - 'WaermeWW12M': {'read': True, 'write': False, 'opcode': '1660', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 4}}, # Wärmeenergie für WW-Bereitung der letzten 12 Monate (kWh) - 'ElektroWW12M': {'read': True, 'write': False, 'opcode': '1670', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'V', 'params': {'value': 'VAL', 'mult': 10, 'len': 4}}, # elektr. Energie für WW-Bereitung der letzten 12 Monate (kWh) - } + # generelle Infos + 'Anlagentyp': {'addr': '00f8', 'len': 2, 'unit': 'DT', 'set': False}, # getAnlTyp -- Information - Allgemein: Anlagentyp (204D) + 'Aussentemperatur': {'addr': '0101', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempA -- Information - Allgemein: Aussentemperatur (-40..70) + # Anlagenstatus + 'Betriebsart': {'addr': 'b000', 'len': 1, 'unit': 'BA', 'set': True}, # getBetriebsart -- Bedienung HK1 - Heizkreis 1: Betriebsart (Textstring) + 'Manuell': {'addr': 'b020', 'len': 1, 'unit': 'IUNON', 'set': True, 'min_value': 0, 'max_value': 2}, # getManuell / setManuell -- 0 = normal, 1 = manueller Heizbetrieb, 2 = 1x Warmwasser auf Temp2 + 'Sekundaerpumpe': {'addr': '0484', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusSekP -- Diagnose - Anlagenuebersicht: Sekundaerpumpe 1 (0..1) + 'Heizkreispumpe': {'addr': '048d', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusPumpe -- Information - Heizkreis HK1: Heizkreispumpe (0..1) + 'Zirkulationspumpe': {'addr': '0490', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusPumpeZirk -- Information - Warmwasser: Zirkulationspumpe (0..1) + 'VentilHeizenWW': {'addr': '0494', 'len': 1, 'unit': 'RT', 'set': False}, # getStatusVentilWW -- Diagnose - Waermepumpe: 3-W-Ventil Heizen WW1 (0 (Heizen)..1 (WW)) + 'Vorlaufsolltemp': {'addr': '1800', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempVLSoll -- Diagnose - Heizkreis HK1: Vorlaufsolltemperatur HK1 (0..95) + 'Outdoor_Fanspeed': {'addr': '1a52', 'len': 1, 'unit': 'IUNON', 'set': False}, # getSpdFanOut -- Outdoor Fanspeed + 'Status_Fanspeed': {'addr': '1a53', 'len': 1, 'unit': 'IUNON', 'set': False}, # getSpdFan -- Geschwindigkeit Luefter + 'Kompressor_Freq': {'addr': '1a54', 'len': 1, 'unit': 'IUNON', 'set': False}, # getSpdKomp -- Compressor Frequency + # Temperaturen + 'SolltempWarmwasser': {'addr': '6000', 'len': 2, 'unit': 'IS10', 'set': True, 'min_value': 10, 'max_value': 60}, # getTempWWSoll -- Bedienung WW - Betriebsdaten WW: Warmwassersolltemperatur (10..60 (95)) + 'VorlauftempSek': {'addr': '0105', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekVL -- Information - Heizkreis HK1: Vorlauftemperatur Sekundaer 1 (0..95) + 'RuecklauftempSek': {'addr': '0106', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekRL -- Diagnose - Anlagenuebersicht: Ruecklauftemperatur Sekundaer 1 (0..95) + 'Warmwassertemperatur': {'addr': '010d', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempWWIstOben -- Information - Warmwasser: Warmwassertemperatur oben (0..95) + # Stellwerte + 'Raumsolltemp': {'addr': '2000', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempRaumSollNormal -- Bedienung HK1 - Heizkreis 1: Raumsolltemperatur normal (10..30) + 'RaumsolltempReduziert': {'addr': '2001', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempRaumSollRed -- Bedienung HK1 - Heizkreis 1: Raumsolltemperatur reduzierter Betrieb (10..30) + 'HeizkennlinieNiveau': {'addr': '2006', 'len': 2, 'unit': 'IS10', 'set': False}, # getHKLNiveau -- Bedienung HK1 - Heizkreis 1: Niveau der Heizkennlinie (-15..40) + 'HeizkennlinieNeigung': {'addr': '2007', 'len': 2, 'unit': 'IS10', 'set': False}, # getHKLNeigung -- Bedienung HK1 - Heizkreis 1: Neigung der Heizkennlinie (0..35) + 'RaumsolltempParty': {'addr': '2022', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempRaumSollParty -- Bedienung HK1 - Heizkreis 1: Party Solltemperatur (10..30) + # Statistiken / Laufzeiten + 'EinschaltungenSekundaer': {'addr': '0504', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzQuelleSek -- Statistik - Schaltzyklen Anlage: Einschaltungen Sekundaerquelle (?) + 'EinschaltungenHeizstab1': {'addr': '0508', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzHeizstabSt1 -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizstab Stufe 1 (?) + 'EinschaltungenHeizstab2': {'addr': '0509', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzHeizstabSt2 -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizstab Stufe 2 (?) + 'EinschaltungenHK': {'addr': '050d', 'len': 4, 'unit': 'IUNON', 'set': False}, # getAnzHK -- Statistik - Schaltzyklen Anlage: Einschaltungen Heizkreis (?) + 'LZSekundaerpumpe': {'addr': '0584', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZPumpeSek -- Statistik - Betriebsstunden Anlage: Betriebsstunden Sekundaerpumpe (?) + 'LZHeizstab1': {'addr': '0588', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZHeizstabSt1 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Heizstab Stufe 1 (?) + 'LZHeizstab2': {'addr': '0589', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZHeizstabSt2 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Heizstab Stufe 2 (?) + 'LZPumpeHK': {'addr': '058d', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZPumpe -- Statistik - Betriebsstunden Anlage: Betriebsstunden Pumpe HK1 (0..1150000) + 'LZWWVentil': {'addr': '0594', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZVentilWW -- Statistik - Betriebsstunden Anlage: Betriebsstunden Warmwasserventil (?) + 'LZVerdichterStufe1': {'addr': '1620', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt1 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 1 (?) + 'LZVerdichterStufe2': {'addr': '1622', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt2 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 2 (?) + 'LZVerdichterStufe3': {'addr': '1624', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt3 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 3 (?) + 'LZVerdichterStufe4': {'addr': '1626', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt4 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 4 (?) + 'LZVerdichterStufe5': {'addr': '1628', 'len': 4, 'unit': 'IUNON', 'set': False}, # getLZVerdSt5 -- Statistik - Betriebsstunden Anlage: Betriebsstunden Verdichter auf Stufe 5 (?) + 'VorlauftempSekMittel': {'addr': '16b2', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekVLMittel -- Statistik - Energiebilanz: mittlere sek. Vorlauftemperatur (0..95) + 'RuecklauftempSekMittel': {'addr': '16b3', 'len': 2, 'unit': 'IS10', 'set': False}, # getTempSekRLMittel -- Statistik - Energiebilanz: mittlere sek.Temperatur RL1 (0..95) + 'OAT_Temperature': {'addr': '1a5c', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempOAT -- OAT Temperature + 'ICT_Temperature': {'addr': '1a5d', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempICT -- OCT Temperature + 'CCT_Temperature': {'addr': '1a5e', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempCCT -- CCT Temperature + 'HST_Temperature': {'addr': '1a5f', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempHST -- HST Temperature + 'OMT_Temperature': {'addr': '1a60', 'len': 1, 'unit': 'IUNON', 'set': False}, # getTempOMT -- OMT Temperature + 'LZVerdichterWP': {'addr': '5005', 'len': 4, 'unit': 'IU3600', 'set': False}, # getLZWP -- Statistik - Betriebsstunden Anlage: Betriebsstunden Waermepumpe (0..1150000) + 'SollLeistungVerdichter': {'addr': '5030', 'len': 1, 'unit': 'IUNON', 'set': False}, # getPwrSollVerdichter -- Diagnose - Anlagenuebersicht: Soll-Leistung Verdichter 1 (0..100) + 'WaermeWW12M': {'addr': '1660', 'len': 4, 'unit': 'IU10', 'set': False}, # Wärmeenergie für WW-Bereitung der letzten 12 Monate (kWh) + 'ElektroWW12M': {'addr': '1670', 'len': 4, 'unit': 'IU10', 'set': False}, # elektr. Energie für WW-Bereitung der letzten 12 Monate (kWh) + }, +} + +unitset = { + 'P300': { + 'BA': {'unit_de': 'Betriebsart', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: BA + 'CT': {'unit_de': 'CycleTime', 'type': 'timer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: CT + 'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: DT + 'ES': {'unit_de': 'ErrorState', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ES + 'IU2': {'unit_de': 'INT unsigned 2', 'type': 'integer', 'signed': False, 'read_value_transform': '2'}, # vito unit: UT1U, PR1 + 'IU10': {'unit_de': 'INT unsigned 10', 'type': 'integer', 'signed': False, 'read_value_transform': '10'}, # vito unit: + 'IU100': {'unit_de': 'INT unsigned 100', 'type': 'integer', 'signed': False, 'read_value_transform': '100'}, # vito unit: + 'IU3600': {'unit_de': 'INT unsigned 3600', 'type': 'integer', 'signed': False, 'read_value_transform': '3600'}, # vito unit: CS + 'IUBOOL': {'unit_de': 'INT unsigned bool', 'type': 'integer', 'signed': False, 'read_value_transform': 'bool'}, # vito unit: + 'IUINT': {'unit_de': 'INT unsigned int', 'type': 'integer', 'signed': False, 'read_value_transform': '1'}, # vito unit: + 'IUNON': {'unit_de': 'INT unsigned non', 'type': 'integer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: UTI, CO + 'IS2': {'unit_de': 'INT signed 2', 'type': 'integer', 'signed': True, 'read_value_transform': '2'}, # vito unit: UT1, PR + 'IS10': {'unit_de': 'INT signed 10', 'type': 'integer', 'signed': True, 'read_value_transform': '10'}, # vito unit: UT, UN + 'IS100': {'unit_de': 'INT signed 100', 'type': 'integer', 'signed': True, 'read_value_transform': '100'}, # vito unit: + 'IS1000': {'unit_de': 'INT signed 1000', 'type': 'integer', 'signed': True, 'read_value_transform': '1000'}, # vito unit: + 'ISNON': {'unit_de': 'INT signed non', 'type': 'integer', 'signed': True, 'read_value_transform': 'non'}, # vito unit: + 'RT': {'unit_de': 'ReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ST, RT + 'SC': {'unit_de': 'SystemScheme', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'SN': {'unit_de': 'Sachnummer', 'type': 'serial', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'SR': {'unit_de': 'SetReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'TI': {'unit_de': 'SystemTime', 'type': 'datetime', 'signed': False, 'read_value_transform': 'non'}, # vito unit: TI + 'DA': {'unit_de': 'Date', 'type': 'date', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'HEX': {'unit_de': 'HexString', 'type': 'string', 'signed': False, 'read_value_transform': 'hex'}, # vito unit: + }, + 'KW': { + 'BA': {'unit_de': 'Betriebsart', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: BA + 'CT': {'unit_de': 'CycleTime', 'type': 'timer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: CT + 'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: DT + 'ES': {'unit_de': 'ErrorState', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ES + 'IU2': {'unit_de': 'INT unsigned 2', 'type': 'integer', 'signed': False, 'read_value_transform': '2'}, # vito unit: UT1U, PR1 + 'IU10': {'unit_de': 'INT unsigned 10', 'type': 'integer', 'signed': False, 'read_value_transform': '10'}, # vito unit: + 'IU100': {'unit_de': 'INT unsigned 100', 'type': 'integer', 'signed': False, 'read_value_transform': '100'}, # vito unit: + 'IU1000': {'unit_de': 'INT unsigned 1000', 'type': 'integer', 'signed': False, 'read_value_transform': '1000'}, # vito unit: + 'IU3600': {'unit_de': 'INT unsigned 3600', 'type': 'integer', 'signed': False, 'read_value_transform': '3600'}, # vito unit: CS + 'IUPR': {'unit_de': 'INT unsigned 2.55', 'type': 'integer', 'signed': False, 'read_value_transform': '2.55'}, # vito unit: PP + 'IUBOOL': {'unit_de': 'INT unsigned bool', 'type': 'integer', 'signed': False, 'read_value_transform': 'bool'}, # vito unit: + 'IUINT': {'unit_de': 'INT unsigned int', 'type': 'integer', 'signed': False, 'read_value_transform': '1'}, # vito unit: + 'IUNON': {'unit_de': 'INT unsigned non', 'type': 'integer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: UTI, CO + 'IS2': {'unit_de': 'INT signed 2', 'type': 'integer', 'signed': True, 'read_value_transform': '2'}, # vito unit: UT1, PR + 'IS10': {'unit_de': 'INT signed 10', 'type': 'integer', 'signed': True, 'read_value_transform': '10'}, # vito unit: UT, UN + 'IS100': {'unit_de': 'INT signed 100', 'type': 'integer', 'signed': True, 'read_value_transform': '100'}, # vito unit: + 'IS1000': {'unit_de': 'INT signed 1000', 'type': 'integer', 'signed': True, 'read_value_transform': '1000'}, # vito unit: + 'ISNON': {'unit_de': 'INT signed non', 'type': 'integer', 'signed': True, 'read_value_transform': 'non'}, # vito unit: + 'RT': {'unit_de': 'ReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ST, RT + 'BT': {'unit_de': 'Brennertyp', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'SC': {'unit_de': 'SystemScheme', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'SN': {'unit_de': 'Sachnummer', 'type': 'serial', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'SR': {'unit_de': 'SetReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'TI': {'unit_de': 'SystemTime', 'type': 'datetime', 'signed': False, 'read_value_transform': 'non'}, # vito unit: TI + 'DA': {'unit_de': 'Date', 'type': 'date', 'signed': False, 'read_value_transform': 'non'}, # vito unit: + 'HEX': {'unit_de': 'HexString', 'type': 'string', 'signed': False, 'read_value_transform': 'hex'}, # vito unit: } } -lookups = { - 'ALL': { - 'devicetypes': { - '2098': 'V200KW2', # Protokoll: KW - '2053': 'GWG_VBEM', # Protokoll: GWG - '20CB': 'VScotHO1', # Protokoll: P300 - '2094': 'V200KW1', # Protokoll: KW - '209F': 'V200KO1B', # Protokoll: P300 - '204D': 'V200WO1C', # Protokoll: P300 - '20B8': 'V333MW1', - '20A0': 'V100GC1', - '20C2': 'VDensHO1', - '20A4': 'V200GW1', - '20C8': 'VPlusHO1', - '2046': 'V200WO1', - '2047': 'V200WO1', - '2049': 'V200WO1', - '2032': 'VBC550', - '2033': 'VBC550' - }, - 'errors': { - '00': 'Regelbetrieb (kein Fehler)', - '0F': 'Wartung (fuer Reset Codieradresse 24 auf 0 stellen)', - '10': 'Kurzschluss Aussentemperatursensor', - '18': 'Unterbrechung Aussentemperatursensor', - '19': 'Unterbrechung Kommunikation Aussentemperatursensor RF', - '1D': 'Keine Kommunikation mit Sensor', - '1E': 'Strömungssensor defekt', - '1F': 'Strömungssensor defekt', - '20': 'Kurzschluss Vorlauftemperatursensor', - '21': 'Kurzschluss Ruecklauftemperatursensor', - '28': 'Unterbrechung Aussentemperatursensor / Vorlauftemperatursensor Anlage', - '29': 'Unterbrechung Ruecklauftemperatursensor', - '30': 'Kurzschluss Kesseltemperatursensor', - '38': 'Unterbrechung Kesseltemperatursensor', - '40': 'Kurzschluss Vorlauftemperatursensor M2', - '42': 'Unterbrechung Vorlauftemperatursensor M2', - '44': 'Kurzschluss Vorlauftemperatursensor Heizkreis 3', - '48': 'Unterbrechung Vorlauftemperatursensor Heizkreis 3', - '50': 'Kurzschluss Speichertemperatursensor', - '51': 'Kurzschluss Auslauftemperatursensor', - '58': 'Unterbrechung Speichertemperatursensor', - '59': 'Unterbrechung Auslauftemperatursensor', - '92': 'Solar: Kurzschluss Kollektortemperatursensor', - '93': 'Solar: Kurzschluss Sensor S3', - '94': 'Solar: Kurzschluss Speichertemperatursensor', - '9A': 'Solar: Unterbrechung Kollektortemperatursensor', - '9B': 'Solar: Unterbrechung Sensor S3', - '9C': 'Solar: Unterbrechung Speichertemperatursensor', - '9E': 'Solar: Zu geringer bzw. kein Volumenstrom oder Temperaturwächter ausgeloest', - '9F': 'Solar: Fehlermeldung Solarteil (siehe Solarregler)', - 'A4': 'Amx. Anlagendruck überschritten', - 'A7': 'Bedienteil defekt', - 'A8': 'Luft in der internen Umwaelzpumpe oder Mindest-Volumenstrom nicht erreicht', - 'B0': 'Kurzschluss Abgastemperatursensor', - 'B1': 'Kommunikationsfehler Bedieneinheit', - 'B4': 'Interner Fehler (Elektronik)', - 'B5': 'Interner Fehler (Elektronik)', - 'B6': 'Ungueltige Hardwarekennung (Elektronik)', - 'B7': 'Interner Fehler (Kesselkodierstecker)', - 'B8': 'Unterbrechung Abgastemperatursensor', - 'B9': 'Interner Fehler (Dateneingabe wiederholen)', - 'V': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2', - 'BB': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis 3', - 'BC': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1', - 'BD': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2', - 'BE': 'Falsche Codierung Fernbedienung Vitorol', - 'BF': 'Falsches Kommunikationsmodul LON', - 'C1': 'Externe Sicherheitseinrichtung (Kessel kuehlt aus)', - 'C2': 'Kommunikationsfehler Solarregelung', - 'C3': 'Kommunikationsfehler Erweiterung AM1', - 'C4': 'Kommunikationsfehler Erweiterumg Open Therm', - 'C5': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1', - 'C6': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2', - 'C7': 'Falsche Codierung der Heizkreispumpe', - 'C8': 'Kommunikationsfehler drehzahlgeregelte, externe Heizkreispumpe 3', - 'C9': 'Stoermeldeeingang am Schaltmodul-V aktiv', - 'CD': 'Kommunikationsfehler Vitocom 100 (KM-BUS)', - 'CE': 'Kommunikationsfehler Schaltmodul-V', - 'CF': 'Kommunikationsfehler LON Modul', - 'D1': 'Brennerstoerung', - 'D4': 'Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt', - 'D6': 'Eingang DE1 an Erweiterung EA1 meldet eine Stoerung', - 'D7': 'Eingang DE2 an Erweiterung EA1 meldet eine Stoerung', - 'D8': 'Eingang DE3 an Erweiterung EA1 meldet eine Stoerung', - 'D': 'Kurzschluss Raumtemperatursensor, Heizkreis M1', - 'DB': 'Kurzschluss Raumtemperatursensor, Heizkreis M2', - 'DC': 'Kurzschluss Raumtemperatursensor, Heizkreis 3', - 'DD': 'Unterbrechung Raumtemperatursensor, Heizkreis M1', - 'DE': 'Unterbrechung Raumtemperatursensor, Heizkreis M2', - 'DF': 'Unterbrechung Raumtemperatursensor, Heizkreis 3', - 'E0': 'Fehler externer LON Teilnehmer', - 'E1': 'Isolationsstrom waehrend des Kalibrierens zu hoch', - 'E3': 'Zu geringe Wärmeabnahme während des Kalibrierens, Temperaturwächter hat ausgeschaltet', - 'E4': 'Fehler Versorgungsspannung', - 'E5': 'Interner Fehler, Flammenverstärker(Ionisationselektrode)', - 'E6': 'Abgas- / Zuluftsystem verstopft, Anlagendruck zu niedrig', - 'E7': 'Ionisationsstrom waehrend des Kalibrierens zu gering', - 'E8': 'Ionisationsstrom nicht im gültigen Bereich', - 'EA': 'Ionisationsstrom waehrend des Kalibrierens nicht im gueltigen Bereich', - 'EB': 'Wiederholter Flammenverlust waehrend des Kalibrierens', - 'EC': 'Parameterfehler waehrend des Kalibrierens', - 'ED': 'Interner Fehler', - 'EE': 'Flammensignal ist bei Brennerstart nicht vorhanden oder zu gering', - 'EF': 'Flammenverlust direkt nach Flammenbildung (waehrend der Sicherheitszeit)', - 'F0': 'Interner Fehler (Regelung tauschen)', - 'F1': 'Abgastemperaturbegrenzer ausgeloest', - 'F2': 'Temperaturbegrenzer ausgeloest', - 'F3': 'Flammensigal beim Brennerstart bereits vorhanden', - 'F4': 'Flammensigal nicht vorhanden', - 'F7': 'Differenzdrucksensor defekt, Kurzschluss ider Wasserdrucksensor', - 'F8': 'Brennstoffventil schliesst zu spaet', - 'F9': 'Geblaesedrehzahl beim Brennerstart zu niedrig', - 'FA': 'Geblaesestillstand nicht erreicht', - 'FC': 'Gaskombiregler defekt oder fehlerhafte Ansteuerung Modulationsventil oder Abgasweg versperrt', - 'FD': 'Fehler Gasfeuerungsautomat, Kesselkodierstecker fehlt(in Verbindung mit B7)', - 'FE': 'Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt', - 'FF': 'Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler' - }, - 'operatingmodes': { - '00': 'Abschaltbetrieb', - '01': 'Reduzierter Betrieb', - '02': 'Normalbetrieb', - '03': 'Dauernd Normalbetrieb' - }, - 'returnstatus': { - '00': '0', - '01': '1', - '03': '2', - 'AA': 'NOT OK', - }, - 'setreturnstatus': { - '00': 'OK', - '05': 'SYNC (NOT OK)', - } +errorset = { + 'P300': { + '00': 'Regelbetrieb (kein Fehler)', + '0F': 'Wartung (fuer Reset Codieradresse 24 auf 0 stellen)', + '10': 'Kurzschluss Aussentemperatursensor', + '18': 'Unterbrechung Aussentemperatursensor', + '19': 'Unterbrechung Kommunikation Außentemperatursensor RF', + '1D': 'Keine Kommunikation mit Sensor', + '1E': 'Strömungssensor defekt', + '1F': 'Strömungssensor defekt', + '20': 'Kurzschluss Vorlauftemperatursensor', + '21': 'Kurzschluss Ruecklauftemperatursensor', + '28': 'Unterbrechung Aussentemperatursensor / Vorlauftemperatursensor Anlage', + '29': 'Unterbrechung Ruecklauftemperatursensor', + '30': 'Kurzschluss Kesseltemperatursensor', + '38': 'Unterbrechung Kesseltemperatursensor', + '40': 'Kurzschluss Vorlauftemperatursensor M2', + '42': 'Unterbrechung Vorlauftemperatursensor M2', + '44': 'Kurzschluss Vorlauftemperatursensor Heizkreis 3', + '48': 'Unterbrechung Vorlauftemperatursensor Heizkreis 3', + '50': 'Kurzschluss Speichertemperatursensor', + '51': 'Kurzschluss Auslauftemperatursensor', + '58': 'Unterbrechung Speichertemperatursensor', + '59': 'Unterbrechung Auslauftemperatursensor', + '92': 'Solar: Kurzschluss Kollektortemperatursensor', + '93': 'Solar: Kurzschluss Sensor S3', + '94': 'Solar: Kurzschluss Speichertemperatursensor', + '9A': 'Solar: Unterbrechung Kollektortemperatursensor', + '9B': 'Solar: Unterbrechung Sensor S3', + '9C': 'Solar: Unterbrechung Speichertemperatursensor', + '9E': 'Solar: Zu geringer bzw. kein Volumenstrom oder Temperaturwächter ausgeloest', + '9F': 'Solar: Fehlermeldung Solarteil (siehe Solarregler)', + 'A4': 'Amx. Anlagendruck überschritten', + 'A7': 'Bedienteil defekt', + 'A8': 'Luft in der internen Umwaelzpumpe oder Mindest-Volumenstrom nicht erreicht', + 'B0': 'Kurzschluss Abgastemperatursensor', + 'B1': 'Kommunikationsfehler Bedieneinheit', + 'B4': 'Interner Fehler (Elektronik)', + 'B5': 'Interner Fehler (Elektronik)', + 'B6': 'Ungueltige Hardwarekennung (Elektronik)', + 'B7': 'Interner Fehler (Kesselkodierstecker)', + 'B8': 'Unterbrechung Abgastemperatursensor', + 'B9': 'Interner Fehler (Dateneingabe wiederholen)', + 'BA': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2', + 'BB': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis 3', + 'BC': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1', + 'BD': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2', + 'BE': 'Falsche Codierung Fernbedienung Vitorol', + 'BF': 'Falsches Kommunikationsmodul LON', + 'C1': 'Externe Sicherheitseinrichtung (Kessel kuehlt aus)', + 'C2': 'Kommunikationsfehler Solarregelung', + 'C3': 'Kommunikationsfehler Erweiterung AM1', + 'C4': 'Kommunikationsfehler Erweiterumg Open Therm', + 'C5': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1', + 'C6': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2', + 'C7': 'Falsche Codierung der Heizkreispumpe', + 'C8': 'Kommunikationsfehler drehzahlgeregelte, externe Heizkreispumpe 3', + 'C9': 'Stoermeldeeingang am Schaltmodul-V aktiv', + 'CD': 'Kommunikationsfehler Vitocom 100 (KM-BUS)', + 'CE': 'Kommunikationsfehler Schaltmodul-V', + 'CF': 'Kommunikationsfehler LON Modul', + 'D1': 'Brennerstoerung', + 'D4': 'Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt', + 'D6': 'Eingang DE1 an Erweiterung EA1 meldet eine Stoerung', + 'D7': 'Eingang DE2 an Erweiterung EA1 meldet eine Stoerung', + 'D8': 'Eingang DE3 an Erweiterung EA1 meldet eine Stoerung', + 'DA': 'Kurzschluss Raumtemperatursensor, Heizkreis M1', + 'DB': 'Kurzschluss Raumtemperatursensor, Heizkreis M2', + 'DC': 'Kurzschluss Raumtemperatursensor, Heizkreis 3', + 'DD': 'Unterbrechung Raumtemperatursensor, Heizkreis M1', + 'DE': 'Unterbrechung Raumtemperatursensor, Heizkreis M2', + 'DF': 'Unterbrechung Raumtemperatursensor, Heizkreis 3', + 'E0': 'Fehler externer LON Teilnehmer', + 'E1': 'Isolationsstrom waehrend des Kalibrierens zu hoch', + 'E3': 'Zu geringe Wärmeabnahme während des Kalibrierens, Temperaturwächter hat ausgeschaltet', + 'E4': 'Fehler Versorgungsspannung', + 'E5': 'Interner Fehler, Flammenverstärker(Ionisationselektrode)', + 'E6': 'Abgas- / Zuluftsystem verstopft, Anlagendruck zu niedrig', + 'E7': 'Ionisationsstrom waehrend des Kalibrierens zu gering', + 'E8': 'Ionisationsstrom nicht im gültigen Bereich', + 'EA': 'Ionisationsstrom waehrend des Kalibrierens nicht im gueltigen Bereich', + 'EB': 'Wiederholter Flammenverlust waehrend des Kalibrierens', + 'EC': 'Parameterfehler waehrend des Kalibrierens', + 'ED': 'Interner Fehler', + 'EE': 'Flammensignal ist bei Brennerstart nicht vorhanden oder zu gering', + 'EF': 'Flammenverlust direkt nach Flammenbildung (waehrend der Sicherheitszeit)', + 'F0': 'Interner Fehler (Regelung tauschen)', + 'F1': 'Abgastemperaturbegrenzer ausgeloest', + 'F2': 'Temperaturbegrenzer ausgeloest', + 'F3': 'Flammensigal beim Brennerstart bereits vorhanden', + 'F4': 'Flammensigal nicht vorhanden', + 'F7': 'Differenzdrucksensor defekt, Kurzschluss ider Wasserdrucksensor', + 'F8': 'Brennstoffventil schliesst zu spaet', + 'F9': 'Geblaesedrehzahl beim Brennerstart zu niedrig', + 'FA': 'Geblaesestillstand nicht erreicht', + 'FC': 'Gaskombiregler defekt oder fehlerhafte Ansteuerung Modulationsventil oder Abgasweg versperrt', + 'FD': 'Fehler Gasfeuerungsautomat, Kesselkodierstecker fehlt(in Verbindung mit B7)', + 'FE': 'Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt', + 'FF': 'Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler' + }, + 'KW': { + '00': 'Regelbetrieb (kein Fehler)', + '0F': 'Wartung (fuer Reset Codieradresse 24 auf 0 stellen)', + '10': 'Kurzschluss Aussentemperatursensor', + '18': 'Unterbrechung Aussentemperatursensor', + '19': 'Unterbrechung Kommunikation Außentemperatursensor RF', + '1D': 'Keine Kommunikation mit Sensor', + '1E': 'Strömungssensor defekt', + '1F': 'Strömungssensor defekt', + '20': 'Kurzschluss Vorlauftemperatursensor', + '21': 'Kurzschluss Ruecklauftemperatursensor', + '28': 'Unterbrechung Aussentemperatursensor / Vorlauftemperatursensor Anlage', + '29': 'Unterbrechung Ruecklauftemperatursensor', + '30': 'Kurzschluss Kesseltemperatursensor', + '38': 'Unterbrechung Kesseltemperatursensor', + '40': 'Kurzschluss Vorlauftemperatursensor M2', + '42': 'Unterbrechung Vorlauftemperatursensor M2', + '44': 'Kurzschluss Vorlauftemperatursensor Heizkreis 3', + '48': 'Unterbrechung Vorlauftemperatursensor Heizkreis 3', + '50': 'Kurzschluss Speichertemperatursensor', + '51': 'Kurzschluss Auslauftemperatursensor', + '58': 'Unterbrechung Speichertemperatursensor', + '59': 'Unterbrechung Auslauftemperatursensor', + '92': 'Solar: Kurzschluss Kollektortemperatursensor', + '93': 'Solar: Kurzschluss Sensor S3', + '94': 'Solar: Kurzschluss Speichertemperatursensor', + '9A': 'Solar: Unterbrechung Kollektortemperatursensor', + '9B': 'Solar: Unterbrechung Sensor S3', + '9C': 'Solar: Unterbrechung Speichertemperatursensor', + '9E': 'Solar: Zu geringer bzw. kein Volumenstrom oder Temperaturwächter ausgeloest', + '9F': 'Solar: Fehlermeldung Solarteil (siehe Solarregler)', + 'A4': 'Amx. Anlagendruck überschritten', + 'A7': 'Bedienteil defekt', + 'A8': 'Luft in der internen Umwaelzpumpe oder Mindest-Volumenstrom nicht erreicht', + 'B0': 'Kurzschluss Abgastemperatursensor', + 'B1': 'Kommunikationsfehler Bedieneinheit', + 'B4': 'Interner Fehler (Elektronik)', + 'B5': 'Interner Fehler (Elektronik)', + 'B6': 'Ungueltige Hardwarekennung (Elektronik)', + 'B7': 'Interner Fehler (Kesselkodierstecker)', + 'B8': 'Unterbrechung Abgastemperatursensor', + 'B9': 'Interner Fehler (Dateneingabe wiederholen)', + 'BA': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2', + 'BB': 'Kommunikationsfehler Erweiterungssatz fuer Mischerkreis 3', + 'BC': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1', + 'BD': 'Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2', + 'BE': 'Falsche Codierung Fernbedienung Vitorol', + 'BF': 'Falsches Kommunikationsmodul LON', + 'C1': 'Externe Sicherheitseinrichtung (Kessel kuehlt aus)', + 'C2': 'Kommunikationsfehler Solarregelung', + 'C3': 'Kommunikationsfehler Erweiterung AM1', + 'C4': 'Kommunikationsfehler Erweiterumg Open Therm', + 'C5': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1', + 'C6': 'Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2', + 'C7': 'Falsche Codierung der Heizkreispumpe', + 'C8': 'Kommunikationsfehler drehzahlgeregelte, externe Heizkreispumpe 3', + 'C9': 'Stoermeldeeingang am Schaltmodul-V aktiv', + 'CD': 'Kommunikationsfehler Vitocom 100 (KM-BUS)', + 'CE': 'Kommunikationsfehler Schaltmodul-V', + 'CF': 'Kommunikationsfehler LON Modul', + 'D1': 'Brennerstoerung', + 'D4': 'Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt', + 'D6': 'Eingang DE1 an Erweiterung EA1 meldet eine Stoerung', + 'D7': 'Eingang DE2 an Erweiterung EA1 meldet eine Stoerung', + 'D8': 'Eingang DE3 an Erweiterung EA1 meldet eine Stoerung', + 'DA': 'Kurzschluss Raumtemperatursensor, Heizkreis M1', + 'DB': 'Kurzschluss Raumtemperatursensor, Heizkreis M2', + 'DC': 'Kurzschluss Raumtemperatursensor, Heizkreis 3', + 'DD': 'Unterbrechung Raumtemperatursensor, Heizkreis M1', + 'DE': 'Unterbrechung Raumtemperatursensor, Heizkreis M2', + 'DF': 'Unterbrechung Raumtemperatursensor, Heizkreis 3', + 'E0': 'Fehler externer LON Teilnehmer', + 'E1': 'Isolationsstrom waehrend des Kalibrierens zu hoch', + 'E3': 'Zu geringe Wärmeabnahme während des Kalibrierens, Temperaturwächter hat ausgeschaltet', + 'E4': 'Fehler Versorgungsspannung', + 'E5': 'Interner Fehler, Flammenverstärker(Ionisationselektrode)', + 'E6': 'Abgas- / Zuluftsystem verstopft, Anlagendruck zu niedrig', + 'E7': 'Ionisationsstrom waehrend des Kalibrierens zu gering', + 'E8': 'Ionisationsstrom nicht im gültigen Bereich', + 'EA': 'Ionisationsstrom waehrend des Kalibrierens nicht im gueltigen Bereich', + 'EB': 'Wiederholter Flammenverlust waehrend des Kalibrierens', + 'EC': 'Parameterfehler waehrend des Kalibrierens', + 'ED': 'Interner Fehler', + 'EE': 'Flammensignal ist bei Brennerstart nicht vorhanden oder zu gering', + 'EF': 'Flammenverlust direkt nach Flammenbildung (waehrend der Sicherheitszeit)', + 'F0': 'Interner Fehler (Regelung tauschen)', + 'F1': 'Abgastemperaturbegrenzer ausgeloest', + 'F2': 'Temperaturbegrenzer ausgeloest', + 'F3': 'Flammensigal beim Brennerstart bereits vorhanden', + 'F4': 'Flammensigal nicht vorhanden', + 'F7': 'Differenzdrucksensor defekt, Kurzschluss ider Wasserdrucksensor', + 'F8': 'Brennstoffventil schliesst zu spaet', + 'F9': 'Geblaesedrehzahl beim Brennerstart zu niedrig', + 'FA': 'Geblaesestillstand nicht erreicht', + 'FC': 'Gaskombiregler defekt oder fehlerhafte Ansteuerung Modulationsventil oder Abgasweg versperrt', + 'FD': 'Fehler Gasfeuerungsautomat, Kesselkodierstecker fehlt(in Verbindung mit B7)', + 'FE': 'Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt', + 'FF': 'Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler' }, +} + +operatingmodes = { 'V200KW2': { - 'operatingmodes': { - '00': 'Warmwasser (Schaltzeiten)', - '01': 'reduziert Heizen (dauernd)', - '02': 'normal Heizen (dauernd)', - '04': 'Heizen und Warmwasser (FS)', - '03': 'Heizen und Warmwasser (Schaltzeiten)', - '05': 'Standby' - }, - 'systemschemes': { - '00': '-', - '01': 'A1', - '02': 'A1 + WW', - '03': 'M2', - '04': 'M2 + WW', - '05': 'A1 + M2', - '06': 'A1 + M2 + WW', - '07': 'M2 + M3', - '08': 'M2 + M3 + WW', - '09': 'M2 + M3 + WW', - '10': 'A1 + M2 + M3 + WW' - }, + '00': 'Warmwasser (Schaltzeiten)', + '01': 'reduziert Heizen (dauernd)', + '02': 'normal Heizen (dauernd)', + '04': 'Heizen und Warmwasser (FS)', + '03': 'Heizen und Warmwasser (Schaltzeiten)', + '05': 'Standby', }, 'V200KO1B': { - 'operatingmodes': { - '00': 'Warmwasser (Schaltzeiten)', - '01': 'reduziert Heizen (dauernd)', - '02': 'normal Heizen (dauernd)', - '04': 'Heizen und Warmwasser (FS)', - '03': 'Heizen und Warmwasser (Schaltzeiten)', - '05': 'Standby' - }, - 'systemschemes': { - '01': 'A1', - '02': 'A1 + WW', - '04': 'M2', - '03': 'M2 + WW', - '05': 'A1 + M2', - '06': 'A1 + M2 + WW' - } + '00': 'Warmwasser (Schaltzeiten)', + '01': 'reduziert Heizen (dauernd)', + '02': 'normal Heizen (dauernd)', + '04': 'Heizen und Warmwasser (FS)', + '03': 'Heizen und Warmwasser (Schaltzeiten)', + '05': 'Standby', + }, + 'aktuelle_Betriebsart': { + '00': 'Abschaltbetrieb', + '01': 'Reduzierter Betrieb', + '02': 'Normalbetrieb', + '03': 'Dauernd Normalbetrieb', }, 'V200WO1C': { - 'operatingmodes': { - '00': 'Abschaltbetrieb', - '01': 'Warmwasser', - '02': 'Heizen und Warmwasser', - '03': 'undefiniert', - '04': 'dauernd reduziert', - '05': 'dauernd normal', - '06': 'normal Abschalt', - '07': 'nur kühlen' - }, - 'systemschemes': { - '01': 'WW', - '02': 'HK + WW', - '04': 'HK + WW', - '05': 'HK + WW' - }, + '00': 'Abschaltbetrieb', + '01': 'Warmwasser', + '02': 'Heizen und Warmwasser', + '03': 'undefiniert', + '04': 'dauernd reduziert', + '05': 'dauernd normal', + '06': 'normal Abschalt', + '07': 'nur kühlen', }, 'V200HO1C': { - 'operatingmodes': { - '00': 'Abschaltbetrieb', - '01': 'Warmwasser', - '02': 'Heizen und Warmwasser', - '03': 'Normal reduziert', - '04': 'Normal dauernd' - }, - 'systemschemes': { - '01': 'WW', - '02': 'HK + WW', - '04': 'HK + WW', - '05': 'HK + WW' - } + '00': 'Abschaltbetrieb', + '01': 'Warmwasser', + '02': 'Heizen und Warmwasser', + '03': 'Normal reduziert', + '04': 'Normal dauernd' } } + +systemschemes = { + 'V200KW2': { + '00': '-', + '01': 'A1', + '02': 'A1 + WW', + '03': 'M2', + '04': 'M2 + WW', + '05': 'A1 + M2', + '06': 'A1 + M2 + WW', + '07': 'M2 + M3', + '08': 'M2 + M3 + WW', + '09': 'M2 + M3 + WW', + '10': 'A1 + M2 + M3 + WW' + }, + 'V200KO1B': { + '01': 'A1', + '02': 'A1 + WW', + '04': 'M2', + '03': 'M2 + WW', + '05': 'A1 + M2', + '06': 'A1 + M2 + WW' + }, + 'V200WO1C': { + '01': 'WW', + '02': 'HK + WW', + '04': 'HK + WW', + '05': 'HK + WW' + }, + 'V200HO1C': { + '01': 'WW', + '02': 'HK + WW', + '04': 'HK + WW', + '05': 'HK + WW' + } +} + +devicetypes = { + '2098': 'V200KW2', # Protokoll: KW + '2053': 'GWG_VBEM', # Protokoll: GWG + '20CB': 'VScotHO1', # Protokoll: P300 + '2094': 'V200KW1', # Protokoll: KW + '209F': 'V200KO1B', # Protokoll: P300 + '204D': 'V200WO1C', # Protokoll: P300 + '20B8': 'V333MW1', + '20A0': 'V100GC1', + '20C2': 'VDensHO1', + '20A4': 'V200GW1', + '20C8': 'VPlusHO1', + '2046': 'V200WO1', + '2047': 'V200WO1', + '2049': 'V200WO1', + '2032': 'VBC550', + '2033': 'VBC550' +} + +returnstatus = { + 'P300': { + '00': '0', + '01': '1', + '03': '2', + 'AA': 'NOT OK', + # At least for device 20CB the heating circuit pump returns status 03 when it's on and the heating runs in in night mode + }, + 'KW': { + '00': '0', + '01': '1', + '03': '2', + 'AA': 'NOT OK', + }, +} + +setreturnstatus = { + 'P300': { + '00': 'OK', + '05': 'SYNC (NOT OK)', + }, + 'KW': { + '00': 'OK', + '05': 'SYNC (NOT OK)', + }, +} + + +# P300 Protokoll +# +# Beispiel +# +# Senden 41 5 0 1 55 25 2 82 +# Read Request -- - - - ----- - -- +# | | | | | | +------- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex +# | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden +# | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur +# | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call +# | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler +# | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) +# +------------------------ Telegramm-Start-Byte +# +# Empfangen : 6 ----------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) +# 5 ----------------------- Schnittstelle ist aktiv und wartet auf eine Initialisierung +# 15 ----------------------- Schnittstelle meldet einen Fehler zurück +# +# 41 7 1 1 55 25 2 EF 0 74 +# -- - - - ----- - ---- -- +# | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) +# | | | | | | +------ Wert +# | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden +# | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur +# | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call +# | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler +# | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) +# +------------------------ Telegramm-Start-Byte +# Kommunikationsbeispiele +# Information Kessel Außentemperatur read 2-Byte -60..60 0x5525 +# DATA TX: 41 5 0 1 55 25 2 82 +# DATA RX: 41 7 1 1 55 25 2 EF 0 74 --> 00EF = 239 --> 23.9°C (Faktor 0.1) +# --> Senden 41 5 0 1 55 25 2 82 +# -- - - - ----- - -- +# | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex +# | | | | | +----- XX Anzahl der Bytes, die in der Antwort erwartet werden +# | | | | +--------- XX XX 2 byte Adresse der Daten oder Prozedur +# | | | +------------- XX 01 = ReadData, 02 = WriteData, 07 = Function Call +# | | +--------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler +# | +----------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) +# +------------------- Telegramm-Start-Byte +# +# --> Empfangen 6 41 7 1 1 55 25 2 EF 0 74 +# - -- - - - ----- - ---- -- +# | | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) +# | | | | | | | +------ Wert +# | | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden +# | | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur +# | | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call +# | | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler +# | | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) +# | +------------------------ Telegramm-Start-Byte +# +--------------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) +# +# --> Antwort: 0x00EF = 239 = 23.9° diff --git a/viessmann/datatypes.py b/viessmann/datatypes.py deleted file mode 100644 index f3b827cf6..000000000 --- a/viessmann/datatypes.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab - -import lib.model.sdp.datatypes as DT - -import re -import dateutil -import datetime - - -# V = Viessmann, generic numeric type -class DT_V(DT.Datatype): - def get_send_data(self, data, **kwargs): - if data is None: - return None - - len = kwargs.get('len', 1) - signed = kwargs.get('signed', False) - mult = kwargs.get('mult', 0) - if mult: - data = int(float(data) * float(mult)) - bytes = int2bytes(data, len, signed) - return bytes - - def get_shng_data(self, data, type=None, **kwargs): - signed = kwargs.get('signed', False) - mult = kwargs.get('mult', 0) - - val = bytes2int(data, signed) - if mult: - val = round(float(val) / float(mult), 2) - if isinstance(mult, int): - val = int(val) - - if type is None: - return val - else: - return type(val) - - -# S = serial -class DT_S(DT_V): - def get_send_data(self, data, **kwargs): - raise RuntimeError('write of serial number not possible') - - def get_shng_data(self, data, type=None, **kwargs): - b = data[:7] - sn = 0 - b.reverse() - for byte in range(0, len(b)): - sn += (b[byte] - 48) * 10 ** byte - return hex(sn).upper() - - -# T = time -class DT_T(DT_V): - def get_send_data(self, data, **kwargs): - try: - datestring = dateutil.parser.isoparse(data).strftime('%Y%m%d%w%H%M%S') - # Viessmann erwartet 2 digits für Wochentag, daher wird hier noch eine 0 eingefügt - datestring = datestring[:8] + '0' + datestring[8:] - valuebytes = bytes.fromhex(datestring) - self.logger.debug(f'created value bytes as bytes: {valuebytes}') - return valuebytes - except Exception as e: - raise ValueError(f'incorrect data format, YYYY-MM-DD expected. Error was: {e}') - - def get_shng_data(self, data, type=None, **kwargs): - return datetime.strptime(data.hex(), '%Y%m%d%W%H%M%S').isoformat() - - -# D = date -class DT_D(DT_T): - def get_shng_data(self, data, type=None, **kwargs): - return datetime.strptime(data.hex(), '%Y%m%d%W%H%M%S').date().isoformat() - - -# C = control timer (?) -class DT_C(DT_V): - def get_send_data(self, data, **kwargs): - try: - times = '' - for switching_time in data: - an = encode_timer(switching_time['An']) - aus = encode_timer(switching_time['Aus']) - times += f'{an:02x}{aus:02x}' - valuebytes = bytes.fromhex(times) - self.logger.debug(f'created value bytes as hexstring: {bytes2hexstring(valuebytes)} and as bytes: {valuebytes}') - except Exception as e: - raise ValueError(f'incorrect data format, (An: hh:mm Aus: hh:mm) expected. Error was: {e}') - - def get_shng_data(self, data, type=None, **kwargs): - timer = self._decode_timer(data.hex()) - return [{'An': on_time, 'Aus': off_time} for on_time, off_time in zip(timer, timer)] - - -# H = hex -class DT_H(DT_V): - def get_send_data(self, data, **kwargs): - if isinstance(data, str): - try: - data = int(data, 16) - except ValueError: - pass - - return super().get_send_data(data, **kwargs) - - def get_shng_data(self, data, type=None, **kwargs): - try: - return data.hex().upper() - except AttributeError: - return - - # return ' '.join([hexstr[i:i + 2] for i in range(0, len(hexstr), 2)]) - - -""" -'BA': {'unit_de': 'Betriebsart', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: BA -'BT': {'unit_de': 'Brennertyp', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: -'CT': {'unit_de': 'CycleTime', 'type': 'timer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: CT -'DA': {'unit_de': 'Date', 'type': 'date', 'signed': False, 'read_value_transform': 'non'}, # vito unit: -'DT': {'unit_de': 'DeviceType', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: DT -'ES': {'unit_de': 'ErrorState', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ES -'HEX': {'unit_de': 'HexString', 'type': 'string', 'signed': False, 'read_value_transform': 'hex'}, # vito unit: -'IS10': {'unit_de': 'INT signed 10', 'type': 'integer', 'signed': True, 'read_value_transform': '10'}, # vito unit: UT, UN -'IS100': {'unit_de': 'INT signed 100', 'type': 'integer', 'signed': True, 'read_value_transform': '100'}, # vito unit: -'IS1000': {'unit_de': 'INT signed 1000', 'type': 'integer', 'signed': True, 'read_value_transform': '1000'}, # vito unit: -'IS2': {'unit_de': 'INT signed 2', 'type': 'integer', 'signed': True, 'read_value_transform': '2'}, # vito unit: UT1, PR -'ISNON': {'unit_de': 'INT signed non', 'type': 'integer', 'signed': True, 'read_value_transform': 'non'}, # vito unit: -'IU10': {'unit_de': 'INT unsigned 10', 'type': 'integer', 'signed': False, 'read_value_transform': '10'}, # vito unit: -'IU100': {'unit_de': 'INT unsigned 100', 'type': 'integer', 'signed': False, 'read_value_transform': '100'}, # vito unit: -'IU1000': {'unit_de': 'INT unsigned 1000', 'type': 'integer', 'signed': False, 'read_value_transform': '1000'}, # vito unit: -'IU2': {'unit_de': 'INT unsigned 2', 'type': 'integer', 'signed': False, 'read_value_transform': '2'}, # vito unit: UT1U, PR1 -'IU3600': {'unit_de': 'INT unsigned 3600', 'type': 'integer', 'signed': False, 'read_value_transform': '3600'}, # vito unit: CS -'IUBOOL': {'unit_de': 'INT unsigned bool', 'type': 'integer', 'signed': False, 'read_value_transform': 'bool'}, # vito unit: -'IUINT': {'unit_de': 'INT unsigned int', 'type': 'integer', 'signed': False, 'read_value_transform': '1'}, # vito unit: -'IUNON': {'unit_de': 'INT unsigned non', 'type': 'integer', 'signed': False, 'read_value_transform': 'non'}, # vito unit: UTI, CO -'IUPR': {'unit_de': 'INT unsigned 2.55', 'type': 'integer', 'signed': False, 'read_value_transform': '2.55'}, # vito unit: PP -'RT': {'unit_de': 'ReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: ST, RT -'SC': {'unit_de': 'SystemScheme', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: -'SN': {'unit_de': 'Sachnummer', 'type': 'serial', 'signed': False, 'read_value_transform': 'non'}, # vito unit: -'SR': {'unit_de': 'SetReturnStatus', 'type': 'list', 'signed': False, 'read_value_transform': 'non'}, # vito unit: -'TI': {'unit_de': 'SystemTime', 'type': 'datetime', 'signed': False, 'read_value_transform': 'non'}, # vito unit: TI -""" - - -def int2bytes(value, length=0, signed=False): - """ convert value to bytearray, see MD_Command.py """ - if not length: - length = len(value) - value = value % (2 ** (length * 8)) - return value.to_bytes(length, byteorder='big', signed=signed) - - -def bytes2int(rawbytes, signed): - """ convert bytearray to value, see MD_Command.py """ - return int.from_bytes(rawbytes, byteorder='little', signed=signed) - - -def bytes2hexstring(bytesvalue): - """ create hex-string from bytearray, see MD_Command.py """ - return ''.join(f'{c:02x}' for c in bytesvalue) - - -def decode_timer(rawdatabytes): - """ generator to convert byte sequence to a number of time strings """ - while rawdatabytes: - hours, minutes = divmod(int(rawdatabytes[:2], 16), 8) - if minutes >= 6 or hours >= 24: - # not a valid time - yield '00:00' - else: - yield f'{hours:02d}:{(minutes * 10):02d}' - rawdatabytes = rawdatabytes[2:] - return None - - -def encode_timer(switching_time): - """ convert time string to encoded time value """ - if switching_time == '00:00': - return 0xff - clocktime = re.compile(r'(\d\d):(\d\d)') - mo = clocktime.search(switching_time) - number = int(mo.group(1)) * 8 + int(mo.group(2)) // 10 - return number diff --git a/viessmann/_pv_1_2_3/locale.yaml b/viessmann/locale.yaml similarity index 100% rename from viessmann/_pv_1_2_3/locale.yaml rename to viessmann/locale.yaml diff --git a/viessmann/plugin.yaml b/viessmann/plugin.yaml old mode 100644 new mode 100755 index 0f419dc09..a77d0a8ed --- a/viessmann/plugin.yaml +++ b/viessmann/plugin.yaml @@ -1,4203 +1,231 @@ +%YAML 1.1 +# vim: set et ts=4 sts=4 sw=4 ai ff=unix nu wrap : +--- +# Metadata for the Smart-Plugin plugin: - type: gateway - + # Global plugin attributes + type: interface # plugin type (gateway, interface, protocol, system, web) description: - de: Lesen und Schreiben von Werten einer Viessmann Heizung - en: Read and write data from/to a Viessmann heating system + de: 'Lesen und Schreiben von Werten einer Viessmann Heizung' + en: 'Read and write data of a Viessmann heating system' maintainer: Morg - state: develop - keywords: iot device sdp - version: 1.3.0 - sh_minversion: 1.9.3.1 + tester: sisamiwe, tcr82 + keywords: viessmann heating optolink + state: ready # change to ready when done with development + version: 1.2.3 # Plugin version + sh_minversion: 1.6.0 # minimum shNG version to use this plugin py_minversion: 3.6 - multi_instance: false + multi_instance: false # plugin supports multi instance restartable: true - classname: viessmann + classname: Viessmann # class containing the plugin + support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1455991-viessmann-plugin-neuentwicklung-python-hilfe/ parameters: - + # Definition of parameters to be configured in etc/plugin.yaml serialport: type: str - mandatory: true - description: Serieller Port - - model: - type: foo - default: None - description: Gerätemodell - - viess_proto: - type: str - default: P300 - valid_list: - - P300 - - KW - description: Kommunikationsprotokoll der Heizung + default: '' + description: + de: 'Serieller Port, an dem der Lesekopf angeschlossen ist' + en: 'Serial port the device is connected to' - suspend_item: + heating_type: type: str default: '' - description: - de: Item-Pfad für das Suspend-Item - en: item path for suspend switch item + de: 'Gerätetype der Heizung' + en: 'Device type of heating system' - command_class: + protocol: type: str - default: SDPCommandViessmann - description: Name der Klasse für Commands + default: 'P300' + valid list: + - 'P300' + - 'KW' + description: + de: 'Protokoll der Heizung' + en: 'Protocol of heating system' - clean_structs: - type: bool - default: true - description: Entferne Struct-Elemente, die vom gewählten Modell nicht unterstützt werden + timeout: + type: num + default: 1.5 + description: + de: 'Zeitbegrenzung für das Lesen vom seriellen Port in Sekunden' + en: 'Timeout for serial read operations in seconds' item_attributes: - - viess_command: + # Definition of item attributes defined by this plugin + viess_send: type: str - description: - de: Legt das angegebene Kommando für das Item fest - en: Assigns the given command to the item + de: 'Änderung des Items wird mit konfiguriertem Kommando an die Heizung geschickt' + en: 'Changes to this item result in sending the configured command to the heating system' viess_read: - type: bool - + type: str description: - de: Liest/erhält Werte vom Gerät - en: Reads/receives data from the device - - viess_read_group: - type: list(str) + de: 'Liest Wert mit konfiguriertem Kommando aus der Heizung aus' + en: 'The item value should be read by using the configured command' + viess_read_afterwrite: + type: num description: - de: Weist das Item der angegebenen Gruppe zum gesammelten Lesen zu. Gruppe kann int oder str sein, mehrere Gruppen können als Liste angegeben werden. - en: Assigns the item to the given group for collective reading. Groups can be int or str, multiple groups can be provided as a list. + de: 'Konfiguriert eine Verzögerung in Sekunden nachdem ein Lesekommando nach einem Schreibkommando an die Heizung geschickt wird' + en: 'Configures delay in seconds to issue a read command after write command' viess_read_cycle: type: num - - description: - de: Konfiguriert ein Intervall in Sekunden für regelmäßiges Lesen - en: Configures a interval in seconds for cyclic read actions - - viess_read_initial: - type: bool - description: - de: Legt fest, dass der Wert beim Start vom Gerät gelesen wird - en: Sets item value to be read from the device on startup + de: 'Konfiguriert ein Intervall in Sekunden für das Lesekommando' + en: 'Configures a interval in seconds for the read command' - viess_write: + viess_init: type: bool - description: - de: Änderung des Items werden an das Gerät gesendet - en: Changes to this item will be sent to the device - - viess_read_group_trigger: - type: str + de: 'Konfiguriert, ob der Wert aus der Heizung initialisiert werden soll' + en: 'Configures to initialize the item value with the value from the KWL system' + viess_trigger: + type: list(str) description: - de: Wenn diesem Item ein beliebiger Wert zugewiesen wird, werden alle zum Lesen konfigurierten Items der angegebenen Gruppe neu vom Gerät gelesen, bei Gruppe 0 werden alle zum Lesen konfigurierten Items neu gelesen. Das Item kann nicht gleichzeitig mit viess_command belegt werden. - en: When set to any value, all items configured for reading for the given group will update their value from the device, if group is 0, all items configured for reading will update. The item cannot be used with md_command in parallel. - - viess_lookup: - type: str + de: 'Konfiguriert Lesekommandos, die nach einem Schreibvorgang auf das Item aufgerufen werden' + en: 'Configures read commands after an update to the item' + viess_trigger_afterwrite: + type: num description: - de: Der Inhalt der Lookup-Tabelle mit dem angegebenen Namen wird beim Start einmalig als dict oder list in das Item geschrieben. - en: The lookup table with the given name will be assigned to the item in dict or list format once on startup. - - description_long: - de: "Der Inhalt der Lookup-Tabelle mit dem angegebenen Namen wird beim\nStart einmalig als dict oder list in das Item geschrieben.\n\n\nDurch Anhängen von \"#\" an den Namen der Tabelle kann die Art\nder Tabelle ausgewählt werden:\n- fwd liefert die Tabelle Gerät -> SmartHomeNG (Standard)\n- rev liefert die Tabelle SmartHomeNG -> Gerät\n- rci liefert die Tabelle SmarthomeNG -> Gerät in Kleinbuchstaben\n- list liefert die Liste der Namen für SmartHomeNG" - en: "The lookup table with the given name will be assigned to the item\nin dict or list format once on startup.\n\n\nBy appending \"#\" to the tables name the type of table can\nbe selected:\n- fwd returns the table device -> SmartHomeNG (default)\n- rev returns the table SmartHomeNG -> device\n- rci returns the table SmartHomeNG -> device in lower case\n- list return the list of names for SmartHomeNG" - - viess_custom1: - type: str + de: 'Konfiguriert eine Verzögerung in Sekunden, bis ein Trigger ausgeführt werden soll, nachdem ein Wert gesetzt wurde' + en: 'Configures delay in seconds to run trigger commands after item update' + viess_update: + type: bool description: - de: Der Inhalt dieses Items kann vom jeweiligen Gerät für spezielle Zwecke genutzt werden. - en: For custom use of each device respectively. - - description_long: - de: 'Der Inhalt dieses Items kann vom jeweiligen Gerät für spezielle Zwecke genutzt werden. Durch den Parameter "recursive_custom: 1" in der Geräte-Konfiguration wird der Wert rekursiv für alle Unteritems gesetzt.' - en: 'For custom use of each device respectively. By setting "recursive_custom: 1" in the device configuration, the value of this attribute will be set for all sub-items.' + de: 'Liest alle konfigurierten Items neu, wenn es auf True gesetzt wird' + en: 'Triggers reading of all configured items if set to True' - viess_custom2: + viess_timer: type: str - description: - de: Der Inhalt dieses Items kann vom jeweiligen Gerät für spezielle Zwecke genutzt werden. - en: For custom use of each device respectively. - - description_long: - de: 'Der Inhalt dieses Items kann vom jeweiligen Gerät für spezielle Zwecke genutzt werden. Durch den Parameter "recursive_custom: 2" in der Geräte-Konfiguration wird der Wert rekursiv für alle Unteritems gesetzt.' - en: 'For custom use of each device respectively. By setting "recursive_custom: 2" in the device configuration, the value of this attribute will be set for all sub-items.' - - viess_custom3: - type: str + de: 'Liest alle Timer zur übergebenen Anwendung (z.B. Heizkreis_A1M1) und stellt diese für die Nutzung mit UZSU zur Verfügung' + en: 'Provides an UZSU-compatible dict with all timers for the given application (e.g. Heizkreis_A1M1)' + viess_ba_list: + type: bool description: - de: Der Inhalt dieses Items kann vom jeweiligen Gerät für spezielle Zwecke genutzt werden. - en: For custom use of each device respectively. - - description_long: - de: 'Der Inhalt dieses Items kann vom jeweiligen Gerät für spezielle Zwecke genutzt werden. Durch den Parameter "recursive_custom: 3" in der Geräte-Konfiguration wird der Wert rekursiv für alle Unteritems gesetzt.' - en: 'For custom use of each device respectively. By setting "recursive_custom: 3" in the device configuration, the value of this attribute will be set for all sub-items.' -plugin_functions: NONE -logic_parameters: NONE + de: 'Gibt nach der Initialisierung eine Liste aller für die konfigurierte Heizung gültigen Betriebsarten zurück' + en: 'Returns a list of valid operating modes for the configured device type after initialization' item_structs: + timer: + name: Schaltzeiten in Einzelzeiten fuer An und Aus - ALL: - - Anlagentyp: + an1: + name: erste Anschaltzeit type: str - viess_command@instance: Anlagentyp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - ALL - viess_read_initial@instance: true + visu_acl: rw - V200KO1B: - - Anlagentyp: + aus1: + name: erste Ausschaltzeit type: str - viess_command@instance: Anlagentyp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - viess_read_initial@instance: true - - Allgemein: + visu_acl: rw - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein.Temperatur - - Aussen: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Aussen_TP: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen_TP - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Aussen_Dp: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen_Dp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Speicher_Ladesensor: - type: num - viess_command@instance: Allgemein.Temperatur.Speicher_Ladesensor - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Auslauf: - type: num - viess_command@instance: Allgemein.Temperatur.Auslauf - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Abgas: - type: num - viess_command@instance: Allgemein.Temperatur.Abgas - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Gem_Vorlauf: - type: num - viess_command@instance: Allgemein.Temperatur.Gem_Vorlauf - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Allgemein.Temperatur - - Relais_K12: - type: bool - viess_command@instance: Allgemein.Relais_K12 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Eingang_0-10_V: - type: bool - viess_command@instance: Allgemein.Eingang_0-10_V - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - EA1_Kontakt_0: - type: bool - viess_command@instance: Allgemein.EA1_Kontakt_0 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - EA1_Kontakt_1: - type: bool - viess_command@instance: Allgemein.EA1_Kontakt_1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein + an2: + name: zweite Anschaltzeit + type: str + visu_acl: rw - EA1_Kontakt_2: - type: bool - viess_command@instance: Allgemein.EA1_Kontakt_2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein + aus2: + name: zweite Ausschaltzeit + type: str + visu_acl: rw - EA1_Externer_Soll_0-10V: - type: bool - viess_command@instance: Allgemein.EA1_Externer_Soll_0-10V - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein + an3: + name: dritte Anschaltzeit + type: str + visu_acl: rw - EA1_Relais_0: - type: bool - viess_command@instance: Allgemein.EA1_Relais_0 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein + aus3: + name: dritte Ausschaltzeit + type: str + visu_acl: rw - AM1_Ausgang_1: - type: bool - viess_command@instance: Allgemein.AM1_Ausgang_1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein + an4: + name: vierte Anschaltzeit + type: str + visu_acl: rw - AM1_Ausgang_2: - type: bool - viess_command@instance: Allgemein.AM1_Ausgang_2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein + aus4: + name: vierte Ausschaltzeit + type: str + visu_acl: rw - TempKOffset: - type: num - viess_command@instance: Allgemein.TempKOffset - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Allgemein + betriebsart: + name: Betriebsart in string wandeln - Systemtime: - type: bool - viess_command@instance: Allgemein.Systemtime - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Allgemein + betriebsart_str: + type: str + eval: "'Neustart' if value == '' else ['Standby', 'Warmwasser (Schaltzeiten)', 'Heizen und Warmwasser (Schaltzeiten)', 'reduziert Heizen (dauernd)', 'normal Heizen (dauernd)'][int(value)]" + eval_trigger: .. - Anlagenschema: - type: num - viess_command@instance: Allgemein.Anlagenschema - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein +logic_parameters: NONE +# Definition of logic parameters defined by this plugin - Inventory: +plugin_functions: + update_all_read_items: + type: NONE + description: + de: 'Stößt das Lesen aller konfigurierten Items an' + en: 'Triggers reading of all configured items' + read_addr: + type: foo + description: + de: 'Stößt das Lesen des angegebenen Datenpunkts an, der nicht an ein Item gebunden sein muss. Es erfolgt keine Zuweisung an ein Item. Rückgabewert ist der gelesene Wert, oder NONE bei Fehler' + en: 'Triggers reading of the supplied data point, which doesn''t have to be bound to an item. Result will not be assigned to an item. Return value is the read value, or NONE if an error occurred' + parameters: + addr: type: str - viess_command@instance: Allgemein.Inventory - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - CtrlId: - type: num - viess_command@instance: Allgemein.CtrlId - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Allgemein - - Kessel: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Kessel - - Ist: - type: num - viess_command@instance: Kessel.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Kessel - - TP: - type: num - viess_command@instance: Kessel.TP - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Kessel - - Soll: - type: num - viess_command@instance: Kessel.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Kessel - - Fehler: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Fehler - - Sammelstoerung: - type: num - viess_command@instance: Fehler.Sammelstoerung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error0: - type: num - viess_command@instance: Fehler.Error0 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error1: - type: num - viess_command@instance: Fehler.Error1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error2: - type: num - viess_command@instance: Fehler.Error2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error3: - type: num - viess_command@instance: Fehler.Error3 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error4: - type: num - viess_command@instance: Fehler.Error4 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error5: - type: num - viess_command@instance: Fehler.Error5 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error6: - type: num - viess_command@instance: Fehler.Error6 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error7: - type: num - viess_command@instance: Fehler.Error7 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error8: - type: num - viess_command@instance: Fehler.Error8 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Error9: - type: num - viess_command@instance: Fehler.Error9 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Fehler - - Pumpen: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Pumpen - - Speicherlade: - type: bool - viess_command@instance: Pumpen.Speicherlade - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Zirkulation: - type: bool - viess_command@instance: Pumpen.Zirkulation - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Intern: - type: bool - viess_command@instance: Pumpen.Intern - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Heizkreis_A1M1: - type: bool - viess_command@instance: Pumpen.Heizkreis_A1M1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Heizkreis_A1M1_RPM: - type: bool - viess_command@instance: Pumpen.Heizkreis_A1M1_RPM - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Heizkreis_M2: - type: bool - viess_command@instance: Pumpen.Heizkreis_M2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Heizkreis_M2_RPM: - type: bool - viess_command@instance: Pumpen.Heizkreis_M2_RPM - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Relais_Status: - type: bool - viess_command@instance: Pumpen.Relais_Status - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Pumpen - - Brenner: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Brenner - - Starts: - type: num - viess_command@instance: Brenner.Starts - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Brenner - - Betriebsstunden: - type: num - viess_command@instance: Brenner.Betriebsstunden - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Brenner - - Status_1: - type: bool - viess_command@instance: Brenner.Status_1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Brenner - - Status_2: - type: bool - viess_command@instance: Brenner.Status_2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Brenner - - Oeldurchsatz: - type: num - viess_command@instance: Brenner.Oeldurchsatz - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Brenner - - Oelverbrauch: - type: num - viess_command@instance: Brenner.Oelverbrauch - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Brenner - - Solar: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Solar - - Nachladeunterdrueckung: - type: bool - viess_command@instance: Solar.Nachladeunterdrueckung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Solar - - Pumpe: - type: bool - viess_command@instance: Solar.Pumpe - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Solar - - Kollektortemperatur: - type: num - viess_command@instance: Solar.Kollektortemperatur - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Solar - - Speichertemperatur: - type: num - viess_command@instance: Solar.Speichertemperatur - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Solar - - Betriebsstunden: - type: num - viess_command@instance: Solar.Betriebsstunden - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Solar - - Steuerung: - type: num - viess_command@instance: Solar.Steuerung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Solar - - Heizkreis: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis - - A1M1: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Temperatur - - Raum: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Temperatur.Raum - - Ist: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Soll_Normalbetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Soll_Normalbetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Soll_Red_Betrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Soll_Red_Betrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Soll_Party_Betrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Soll_Party_Betrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Vorlauf: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Temperatur.Vorlauf - - Ist: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Soll: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Min: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Min - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Max: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Max - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Erhoehung_Soll: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Erhoehung_Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Erhoehung_Zeit: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Erhoehung_Zeit - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Grenze_red_Betrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Grenze_red_Betrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Grenze_red_Raumtemp: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Grenze_red_Raumtemp - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Status: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Status - - Aktuelle_Betriebsart: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Aktuelle_Betriebsart - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Betriebsart: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Sparbetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Sparbetrieb - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Zustand_Sparbetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Zustand_Sparbetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Partybetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Partybetrieb - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Zustand_Partybetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Zustand_Partybetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - StatusFrost: - type: num - viess_command@instance: Heizkreis.A1M1.Status.StatusFrost - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Externe_Raumsolltemperatur_Normal: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Externe_Raumsolltemperatur_Normal - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Externe_Betriebsartenumschaltung: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Externe_Betriebsartenumschaltung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Speichervorrang: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Speichervorrang - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Frostschutzgrenze: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Frostschutzgrenze - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Frostschutz: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Frostschutz - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Heizkreispumpenlogik: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Heizkreispumpenlogik - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Sparschaltung: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Sparschaltung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Mischersparfunktion: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Mischersparfunktion - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Pumpenstillstandzeit: - type: num - viess_command@instance: Heizkreis.A1M1.Status.Pumpenstillstandzeit - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Status - - Heizkennlinie: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Heizkennlinie - - Neigung: - type: num - viess_command@instance: Heizkreis.A1M1.Heizkennlinie.Neigung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Heizkennlinie - - Niveau: - type: num - viess_command@instance: Heizkreis.A1M1.Heizkennlinie.Niveau - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Heizkennlinie - - Partybetrieb_Zeitbegrenzung: - type: num - viess_command@instance: Heizkreis.A1M1.Partybetrieb_Zeitbegrenzung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.A1M1 - - M2: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Temperatur - - Raum: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Temperatur.Raum - - Ist: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Soll_Normalbetrieb: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Soll_Normalbetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Soll_Red_Betrieb: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Soll_Red_Betrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Soll_Party_Betrieb: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Soll_Party_Betrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Vorlauf: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Temperatur.Vorlauf - - Ist: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Soll: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Min: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Min - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Max: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Max - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Erhoehung_Soll: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Erhoehung_Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Erhoehung_Zeit: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Erhoehung_Zeit - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Grenze_red_Betrieb: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Grenze_red_Betrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Grenze_red_Raumtemp: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Grenze_red_Raumtemp - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Status: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Status - - Aktuelle_Betriebsart: - type: num - viess_command@instance: Heizkreis.M2.Status.Aktuelle_Betriebsart - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Betriebsart: - type: num - viess_command@instance: Heizkreis.M2.Status.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Sparbetrieb: - type: num - viess_command@instance: Heizkreis.M2.Status.Sparbetrieb - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Zustand_Sparbetrieb: - type: num - viess_command@instance: Heizkreis.M2.Status.Zustand_Sparbetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Partybetrieb: - type: num - viess_command@instance: Heizkreis.M2.Status.Partybetrieb - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Zustand_Partybetrieb: - type: num - viess_command@instance: Heizkreis.M2.Status.Zustand_Partybetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - StatusFrost: - type: num - viess_command@instance: Heizkreis.M2.Status.StatusFrost - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Externe_Raumsolltemperatur_Normal: - type: num - viess_command@instance: Heizkreis.M2.Status.Externe_Raumsolltemperatur_Normal - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Externe_Betriebsartenumschaltung: - type: num - viess_command@instance: Heizkreis.M2.Status.Externe_Betriebsartenumschaltung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Speichervorrang: - type: num - viess_command@instance: Heizkreis.M2.Status.Speichervorrang - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Frostschutzgrenze: - type: num - viess_command@instance: Heizkreis.M2.Status.Frostschutzgrenze - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Frostschutz: - type: num - viess_command@instance: Heizkreis.M2.Status.Frostschutz - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Heizkreispumpenlogik: - type: num - viess_command@instance: Heizkreis.M2.Status.Heizkreispumpenlogik - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Sparschaltung: - type: num - viess_command@instance: Heizkreis.M2.Status.Sparschaltung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Mischersparfunktion: - type: num - viess_command@instance: Heizkreis.M2.Status.Mischersparfunktion - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Pumpenstillstandzeit: - type: num - viess_command@instance: Heizkreis.M2.Status.Pumpenstillstandzeit - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Status - - Heizkennlinie: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Heizkennlinie - - Neigung: - type: num - viess_command@instance: Heizkreis.M2.Heizkennlinie.Neigung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Heizkennlinie - - Niveau: - type: num - viess_command@instance: Heizkreis.M2.Heizkennlinie.Niveau - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Heizkennlinie - - Partybetrieb_Zeitbegrenzung: - type: num - viess_command@instance: Heizkreis.M2.Partybetrieb_Zeitbegrenzung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Heizkreis - - Heizkreis.M2 - - Warmwasser: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Warmwasser - - Ist: - type: num - viess_command@instance: Warmwasser.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Warmwasser - - Soll: - type: num - viess_command@instance: Warmwasser.Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Warmwasser - - Status: - type: bool - viess_command@instance: Warmwasser.Status - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Warmwasser - - PumpenNachlauf: - type: num - viess_command@instance: Warmwasser.PumpenNachlauf - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Warmwasser - - Ferienprogramm: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Ferienprogramm - - A1M1: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Ferienprogramm.A1M1 - - Status: - type: num - viess_command@instance: Ferienprogramm.A1M1.Status - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Ferienprogramm - - Ferienprogramm.A1M1 - - Abreisetag: - type: bool - viess_command@instance: Ferienprogramm.A1M1.Abreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Ferienprogramm - - Ferienprogramm.A1M1 - - Rückreisetag: - type: bool - viess_command@instance: Ferienprogramm.A1M1.Rückreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Ferienprogramm - - Ferienprogramm.A1M1 - - M2: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Ferienprogramm.M2 - - Status: - type: num - viess_command@instance: Ferienprogramm.M2.Status - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KO1B - - Ferienprogramm - - Ferienprogramm.M2 - - Abreisetag: - type: bool - viess_command@instance: Ferienprogramm.M2.Abreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Ferienprogramm - - Ferienprogramm.M2 - - Rückreisetag: - type: bool - viess_command@instance: Ferienprogramm.M2.Rückreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Ferienprogramm - - Ferienprogramm.M2 - - Timer: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer - - Warmwasser: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.Warmwasser - - Mo: - type: list - viess_command@instance: Timer.Warmwasser.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - Di: - type: list - viess_command@instance: Timer.Warmwasser.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - Mi: - type: list - viess_command@instance: Timer.Warmwasser.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - Do: - type: list - viess_command@instance: Timer.Warmwasser.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - Fr: - type: list - viess_command@instance: Timer.Warmwasser.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - Sa: - type: list - viess_command@instance: Timer.Warmwasser.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - So: - type: list - viess_command@instance: Timer.Warmwasser.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Warmwasser - - A1M1: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.A1M1 - - Mo: - type: list - viess_command@instance: Timer.A1M1.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - Di: - type: list - viess_command@instance: Timer.A1M1.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - Mi: - type: list - viess_command@instance: Timer.A1M1.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - Do: - type: list - viess_command@instance: Timer.A1M1.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - Fr: - type: list - viess_command@instance: Timer.A1M1.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - Sa: - type: list - viess_command@instance: Timer.A1M1.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - So: - type: list - viess_command@instance: Timer.A1M1.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.A1M1 - - M2: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.M2 - - Mo: - type: list - viess_command@instance: Timer.M2.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - Di: - type: list - viess_command@instance: Timer.M2.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - Mi: - type: list - viess_command@instance: Timer.M2.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - Do: - type: list - viess_command@instance: Timer.M2.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - Fr: - type: list - viess_command@instance: Timer.M2.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - Sa: - type: list - viess_command@instance: Timer.M2.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - So: - type: list - viess_command@instance: Timer.M2.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.M2 - - Zirkulation: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.Zirkulation - - Mo: - type: list - viess_command@instance: Timer.Zirkulation.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - Di: - type: list - viess_command@instance: Timer.Zirkulation.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - Mi: - type: list - viess_command@instance: Timer.Zirkulation.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - Do: - type: list - viess_command@instance: Timer.Zirkulation.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - Fr: - type: list - viess_command@instance: Timer.Zirkulation.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - Sa: - type: list - viess_command@instance: Timer.Zirkulation.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - So: - type: list - viess_command@instance: Timer.Zirkulation.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KO1B - - Timer - - Timer.Zirkulation - - V200HO1C: - - Anlagentyp: - type: str - viess_command@instance: Anlagentyp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - viess_read_initial@instance: true - - Allgemein: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein - - Anlagenschema: - type: num - viess_command@instance: Allgemein.Anlagenschema - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Allgemein - - Frostgefahr: - type: num - viess_command@instance: Allgemein.Frostgefahr - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Allgemein - - Anlagenleistung: - type: num - viess_command@instance: Allgemein.Anlagenleistung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Allgemein - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein.Temperatur - - Aussen_TP: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen_TP - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Allgemein - - Allgemein.Temperatur - - Aussen_Dp: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen_Dp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Allgemein - - Allgemein.Temperatur - - Kessel: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Kessel - - TP: - type: num - viess_command@instance: Kessel.TP - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Kessel - - Soll: - type: num - viess_command@instance: Kessel.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Kessel - - Abgastemperatur: - type: num - viess_command@instance: Kessel.Abgastemperatur - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Kessel - - Fehler: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Fehler - - Sammelstoerung: - type: num - viess_command@instance: Fehler.Sammelstoerung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error0: - type: num - viess_command@instance: Fehler.Error0 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error1: - type: num - viess_command@instance: Fehler.Error1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error2: - type: num - viess_command@instance: Fehler.Error2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error3: - type: num - viess_command@instance: Fehler.Error3 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error4: - type: num - viess_command@instance: Fehler.Error4 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error5: - type: num - viess_command@instance: Fehler.Error5 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error6: - type: num - viess_command@instance: Fehler.Error6 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error7: - type: num - viess_command@instance: Fehler.Error7 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error8: - type: num - viess_command@instance: Fehler.Error8 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Error9: - type: num - viess_command@instance: Fehler.Error9 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Fehler - - Pumpen: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Pumpen - - Speicherlade: - type: bool - viess_command@instance: Pumpen.Speicherlade - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Pumpen - - Zirkulation: - type: bool - viess_command@instance: Pumpen.Zirkulation - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200HO1C - - Pumpen - - Intern: - type: bool - viess_command@instance: Pumpen.Intern - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Pumpen - - Heizkreis_1: - type: bool - viess_command@instance: Pumpen.Heizkreis_1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Pumpen - - Heizkreis_2: - type: bool - viess_command@instance: Pumpen.Heizkreis_2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Pumpen - - Brenner: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Brenner - - Starts: - type: num - viess_command@instance: Brenner.Starts - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Brenner - - Leistung: - type: num - viess_command@instance: Brenner.Leistung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Brenner - - Betriebsstunden: - type: num - viess_command@instance: Brenner.Betriebsstunden - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Brenner - - Solar: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Solar - - Pumpe: - type: bool - viess_command@instance: Solar.Pumpe - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Solar - - Kollektortemperatur: - type: num - viess_command@instance: Solar.Kollektortemperatur - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Solar - - Speichertemperatur: - type: num - viess_command@instance: Solar.Speichertemperatur - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Solar - - Betriebsstunden: - type: num - viess_command@instance: Solar.Betriebsstunden - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Solar - - Waermemenge: - type: num - viess_command@instance: Solar.Waermemenge - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Solar - - Ausbeute: - type: num - viess_command@instance: Solar.Ausbeute - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Solar - - Heizkreis: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis - - '1': - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.1 - - Betriebsart: - type: num - viess_command@instance: Heizkreis.1.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.1 - - Heizart: - type: num - viess_command@instance: Heizkreis.1.Heizart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.1 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.1.Temperatur - - Vorlauf_Soll: - type: num - viess_command@instance: Heizkreis.1.Temperatur.Vorlauf_Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.1 - - Heizkreis.1.Temperatur - - Vorlauf_Ist: - type: num - viess_command@instance: Heizkreis.1.Temperatur.Vorlauf_Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.1 - - Heizkreis.1.Temperatur - - '2': - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.2 - - Betriebsart: - type: num - viess_command@instance: Heizkreis.2.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.2 - - Heizart: - type: num - viess_command@instance: Heizkreis.2.Heizart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.2 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.2.Temperatur - - Vorlauf_Soll: - type: num - viess_command@instance: Heizkreis.2.Temperatur.Vorlauf_Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.2 - - Heizkreis.2.Temperatur - - Vorlauf_Ist: - type: num - viess_command@instance: Heizkreis.2.Temperatur.Vorlauf_Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Heizkreis - - Heizkreis.2 - - Heizkreis.2.Temperatur - - Warmwasser: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Warmwasser - - Ist: - type: num - viess_command@instance: Warmwasser.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Warmwasser - - Soll: - type: num - viess_command@instance: Warmwasser.Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200HO1C - - Warmwasser - - Austritt: - type: num - viess_command@instance: Warmwasser.Austritt - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200HO1C - - Warmwasser - - V200KW2: - - Anlagentyp: - type: str - viess_command@instance: Anlagentyp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - viess_read_initial@instance: true - - Allgemein: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein.Temperatur - - Aussen: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Allgemein - - Allgemein.Temperatur - - Aussen_Dp: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen_Dp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Allgemein - - Allgemein.Temperatur - - Anlagenschema: - type: num - viess_command@instance: Allgemein.Anlagenschema - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Allgemein - - AnlagenSoftwareIndex: - type: num - viess_command@instance: Allgemein.AnlagenSoftwareIndex - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Allgemein - - Systemtime: - type: bool - viess_command@instance: Allgemein.Systemtime - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Allgemein - - Kessel: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Kessel - - TempKOffset: - type: num - viess_command@instance: Kessel.TempKOffset - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Kessel - - Ist: - type: num - viess_command@instance: Kessel.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Kessel - - Soll: - type: num - viess_command@instance: Kessel.Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Kessel - - Fehler: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Fehler - - Sammelstoerung: - type: num - viess_command@instance: Fehler.Sammelstoerung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Brennerstoerung: - type: num - viess_command@instance: Fehler.Brennerstoerung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error0: - type: num - viess_command@instance: Fehler.Error0 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error1: - type: num - viess_command@instance: Fehler.Error1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error2: - type: num - viess_command@instance: Fehler.Error2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error3: - type: num - viess_command@instance: Fehler.Error3 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error4: - type: num - viess_command@instance: Fehler.Error4 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error5: - type: num - viess_command@instance: Fehler.Error5 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error6: - type: num - viess_command@instance: Fehler.Error6 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error7: - type: num - viess_command@instance: Fehler.Error7 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error8: - type: num - viess_command@instance: Fehler.Error8 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Error9: - type: num - viess_command@instance: Fehler.Error9 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Fehler - - Pumpen: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Pumpen - - Speicherlade: - type: bool - viess_command@instance: Pumpen.Speicherlade - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Pumpen - - Zirkulation: - type: bool - viess_command@instance: Pumpen.Zirkulation - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Pumpen - - Heizkreis_A1M1: - type: bool - viess_command@instance: Pumpen.Heizkreis_A1M1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Pumpen - - Heizkreis_M2: - type: bool - viess_command@instance: Pumpen.Heizkreis_M2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Pumpen - - Brenner: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Brenner - - Typ: - type: num - viess_command@instance: Brenner.Typ - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Brenner - - Stufe: - type: num - viess_command@instance: Brenner.Stufe - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Brenner - - Starts: - type: num - viess_command@instance: Brenner.Starts - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Brenner - - Status_1: - type: bool - viess_command@instance: Brenner.Status_1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Brenner - - Status_2: - type: bool - viess_command@instance: Brenner.Status_2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Brenner - - BetriebsstundenStufe1: - type: num - viess_command@instance: Brenner.BetriebsstundenStufe1 - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Brenner - - BetriebsstundenStufe2: - type: num - viess_command@instance: Brenner.BetriebsstundenStufe2 - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Brenner - - Heizkreis: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis - - A1M1: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Temperatur - - Raum: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Temperatur.Raum - - Soll_Normal: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Soll_Normal - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Soll_Reduziert: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Soll_Reduziert - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Soll_Party: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Raum.Soll_Party - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Raum - - Vorlauf: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Temperatur.Vorlauf - - Ist: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Soll: - type: num - viess_command@instance: Heizkreis.A1M1.Temperatur.Vorlauf.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Temperatur - - Heizkreis.A1M1.Temperatur.Vorlauf - - Betriebsart: - type: num - viess_command@instance: Heizkreis.A1M1.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Aktuelle_Betriebsart: - type: num - viess_command@instance: Heizkreis.A1M1.Aktuelle_Betriebsart - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Sparbetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Sparbetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Partybetrieb_Zeit: - type: num - viess_command@instance: Heizkreis.A1M1.Partybetrieb_Zeit - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Partybetrieb: - type: num - viess_command@instance: Heizkreis.A1M1.Partybetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - MischerM1: - type: num - viess_command@instance: Heizkreis.A1M1.MischerM1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreispumpenlogik: - type: num - viess_command@instance: Heizkreis.A1M1.Heizkreispumpenlogik - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Sparschaltung: - type: num - viess_command@instance: Heizkreis.A1M1.Sparschaltung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkennlinie: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.A1M1.Heizkennlinie - - Neigung: - type: num - viess_command@instance: Heizkreis.A1M1.Heizkennlinie.Neigung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Heizkennlinie - - Niveau: - type: num - viess_command@instance: Heizkreis.A1M1.Heizkennlinie.Niveau - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.A1M1 - - Heizkreis.A1M1.Heizkennlinie - - M2: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Temperatur - - Raum: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Temperatur.Raum - - Soll_Normal: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Soll_Normal - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Soll_Reduziert: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Soll_Reduziert - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Soll_Party: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Raum.Soll_Party - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Raum - - Vorlauf: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Temperatur.Vorlauf - - Soll: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Ist: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Min: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Min - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Max: - type: num - viess_command@instance: Heizkreis.M2.Temperatur.Vorlauf.Max - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Temperatur - - Heizkreis.M2.Temperatur.Vorlauf - - Betriebsart: - type: num - viess_command@instance: Heizkreis.M2.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Aktuelle_Betriebsart: - type: num - viess_command@instance: Heizkreis.M2.Aktuelle_Betriebsart - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Sparbetrieb: - type: num - viess_command@instance: Heizkreis.M2.Sparbetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Partybetrieb: - type: num - viess_command@instance: Heizkreis.M2.Partybetrieb - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Partybetrieb_Zeit: - type: num - viess_command@instance: Heizkreis.M2.Partybetrieb_Zeit - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - MischerM2: - type: num - viess_command@instance: Heizkreis.M2.MischerM2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - MischerM2Auf: - type: bool - viess_command@instance: Heizkreis.M2.MischerM2Auf - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - MischerM2Zu: - type: bool - viess_command@instance: Heizkreis.M2.MischerM2Zu - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreispumpenlogik: - type: num - viess_command@instance: Heizkreis.M2.Heizkreispumpenlogik - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Sparschaltung: - type: num - viess_command@instance: Heizkreis.M2.Sparschaltung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - StatusKlemme2: - type: bool - viess_command@instance: Heizkreis.M2.StatusKlemme2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - StatusKlemme17: - type: bool - viess_command@instance: Heizkreis.M2.StatusKlemme17 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkennlinie: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.M2.Heizkennlinie - - Neigung: - type: num - viess_command@instance: Heizkreis.M2.Heizkennlinie.Neigung - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Heizkennlinie - - Niveau: - type: num - viess_command@instance: Heizkreis.M2.Heizkennlinie.Niveau - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Heizkreis - - Heizkreis.M2 - - Heizkreis.M2.Heizkennlinie - - Warmwasser: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Warmwasser - - Status: - type: bool - viess_command@instance: Warmwasser.Status - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Warmwasser - - KesselOffset: - type: num - viess_command@instance: Warmwasser.KesselOffset - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Warmwasser - - BeiPartyDNormal: - type: num - viess_command@instance: Warmwasser.BeiPartyDNormal - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Warmwasser - - Ist: - type: num - viess_command@instance: Warmwasser.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Warmwasser - - Soll: - type: num - viess_command@instance: Warmwasser.Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Warmwasser - - SollAktuell: - type: num - viess_command@instance: Warmwasser.SollAktuell - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Warmwasser - - SollMax: - type: num - viess_command@instance: Warmwasser.SollMax - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Warmwasser - - Ferienprogramm: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Ferienprogramm - - A1M1: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Ferienprogramm.A1M1 - - Status: - type: num - viess_command@instance: Ferienprogramm.A1M1.Status - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Ferienprogramm - - Ferienprogramm.A1M1 - - Abreisetag: - type: bool - viess_command@instance: Ferienprogramm.A1M1.Abreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Ferienprogramm - - Ferienprogramm.A1M1 - - Rückreisetag: - type: bool - viess_command@instance: Ferienprogramm.A1M1.Rückreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Ferienprogramm - - Ferienprogramm.A1M1 - - M2: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Ferienprogramm.M2 - - Status: - type: num - viess_command@instance: Ferienprogramm.M2.Status - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200KW2 - - Ferienprogramm - - Ferienprogramm.M2 - - Abreisetag: - type: bool - viess_command@instance: Ferienprogramm.M2.Abreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Ferienprogramm - - Ferienprogramm.M2 - - Rückreisetag: - type: bool - viess_command@instance: Ferienprogramm.M2.Rückreisetag - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Ferienprogramm - - Ferienprogramm.M2 - - Timer: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer - - Warmwasser: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.Warmwasser - - Mo: - type: list - viess_command@instance: Timer.Warmwasser.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - Di: - type: list - viess_command@instance: Timer.Warmwasser.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - Mi: - type: list - viess_command@instance: Timer.Warmwasser.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - Do: - type: list - viess_command@instance: Timer.Warmwasser.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - Fr: - type: list - viess_command@instance: Timer.Warmwasser.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - Sa: - type: list - viess_command@instance: Timer.Warmwasser.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - So: - type: list - viess_command@instance: Timer.Warmwasser.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.Warmwasser - - A1M1: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.A1M1 - - Mo: - type: list - viess_command@instance: Timer.A1M1.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - Di: - type: list - viess_command@instance: Timer.A1M1.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - Mi: - type: list - viess_command@instance: Timer.A1M1.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - Do: - type: list - viess_command@instance: Timer.A1M1.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - Fr: - type: list - viess_command@instance: Timer.A1M1.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - Sa: - type: list - viess_command@instance: Timer.A1M1.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - So: - type: list - viess_command@instance: Timer.A1M1.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.A1M1 - - M2: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Timer.M2 - - Mo: - type: list - viess_command@instance: Timer.M2.Mo - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - Di: - type: list - viess_command@instance: Timer.M2.Di - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - Mi: - type: list - viess_command@instance: Timer.M2.Mi - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - Do: - type: list - viess_command@instance: Timer.M2.Do - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - Fr: - type: list - viess_command@instance: Timer.M2.Fr - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - Sa: - type: list - viess_command@instance: Timer.M2.Sa - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - So: - type: list - viess_command@instance: Timer.M2.So - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200KW2 - - Timer - - Timer.M2 - - V200WO1C: - - Anlagentyp: - type: str - viess_command@instance: Anlagentyp - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - viess_read_initial@instance: true - - Allgemein: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein - viess_read_cycle@instance: 45 - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Allgemein.Temperatur - - Aussen: - type: num - viess_command@instance: Allgemein.Temperatur.Aussen - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Allgemein - - Allgemein.Temperatur - - Betriebsart: + description: + de: 'Vierstellige Hex-Adresse des Datenpunktes' + en: 'Four-digit hex address of the data point' + read_temp_addr: + type: foo + description: + de: 'Stößt das Lesen eines beliebigen Datenpunkts an, der nicht konfiguriert oder bekannt sein muss. Es erfolgt keine Zuweisung an ein Item. Rückgabewert ist der gelesene Wert, oder NONE bei Fehler' + en: 'Triggers reading of an arbitrary data point, which doesn''t have to be configured or known. Result will not be assigned to an item. Return value is the read value, or NONE if an error occurred' + parameters: + addr: type: str - viess_command@instance: Allgemein.Betriebsart - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200WO1C - - Allgemein - viess_read_initial@instance: true - - lookup: - type: list - viess_lookup@instance: operatingmodes#list - - Manuell: - type: num - viess_command@instance: Allgemein.Manuell - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200WO1C - - Allgemein - - Outdoor_Fanspeed: - type: num - viess_command@instance: Allgemein.Outdoor_Fanspeed - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Allgemein - - Status_Fanspeed: - type: num - viess_command@instance: Allgemein.Status_Fanspeed - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Allgemein - - Kompressor_Freq: - type: num - viess_command@instance: Allgemein.Kompressor_Freq - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Allgemein - - SollLeistungVerdichter: - type: num - viess_command@instance: Allgemein.SollLeistungVerdichter - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Allgemein - - Pumpen: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Pumpen - - Sekundaer: - type: bool - viess_command@instance: Pumpen.Sekundaer - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Pumpen - - Heizkreis: - type: bool - viess_command@instance: Pumpen.Heizkreis - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Pumpen - - Zirkulation: - type: bool - viess_command@instance: Pumpen.Zirkulation - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Pumpen - - Heizkreis: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis - - Temperatur: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.Temperatur - - Raum: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.Temperatur.Raum - - Soll: - type: num - viess_command@instance: Heizkreis.Temperatur.Raum.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Raum - - Soll_Reduziert: - type: num - viess_command@instance: Heizkreis.Temperatur.Raum.Soll_Reduziert - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Raum - - Soll_Party: - type: num - viess_command@instance: Heizkreis.Temperatur.Raum.Soll_Party - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Raum - - Vorlauf: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.Temperatur.Vorlauf - - Ist: - type: num - viess_command@instance: Heizkreis.Temperatur.Vorlauf.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Vorlauf - - Soll: - type: num - viess_command@instance: Heizkreis.Temperatur.Vorlauf.Soll - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Vorlauf - - Mittel: - type: num - viess_command@instance: Heizkreis.Temperatur.Vorlauf.Mittel - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Vorlauf - - Ruecklauf: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.Temperatur.Ruecklauf - - Ist: - type: num - viess_command@instance: Heizkreis.Temperatur.Ruecklauf.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Ruecklauf - - Mittel: - type: num - viess_command@instance: Heizkreis.Temperatur.Ruecklauf.Mittel - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Temperatur - - Heizkreis.Temperatur.Ruecklauf - - Heizkennlinie: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Heizkreis.Heizkennlinie - - Niveau: - type: num - viess_command@instance: Heizkreis.Heizkennlinie.Niveau - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Heizkennlinie - - Neigung: - type: num - viess_command@instance: Heizkreis.Heizkennlinie.Neigung - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Heizkreis - - Heizkreis.Heizkennlinie - - Warmwasser: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Warmwasser - - Ist: - type: num - viess_command@instance: Warmwasser.Ist - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Warmwasser - - Soll: - type: num - viess_command@instance: Warmwasser.Soll - viess_read@instance: true - viess_write@instance: true - viess_read_group@instance: - - V200WO1C - - Warmwasser - - Ventil: - type: bool - viess_command@instance: Warmwasser.Ventil - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Warmwasser - - Statistik: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Statistik - - Einschaltungen: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Statistik.Einschaltungen - - Sekundaer: - type: num - viess_command@instance: Statistik.Einschaltungen.Sekundaer - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Einschaltungen - - Heizstab1: - type: num - viess_command@instance: Statistik.Einschaltungen.Heizstab1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Einschaltungen - - Heizstab2: - type: num - viess_command@instance: Statistik.Einschaltungen.Heizstab2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Einschaltungen - - HK: - type: num - viess_command@instance: Statistik.Einschaltungen.HK - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Einschaltungen - - Laufzeiten: - - read: - type: bool - enforce_updates: true - viess_read_group_trigger@instance: Statistik.Laufzeiten - - Sekundaerpumpe: - type: num - viess_command@instance: Statistik.Laufzeiten.Sekundaerpumpe - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - Heizstab1: - type: num - viess_command@instance: Statistik.Laufzeiten.Heizstab1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - Heizstab2: - type: num - viess_command@instance: Statistik.Laufzeiten.Heizstab2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - PumpeHK: - type: num - viess_command@instance: Statistik.Laufzeiten.PumpeHK - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - WWVentil: - type: num - viess_command@instance: Statistik.Laufzeiten.WWVentil - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - VerdichterStufe1: - type: num - viess_command@instance: Statistik.Laufzeiten.VerdichterStufe1 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - VerdichterStufe2: - type: num - viess_command@instance: Statistik.Laufzeiten.VerdichterStufe2 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - VerdichterStufe3: - type: num - viess_command@instance: Statistik.Laufzeiten.VerdichterStufe3 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - VerdichterStufe4: - type: num - viess_command@instance: Statistik.Laufzeiten.VerdichterStufe4 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - VerdichterStufe5: - type: num - viess_command@instance: Statistik.Laufzeiten.VerdichterStufe5 - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - VerdichterWP: - type: num - viess_command@instance: Statistik.Laufzeiten.VerdichterWP - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - Statistik.Laufzeiten - - OAT_Temperature: - type: num - viess_command@instance: Statistik.OAT_Temperature - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - ICT_Temperature: - type: num - viess_command@instance: Statistik.ICT_Temperature - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - CCT_Temperature: - type: num - viess_command@instance: Statistik.CCT_Temperature - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - HST_Temperature: - type: num - viess_command@instance: Statistik.HST_Temperature - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - OMT_Temperature: - type: num - viess_command@instance: Statistik.OMT_Temperature - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - WaermeWW12M: - type: num - viess_command@instance: Statistik.WaermeWW12M - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik - - ElektroWW12M: - type: num - viess_command@instance: Statistik.ElektroWW12M - viess_read@instance: true - viess_write@instance: false - viess_read_group@instance: - - V200WO1C - - Statistik + mandatory: yes + description: + de: 'Vierstellige Hex-Adresse des Datenpunktes' + en: 'Four-digit hex address of the data point' + length: + type: int + mandatory: yes + description: + de: 'Länge der Geräteantwort in Bytes (1-8)' + en: 'Lengh of device response in bytes (1-8)' + valid_min: 1 + valid_max: 8 + unit: + type: str + mandatory: yes + description: + de: 'Einheitencode für die Konvertierung der Antwort. Muss in der Protokollkonfiguration ``unitset`` in commands.py definiert sein' + en: 'Unit code for converting the response value. Needs to be defined in the protocol configuration ``unitset`` in commands.py' + write_addr: + type: foo + description: + de: 'Stößt das Schreiben des angegebenen Datenpunkts an, der nicht an ein Item gebunden sein muss. Der übergebene Wert muss zum konfigurierten Datentyp passen' + en: 'Triggers writing of the supplied data point, which doesn''t have to be bound to an item. The submitted value must match the configured data type' + parameters: + addr: + type: str + description: + de: 'Vierstellige Hex-Adresse des Datenpunktes' + en: 'Four-digit hex address of the data point' + value: + description: + de: 'Zu schreibender Wert' + en: 'Value to be written' diff --git a/viessmann/protocol.py b/viessmann/protocol.py deleted file mode 100644 index 315b85e98..000000000 --- a/viessmann/protocol.py +++ /dev/null @@ -1,507 +0,0 @@ -#!/usr/bin/env python3 -# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab -######################################################################### -# Copyright 2020- Sebastian Helms Morg @ knx-user-forum -######################################################################### -# This file aims to become part of SmartHomeNG. -# https://www.smarthomeNG.de -# https://knx-user-forum.de/forum/supportforen/smarthome-py -# -# SDPProtocolViessmann for sdp_viessmann plugin -# -# SmartHomeNG 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. -# -# SmartHomeNG 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 SmartHomeNG. If not, see . -# -######################################################################### - -import logging - -from lib.model.sdp.globals import (CONN_SER_DIR, PLUGIN_ATTR_CB_ON_CONNECT, PLUGIN_ATTR_CB_ON_DISCONNECT, PLUGIN_ATTR_CONNECTION, PLUGIN_ATTR_CONN_AUTO_CONN, PLUGIN_ATTR_CONN_BINARY, PLUGIN_ATTR_CONN_CYCLE, PLUGIN_ATTR_CONN_RETRIES, PLUGIN_ATTR_CONN_TIMEOUT, PLUGIN_ATTR_SERIAL_BAUD, PLUGIN_ATTR_SERIAL_BSIZE, PLUGIN_ATTR_SERIAL_PARITY, PLUGIN_ATTR_SERIAL_PORT, PLUGIN_ATTR_SERIAL_STOP) -from lib.model.sdp.protocol import SDPProtocol - -from time import sleep -import threading - - -############################################################################################################################################################################################################################################# -# -# class SDPProtocol and subclasses -# -############################################################################################################################################################################################################################################# - -class SDPProtocolViessmann(SDPProtocol): - """ Protocol support for Viessmann heating systems - - This class implements a Viessmann protocol layer. By default, this uses - the P300 protocol. By supplying the 'viess_proto' attribute, the older 'KW' - protocol can be selected. - - At the moment, this is oriented towards serial connections. By supplying - your own connection type, you could try to use it over networked connections. - Be advised that the necessary "reply" client and the methods needed are not - implemented for network access as of this time... - """ - - def __init__(self, data_received_callback, name=None, **kwargs): - - self.logger = logging.getLogger(__name__) - - if SDP_standalone: - self.logger = logging.getLogger('__main__') - - self.logger.debug(f'protocol initializing from {self.__class__.__name__} with arguments {kwargs}') - - # set class properties - self._is_connected = False - self._error_count = 0 - self._lock = threading.Lock() - self._is_initialized = False - self._data_received_callback = data_received_callback - - # try to assure no concurrent sending is done - self._send_lock = threading.Lock() - self.use_send_lock = True - - self._controlsets = { - 'P300': { - 'baudrate': 4800, - 'bytesize': 8, - 'parity': 'E', - 'stopbits': 2, - 'timeout': 0.5, - 'startbyte': 0x41, - 'request': 0x00, - 'response': 0x01, - 'error': 0x03, - 'read': 0x01, - 'write': 0x02, - 'functioncall': 0x7, - 'acknowledge': 0x06, - 'not_initiated': 0x05, - 'init_error': 0x15, - 'reset_command': 0x04, - 'reset_command_response': 0x05, - 'sync_command': 0x160000, - 'sync_command_response': 0x06, - 'command_bytes_read': 5, - 'command_bytes_write': 5, - # init: send'Reset_Command' receive'Reset_Command_Response' send'Sync_Command' - # request: send('StartByte' 'Länge der Nutzdaten als Anzahl der Bytes zwischen diesem Byte und der Prüfsumme' 'Request' 'Read' 'addr' 'checksum') - # request_response: receive('Acknowledge' 'StartByte' 'Länge der Nutzdaten als Anzahl der Bytes zwischen diesem Byte und der Prüfsumme' 'Response' 'Read' 'addr' 'Anzahl der Bytes des Wertes' 'Wert' 'checksum') - }, - 'KW': { - 'baudrate': 4800, - 'bytesize': 8, # 'EIGHTBITS' - 'parity': 'E', # 'PARITY_EVEN', - 'stopbits': 2, # 'STOPBITS_TWO', - 'timeout': 1, - 'startbyte': 0x01, - 'read': 0xF7, - 'write': 0xF4, - 'acknowledge': 0x01, - 'reset_command': 0x04, - 'not_initiated': 0x05, - 'write_ack': 0x00, - }, - } - - # get protocol or default to P300 - self._viess_proto = kwargs.get('viess_proto', 'P300') - if self._viess_proto not in self._controlsets: - self._viess_proto = 'P300' - # select controlset for viess_proto - self._controlset = self._controlsets[self._viess_proto] - - # make sure we have a basic set of parameters for the TCP connection - self._params = {PLUGIN_ATTR_SERIAL_PORT: '', - PLUGIN_ATTR_SERIAL_BAUD: self._controlset[PLUGIN_ATTR_SERIAL_BAUD], - PLUGIN_ATTR_SERIAL_BSIZE: self._controlset[PLUGIN_ATTR_SERIAL_BSIZE], - PLUGIN_ATTR_SERIAL_PARITY: self._controlset[PLUGIN_ATTR_SERIAL_PARITY], - PLUGIN_ATTR_SERIAL_STOP: self._controlset[PLUGIN_ATTR_SERIAL_STOP], - PLUGIN_ATTR_CONN_TIMEOUT: self._controlset[PLUGIN_ATTR_CONN_TIMEOUT], - PLUGIN_ATTR_CONN_AUTO_CONN: True, - PLUGIN_ATTR_CONN_BINARY: True, - PLUGIN_ATTR_CONN_RETRIES: 0, - PLUGIN_ATTR_CONN_CYCLE: 3, - PLUGIN_ATTR_CB_ON_CONNECT: None, - PLUGIN_ATTR_CB_ON_DISCONNECT: None, - PLUGIN_ATTR_CONNECTION: CONN_SER_DIR} - self._params.update(kwargs) - - # check if some of the arguments are usable - self._set_connection_params() - - # initialize connection - self._get_connection(name=name) - - # set "method pointers" - self._send_bytes = self._connection._send_bytes - self._read_bytes = self._connection._read_bytes - - # tell someone about our actual class - self.logger.debug(f'protocol initialized from {self.__class__.__name__}') - - def _close(self): - self._is_initialized = False - super()._close() - - def _send_init_on_send(self): - """ - setup the communication protocol prior to sending - - :return: Returns True, if communication was established successfully, False otherwise - :rtype: bool - """ - if self._viess_proto == 'P300': - - if self._is_initialized: - return True - - # init procedure is - # interface: 0x04 (reset) - # device: 0x05 (repeated) - # interface: 0x160000 (sync) - # device: 0x06 (sync ok) - # interface: resume communication, periodically send 0x160000 as keepalive if necessary - - RESET = self._int2bytes(self._controlset['reset_command'], 1) - NOTINIT = self._int2bytes(self._controlset["not_initiated"], 1) - ACK = self._int2bytes(self._controlset['acknowledge'], 1) - SYNC = self._int2bytes(self._controlset['sync_command'], 3) - ERR = self._int2bytes(self._controlset['init_error'], 1) - - self.logger.debug('init communication....') - self.__syncsent = False - empty_replies = 0 - - self.logger.debug(f'send_bytes: send reset command {RESET}') - self._send_bytes(RESET) - - for i in range(10): - readbyte = self._read_bytes(1) - self.logger.debug(f'read_bytes: read {readbyte}') - - if self.__syncsent and readbyte == ACK: - self.logger.debug('device acknowledged initialization') - self._is_initialized = True - break - elif readbyte == NOTINIT: - self.logger.debug(f'send_bytes: send sync command {SYNC}') - self._send_bytes(SYNC) - self.__syncsent = True - empty_replies = 0 - elif readbyte == ERR: - self.logger.error(f'interface reported an error, loop increment {i}') - self.logger.debug(f'send_bytes: send reset command {RESET}') - self._send_bytes(RESET) - self.__syncsent = False - empty_replies = 0 - elif readbyte == b'': - # allow for some (5) empty replies due to timing issues without breaking sync - empty_replies += 1 - if empty_replies > 5: - self.logger.debug(f'send_bytes: too many empty replies, send reset command {RESET}') - self._send_bytes(RESET) - self.__syncsent = False - empty_replies = 0 - else: - self.logger.debug(f'RESET send_bytes: send reset command {RESET}') - self._send_bytes(RESET) - self.__syncsent = False - empty_replies = 0 - - self.logger.debug(f'communication initialized: {self._is_initialized}') - return self._is_initialized - - elif self._viess_proto == 'KW': - - retries = 5 - RESET = self._int2bytes(self._controlset['reset_command'], 1) - NOINIT = self._int2bytes(self._controlset['not_initiated'], 1, signed=False) - - # try to reset communication, especially if previous P300 comms is still open - self._send_bytes(RESET) - - attempt = 0 - while attempt < retries: - self.logger.debug(f'starting sync loop - attempt {attempt + 1}/{retries}') - - self._connection.reset_input_buffer() - chunk = self._read_bytes(1) - # enable for 'raw' debugging - # self.logger.debug(f'sync loop - got {self._bytes2hexstring(chunk)}') - if chunk == NOINIT: - self.logger.debug('got sync, commencing command send') - self._is_initialized = True - return True - sleep(.8) - attempt = attempt + 1 - self.logger.error(f'sync not acquired after {attempt} attempts') - self._close() - return False - - return True - - def _send(self, data_dict): - """ - send data. data_dict needs to contain the following information: - - data_dict['payload']: address from/to which to read/write (hex, str) - data_dict['data']['len']: length of command to send - data_dict['data']['value']: value bytes to write, None if reading - - :param data_dict: send data - :param read_response: KW only: read response value (True) or only return status byte - :type data_dict: dict - :type read_response: bool - :return: Response packet (bytearray) if no error occured, None otherwise - """ - (packet, responselen) = self._build_payload(data_dict) - - # send payload - self._lock.acquire() - try: - self._send_bytes(packet) - self.logger.debug(f'successfully sent packet {self._bytes2hexstring(packet)}') - - # receive response - response_packet = bytearray() - self.logger.debug(f'trying to receive {responselen} bytes of the response') - chunk = self._read_bytes(responselen) - if self._viess_proto == 'P300': - self.logger.debug(f'received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') - if len(chunk) != 0: - if chunk[:1] == self._int2bytes(self._controlset['error'], 1): - self.logger.error(f'interface returned error, response was {chunk}') - elif len(chunk) == 1 and chunk[:1] == self._int2bytes(self._controlset['not_initiated'], 1): - self.logger.error('received invalid chunk, connection not initialized, forcing re-initialize...') - self._initialized = False - elif chunk[:1] != self._int2bytes(self._controlset['acknowledge'], 1): - self.logger.error(f'received invalid chunk, not starting with ACK, response was {chunk}') - self._error_count += 1 - if self._error_count >= 5: - self.logger.warning('encountered 5 invalid chunks in sequence, maybe communication was lost, forcing re-initialize') - self._initialized = False - else: - response_packet.extend(chunk) - self._error_count = 0 - return self._parse_response(response_packet) - else: - self.logger.error(f'received 0 bytes chunk - ignoring response_packet, chunk was {chunk}') - elif self._protocol == 'KW': - self.logger.debug(f'received {len(chunk)} bytes chunk of response as hexstring {self._bytes2hexstring(chunk)} and as bytes {chunk}') - if len(chunk) != 0: - response_packet.extend(chunk) - return self._parse_response(response_packet, data_dict['data']['value'] is None) - else: - self.logger.error('received 0 bytes chunk - this probably is a communication error, possibly a wrong datapoint address?') - except IOError as e: - self.logger.error(f'send_command_packet failed with IO error, trying to reconnect. Error was: {e}') - self._close() - except Exception as e: - self.logger.error(f'send_command_packet failed with error: {e}') - finally: - try: - self._lock.release() - except RuntimeError: - pass - - # if we didn't return with data earlier, we hit an error. Act accordingly - return None - - def _parse_response(self, response, read_response=True): - """ - Process device response data, try to parse type and value - - :param response: Data received from device - :type response: bytearray - :param read_response: True if command was read command and value is expected, False if only status byte is expected (only needed for KW protocol) - :type read_response: bool - :return: tuple of (parsed response value, commandcode) or None if error - """ - if self._viess_proto == 'P300': - - # A read_response telegram looks like this: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of valuebytes (1 byte), value (bytes as per last byte), checksum (1 byte) - # A write_response telegram looks like this: ACK (1 byte), startbyte (1 byte), data length in bytes (1 byte), request/response (1 byte), read/write (1 byte), addr (2 byte), amount of bytes written (1 byte), checksum (1 byte) - - # Validate checksum - checksum = self._calc_checksum(response[1:len(response) - 1]) # first, cut first byte (ACK) and last byte (checksum) and then calculate checksum - received_checksum = response[len(response) - 1] - if received_checksum != checksum: - self.logger.error(f'calculated checksum {checksum} does not match received checksum of {received_checksum}! Ignoring reponse') - return None - - # Extract command/address, valuebytes and valuebytecount out of response - responsetypecode = response[3] # 0x00 = query, 0x01 = reply, 0x03 = error - responsedatacode = response[4] # 0x01 = ReadData, 0x02 = WriteData, 0x07 = Function Call - valuebytecount = response[7] - - # Extract databytes out of response - rawdatabytes = bytearray() - rawdatabytes.extend(response[8:8 + (valuebytecount)]) - elif self._protocol == 'KW': - - # imitate P300 response code data for easier combined handling afterwards - # a read_response telegram consists only of the value bytes - # a write_response telegram is 0x00 for OK, 0xXX for error - responsetypecode = 1 - valuebytecount = len(response) - rawdatabytes = response - - if read_response: - # value response to read request, error detection by empty = no response - responsedatacode = 1 - if len(rawdatabytes) == 0: - # error, no answer means wrong address (?) - responsetypecode = 3 - else: - # status response to write request - responsedatacode = 2 - if (len(rawdatabytes) == 1 and rawdatabytes[0] != 0) or len(rawdatabytes) == 0: - # error if status reply is not 0x00 - responsetypecode = 3 - - self.logger.debug(f'Response decoded to: responsedatacode: {responsedatacode}, valuebytecount: {valuebytecount}, responsetypecode: {responsetypecode}') - - if responsetypecode == 3: - raise ValueError(f'error on reading reply {rawdatabytes}') - - if responsedatacode == 2: - self.logger.debug('write request successful') - return None - - self.logger.debug(f'read request successful, read bytes {rawdatabytes}') - return rawdatabytes - - def _build_payload(self, data_dict): - """ - create payload from data_dict. Necessary data: - - data_dict['payload']: address from/to which to read/write (hex, str) - data_dict['data']['len']: length of command to send - data_dict['data']['value']: value bytes to write, None if reading - data_dict['data']['kwseq']: packet is follow-up packet in KW - - :param data_dict: data to convert - :type data_dict: dict - :return: (packet, responselen) - :rtype: tuple - """ - try: - addr = data_dict['payload'].lower() - cmdlen = data_dict['data']['len'] - valuebytes = data_dict['data']['value'] - KWFollowUp = data_dict['data'].get('kwseq', False) - except Exception as e: - raise ValueError(f'data_dict {data_dict} not usable, data not sent. Error was: {e}') - - write = valuebytes is not None - - # build payload - if write: - payloadlength = int(self._controlset.get('command_bytes_write', 0)) + cmdlen # int(valuebytes) - self.logger.debug(f'Payload length is: {payloadlength} bytes') - - packet = bytearray() - if not KWFollowUp: - packet.extend(self._int2bytes(self._controlset['startbyte'], 1)) - if self._viess_proto == 'P300': - if write: - packet.extend(self._int2bytes(payloadlength, 1)) - else: - packet.extend(self._int2bytes(self._controlset['command_bytes_read'], 1)) - packet.extend(self._int2bytes(self._controlset['request'], 1)) - - if write: - packet.extend(self._int2bytes(self._controlset['write'], 1)) - else: - packet.extend(self._int2bytes(self._controlset['read'], 1)) - packet.extend(bytes.fromhex(addr)) - packet.extend(self._int2bytes(cmdlen, 1)) - if write: - packet.extend(valuebytes) - if self._viess_proto == 'P300': - packet.extend(self._int2bytes(self._calc_checksum(packet), 1)) - - if self._viess_proto == 'P300': - responselen = int(self._controlset['command_bytes_read']) + 4 + (0 if write else int(cmdlen)) - else: - responselen = 1 if write else int(cmdlen) - - if write: - self.logger.debug(f'created payload to be sent as hexstring: {self._bytes2hexstring(packet)} and as bytes: {packet} with value {self._bytes2hexstring(valuebytes)})') - else: - self.logger.debug(f'created payload to be sent as hexstring: {self._bytes2hexstring(packet)} and as bytes: {packet}') - - return (packet, responselen) - - @staticmethod - def _calc_checksum(packet): - """ - Calculate checksum for P300 protocol packets - - :parameter packet: Data packet for which to calculate checksum - :type packet: bytearray - :return: Calculated checksum - :rtype: int - """ - checksum = 0 - if len(packet) > 0: - if packet[:1] == b'\x41': - packet = packet[1:] - checksum = sum(packet) - checksum = checksum - int(checksum / 256) * 256 - return checksum - - @staticmethod - def _int2bytes(value, length, signed=False): - """ - Convert value to bytearray with respect to defined length and sign format. - Value exceeding limit set by length and sign will be truncated - - :parameter value: Value to convert - :type value: int - :parameter length: number of bytes to create - :type length: int - :parameter signed: True if result should be a signed int, False for unsigned - :type signed: bool - :return: Converted value - :rtype: bytearray - """ - value = value % (2 ** (length * 8)) - return value.to_bytes(length, byteorder='big', signed=signed) - - @staticmethod - def _bytes2int(rawbytes, signed): - """ - Convert bytearray to value with respect to sign format - - :parameter rawbytes: Bytes to convert - :type value: bytearray - :parameter signed: True if result should be a signed int, False for unsigned - :type signed: bool - :return: Converted value - :rtype: int - """ - return int.from_bytes(rawbytes, byteorder='little', signed=signed) - - @staticmethod - def _bytes2hexstring(bytesvalue): - """ - Create hex-formatted string from bytearray - :param bytesvalue: Bytes to convert - :type bytesvalue: bytearray - :return: Converted hex string - :rtype: str - """ - return ''.join(f'{c:02x}' for c in bytesvalue) diff --git a/viessmann/_pv_1_2_3/requirements.txt b/viessmann/requirements.txt similarity index 100% rename from viessmann/_pv_1_2_3/requirements.txt rename to viessmann/requirements.txt diff --git a/viessmann/user_doc.rst b/viessmann/user_doc.rst old mode 100644 new mode 100755 index 4dab67e7c..c9147d140 --- a/viessmann/user_doc.rst +++ b/viessmann/user_doc.rst @@ -24,41 +24,9 @@ Das Plugin unterstützt die serielle Kommunikation mit dem Lesekopf (ggf. über Zur Identifizierung des Heizungstyps kann das Plugin auch im Standalone-Modus betrieben werden (s.u.) - -Anpassungen durch Update auf sdp --------------------------------- - -Durch die Umstellung auf sdp haben sich sowohl Änderungen in der Plugin- als auch der Item-Konfiguration geändert. - -Plugin-Konfiguration: -~~~~~~~~~~~~~~~~~~~~~ - -- der Parameter ``heating_type`` ist in ``model`` umbenannt worden -- der Parameter ``suspend_item`` ist neu hinzugefügt worden und bestimmt (bei Bedarf) das Item zum Steuern des Suspend-Modus - -Item-Konfiguration: -~~~~~~~~~~~~~~~~~~~ - -Die Item-Konfiguration von sdp wird durch mitgelieferte Structs unterstützt. Zu Details siehe weiter unten. - -Das Attribut ``viess_balist`` gibt es nicht mehr, die Funktionalität wird durch Lookup-Tabellen abgebildet. Die Lookup-Tabelle zur Betriebsart ist im Item ``Allgemein.Betriebsart.lookup`` standardmäßig verfügbar. - -Plugin-Funktionen: -~~~~~~~~~~~~~~~~~~ - -Die Funktion ``update_all_read_items`` existiert nicht mehr. SmartDevicePlugin bietet - generell - die Funktion ``read_all_commands(group='')`` an, die die gleiche Funktionalität darstellt. Hier kann eine Gruppe, eine Liste von Gruppen oder 0 (für alle Items) angegeben werden, die gelesen werden sollen. Die Konfiguration entspricht den read_groups_triggers (die intern nur diese Funktion anstoßen). - - Changelog --------- -1.3.0 -~~~~~ - -- komplettes Rewrite auf Basis SmartDevicePlugin -- Umfang der unterstützten Geräte beibehalten -- breaking Change: Konfiguration (Plugin und Items) müssen angepasst werden - 1.2.2 ~~~~~ @@ -118,56 +86,61 @@ plugin.yaml viessmann: protocol: P300 plugin_name: viessmann - model: V200KO1B + heating_type: V200KO1B serialport: /dev/ttyUSB_optolink items.yaml ---------- -Zur Vereinfachung werden fertige Structs für alle unterstützten Gerätetypen mitgeliefert. Diese können wie folgt eingebunden werden: +Die Verknüfpung von SmartHomeNG-Items und Heizungsparametern ist vollständig flexibel und konfigurierbar. Mit den Item-Attributen kann das Verhalten des Plugins festgelegt werden. -.. code:: yaml +Die folgenden Attribute werden unterstützt: - heizungsitem: - struct: viessmann.MODEL +viess\_read +~~~~~~~~~~~ -:note: Das Wort "MODEL" in der Itemkonfiguration bleibt wörtlich so stehen, sdp verwendet automatisch den entsprechend passenden Struct. +Der Wert des angegebenen Parameters wird gelesen und dem Item zugewiesen. +.. code:: yaml -Sofern keine weiteren Angaben gewünscht sind, ist die Item-Konfiguration damit abgeschlossen. Da die Item-Struktur der Kommando-Struktur entspricht, werden sich die Items ändern, d.h. verschieben und ggf. umbenennen. Item-Referenzen müssen entsprechend angepasst werden. + item: + viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 -Sofern eine manuelle Item-Konfiguration gewünscht wird, ist dies auch möglich. Die Verknüfpung von SmartHomeNG-Items und Heizungsparametern ist vollständig flexibel und konfigurierbar. Mit den Item-Attributen kann das Verhalten des Plugins festgelegt werden. +viess\_send +~~~~~~~~~~~ -Die folgenden Attribute werden unterstützt: +Der angegebene Parameter wird bei Änderungen an diesem Item an die Heizung gesendet. +.. code:: yaml -viess\_command -~~~~~~~~~~~~~~ + item: + viess_send: Raumtemperatur_Soll_Normalbetrieb_A1M1 -Dieses Attribut legt fest, welcher Befehl ausgeführt bzw. welcher Parameter vom Gerät gelesen oder geschrieben werden soll. +Sofern das Item sowohl zum Lesen als auch zum Schreiben eines Parameters konfiguriert wird, kann die vereinfachte Konfiguration mit ``true`` erfolgen: .. code:: yaml item: - viess_command: Allgemein.Temperatur.Aussen - + viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 + viess_send: true -:note: Dies entspricht prinzipiell dem bisherigen Attribut `viess_read`, ohne Aussagen über Lese- oder Schreibverhalten zu treffen. Durch die Umstellung der Befehlsstruktur müssen die Werte angepasst werden. +viess\_read\_afterwrite +~~~~~~~~~~~~~~~~~~~~~~~ -viess\_read -~~~~~~~~~~~ - -Das Item erhält Werte vom Gerät (Wert kann gelesen werden). Typ bool. (Entspricht grob dem alten Attribut `viess_read`) +Wenn dieses Attribut mit einer Dauer in Sekunden angegeben ist, wird nach eine Schreibvorgang die angegebene Anzahl an Sekunden gewartet und ein erneuter Lesevorgang ausgelöst. +Damit dieses Attribut verwendet werden kann, muss das Item sowohl die Attribute ``viess_read`` als auch ``viess_send`` enthalten. -viess\_write -~~~~~~~~~~~~ +.. code:: yaml -Der Wert des Items wird bei Änderungen an die Heizung gesendet. Typ bool. (Entspricht grob dem alten Attribut `viess_send`) + item: + viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 + viess_send: true + viess_read_afterwrite: 1 # seconds viess\_read\_cycle @@ -178,60 +151,97 @@ Mit einer Angabe in Sekunden wird ein periodisches Lesen angefordert. ``viess_re .. code:: yaml item: - viess_command: Allgemein.Temperatur.Aussen + viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 viess_read_cycle: 3600 # every hour -viess\_read\_initial -~~~~~~~~~~~~~~~~~~~~ +viess\_init +~~~~~~~~~~~ Wenn dieses Attribut vorhanden und auf ``true`` gesetzt ist, wird das Item nach dem Start von SmartHomeNG einmalig gelesen. +``viess_read`` muss zusätzlich konfiguriert sein. .. code:: yaml item: - viess_command: Allgemein.Temperatur.Aussen - viess_read_initial: true + viess_read: Raumtemperatur_Soll_Normalbetrieb_A1M1 + viess_init: true -viess\_read\_group: -~~~~~~~~~~~~~~~~~~~ +viess\_trigger +~~~~~~~~~~~~~~ + +Enthält eine Liste von Parametern. Wenn dieses Item aktualisiert wird, wird ein Lesevorgang für jeden Eintrag in der Liste angestoßen. ``viess_send`` muss zusätzlich konfiguriert sein. -Weist das Item der angegebenen Gruppe zum gesammelten Lesen zu. Die Gruppe kann alt int-Wert oder als str (Name) angegeben werden, mehrere Gruppen können als Liste zugewiesen werden. +Zwischen dem Schreibvorgang und den folgenden Lesevorgängen ist standardmäßig eine Verzögerung von 5 Sekunden eingestellt. Diese kann mit ``viess_trigger_afterwrite`` verändert werden. + +Beispiel: wenn der Betriebsmodus geändert wird, können neue Sollwerte für Raum- und Wassertemperaturen gelesen werden. .. code:: yaml item: - viess_command: Betriebsart_A1M1 - viess_read_group: - - Status - - Betrieb - - 5 + viess_send: Betriebsart_A1M1 + viess_trigger: + - Raumtemperatur_Soll + - Wassertemperatur_Soll -Standardmäßig sind in den Structs bereits Gruppen für alle Strukturbäume vorhanden. +viess\_trigger\_afterwrite +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Wenn ein ``viess_trigger`` konfiguriert ist, kann mit diesem Attribut die Verzögerung zwischen Schreib- und Lesevorgang verändert werden. -viess\_read\_group\_trigger: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Standardmäßig beträgt diese Verzögerung 5 Sekunden. -Ein Item mit diesem Attribut löst das Lesen der angegebenen Gruppe(n) aus (siehe `viess_read_group`). Mehrere Gruppen können als Liste angegeben werden, wenn als Gruppe 0 angegeben wird, werden alle Werte vom Gerät gelesen. +.. code:: yaml -Dieses Attribut kann nicht gleichzeitig mit ``viess_command`` gesetzt werden. + item: + viess_send: Betriebsart_A1M1 + viess_trigger: + - Raumtemperatur_Soll + - Wassertemperatur_Soll + viess_trigger_afterwrite: 10 # seconds -viess\_lookup: -~~~~~~~~~~~~~~ +viess\_update +~~~~~~~~~~~~~ +Das Zuweisen von ``true`` an ein Item mit diesem Attribut löst den Lesevorgang aller konfigurierter Items mit ``viess_read`` aus. -Wenn ein Befehl mit einer Lookup-Tabelle versehen ist, kann die Lookup-Tabelle mit dem angegebenen Namen beim Start einmalig in das Item geschrieben werden. Damit können z.B. Klartextwerte für die Visualisierung angeboten werden. +Der in der Itemkonfiguration angegebene Wert wird nicht ausgewertet. .. code:: yaml item: - viess_lookup: operationmode + viess_update: 'egal' -:note: In den vorgefertigten Structs sind bei Items, die Werte aus Lookup-Tabellen zurückgeben, die jeweiligen Lookup-Tabellen in Unteritems mit dem Namen ``lookup`` vorhanden. +viess\_timer +~~~~~~~~~~~~ +Das Item mit diesem Attribut übergibt als Attributwert den Namen einer Anwendung, z.B. Heizkreis_A1M1, und das Plugin gibt ein UZSU-formatiertes dict mit allen zugehörigen Timern der Heizung zurück +Beim Schreiben wird das UZSU-dict in die einzelnen Tagestimer aufgeteilt und an die Heizung gesendet. + +.. code:: yaml + + item: + viess_timer: 'Heizkreis_A1M1' + + +viess\_ba\_list +~~~~~~~~~~~~~~~ +Das Item mit diesem Attribut erhält einmalig beim Start des Plugins die Liste der für den konfigurierten Heizungstyp gültigen Betriebsarten. + +Diese kann z.B. in SmartVISU wie folgt eingebunden werden: + +.. code:: yaml + + item: + viess_ba_list: 'egal' + +.. code:: + + {{ basic.select('heizen_ba_item', 'heizung.betriebsart', 'menu', '', '', '', '', '', 'heizung.ba_list') }} + +Dies erzeugt eine ("Menü"-) Auswahlliste, aus der die Betriebsart ausgewählt werden kann, die dann vom Plugin an die Heizung übergeben wird. Beispiel @@ -243,12 +253,138 @@ V200KO1B: .. code:: yaml viessmann: - struct: MODEL + viessmann_update: + name: Update aller Items mit 'viess_read' + type: bool + visu_acl: rw + viess_update: 1 + enforce_updates: true + autotimer: 1 = false = latest + + allgemein: + aussentemp: + name: Aussentemperatur + type: num + viess_read: Aussentemperatur + viess_read_cycle: 300 + viess_init: true + database: true + + aussentemp_gedaempft: + name: Aussentemperatur + type: num + viess_read: Aussentemperatur_TP + viess_read_cycle: 300 + viess_init: true + database: true + + kessel: + kesseltemperatur_ist: + name: Kesseltemperatur_Ist + type: num + viess_read: Kesseltemperatur + viess_read_cycle: 180 + viess_init: true + database: init + kesseltemperatur_soll: + name: Kesselsolltemperatur_Soll + type: num + viess_read: Kesselsolltemperatur + viess_read_cycle: 180 + viess_init: true + abgastemperatur: + name: Abgastemperatur + type: num + viess_read: Abgastemperatur + viess_read_cycle: 180 + viess_init: true + database: init + heizkreis_a1m1: + betriebsart: + betriebsart_aktuell: + name: Aktuelle_Betriebsart_A1M1 + type: str + viess_read: Aktuelle_Betriebsart_A1M1 + viess_read_cycle: 3600 + viess_init: true + betriebsart: + name: Betriebsart_A1M1 + type: num + viess_read: Betriebsart_A1M1 + viess_send: true + viess_read_afterwrite: 5 + viess_init: true + cache: true + enforce_updates: true + viess_trigger: + - Aktuelle_Betriebsart_A1M1 + struct: viessmann.betriebsart + visu_acl: rw + sparbetrieb: + name: Sparbetrieb_A1M1 + type: bool + viess_read: Sparbetrieb_A1M1 + viess_send: true + viess_read_afterwrite: 5 + viess_trigger: + - Betriebsart_A1M1 + - Aktuelle_Betriebsart_A1M1 + viess_init: true + visu_acl: rw + schaltzeiten: + montag: + name: Timer_A1M1_Mo + type: list + viess_read: Timer_A1M1_Mo + viess_send: true + viess_read_afterwrite: 5 + viess_init: true + struct: viessmann.timer + visu_acl: rw + dienstag: + name: Timer_A1M1_Di + type: list + viess_read: Timer_A1M1_Di + viess_send: true + viess_read_afterwrite: 5 + viess_init: true + struct: viessmann.timer + visu_acl: rw + ferienprogramm: + status: + name: Ferienprogramm_A1M1 + type: num + viess_read: Ferienprogramm_A1M1 + viess_read_cycle: 3600 + viess_init: true + starttag: + name: Ferien_Abreisetag_A1M1 + type: str + viess_read: Ferien_Abreisetag_A1M1 + viess_send: true + viess_read_afterwrite: 5 + viess_init: true + visu_acl: rw + eval: value[:10] + endtag: + name: Ferien_Rückreisetag_A1M1 + type: str + viess_read: Ferien_Rückreisetag_A1M1 + viess_send: true + viess_read_afterwrite: 5 + viess_init: true + visu_acl: rw Funktionen ========== +update\_all\_read\_items() +-------------------------- + +Diese Funktion stößt den Lesevorgang aller konfigurierten Items mit ``viess_read``-Attribut an. + + read\_addr(addr) ---------------- @@ -256,10 +392,10 @@ Diese Funktion löst das Lesen des Parameters mit der übergebenen Adresse ``add Der Rückgabewert ist das Ergebnis des Lesevorgangs oder None, wenn ein Fehler aufgetreten ist. -read\_temp\_addr(addr, length=1, mult=0, signed=False) +read\_temp\_addr(addr, length, unit) ------------------------------------ -Diese Funktion versucht, den Parameter an der Adresse ``addr`` zu lesen und einen Wert von ``length`` Bytes (ggf. mit einem Multiplikator ``mult`` und (nicht) vorzeichenbehaftet) zu konvertieren. Die Adresse muss als vierstellige Hex-Zahl im String-Format übergeben werden, im Gegensatz zu ``read_addr()`` aber nicht im Befehlssatz definiert sein. ``length`` ist auf Werte zwischen 1 und 8 (Bytes) beschränkt. ``mult`` gibt den Divisor an und ``signed``, ob der Wert vorzeichenbehaftet ist. +Diese Funktion versucht, den Parameter an der Adresse ``addr`` zu lesen und einen Wert von ``length`` Bytes in die Einheit ``unit`` zu konvertieren. Die Adresse muss als vierstellige Hex-Zahl im String-Format übergeben werden, im Gegensatz zu ``read_addr()`` aber nicht im Befehlssatz definiert sein. ``length`` ist auf Werte zwischen 1 und 8 (Bytes) beschränkt. ``unit`` muss im aktuellen Befehlssatz definiert sein. Der Rückgabewert ist das Ergebnis des Lesevorgangs oder None, wenn ein Fehler aufgetreten ist. @@ -302,7 +438,6 @@ Dazu muss das Plugin im Plugin-Ordner direkt aufgerufen werden: Der serielle Port ist dabei die Gerätedatei bzw. der entsprechende Port, an dem der Lesekopf angeschlossen ist, z.B. ``/dev/ttyUSB0``. Dieses Argument ist verpflichtend. -Das optionale zweite Argument ``-v`` weist das Plugin an, zusätzliche Debug-Ausgaben zu erzeugen. Solange keine Probleme beim Aufruf auftreten, ist das nicht erforderlich. - -Sollte die Datei sich nicht starten lassen, muss ggf. der Dateimodus angepasst werden. Mit ``chmod u+x __init__.py`` kann die z.B. unter Linux erfolgen. +Das optionale zweite Argument `-v` weist das Plugin an, zusätzliche Debug-Ausgaben zu erzeugen. Solange keine Probleme beim Aufruf auftreten, ist das nicht erforderlich. +Sollte die Datei sich nicht starten lassen, muss ggf. der Dateimodus angepasst werden. Mit ``chmod u+x __init__.py`` kann die z.B. unter Linux erfolgen. \ No newline at end of file diff --git a/viessmann/webif/__init__.py b/viessmann/webif/__init__.py deleted file mode 100644 index 0292f0c0e..000000000 --- a/viessmann/webif/__init__.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 -# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab -######################################################################### -# Copyright 2020- Sebastian Helms Morg @ knx-user-forum -######################################################################### -# This file aims to become part of SmartHomeNG. -# https://www.smarthomeNG.de -# https://knx-user-forum.de/forum/supportforen/smarthome-py -# -# MultiDevice plugin for handling arbitrary devices via network or serial -# connection. -# -# SmartHomeNG 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. -# -# SmartHomeNG 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 SmartHomeNG. If not, see . -# -######################################################################### - -import json - -from lib.item import Items -from lib.model.smartplugin import SmartPluginWebIf -from lib.model.sdp.globals import * -import cherrypy - - -############################################################################################################################################################################################################################################# -# -# class WebInterface -# -############################################################################################################################################################################################################################################# - -class WebInterface(SmartPluginWebIf): - - def __init__(self, webif_dir, plugin): - """ - Initialization of instance of class WebInterface - - :param webif_dir: directory where the webinterface of the plugin resides - :param plugin: instance of the plugin - :type webif_dir: str - :type plugin: object - """ - self.logger = plugin.logger - self.webif_dir = webif_dir - self.plugin = plugin - self.items = Items.get_instance() - - self.tplenv = self.init_template_environment() - - @cherrypy.expose - def index(self, reload=None): - """ - Build index.html for cherrypy - - Render the template and return the html file to be delivered to the browser - - :return: contents of the template after beeing rendered - """ - tmpl = self.tplenv.get_template('index.html') - # add values to be passed to the Jinja2 template eg: tmpl.render(p=self.plugin, interface=interface, ...) - - plgitems = [] - for item in self.items.return_items(): - if any(elem in item.property.attributes for elem in ITEM_ATTRS): - plgitems.append(item) - - return tmpl.render(p=self.plugin, - items=sorted(self.items.return_items(), key=lambda k: str.lower(k['_path'])), - item_count=0, - plgitems=plgitems, - running=self.plugin.alive, - lookups=self.plugin._commands._lookups) - - @cherrypy.expose - def submit(self, button=None, param=None): - """ - Submit handler for Ajax - """ - if button is not None: - - notify = None - - if '#' in button: - - # run/stop command - cmd, __, dev = button.partition('#') - device = self.plugin.get_device(dev) - if device: - if cmd == 'run': - self.logger.info(f'Webinterface starting device {dev}') - device.start() - elif cmd == 'stop': - self.logger.info(f'Webinterface stopping device {dev}') - device.stop() - elif '.' in button: - - # set device arg - but only when stopped - dev, __, arg = button.partition('.') - if param is not None: - param = sanitize_param(param) - try: - self.logger.info(f'Webinterface setting param {arg} of device {dev} to {param}') - self.plugin._devices[dev]['params'][arg] = param - self.plugin._update_device_params(dev) - notify = dev + '-' + arg + '-notify' - except Exception as e: - self.logger.info(f'Webinterface failed to set param {arg} of device {dev} to {param} with error {e}') - - # # possibly prepare data for returning - # read_cmd = self.plugin._commandname_by_commandcode(button) - # if read_cmd is not None: - # self._last_read[button] = {'addr': button, 'cmd': read_cmd, 'val': read_val} - # self._last_read['last'] = self._last_read[button] - - data = {'running': {dev: self.plugin._devices[dev]['device'].alive for dev in self.plugin._devices}, 'notify': notify} - - # # possibly return data to WebIf - cherrypy.response.headers['Content-Type'] = 'application/json' - return json.dumps(data).encode('utf-8') - - @cherrypy.expose - def get_data_html(self, dataSet=None): - """ - Return data to update the webpage - - For the standard update mechanism of the web interface, the dataSet to return the data for is None - - :param dataSet: Dataset for which the data should be returned (standard: None) - :return: dict with the data needed to update the web page. - """ - if dataSet is None: - # get the new data - # data = {} - pass - - # data['item'] = {} - # for i in self.plugin.items: - # data['item'][i]['value'] = self.plugin.getitemvalue(i) - # - # return it as json the the web page - # try: - # return json.dumps(data) - # except Exception as e: - # self.logger.error('get_data_html exception: {}'.format(e)) - return {} diff --git a/viessmann/_pv_1_2_3/webif/static/datatables_min.css b/viessmann/webif/static/datatables_min.css similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/datatables_min.css rename to viessmann/webif/static/datatables_min.css diff --git a/viessmann/_pv_1_2_3/webif/static/datatables_min.js b/viessmann/webif/static/datatables_min.js similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/datatables_min.js rename to viessmann/webif/static/datatables_min.js diff --git a/viessmann/webif/static/img/plugin_logo.svg b/viessmann/webif/static/img/plugin_logo.svg old mode 100644 new mode 100755 index e1c8a9993..16c50e23d --- a/viessmann/webif/static/img/plugin_logo.svg +++ b/viessmann/webif/static/img/plugin_logo.svg @@ -1,88 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Multidevice - +Element 1 \ No newline at end of file diff --git a/viessmann/_pv_1_2_3/webif/static/img/sort_asc.png b/viessmann/webif/static/img/sort_asc.png similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/img/sort_asc.png rename to viessmann/webif/static/img/sort_asc.png diff --git a/viessmann/_pv_1_2_3/webif/static/img/sort_asc_disabled.png b/viessmann/webif/static/img/sort_asc_disabled.png similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/img/sort_asc_disabled.png rename to viessmann/webif/static/img/sort_asc_disabled.png diff --git a/viessmann/_pv_1_2_3/webif/static/img/sort_both.png b/viessmann/webif/static/img/sort_both.png similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/img/sort_both.png rename to viessmann/webif/static/img/sort_both.png diff --git a/viessmann/_pv_1_2_3/webif/static/img/sort_desc.png b/viessmann/webif/static/img/sort_desc.png similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/img/sort_desc.png rename to viessmann/webif/static/img/sort_desc.png diff --git a/viessmann/_pv_1_2_3/webif/static/img/sort_desc_disabled.png b/viessmann/webif/static/img/sort_desc_disabled.png similarity index 100% rename from viessmann/_pv_1_2_3/webif/static/img/sort_desc_disabled.png rename to viessmann/webif/static/img/sort_desc_disabled.png diff --git a/viessmann/webif/templates/index.html b/viessmann/webif/templates/index.html old mode 100644 new mode 100755 index f6aa9dfbe..d522eeefb --- a/viessmann/webif/templates/index.html +++ b/viessmann/webif/templates/index.html @@ -1,75 +1,136 @@ + {% extends "base_plugin.html" %} +{% set tabcount = 2 %} +{% set tab1title = _('Viessmann Items') %} +{% set tab2title = _('Alle Datenpunkte') %} +{% set language = p.get_sh().get_defaultlanguage() %} +{% if last_read_cmd != "" %} +{% set start_tab = 3 %} +{% endif %} +{% if language not in ['en','de'] %} +{% set language = 'en' %} +{% endif %} -{% set logo_frame = false %} - - -{% set update_interval = 0 %} - - {% block pluginscripts %} +/* + * The combined file was created by the DataTables downloader builder: + * https://datatables.net/download + * + * To rebuild or modify this file with the latest versions of the included + * software please visit: + * https://datatables.net/download/#dt/dt-1.10.21/fh-3.1.7/r-2.2.5 + * + * Included libraries: + * DataTables 1.10.21, FixedHeader 3.1.7, Responsive 2.2.5 + */ + + - {% endblock pluginscripts %} @@ -78,139 +139,67 @@ - - + + - - + + + + + + + + + + - - + + + + + + + + + + + - - -
{{ _('Aktiv') }}{{ p.alive }}{{ _('Serieller Port') }}{{ p._serialport }} {{ _('Anzahl Geräte') }}{{ p._devices|length }}{{ _('Anzahl Items') }}{{ p._params|length }}
{{ _('Heizungstyp') }}{{ p._heating_type }}{{ _('Verbunden') }}{{ p._connected }}
{{ _('') }}{{ _('Protokoll') }}{{ p._protocol }}{{ _('Verbindung aktiv') }}{{ p._initialized }}
{{ _('Letzter manuell gelesener Wert') }}{{ last_read_cmd + ": " if last_read_cmd else '---' }} {{ last_read_value }} {{ _('Anzahl Items') }}{{ plgitems|length }}
{% endblock headtable %} - - {% block buttons %} -{% if 1==2 %} -
- -
-{% endif %} + {% endblock %} - -{% set tabcount = 2 %} - -{% set tab1title = "" ~ _('Geräte') ~ "" %} {% block bodytab1 %}
-
- - - {% if devices|length %} - - {% for dev in devices %} - - - - - - - - - - - - - - - {% if devices[dev]['params']|length %} - {% for arg in devices[dev]['params'] %} - {% if not loop.first -%} - - - - {%- endif %} - - - - - {% endfor %} - {% else %} - - - - {% endif %} - - {% endfor %} -
{{ _('Geräte-ID') }}:{{ dev }} - - -
 {{ _('Geräte-Typ') }}:{{ devices[dev]['device_type'] }} 
 {{ _('Parameter') }}:
  {{ arg }} - ({{ _('Typ') }}: {% if devices[dev]['params'][arg] is sameas true or devices[dev]['params'][arg] is sameas false %}{{ _('Bool') }}{% elif devices[dev]['params'][arg] is number %}{{ _('Zahl') }}{% else %}{{ _('String') }}{% endif %}) -
{{ _('keine') }} 
 
- {% endif %} -
-
-
-{% endblock bodytab1 %} - - - - -{% set tab2title = " Items (" ~ plgitems|length ~ ")" %} -{% block bodytab2 %} -
-
- {% if plgitems|length %} + {% if p._params|length %} - + - - - - - {% for item in plgitems %} + {% for commandcode in p._params %} - - - - - - - - - - + + + + + + {% endfor %} @@ -218,31 +207,58 @@ {% endif %} -{% endblock bodytab2 %} - - - -{% set tab3title = " Items (Baum) (" ~ plgitems|length ~ ")" %} -{% block bodytab3 %} +{% block bodytab2 %}
-
+
+ {% if cmds|length %} +
+ +
{{ _('Item') }}{{ _('Gerät') }}{{ _('Datenpunkt') }} {{ _('Befehlsname') }}{{ _('Lesen') }}{{ _('Schreiben') }}{{ _('Init') }}{{ _('Cycle') }} {{ _('Typ') }} {{ _('Wert') }} {{ _('Letzte Aktualisierung') }}
{{ item }}{% if 'md_device' in item.conf %}{{ item.conf['md_device'] }}{% endif %}{% if 'md_command' in item.conf %} - {{ item.conf['md_command'] }} - {% elif 'md_read_all' in item.conf %} - {{ _('update_all') }} - {% endif %}{% if 'md_read' in item.conf %}{{ item.conf['md_read'] }}{% endif %}{% if 'md_write' in item.conf %}{{ item.conf['md_write'] }}{% endif %}{% if 'md_read_initial' in item.conf %}{{ item.conf['md_read_initial'] }}{% endif %}{% if 'md_cycle' in item.conf %}{{ item.conf['md_cycle'] }}{% endif %}{{ item.type() }}{{ item() }}{{ item.last_update().strftime('%Y-%m-%d %H:%M:%S') }}{{ p._params[commandcode]['item'].path() }}{{ commandcode }}{{ p._params[commandcode]['commandname'] }}{{ p._params[commandcode]['item'].type() }}{{ p._params[commandcode]['item']() }}{{ p._params[commandcode]['item'].last_update() }}
+ + + + + + + + + + + + + + + + + + + + + + + {% for cmd in cmds.keys() %} + + + + + + + + + + {% endfor %} + +
{{ _('Befehlsname') }}{{ _('Datenpunkt') }}{{ _('Länge') }}{{ _('Einheit') }}{{ _('Lesen/Schreiben') }}{{ _('Datenpunkt lesen') }}{{ _('gelesener Wert') }}
{{ _('_Custom') }} + + False 
{{ cmd }}{{ cmds[cmd]['addr'] }}{{ cmds[cmd]['len'] }}{{ cmds[cmd]['unit'] }}{{ cmds[cmd]['set'] }} 
+ + {% endif %}
-{% endblock bodytab3 %} - - - -{% block bodytab4 %} -{% endblock bodytab4 %} +{% endblock bodytab2 %}