Ankündigung

Einklappen
Keine Ankündigung bisher.

Drexel&Weiss Plugin

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Onkelandy
    antwortet
    Oki, fein, bei mir läuft eigtl. auch immer alles glatt.. mal sehen, wie ich das ins develop bekomme

    Einen Kommentar schreiben:


  • brandst
    antwortet
    Also auf den ersten Blick funktioniert es ganz wunderbar. Meine Stratos wird beim starten erkannt. Änderungen in SmartVISU werden von der Stratos empfangen und umgesetzt. Auch die Änderungen am Raumcontroller werden in smartHOME empfangen und in smartVISU angezeigt. Super Sache, danke für die Aktualisierung. Ich lass es mal weiter laufen und beobachte.

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Im Prinzip mal aufs Logging.. ob du Warnungen oder Fehler bekommst. Ob eine Verbindung stattfindet und wann genau. Und ob es generell funzt
    Wäre cool, wenn du dann mal ein Logfile hier posten könntest.
    Am besten im logging.yaml unter loggers DEBUG für plugin.drexelundweiss aktivieren. Das müsste jetzt ja Dank Smart Plugin funzen, hoff ich.

    Einen Kommentar schreiben:


  • brandst
    antwortet
    Ich würde es testen - hab ja schon deine vorige Version im Einsatz. Auf was soll ich genau achten?

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Ich habe das Plugin inzwischen "smart" gemacht.. die "alte" Version läuft bei mir seit Monaten wunderbar, die ursprüngliche Variante ging leider gar nicht.. Möchte jemand das Ganze noch testen? Dann würde ich es als Pull Request in den Develop Branch schieben lassen..


    Code:
    #!/usr/bin/env python3
    # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
    #
    # Copyright 2014 KNX-User-Forum e.V. http://knx-user-forum.de/
    #
    # This file is part of SmartHome.py. http://mknx.github.io/smarthome/
    #
    # SmartHome.py 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.
    #
    # SmartHome.py 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 SmartHome.py. If not, see <http://www.gnu.org/licenses/>.
    #
    # encoding=utf8  
    
    import logging
    from lib.model.smartplugin import SmartPlugin
    import threading
    import serial
    import os.path
    import time
    import string
    import re
    
    class DuW(SmartPlugin):
        PLUGIN_VERSION = "1.2.0"
        ALLOW_MULTIINSTANCE = False
    
        def __init__(self, smarthome, tty, LU_ID=130, WP_ID=140, Busmonitor=0, device=0, retrylimit=30):
            self._sh = smarthome
            self._LU_ID = LU_ID
            self._WP_ID = WP_ID
            self._cmd = False
            self.LUregl = {}
            self.WPregl = {}
            self.LUcmdl = {}
            self.WPcmdl = {}
            self.devl = {}
            self._is_connected = False
            self._device = int(device)
            self._retrylimit = int(retrylimit)
            self._lock = threading.Lock()
            self.busmonitor = Busmonitor
            self._pollservice = False
    
            self.devl[1] = {'device': 'aerosilent primus', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_primus.txt'}
            self.devl[2] = {'device': 'aerosilent topo', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_topo.txt'}
            self.devl[3] = {'device': 'aerosilent micro', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_micro.txt'}
            self.devl[4] = {'device': 'aerosmart s', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_s.txt'}
            self.devl[5] = {'device': 'aerosmart m', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_m.txt'}
            self.devl[6] = {'device': 'aerosmart l', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_l.txt'}
            self.devl[7] = {'device': 'aerosmart xls', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_xls.txt'}
            self.devl[8] = {'device': 'aerosilent centro', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_centro.txt'}
            self.devl[9] = {'device': 'termosmart sc', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/termosmart_sc.txt'}
            self.devl[10] = {'device': 'x2', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/x2.txt'}
            self.devl[11] = {'device': 'aerosmart mono', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_mono.txt'}
            self.devl[13] = {'device': 'aerosilent bianco', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_bianco.txt'}
            self.devl[14] = {'device': 'x2 plus', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/x2_plus.txt'}
            self.devl[15] = {'device': 'aerosilent business', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_business.txt'}
            self.devl[17] = {'device': 'aerosilent stratos', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_stratos.txt'}
    
            try:
                self._port = serial.Serial(tty, 115200, timeout=5)
            except:
                self.logger.error("DuW: could not open {}.".format(tty))
                return
            else:
                self._is_connected = True
    
            self._get_device_type()
            if self._cmd:
                self._load_cmd()
    
        def _convertresponse(self,antwort,teil):
            antwort = antwort.decode()
            #self.logger.debug("DuW: Antwort: {}".format(antwort))
            allow = string.digits + ' '
            antwort = re.sub('[^%s]' % allow, '', antwort)
            liste = antwort.splitlines()
            try:
                antwort = liste[0].split()
            except:
                antwort = str("-1")
            if type(antwort) is list and len(antwort) >= 2:
                #self.logger.debug("DuW: Ergebnis ist Liste: {0}".format(antwort))
                if teil == 'id':
                    antwort = str(antwort[0])
                elif teil == 'register':
                    try:
                        antwort = str(antwort[1])
                    except:
                        antwort = '-1'
                elif teil == 'data':
                    try:
                        antwort = str(antwort[2])
                    except:
                        antwort = '-1'
            else:
                #self.logger.debug("DuW: Antwort ist Einzelwert: {0}".format(antwort))
                antwort = str(antwort)
            allow = string.digits
            antwort = re.sub('[^%s]' % allow, '', antwort)
            self.logger.debug("DuW: Response: {1} = {0}".format(antwort, teil))
            return int(antwort)
    
        def _get_device_type(self):
            self.alive = True
            if self._is_connected:
                (data, done) = self._read_register('LU\n', 5000, 1, 0)
                if done:
                    if data in self.devl:
                        self.logger.info("DuW: device: {}".format(self.devl[data]['device']))
                        if os.path.isfile(self.devl[data]['cmdpath']):
                            self._cmd = self.devl[data]['cmdpath']
                            self.logger.debug("DuW: Self Command:{}".format(self._cmd))
                        else:
                            self.logger.error("DuW: no command file found at {}".format(self.devl[data]['cmdpath']))
                            self._cmd = False
    
                    else:
                        self.logger.error("DuW: device not supported: {}".format(data))
                        self._cmd = False
                else:
                    self.logger.error("DuW: Error reading device type! Trying to activate configured device")
                    if os.path.isfile(self.devl[self._device]['cmdpath']):
                        self._cmd = self.devl[self._device]['cmdpath']
                        self.logger.info("DuW: device: {0}".format(self.devl[self._device]['device']))
            else:
                self._cmd = False
                self.logger.error("DuW: no connection")
            self.alive = False
    
        def _send_DW(self, data, pcb):
            if not self._is_connected:
                return False
    
            if (pcb == 'LU\n'):
                device_ID = self._LU_ID
            elif(pcb == 'WP\n'):
                device_ID = self._WP_ID
            else:
                self.logger.error("DuW: wrong pcb description")
                return
    
            if not self._lock.acquire(timeout=2):
                return
            try:
                #self._port.write((str(device_ID) + " " + data + "\r\n").encode())
                self._port.write("{0} {1}\r\n".format(device_ID,data).encode())
            except Exception as e:
                self.logger.exception("DuW: Problem sending {0}".format(e))
            finally:
                self._lock.release()
    
        def _get_register_info(self, register, pcb):
    
            if (pcb == 'LU\n'):
                if register in self.LUcmdl:
                    return self.LUcmdl[register]['reginfo']
                else:
                    return False
            elif(pcb == 'WP\n'):
                if register in self.WPcmdl:
                    return self.WPcmdl[register]['reginfo']
                else:
                    return False
            else:
                self.logger.error("DuW: wrong pcb description")
                return
    
        def _load_cmd(self):
            self.logger.debug("DuW: Opening command file")
            f = open(self._cmd, "r")
            self.logger.debug("DuW: Opened command file")
            try:
                for line in f:
                    if not self._lock.acquire(timeout=2):
                        return
                    try:
                        row = line.split(";")
                        # skip first row
                        if (row[1] == "<Description>"):
                            pass
                        else:
                            if row[7] == 'LU\n':
                                self.LUcmdl[int(row[0])] = {'reginfo': row}
                            elif row[7] == 'WP\n':
                                self.WPcmdl[int(row[0])] = {'reginfo': row}
                            else:
                                self.logger.debug("DuW: Error in Commandfile: " + line)
                    except Exception as e:
                        self.logger.exception("DuW: problems loading commands: {0}".format(e))
                    finally:
                        self._lock.release()
            finally:
                f.close()
    
        def run(self):
            if not self._cmd:
                self.alive = False
                try:
                    if self._is_connected:
                        self._port.close()
                except Exception as e:
                    self.logger.exception(e)
                return
    
            self.alive = True
    
            # LU registers init
            for register in self.LUregl:
                reginfo = self.LUregl[register]['reginfo']
                divisor = int(reginfo[4])
                komma = int(reginfo[5])
                for item in self.LUregl[register]['items']:
                    (data, done) = self._read_register(
                        reginfo[7], register, int(reginfo[4]), int(reginfo[5]))
                    if done:
                        item(data, 'DuW', 'init process')
                    else:
                        self.logger.debug("DuW: Init LU register failed: {}".format(register))
    
            # WP register init
            for register in self.WPregl:
                reginfo = self.WPregl[register]['reginfo']
                divisor = int(reginfo[4])
                komma = int(reginfo[5])
                for item in self.WPregl[register]['items']:
                    (data, done) = self._read_register(
                        reginfo[7], register, int(reginfo[4]), int(reginfo[5]))
                    if done:
                        item(data, 'DuW', 'init process')
                    else:
                        self.logger.debug("DuW: Init WP register failed: {0}".format(register))
    
            # poll DuW interface
            dw_id = 0
            dw_register = 0
            dw_data = 0
            response = bytes()
            self._pollservice = True
            self._port.flushInput()
            try:
                while self.alive:
                    if self._port.inWaiting():
                        if not self._lock.acquire(timeout=2):
                            return
                        try:
                            response += self._port.read()
                            if (len(response) != 0):
                                if (response[-1] == 0x20 and dw_id == 0):
                                    dw_id = self._convertresponse(response,'id')
                                    response = bytes()
    
                                elif (response[-1] == 0x20 and dw_id != 0 and dw_register == 0):
                                    dw_register = self._convertresponse(response,'register')
                                    response = bytes()
    
                                elif (response[-1] == 0x0a):
                                    dw_data = self._convertresponse(response,'data')
    
                                    if (self.busmonitor):
                                        if dw_id == self._LU_ID:
                                            if dw_register in self.LUcmdl:
                                                reginfo = self.LUcmdl[
                                                    dw_register]['reginfo']
                                                divisor = int(reginfo[4])
                                                komma = int(reginfo[5])
                                                self.logger.debug("DuW Busmonitor LU register: {0} {1}: {2}".format(dw_register,reginfo[1],((dw_data / divisor) / (10 ** komma))))
                                            else:
                                                self.logger.debug("DuW Busmonitor: unknown LU register: {0} {1}".format(dw_register,dw_data))
                                        elif dw_id == self._WP_ID:
                                            if dw_register in self.WPcmdl:
                                                reginfo = self.WPcmdl[dw_register][
                                                    'reginfo']
                                                divisor = int(reginfo[4])
                                                komma = int(reginfo[5])
                                                self.logger.debug("DuW Busmonitor WP register: {0} {1}: {2}".format(dw_register,reginfo[1],((dw_data / divisor) / (10 ** komma))))
                                            else:
                                                self.logger.debug("DuW Busmonitor: unknown WP register: {0} {1}".format(dw_register,dw_data))
                                        else:
                                            self.logger.debug(
                                                "DuW Busmonitor: unknown device ID: {}".format(dw_id))
    
                                    if dw_id == self._LU_ID:
                                        if dw_register in self.LUregl:
                                            reginfo = self.LUregl[
                                                dw_register]['reginfo']
                                            divisor = int(reginfo[4])
                                            komma = int(reginfo[5])
                                            for item in self.LUregl[dw_register]['items']:
                                                item(
                                                    ((dw_data / divisor)
                                                     / (10 ** komma)),
                                                    'DuW', 'Poll')
                                        else:
                                            self.logger.debug("DuW: Ignore LU register {}".format(dw_register))
                                    elif dw_id == self._WP_ID:
                                        if dw_register in self.WPregl:
                                            reginfo = self.WPregl[
                                                dw_register]['reginfo']
                                            divisor = int(reginfo[4])
                                            komma = int(reginfo[5])
                                            for item in self.WPregl[dw_register]['items']:
                                                item(
                                                    ((dw_data / divisor)
                                                     / (10 ** komma)),
                                                    'DuW', 'Poll')
                                        else:
                                            self.logger.debug("DuW: Ignore WP register {}" .format(dw_register))
                                    else:
                                        self.logger.debug("DuW: unknown device ID: {}".format(dw_id))
    
                                    dw_id = 0
                                    dw_register = 0
                                    dw_data = 0
                                    response = bytes()
                            else:
                                response = bytes()
                                dw_id = 0
                                dw_register = 0
                                dw_data = 0
                                self.logger.debug("DuW: Read timeout")
                        except Exception as e:
                            self.logger.exception("DuW: Polling error {0}".format(e))
                        finally:
                            self._lock.release()
                    time.sleep(0.1)
                # exit poll service
                self._pollservice = False
            except Exception as e:
                self.logger.exception("DuW: not alive error, {0}".format(e))
    
        def stop(self):
            self.alive = False
            # wait until pollservice closed
            while self._pollservice == True:
                pass
            try:
                if self._is_connected:
                    self._port.close()
            except Exception as e:
                self.logger.exception("DuW: Stop Exception, {}".format(e))
    
        def write_DW(self, pcb, register, value):
            self._send_DW("{0:d} {1:d}".format(int(register), int(value)), pcb)
    
        def req_DW(self, pcb, register):
            self._send_DW("{0:d}".format(int(register)), pcb)
    
        def _read_register(self, pcb, register, divisor, komma):
            if (pcb == 'LU\n'):
                device_ID = self._LU_ID
            elif(pcb == 'WP\n'):
                device_ID = self._WP_ID
            else:
                self.logger.error("DuW: wrong pcb description")
    
            self._port.flushInput()
            self.req_DW(pcb, str(register + 1))
            response = bytes()
            dw_id = 0
            dw_register = 0
            dw_data = 0
            retries = 0
            if not self._lock.acquire(timeout=2):
                return
            try:
                while self.alive:
                    response += self._port.read()
                    allow = string.digits
                    test = re.sub('[^%s]' % allow, '', str(response.decode()))
                    if len(test) != 0:
                        if (response[-1] == 0x20 and dw_id == 0):
                            dw_id = self._convertresponse(response,'id')
                            response = bytes()
    
                        elif response[-1] == 0x20 and dw_id != 0 and dw_register == 0:
                            dw_register = self._convertresponse(response,'register')
                            response = bytes()
    
                        elif response[-1] == 0x0a:
                            dw_data = self._convertresponse(response,'data')
                            break
                            response = bytes()
                    else:
                        retries += 1
                        self.logger.info("DuW: read timeout: {0}. Retries: {1}".format(response, retries))
                        if retries >= self._retrylimit:
                           break
                    time.sleep(0.1)
            except Exception as e:
                self.logger.warning("DuW: Read error: {0}".format(e))
            finally:
                self._lock.release()
    
            if(dw_id == device_ID and (dw_register - 1) == register):
                self.logger.debug("DuW:  Read {1} on Register: {0}".format(register,dw_data))
                try:
                    return (((dw_data / divisor) / (10 ** komma)), 1)
                except:
                    self.logger.debug("Division durch Null Problem")
                    return (((dw_data / 1) / (10 ** 1)), 1)
            else:
                self.logger.error("DuW: read errror Device ID: {0}, register {1}".format(dw_id,dw_register - 1))
                return (0, 0)
    
        def parse_item(self, item):
            if not self._cmd:
                return None
            if self.has_iattr(item.conf, 'DuW_LU_register'):
                register = int(self.get_iattr_value(item.conf, 'DuW_LU_register'))
                reginfo = self._get_register_info(register, 'LU\n')
                if reginfo:
                    if not register in self.LUregl:
                        self.LUregl[register] = {'reginfo':
                                                 reginfo, 'items': [item]}
                    else:
                        if not item in self.LUregl[register]['items']:
                            self.LUregl[register]['items'].append(item)
    
                    return self.update_item
                else:
                    self.logger.warning("DuW: LU register: {} not supported by configured device!".format(register))
                    return None
            if self.has_iattr(item.conf, 'DuW_WP_register'):
                register = int(self.get_iattr_value(item.conf, 'DuW_WP_register'))
                reginfo = self._get_register_info(register, 'WP\n')
                if reginfo:
                    if not register in self.WPregl:
                        self.WPregl[register] = {'reginfo':
                                                 reginfo, 'items': [item]}
                    else:
                        if not item in self.WPregl[register]['items']:
                            self.WPregl[register]['items'].append(item)
    
                    return self.update_item
                else:
                    self.logger.warning("DuW: WP register: {} not supported by configured device!".format(register))
                    return None
    
        def update_item(self, item, caller=None, source=None, dest=None):
            if caller != 'DuW':
                if self.has_iattr(item.conf, 'DuW_LU_register'):
                    register = int(self.get_iattr_value(item.conf, 'DuW_LU_register'))
                    if register in self.LUregl:
                        reginfo = self.LUregl[register]['reginfo']
                        data = item() * int(reginfo[4]) * (10 ** int(reginfo[5]))
                        if (data < int(reginfo[2]) or data > int(reginfo[3])):
                            self.logger.error("DuW: value of LU register: {} out of range, changes ignored!".format(register))
                            pass
                        else:
                            if reginfo[6] == 'R/W':
                                self.logger.debug("DuW: update LU register: {0} {1} with {2}".format(register,reginfo[1],data))
                                self.write_DW(reginfo[7], register, data)
                            else:
                                self.logger.warning("DuW: tried to update read only LU register: {}".format(register))
                if self.has_iattr(item.conf, 'DuW_WP_register'):
                    register = int(self.get_iattr_value(item.conf, 'DuW_WP_register'))
                    if register in self.WPregl:
                        reginfo = self.WPregl[register]['reginfo']
                        data = item() * int(reginfo[4]) * (10 ** int(reginfo[5]))
                        if (data < int(reginfo[2]) or data > int(reginfo[3])):
                            self.logger.error("DuW: value of WP register {} out of range, changes ignored!".format(register))
                            pass
                        else:
                            if reginfo[6] == 'R/W':
                                self.logger.debug("DuW: update WP register: {0} {1} with {2}".format(register,reginfo[1],data))
                                self.write_DW(reginfo[7], register, data)
                            else:
                                self.logger.warning("DuW: tried to update read only WP register: {}".format(register))

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Bernator, vielleicht magst du dir mal meine obigen Änderungen ansehen und das Plugin entsprechend updaten? Wäre cool, wenn die Erweiterungen so aufs Github Develop kämen...

    Code:
    #!/usr/bin/env python3
    # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
    #
    # Copyright 2014 KNX-User-Forum e.V. http://knx-user-forum.de/
    #
    # This file is part of SmartHome.py. http://mknx.github.io/smarthome/
    #
    # SmartHome.py 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.
    #
    # SmartHome.py 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 SmartHome.py. If not, see <http://www.gnu.org/licenses/>.
    #
    
    import logging
    import threading
    import serial
    import os.path
    import time
    import string
    import re
    
    logger = logging.getLogger('')
    
    
    class DuW():
    
        def __init__(self, smarthome, tty, LU_ID=130, WP_ID=140, Busmonitor=0, device=0, retrylimit=100):
            self._sh = smarthome
            self._LU_ID = LU_ID
            self._WP_ID = WP_ID
            self._cmd = False
            self.LUregl = {}
            self.WPregl = {}
            self.LUcmdl = {}
            self.WPcmdl = {}
            self.devl = {}
            self._is_connected = False
            self._device = int(device)
            self._retrylimit = int(retrylimit)
            self._lock = threading.Lock()
            self.busmonitor = Busmonitor
            self._pollservice = False
    
            self.devl[1] = {'device': 'aerosilent primus', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_primus.txt'}
            self.devl[2] = {'device': 'aerosilent topo', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_topo.txt'}
            self.devl[3] = {'device': 'aerosilent micro', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_micro.txt'}
            self.devl[4] = {'device': 'aerosmart s', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_s.txt'}
            self.devl[5] = {'device': 'aerosmart m', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_m.txt'}
            self.devl[6] = {'device': 'aerosmart l', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_l.txt'}
            self.devl[7] = {'device': 'aerosmart xls', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_xls.txt'}
            self.devl[8] = {'device': 'aerosilent centro', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_centro.txt'}
            self.devl[9] = {'device': 'termosmart sc', 'cmdpath':
                            smarthome.base_dir + '/plugins/drexelundweiss/termosmart_sc.txt'}
            self.devl[10] = {'device': 'x2', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/x2.txt'}
            self.devl[11] = {'device': 'aerosmart mono', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosmart_mono.txt'}
            self.devl[13] = {'device': 'aerosilent bianco', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_bianco.txt'}
            self.devl[14] = {'device': 'x2 plus', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/x2_plus.txt'}
            self.devl[15] = {'device': 'aerosilent business', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_business.txt'}
            self.devl[17] = {'device': 'aerosilent stratos', 'cmdpath':
                             smarthome.base_dir + '/plugins/drexelundweiss/aerosilent_stratos.txt'}
    
            try:
                self._port = serial.Serial(tty, 115200, timeout=5)
            except:
                logger.error("DuW: could not open {}.".format(tty))
                return
            else:
                self._is_connected = True
    
            self._get_device_type()
            if self._cmd:
                self._load_cmd()
    
        def _wait(self,time_lapse):
            time_start = time.time()
            time_end = (time_start + time_lapse)
         
            while time_end > time.time():
                pass
    
        def _convertresponse(self,antwort,teil):
            antwort = antwort.decode()
            allow = string.digits + ' '
            antwort = re.sub('[^%s]' % allow, '', antwort)
            liste = antwort.splitlines()
            try:
                antwort = liste[0].split()
            except:
                antwort = str("-1")
            if type(antwort) is list and len(antwort) >= 2:
                #logger.debug("DuW Ergebnis ist Liste: {0}".format(antwort))
                if teil == 'id':
                    antwort = str(antwort[0])
                elif teil == 'register':
                    try:
                        antwort = str(antwort[1])
                    except:
                        antwort = '-1'
                elif teil == 'data':
                    try:
                        antwort = str(antwort[2])
                    except:
                        antwort = '-1'
            else:
                #logger.debug("DuW Antwort ist Einzelwert: {0}".format(antwort))
                antwort = str(antwort)
            allow = string.digits
            antwort = re.sub('[^%s]' % allow, '', antwort)
            logger.debug("DuW Antwort: {1} = {0}".format(antwort, teil))
            return int(antwort)
    
        def _get_device_type(self):
                self.alive = True
                if self._is_connected:
                    (data, done) = self._read_register('LU\n', 5000, 1, 0)
                    if done:
                        if data in self.devl:
                            logger.info("DuW: device: " +
                                         self.devl[data]['device'])
                            if os.path.isfile(self.devl[data]['cmdpath']):
                                self._cmd = self.devl[data]['cmdpath']
                            else:
                                logger.error(
                                    "DuW: no command file found at: " + self.devl[data]['cmdpath'])
                                self._cmd = False
    
                        else:
                            logger.error("DuW: device not supported: " + str(data))
                            self._cmd = False
                    else:
                        logger.error("DuW: Error reading device type! Trying to activate configured device")
                        if os.path.isfile(self.devl[self._device]['cmdpath']):
                                self._cmd = self.devl[self._device]['cmdpath']
                                logger.info("DuW: device: {0}".format(self.devl[self._device]['device']))
                        #self._cmd = False
                else:
                    self._cmd = False
                    logger.error("DuW: Keine Vrbindung")
                self.alive = False
    
        def _send_DW(self, data, pcb):
            if not self._is_connected:
                return False
    
            if (pcb == 'LU\n'):
                device_ID = self._LU_ID
            elif(pcb == 'WP\n'):
                device_ID = self._WP_ID
            else:
                logger.error("wrong pcb description")
                return
    
            if not self._lock.acquire(timeout=2):
                return
            try:
                self._port.write((str(device_ID) + " " + data + "\r\n").encode())
            except Exception as e:
                logger.exception("Drexel sendDW: {0}".format(e))
            finally:
                self._lock.release()
    
        def _get_register_info(self, register, pcb):
    
            if (pcb == 'LU\n'):
                if register in self.LUcmdl:
                    return self.LUcmdl[register]['reginfo']
                else:
                    return False
            elif(pcb == 'WP\n'):
                if register in self.WPcmdl:
                    return self.WPcmdl[register]['reginfo']
                else:
                    return False
            else:
                logger.error("wrong pcb description")
                return
    
        def _load_cmd(self):
            f = open(self._cmd, "r")
            try:
                for line in f:
                    if not self._lock.acquire(timeout=2):
                        return
                    try:
                        row = line.split(";")
                        # skip first row
                        if (row[1] == "<Description>"):
                            pass
                        else:
                            if row[7] == 'LU\n':
                                self.LUcmdl[int(row[0])] = {'reginfo': row}
                            elif row[7] == 'WP\n':
                                self.WPcmdl[int(row[0])] = {'reginfo': row}
                            else:
                                logger.debug("DuW: Error in Commandfile: " + line)
                    except Exception as e:
                        logger.exception("Drexel loadCMD: {0}".format(e))
                    finally:
                        self._lock.release()
            finally:
                f.close()
    
        def run(self):
    
            if not self._cmd:
                self.alive = False
                try:
                    if self._is_connected:
                        self._port.close()
                except Exception as e:
                    logger.exception(e)
                return
    
            self.alive = True
    
            # LU registers init
            for register in self.LUregl:
                reginfo = self.LUregl[register]['reginfo']
                divisor = int(reginfo[4])
                komma = int(reginfo[5])
                for item in self.LUregl[register]['items']:
                    (data, done) = self._read_register(
                        reginfo[7], register, int(reginfo[4]), int(reginfo[5]))
                    if done:
                        item(data, 'DuW', 'init process')
                    else:
                        logger.debug("Drexel: Init LU register: " +
                                     str(register) + " failed!")
    
            # WP register init
            for register in self.WPregl:
                reginfo = self.WPregl[register]['reginfo']
                divisor = int(reginfo[4])
                komma = int(reginfo[5])
                for item in self.WPregl[register]['items']:
                    (data, done) = self._read_register(
                        reginfo[7], register, int(reginfo[4]), int(reginfo[5]))
                    if done:
                        item(data, 'DuW', 'init process')
                    else:
                        logger.debug("Drexel: Init WP register: " +
                                     str(register) + " failed!")
    
            # poll DuW interface
            dw_id = 0
            dw_register = 0
            dw_data = 0
            response = bytes()
            self._pollservice = True
            self._port.flushInput()
            try:
                while self.alive:
                    if self._port.inWaiting():
                        if not self._lock.acquire(timeout=2):
                            return
                        try:
                            response += self._port.read()
                            if (len(response) != 0):
                                if (response[-1] == 0x20 and dw_id == 0):
                                    dw_id = self._convertresponse(response,'id')
                                    #logger.debug("Drexel dw_id: "+(str(dw_id)))
                                    response = bytes()
    
                                elif (response[-1] == 0x20 and dw_id != 0 and dw_register == 0):
                                    dw_register = self._convertresponse(response,'register')
                                    #logger.debug("Drexel dw_register: "+(str(dw_register)))
                                    response = bytes()
    
                                elif (response[-1] == 0x0a):
                                    dw_data = self._convertresponse(response,'data')
                                    #logger.debug("Drexel dw_data: "+(str(dw_data)))
    
                                    if (self.busmonitor):
                                        if dw_id == self._LU_ID:
                                            if dw_register in self.LUcmdl:
                                                reginfo = self.LUcmdl[
                                                    dw_register]['reginfo']
                                                divisor = int(reginfo[4])
                                                komma = int(reginfo[5])
                                                logger.debug("DuW Busmonitor LU register: " + str(dw_register)
                                                             + " " + str(reginfo[1]) + ": " + str(((dw_data / divisor) / (10 ** komma))))
                                            else:
                                                logger.debug(
                                                    "DuW Busmonitor: unknown LU register: " + str(dw_register) + " " + str(dw_data))
                                        elif dw_id == self._WP_ID:
                                            if dw_register in self.WPcmdl:
                                                reginfo = self.WPcmdl[dw_register][
                                                    'reginfo']
                                                divisor = int(reginfo[4])
                                                komma = int(reginfo[5])
                                                logger.debug("DuW Busmonitor WP register: " + str(dw_register)
                                                             + " " + str(reginfo[1]) + ": " + str(((dw_data / divisor) / (10 ** komma))))
                                            else:
                                                logger.debug(
                                                    "DuW Busmonitor: unknown WP register: " + str(dw_register) + " " + str(dw_data))
                                        else:
                                            logger.debug(
                                                "DuW Busmonitor: unknown device ID: " + str(dw_id))
    
                                    if dw_id == self._LU_ID:
                                        if dw_register in self.LUregl:
                                            reginfo = self.LUregl[
                                                dw_register]['reginfo']
                                            divisor = int(reginfo[4])
                                            komma = int(reginfo[5])
                                            for item in self.LUregl[dw_register]['items']:
                                                item(
                                                    ((dw_data / divisor)
                                                     / (10 ** komma)),
                                                    'DuW', 'Poll')
                                        else:
                                            logger.debug(
                                                "Ignore LU register " + str(dw_register))
                                    elif dw_id == self._WP_ID:
                                        if dw_register in self.WPregl:
                                            reginfo = self.WPregl[
                                                dw_register]['reginfo']
                                            divisor = int(reginfo[4])
                                            komma = int(reginfo[5])
                                            for item in self.WPregl[dw_register]['items']:
                                                item(
                                                    ((dw_data / divisor)
                                                     / (10 ** komma)),
                                                    'DuW', 'Poll')
                                        else:
                                            logger.debug(
                                                "Ignore WP register " + str(dw_register))
                                    else:
                                        logger.debug(
                                            "DuW Busmonitor: unknown device ID: " + str(dw_id))
    
                                    dw_id = 0
                                    dw_register = 0
                                    dw_data = 0
                                    response = bytes()
                            else:
                                response = bytes()
                                dw_id = 0
                                dw_register = 0
                                dw_data = 0
                                logger.debug("DuW read timeout: ")
                        except Exception as e:
                            logger.exception("Drexel Polling: {0}".format(e))
                        finally:
                            self._lock.release()
                    self._wait(0.1)
                # exit poll service
                self._pollservice = False
            except Exception as e:
                logger.exception("Drexel nicht alive: {0}".format(e))
    
        def stop(self):
            self.alive = False
            # wait until pollservice closed
            while self._pollservice == True:
                pass
    
            try:
                if self._is_connected:
                    self._port.close()
            except Exception as e:
                logger.exception(e)
    
        def write_DW(self, pcb, register, value):
            self._send_DW("{0:d} {1:d}".format(int(register), int(value)), pcb)
    
        def req_DW(self, pcb, register):
            self._send_DW("{0:d}".format(int(register)), pcb)
    
        def _read_register(self, pcb, register, divisor, komma):
            if (pcb == 'LU\n'):
                device_ID = self._LU_ID
            elif(pcb == 'WP\n'):
                device_ID = self._WP_ID
            else:
                logger.error("wrong pcb description")
    
            self._port.flushInput()
            self.req_DW(pcb, str(register + 1))
            response = bytes()
            dw_id = 0
            dw_register = 0
            dw_data = 0
            retries = 0
            if not self._lock.acquire(timeout=2):
                return
            try:
                while self.alive:
                    response += self._port.read()
                    allow = string.digits
                    test = re.sub('[^%s]' % allow, '', str(response.decode()))
                    if len(test) != 0:
                        if (response[-1] == 0x20 and dw_id == 0):
                            dw_id = self._convertresponse(response,'id')
                            #logger.debug("Drexel Reading dw_id: "+str(dw_id))
                            response = bytes()
    
                        elif response[-1] == 0x20 and dw_id != 0 and dw_register == 0:
                            dw_register = self._convertresponse(response,'register')
                            #logger.debug("Drexel Reading dw_register: "+str(dw_register))
                            response = bytes()
    
                        elif response[-1] == 0x0a:
                            dw_data = self._convertresponse(response,'data')
                            #logger.debug("Drexel Reading dw_data: "+str(dw_data))
                            break
                            response = bytes()
                    else:
                        retries += 1
                        self._wait(0.2)
                        logger.info("Drexel read timeout: {0}. Retries: {1}".format(response, retries))
                        if retries >= self._retrylimit:
                           break
                    self._wait(0.1)
            except Exception as e:
                logger.warning("Drexel Reading: {0}".format(e))
            finally:
                self._lock.release()
    
            if(dw_id == device_ID and (dw_register - 1) == register):
                logger.debug("Drexel: Read {1} on Register: {0}".format(register,dw_data))
                try:
                    return (((dw_data / divisor) / (10 ** komma)), 1)
                except:
                    logger.debug("Division durch Null Problem")
                    return (((dw_data / 1) / (10 ** 1)), 1)
            else:
                logger.error("DuW read errror Device ID: " + str(dw_id)
                             + " register: " + str(dw_register - 1))
                return (0, 0)
    
        def parse_item(self, item):
            if not self._cmd:
                return None
            if 'DuW_LU_register' in item.conf:
                register = int(item.conf['DuW_LU_register'])
                reginfo = self._get_register_info(register, 'LU\n')
                if reginfo:
                    if not register in self.LUregl:
                        self.LUregl[register] = {'reginfo':
                                                 reginfo, 'items': [item]}
                    else:
                        if not item in self.LUregl[register]['items']:
                            self.LUregl[register]['items'].append(item)
    
                    return self.update_item
                else:
                    logger.warning("Drexel: LU register: " + str(register)
                                   + " not supported by configured device!")
                    return None
            if 'DuW_WP_register' in item.conf:
                register = int(item.conf['DuW_WP_register'])
                reginfo = self._get_register_info(register, 'WP\n')
                if reginfo:
                    if not register in self.WPregl:
                        self.WPregl[register] = {'reginfo':
                                                 reginfo, 'items': [item]}
                    else:
                        if not item in self.WPregl[register]['items']:
                            self.WPregl[register]['items'].append(item)
    
                    return self.update_item
                else:
                    logger.warning("Drexel: WP register: " + str(register)
                                   + " not supported by configured device!")
                    return None
    
        def update_item(self, item, caller=None, source=None, dest=None):
            if caller != 'DuW':
                if 'DuW_LU_register' in item.conf:
                    register = int(item.conf['DuW_LU_register'])
                    if register in self.LUregl:
                        reginfo = self.LUregl[register]['reginfo']
                        data = item() * int(reginfo[4]) * (10 ** int(reginfo[5]))
                        if (data < int(reginfo[2]) or data > int(reginfo[3])):
                            logger.error("DuW: value of LU register: " +
                                         str(register) + " out of range, changes ignored!")
                            pass
                        else:
                            if reginfo[6] == 'R/W':
                                logger.debug("DuW: update LU register: " +
                                             str(register) + " " + reginfo[1] + " with: " + str(data))
                                self.write_DW(reginfo[7], register, data)
                            else:
                                logger.warning(
                                    "DuW: tried to update read only LU register: " + str(register))
                if 'DuW_WP_register' in item.conf:
                    register = int(item.conf['DuW_WP_register'])
                    if register in self.WPregl:
                        reginfo = self.WPregl[register]['reginfo']
                        data = item() * int(reginfo[4]) * (10 ** int(reginfo[5]))
                        if (data < int(reginfo[2]) or data > int(reginfo[3])):
                            logger.error("DuW: value of WP register: " +
                                         str(register) + " out of range, changes ignored!")
                            pass
                        else:
                            if reginfo[6] == 'R/W':
                                logger.debug("DuW: update LU register: " +
                                             str(register) + " " + reginfo[1] + " with: " + str(data))
                                self.write_DW(reginfo[7], register, data)
                            else:
                                logger.warning(
                                    "DuW: tried to update read only WP register: " + str(register))
    Dabei gibt es zwei neue Attribute in der plugin.conf:
    Code:
       device = 14
       retrylimit = 100
    Device ist die entsprechende Nummer. Diese wird als Fallback herangezogen, wenn beim Start die Device ID nicht ausgelesen werden kann. Kam bei mir öfters vor, nicht nachvollziehbar.
    Retrylimit definiert die Anzahl an neuen Leseversuchen. Hier habe ich mi 100 eine hohe Zahl, meist erhalte ich sofort oder nach ca. 20 Leseversuchen einen korrekten Wert..

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    brandst - bekommst du im Plugin sofort die Updates von Änderungen, die du über das Panel tätigst?

    Meine CPU Last auf dem Raspi 1 liegt übrigens fast kontinuierlich bei 90%..
    Zuletzt geändert von Onkelandy; 07.07.2016, 23:18.

    Einen Kommentar schreiben:


  • brandst
    antwortet
    Hab die Änderungen von Onkelandy ebenfalls verwenden müssen - komischerweise hat es mit der alten Smarthome Version ohne Probleme funktioniert. Kann es sein, dass SmarthomeNG eine andere Python Version voraussetzt bzw. benutzt? Ich hab von 2.7 bis 3.4 alles auf meinem System :-)

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Soda, hab mich jetzt mit meinen rudimentären Python Kenntnissen doch noch dran gewagt.
    Problem ist, dass ab und zu blödsinnige Antworten kommen oder vermutlich eine Verzögerung in der Übertragung dafür sorgt, dass die Responses nicht sauber getrennt werden. Vermutlich könnte man hier im Abfrage-Code direkt noch was optimieren. Ich habe meine Probleme aber nun wie folgt gelöst:

    * Unknown Register 1348: Habe hier einfach ins txt File das Register eingefügt und ein Item angelegt. Was es bedeutet, weiß ich nicht...
    * Division by zero: Im txt File habe ich beim HEIZUNG+ den Divisor auf 1 statt 0 gesetzt. Zusätzlich im Plugin-Code das Problem mittels try und except abgefangen.
    * Kein Erkennen des Geräts... Problem resultiert wohl wie oben beschrieben darin, dass manchmal die Daten nicht gleich beim ersten Mal richtig kommen.. beim 2. oder 3. Mal aber dann schon. Manchmal gab es eine Reihe an "\x00" vor dem eigentlichen Wert, ab und an offenbar auch mehrere Zeilen am Stück, als "\x00130 5000 14\r\n\x00\x00130 5000 14 etc.". Das fange ich jetzt durch folgende, vermutlich etwas komplizierte Funktion ab:
    Code:
        def _convertresponse(self,antwort,teil):
            antwort = antwort.decode()
            allow = string.digits + ' '
            antwort = re.sub('[^%s]' % allow, '', antwort)
            liste = antwort.splitlines()
            try:
                antwort = liste[0].split()
            except:
                antwort = str(antwort)
            if type(antwort) is list and len(antwort) >= 2:
                if teil == 'id':
                    antwort = str(antwort[0])
                elif teil == 'register':
                    try:
                        antwort = str(antwort[1])
                    except:
                        antwort = '-1'
                elif teil == 'data':
                    try:
                        antwort = str(antwort[2])
                    except:
                        antwort = '-1'
            else:
                antwort = str(antwort)
            allow = string.digits
            antwort = re.sub('[^%s]' % allow, '', antwort)
            #logger.debug("DuW Antwort: {0} fuer Teil {1}".format(antwort, teil))
            return int(antwort)
    Damit die Funktion aufgerufen wird, hab ich im normalen Code das
    dw_data = int(response)
    durch dw_data = self._convertresponse(response,'data')
    ersetzt.

    *Keine bzw. leere Antwort: Hier habe ich Zeile 415 adaptiert. Wenn eine leere Antwort zurück kommt, soll nochmals nachgehakt werden. Nach 100 Versuchen wird abgebrochen..
    Code:
                    else:
                        retries += 1
                        logger.debug("Drexel read timeout: {0}. Retries: {1}".format(response, retries))
                        if retries >= 100:
                           break
    Soweit so gut. Es lässt sich dadurch immer eine stabile Verbindung aufbauen. Ansteuern von Werten über die CLI oder Visu ist kein Problem, auch das Auslesen der Daten beim Start des Plugins nicht.
    z.B.: Item LU.CO2_Stufe2 = 800.0 via DuW init process None

    Allerdings werden die Items nach einer Änderung am Panel nicht wirklich aktualisiert...
    Offenbar wird eine Änderung am Panel zwar registriert.. aber nicht von ID 130 bzw. 140:
    2016-06-12 13:41:02,774 DEBUG DuW DuW Antwort: 120 fuer Teil id -- __init__.py:_convertresponse:118
    2016-06-12 13:41:03,300 DEBUG DuW DuW Antwort: 5016 fuer Teil register -- __init__.py:_convertresponse:118
    2016-06-12 13:41:04,019 DEBUG DuW DuW Antwort: 22000 fuer Teil data -- __init__.py:_convertresponse:118
    2016-06-12 13:41:04,026 DEBUG DuW DuW Busmonitor: unknown device ID: 120 -- __init__.py:run:335

    Sollte hier nicht gleich ein Update vom Gerät selbst gesendet werden?

    Merci!

    Ach ja.. sonderbarerweise kommen direkt nach einem Reboot nur "\x00" daher, wenn der Gerätetyp abgefragt wird. Und das, obwohl das smarthome-Service erst startet, wenn die USB-Verbindung vorhanden ist. Sehr komisch...
    Zuletzt geändert von Onkelandy; 13.06.2016, 21:49.

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Habe hier eine aktuelle Liste mit Parametern gefunden:
    http://filter.drexel-weiss.at/HP/Upl...r_V4.01_DE.pdf

    Hab gerade die gleiche Liste per Mail zugesandt bekommen, ist also aktuell.
    Zuletzt geändert von Onkelandy; 13.06.2016, 10:40.

    Einen Kommentar schreiben:


  • Bernator
    antwortet

    DuW read errror Device ID: 130 register: 5000

    Beim Start wird versucht das register 5000 auszulesen, hier steht die Information um welches Gerät es sich handelt.... Scheinbar git es da ein Kommunikationsproblem, passiert das auch wenn das D&W Gerät bereits länger läuft? Bei mir hab ich beobachtet das nach einem Reset von D&W Gerät + Smarthome.py (Stromausfall) das D&W Gerät scheinbar langsamer Startet und daher Smarthome.py zu früh die ID abruft....

    Modbus-Doku hab ich leider auch nichts aktuelleres....

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Hi!
    Ich nutze SmarthomeNG 1.1 mit Python 3.4.2 und erhalte manchmal folgende Fehlermeldung:

    Code:
    Drexel: invalid literal for int() with base 10: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00130 '
    Bei manchem Start geht's durch und ich erhalte folgende Rückmeldung...:
    Code:
    2016-06-03 15:13:26,035 DEBUG    Main         Drexel dw_id: 130 -- __init__.py:_read_register:371
    2016-06-03 15:13:26,546 DEBUG    Main         Drexel dw_register: 5001 -- __init__.py:_read_register:376
    2016-06-03 15:13:26,957 DEBUG    Main         Drexel dw_data: 14 -- __init__.py:_read_register:381
    2016-06-03 15:13:26,962 ERROR    Main         DuW read errror Device ID: 130 register: 5000 -- __init__.py:_read_register:398
    2016-06-03 15:13:26,970 ERROR    Main         DuW: Error reading device type! -- __init__.py:_get_device_type:114
    Generell scheint es aber gut zu funktionieren und ich kann auch alles steuern wie ich möchte - 1000 Dank schon mal dafür.

    Irgendeine Idee, wie ich die seltenen Problemfälle lösen kann? Cool wäre auch, wenn wer einen Link zur aktuellsten Modbus-Doku hätte, wo ich die aktuellen Register finde. Denn offenbar ist mit den neueren Firmwares noch ein bisschen was dazu gekommen an Funktionen.. insbesondere WP register 1348
    Vielen Dank!!!

    Einen Kommentar schreiben:


  • Bernator
    antwortet
    Ich verwende ein Kabel mit gewinkeltem USB Stecker dann gehts sichs aus.....

    Einen Kommentar schreiben:


  • Onkelandy
    antwortet
    Bin zwar nicht Bernhard.. aber kannst du das Gehäuse nicht aufschrauben von vorne? Dann solltest du Zugang zum USB Anschluss auf dem Board haben. Das Kabel kannst du dann nach hinten zusammen mit Strom und Co raus führen.

    Einen Kommentar schreiben:


  • unifire
    antwortet
    Hallo Bernhard,

    Erst einmal besten Dank für deine Arbeit. Seit kurzem ist meine aerosilent stratos installiert. Technisch bedingt kann ich jedoch den USB Stecker bei geschlossenem Gehäuse nicht nutzen. Die Abdeckung verhindert das. Wie hat du das Problem mit dem USB Stecker gelöst?

    Besten Dank

    Raphael

    Einen Kommentar schreiben:

Lädt...
X