Ankündigung

Einklappen
Keine Ankündigung bisher.

Smartmeter Plugin - Tester gesucht

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

  • JuMi2006
    antwortet
    Hallo Robert, hier will es nicht. Ich habe mir jeweils mal ein "print(response)" eingebaut. Du siehst es kommt nix, auch ein paar feste sleeps habe ich kurz getestet, für mehr reicht die Zeit heute nicht ich muss noch zur Spätschicht.

    Zwei Sachen:
    - Der Knackpunkt liegt (in meiner Version) in der Schleife die STX prüft. Der kritische Zeitraum liegt zwischen dem Empfang der ID und dem senden des ACKs. Hatte ja schon erwähnt dass ein Zähler ohne ACK z.B. gar nichts macht - da bringt auch eine feste Baudrate nichts ... das muss 100% passen.

    - Die Initialisierung des Ports in der self._update_values brachte folgenden Vorteil an den ich mich jetzt gerade erinnere- mea culpa. War der Port bei __init__ intitalisiert erhielten wir ja nur beim ersten Durchlauf die ID. Bei den folgenden wurde vor der ID noch ein /x07 (BEL) mit ausgegeben, damit fiel dann sowohl bei der Echo-Unterdückung als auch bei der Baudrate alles auf die Nase. Komischerweise taucht das hier jetzt nicht auf, aber wer kann das erklären? Grundsätzlich machen wir doch das gleiche.

    Code:
    2013-11-26 17:25:05,253 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-26 17:25:05,755 DEBUG    Scheduler    DLMS next time: 2013-11-26 17:25:20+01:00 -- scheduler.py:_next_time:289
    b'/'
    b'/L'
    b'/LG'
    b'/LGZ'
    b'/LGZ4'
    b'/LGZ4Z'
    b'/LGZ4ZM'
    b'/LGZ4ZMF'
    b'/LGZ4ZMF1'
    b'/LGZ4ZMF10'
    b'/LGZ4ZMF100'
    b'/LGZ4ZMF100A'
    b'/LGZ4ZMF100AC'
    b'/LGZ4ZMF100AC.'
    b'/LGZ4ZMF100AC.M'
    b'/LGZ4ZMF100AC.M2'
    b'/LGZ4ZMF100AC.M23'
    b'/LGZ4ZMF100AC.M23\r'
    2013-11-26 17:25:06,353 DEBUG    DLMS         dlms: meter returned capability for higher baudrate - will request 4800 baud -- __init__.py:_update_values:81
    2013-11-26 17:25:06,355 DEBUG    DLMS         dlms: trying to switch to 4800 baud -- __init__.py:_update_values:95
    b''
    2013-11-26 17:25:08,358 DEBUG    DLMS         dlms: reading took: 3.10s -- __init__.py:_update_values:110
    2013-11-26 17:25:20,289 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    b'/'
    b'/L'
    b'/LG'
    2013-11-26 17:25:20,790 DEBUG    Scheduler    DLMS next time: 2013-11-26 17:25:35+01:00 -- scheduler.py:_next_time:289
    b'/LGZ'
    b'/LGZ4'
    b'/LGZ4Z'
    b'/LGZ4ZM'
    b'/LGZ4ZMF'
    b'/LGZ4ZMF1'
    b'/LGZ4ZMF10'
    b'/LGZ4ZMF100'
    b'/LGZ4ZMF100A'
    b'/LGZ4ZMF100AC'
    b'/LGZ4ZMF100AC.'
    b'/LGZ4ZMF100AC.M'
    b'/LGZ4ZMF100AC.M2'
    b'/LGZ4ZMF100AC.M23'
    b'/LGZ4ZMF100AC.M23\r'
    2013-11-26 17:25:21,309 DEBUG    DLMS         dlms: meter returned capability for higher baudrate - will request 4800 baud -- __init__.py:_update_values:81
    2013-11-26 17:25:21,311 DEBUG    DLMS         dlms: trying to switch to 4800 baud -- __init__.py:_update_values:95
    b''
    2013-11-26 17:25:23,316 DEBUG    DLMS         dlms: reading took: 3.03s -- __init__.py:_update_values:110
    ^C2013-11-26 17:25:25,774 INFO     Main         Number of Threads: 7 -- smarthome.py:stop:348
    2013-11-26 17:25:25,775 INFO     Main         Stop Plugins -- plugin.py:stop:70
    2013-11-26 17:25:26,318 INFO     Main         SmartHome.py stopped -- smarthome.py:stop:372

    Ein anderes Phänomen, vielleicht nicht ganz offtopic und hilft die Sache zu verstehen. Ich hatte das Roomba-Plugin ja auch erst auf serieller Basis und dann auf Sockets umgestellt in der Hoffnung dass ein close dort besser wirkt. Der Roomba hängt an einem Bluetooth Modul und ich wollte da nur Saft rausziehen wenn tatsächlich kommuniziert wird. Wenn ich ein python script in der shell ausführe um die Werte auszulesen sehe ich wie das blinkende Modul auf dauerleuchtend geht und beim beenden des scriptes wieder blinkt. Beim Plugin jedoch bleibt die LED am Modul auf Dauerbetrieb, auch wenn ich close() und del mache (keine exceptions). Beende ich die sh.py Instanz fängt das Modul wieder zu blinken an, also sitzt da noch irgendwas drauf. Kann ein ähnliches Phänomen hier vorliegen?

    Einen Kommentar schreiben:


  • fanta2k
    antwortet
    hi,

    sauber!

    mit dem script aus #78 läufts nun super.

    vorher funktionierte nur ca jeder 4te lesevorgang, jetzt ca jeder 2te.

    2013-11-26 17:26:54,316 DEBUG DLMS dlms: Reading took: 4.20s -- __init__.py:_update_values:122

    2013-11-26 17:28:02,816 DEBUG DLMS dlms: Reading took: 12.35s -- __init__.py:_update_values:122
    2013-11-26 17:28:02,828 DEBUG DLMS dlms: 0.0.0 = 00318956 -- __init__.py:_update_values:144
    2013-11-26 17:28:02,834 DEBUG DLMS dlms: 0.1.0 = 00 -- __init__.py:_update_values:144
    2013-11-26 17:28:02,840 DEBUG DLMS dlms: 0.2.0 = 60900000 -- __init__.py:_update_values:144
    2013-11-26 17:28:02,845 DEBUG DLMS dlms: 0.2.2 = 06002200 -- __init__.py:_update_values:144
    2013-11-26 17:28:02,851 DEBUG DLMS dlms: 0.9.1 = 0172737 -- __init__.py:_update_values:144
    2013-11-26 17:28:02,857 DEBUG DLMS dlms: 0.9.2 = 0131126 -- __init__.py:_update_values:144

    2013-11-26 17:28:54,523 DEBUG DLMS dlms: Reading took: 4.20s -- __init__.py:_update_values:122

    2013-11-26 17:30:02,529 DEBUG DLMS dlms: Reading took: 12.35s -- __init__.py:_update_values:122
    2013-11-26 17:30:02,536 DEBUG DLMS dlms: 0.0.0 = 00318956 -- __init__.py:_update_values:144
    2013-11-26 17:30:02,542 DEBUG DLMS dlms: 0.1.0 = 00 -- __init__.py:_update_values:144
    2013-11-26 17:30:02,547 DEBUG DLMS dlms: 0.2.0 = 60900000 -- __init__.py:_update_values:144
    2013-11-26 17:30:02,553 DEBUG DLMS dlms: 0.2.2 = 06002200 -- __init__.py:_update_values:144
    2013-11-26 17:30:02,559 DEBUG DLMS dlms: 0.9.1 = 0172937 -- __init__.py:_update_values:144
    2013-11-26 17:30:02,565 DEBUG DLMS dlms: 0.9.2 = 0131126 -- __init__.py:_update_values:144
    2013-11-26 17:30:02,571 DEBUG DLMS dlms: 1.8.0 = 001849.0 kWh -- __init__.py:_update_values:147

    2013-11-26 17:30:54,261 DEBUG DLMS dlms: Reading took: 4.20s -- __init__.py:_update_values:122

    angepasst hab ich diesmal nichts (auch kein \n vorm string)

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Hi Mirko,

    sorry, war gerade nur etwas überrascht als ich geupdated habe und beim Probestart das Plugin nicht mehr ging. Bei mir ist "develop" produktiv, da ich sonst immer schalten müsste.

    Ich habe deine Version ja eh auf dem Rechner gehabt und mal versucht das ganze wieder bei mir gangbar zu machen. Vielleicht hast du ja doch noch die Muße das zu probieren. Würde mich freuen:

    PHP-Code:
    #!/usr/bin/env python3
    # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
    #########################################################################
    #  Copyright 2013 KNX-User-Forum e.V.           https://knx-user-forum.de/
    #########################################################################
    #  DLMS plugin for SmartHome.py.         http://mknx.github.io/smarthome/
    #
    #  This plugin is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This plugin is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this plugin. If not, see <http://www.gnu.org/licenses/>.
    #########################################################################

    import logging
    import time
    import serial
    import re

    logger 
    logging.getLogger('DLMS')

    class 
    DLMS():

        
    def __init__(selfsmarthomeserialportbaudrate="auto"update_cycle="60"use_checksum Truereset_baudrate True):
            
    self._sh smarthome
            self
    ._update_cycle int(update_cycle)
            
    self._use_checksum use_checksum
            self
    ._reset_baudrate reset_baudrate
            self
    ._serialport serialport
            
    if (baudrate.lower() == 'auto'):
                
    self._baudrate = -1
            
    else:
                
    self._baudrate int(baudrate)
            
    self._obis_codes = {}
            
    self._request bytearray('\x06000\r\n''ascii')
            
    self._init_seq bytes('/?!\r\n''ascii')
            
    self._serial serial.Serial(self._serialport300bytesize=serial.SEVENBITSparity=serial.PARITY_EVENtimeout=2)

        
    def run(self):
            
    self.alive True
            self
    ._sh.scheduler.add('DLMS'self._update_valuesprio=5cycle=self._update_cycle)

        
    def stop(self):
            
    self.alive False
            self
    ._serial.close()
            
    self._sh.scheduler.remove('DLMS')

        
    def _update_values(self):
            
    logger.debug("dlms: update")
            
    start time.time()
            try:
                if 
    self._reset_baudrate:
                    
    self._serial.baudrate 300
                
    #self._serial = serial.Serial(self._serialport, 300, bytesize=serial.SEVENBITS, parity=serial.PARITY_EVEN, timeout=2)
                
    self._serial.write(self._init_seq)
                
    self._serial.drainOutput()
                
    self._serial.flushInput()
                
    response bytes()
                
    prev_length 0
                
    while self.alive:
                    
    response += self._serial.read()
                    
    length len(response)
                    
    # break if timeout or newline-character
                    
    if (length == prev_length) or (response[-1] == 0x0a):
                        break
                    
    prev_length length
            except Exception 
    as e:
                
    logger.warning("dlms: {0}".format(e))
            
    #logger.warning("dlms: response={}".format(response))
            
    if (len(response) < 5) or ((response[4] - 0x30not in range(6)):
                
    logger.warning("dlms: malformed response to init seq={}".format(response))
                return

            if (
    self._baudrate == -1):
                
    baud_capable 300 * (<< (response[4] - 0x30))
                
    self._request[2] = response[4]
                
    logger.debug("dlms: meter returned capability for {} baud".format(baud_capable))
            else:
                
    baud_capable self._baudrate
                pow2 
    int(baud_capable 300)
                
    self._request[2] = 0x30 1
                
    while (pow2 0):
                    
    pow2 >>= 1
                    self
    ._request[2] += 1
            
    try:
                
    self._serial.write(self._request)
                
    self._serial.drainOutput()
                
    self._serial.flushInput()
                if (
    baud_capable self._serial.baudrate):
                    
    # change request to set higher baudrate
                    
    logger.debug("dlms: trying to switch to {} baud".format(baud_capable))
                    
    self._serial.baudrate baud_capable
                response 
    bytes()
                
    prev_length 0
                
    while self.alive:
                    
    response += self._serial.read()
                    
    length len(response)
                    if (
    length == prev_length) or (not self._use_checksum and (response[-1] == 0x03)) or ((length 1) and (response[-2] == 0x03)):
                        break
                    
    prev_length length
            except Exception 
    as e:
                
    logger.warning("dlms: {0}".format(e))
                return

            
    logger.debug("dlms: reading took: {:.2f}s".format(time.time() - start))
            if 
    self._use_checksum:
                
    # perform checks (start with STX, end with ETX, checksum match)
                
    checksum 0
                
    for i in response[1:]:
                    
    checksum ^= i
                
    if (len(response) < 5) or (response[0] != 0x02) or (response[-2] != 0x03) or (checksum != 0x00):
                    
    logger.warning("dlms: checksum/protocol error: response={} checksum={}".format(' '.join(hex(i) for i in response), checksum))
                    return
            
    #print(str(response[1:-4], 'ascii'))
            
    for line in re.split('\r\n'str(response[1:-4], 'ascii')):
                
    # if re.match('[0-9]+\.[0-9]\.[0-9](.+)', line): # allows only
                # x.y.z(foo)
                
    if re.match('[0-9]+\.[0-9].+(.+)'line):  # allows also x.y(foo)
                    
    try:
                        
    #data = re.split('[(*)]', line)
                        
    data line.split('(')
                        
    data[1:3] = data[1].strip(')').split('*')
                        if (
    len(data) == 2):
                            
    logger.debug("dlms: {} = {}".format(data[0], data[1]))
                        else:
                            
    logger.debug("dlms: {} = {} {}".format(data[0], data[1], data[2]))
                        if 
    data[0in self._obis_codes:
                            for 
    item in self._obis_codes[data[0]]['items']:
                                
    item(data[1], 'DLMS''OBIS {}'.format(data[0]))
                    
    except Exception as e:
                        
    logger.warning("dlms: line={} exception={}".format(linee))

        
    def parse_item(selfitem):
            if 
    'dlms_obis_code' in item.conf:
                
    logger.debug("parse item: {0}".format(item))
                
    obis_code item.conf['dlms_obis_code']
                if 
    not obis_code in self._obis_codes:
                    
    self._obis_codes[obis_code] = {'items': [item], 'logics': []}
                else:
                    
    self._obis_codes[obis_code]['items'].append(item)
            return 
    None 
    Das Neuerzeugen der seriellen Schnittstelle habe ich dir schon mal auskommentiert eingefügt, falls benötigt.

    Ansonsten habe ich den Code für die fixe Baudrate erweitert und die Abbruchbedingung für use_checksum = true eingefügt. Ein Hängen beim zweiten Lesevorgang wird abgefangen. Mit "reset_baudrate" kann verhindert werden, dass weitere init/request wieder mit 300 Baud gesendet werden. Bei mir nimmt er auch 48000 und ist dann logischerweise noch schneller - ist aber wie gesagt dann standardmäßig aus.

    Statt der "sleep" und dem Echo-Canceling habe ich mich mal an drainOutput() und flushInput() versucht - sieht bei mir gut aus - vielleicht hilft das, einige Timingprobleme zu beseitigen?

    Würde mich echt freuen wenn du das noch mal testen könntest!

    Grüße
    Robert

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Zitat von Robert Beitrag anzeigen
    Die Schleife "while self.alive and stx == 'False':" macht ja nix anderes, als "ich schreibe so oft den request bis ich was genehmes zurück bekomme" - da liegt doch was im Argen!
    Ja da fehlt ein Punkt zum abschalten (i=2). Ansonsten macht es Sinn das Signal eben etwas später nochmal zu senden falls der Zähler ein hässliches Timing hat.

    Zitat von Robert Beitrag anzeigen
    Mit fixer Baudrate funktioniert das ganze momentan nicht (300 > 300 = False). Dafür müsste auch _request[2] entsprechend ausgefüllt werden (kann ja nicht kopiert werden).
    Ja das habe ich übersehen.

    Zitat von Robert Beitrag anzeigen
    Dann Effizienz: Warum jedes mal neu den seriellen Port komplett neu erzeugen? Warum nicht "not stx" oder "stx == False"? Da sind immer noch Stringvergleiche drin!?
    Weil das erzeugen des seriellen Ports in der init-Methode (warum auch immer) dazu führt das nur der erste Leseversuch nach dem Start funktioniert ... siehe 2 Posts vorher. Stringvergleich - ja hab ich jetzt auch geschnallt.

    So also Sorry nochmal für den commit.

    Einen Kommentar schreiben:


  • Robert
    antwortet
    So, ich schaffe es nicht, damit die Stände ausgelesen zu bekommen. Bi zur "Id" funktioniert es. Danach wird nur noch die Baudrate periodisch umgeschaltt.

    Die Schleife "while self.alive and stx == 'False':" macht ja nix anderes, als "ich schreibe so oft den request bis ich was genehmes zurück bekomme" - da liegt doch was im Argen!

    Mit fixer Baudrate funktioniert das ganze momentan nicht (300 > 300 = False). Dafür müsste auch _request[2] entsprechend ausgefüllt werden (kann ja nicht kopiert werden).

    Dann Effizienz: Warum jedes mal neu den seriellen Port komplett neu erzeugen? Warum nicht "not stx" oder "stx == False"? Da sind immer noch Stringvergleiche drin!?

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Ich dachte develop sei nicht produktiv.

    Sorry dafür.

    Ich lege das Thema jetzt ad acta - commit ist rückgängig gemacht.

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Zitat von JuMi2006 Beitrag anzeigen
    So ich hab das mal ins develop geschoben und konnte das (hoffentlich) fixen, jeder Versuch klappt hier mit beiden Zählern.
    Sorry Mirko, aber das bringt mich echt auf die Palme! Bei MIR funktioniert es nämlich jetzt nicht mehr. Kann doch nicht sein, dass du was ins Repo schiebst, was mit beim nächsten Pull mein Produktivsystem kaputt macht!? Aus genau dem Grund gibt es doch einen "Maintainer" pro Plugin. Ich "reparier" doch auch nicht in anderen Plugins rum!?

    Wir hatten uns auch dachte ich drauf geeinigt, dass wir das erst hier ausprobieren? Welchen Sinn macht es jetzt, das wieder auf nen Stand zu bringen der bei MIR funktioniert?

    fanta2k hatte auch auf Basis des Repos gearbeitet - was wenn es da jetzt nicht mehr geht?

    Mal genauer: Ich kriege NUR NOCH "Try Read Id" - MEHR NICHT.

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    So ich hab das mal ins develop geschoben und konnte das (hoffentlich) fixen, jeder Versuch klappt hier mit beiden Zählern.

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Nachdem ich "self._serial=...." in die update-Methode geholt habe geht zumindest jeder zweite Leseversuch. Müsste man evtl. mal weiter debuggen.
    Bei dem (jeden zweiten) Versuch der fehlschlägt bleibt dann jeweils das response auf init_seq leer.

    Ich tippe auf irgendwas mit open/close wobei das hier (m.M.n. sinnvoll eingesetzt) teilweise nicht nachvollziehbare exceptions wirft.

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Ich seh grad nicht woran es bei mir hakt. Nach der Intitialisierung alles gut, dann aber nix mehr ... ich mach Schluss für heute.

    Code:
    2013-11-23 22:02:50,925 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:06:10+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:02:51,448 DEBUG    env_stat     Item env.core.threads = 7 via Logic None None -- item.py:__update:363
    2013-11-23 22:02:51,451 DEBUG    env_stat     Item env.core.memory = 11366400 via Logic None None -- item.py:__update:363
    2013-11-23 22:02:51,453 DEBUG    env_stat     Item env.system.load = 0.19 via Logic None None -- item.py:__update:363
    2013-11-23 22:02:51,454 DEBUG    env_stat     Item env.location.moonlight = 68 via Logic None None -- item.py:__update:363
    2013-11-23 22:02:51,513 DEBUG    DLMS         dlms: meter returned capability for higher baudrate - try to change 4800 -- __init__.py:_update_values:83
    2013-11-23 22:02:51,930 DEBUG    Scheduler    env_stat next time: 2013-11-23 22:07:51+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:02:52,516 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:02:53,377 DEBUG    DLMS         dlms: got STX switching took: 0.86s -- __init__.py:_update_values:102
    2013-11-23 22:02:54,152 DEBUG    DLMS         dlms: got ETX rading took: 3.73s -- __init__.py:_update_values:109
    2013-11-23 22:02:54,158 DEBUG    DLMS         dlms: 0.0 =  2200391         -- __init__.py:_update_values:132
    2013-11-23 22:02:54,161 DEBUG    DLMS         dlms: 1.8.1 = 006415.709 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,165 DEBUG    DLMS         Item kwh = 6415.709 via DLMS OBIS 1.8.1 None -- item.py:__update:363
    2013-11-23 22:02:54,168 DEBUG    DLMS         dlms: 1.8.2 = 000000.000 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,169 DEBUG    DLMS         dlms: 1.8.3 = 000000.000 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,170 DEBUG    DLMS         dlms: 1.8.4 = 000000.000 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,171 DEBUG    DLMS         dlms: 1.8.0 = 006415.709 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,172 DEBUG    DLMS         dlms: 2.8.0 = 000000.000 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,173 DEBUG    DLMS         dlms: 15.8.0 = 006415.709 kWh -- __init__.py:_update_values:135
    2013-11-23 22:02:54,174 DEBUG    DLMS         dlms: 32.7 = 238 V -- __init__.py:_update_values:135
    2013-11-23 22:02:54,175 DEBUG    DLMS         dlms: 52.7 = 238 V -- __init__.py:_update_values:135
    2013-11-23 22:02:54,176 DEBUG    DLMS         dlms: 72.7 = 239 V -- __init__.py:_update_values:135
    2013-11-23 22:02:54,177 DEBUG    DLMS         dlms: 31.7 = 009.61 A -- __init__.py:_update_values:135
    2013-11-23 22:02:54,178 DEBUG    DLMS         dlms: 51.7 = 001.93 A -- __init__.py:_update_values:135
    2013-11-23 22:02:54,180 DEBUG    DLMS         dlms: 71.7 = 001.80 A -- __init__.py:_update_values:135
    2013-11-23 22:02:54,181 DEBUG    DLMS         dlms: 16.7 = 002.95 kW -- __init__.py:_update_values:135
    2013-11-23 22:02:54,182 DEBUG    DLMS         dlms: 0.2.0 = M23 -- __init__.py:_update_values:132
    2013-11-23 22:06:10,376 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:06:10,377 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:06:10,878 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:09:30+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:07:51,123 DEBUG    env_stat     Item env.system.load = 0.23 via Logic None None -- item.py:__update:363
    2013-11-23 22:07:51,605 DEBUG    Scheduler    env_stat next time: 2013-11-23 22:12:51+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:09:30,331 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:09:30,332 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:09:30,833 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:12:50+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:12:50,279 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:12:50,280 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:12:50,780 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:16:10+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:12:51,303 DEBUG    env_stat     Item env.system.load = 0.21 via Logic None None -- item.py:__update:363
    2013-11-23 22:12:51,785 DEBUG    Scheduler    env_stat next time: 2013-11-23 22:17:51+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:16:10,230 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:16:10,231 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:16:10,731 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:19:30+01:00 -- scheduler.py:_next_time:289
    Grüße

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Hi Mirko:

    Code:
    2013-11-23 22:26:44,242 INFO     Main         Start Logics -- logic.py:__init__:33
    [...]
    2013-11-23 22:26:44,249 DEBUG    dlms         DLMS next time: 2013-11-23 22:26:55+01:00 -- scheduler.py:_next_time:289
    [...]
    2013-11-23 22:26:55,340 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:26:55,347 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:26:55,849 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:27:15+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:26:56,469 DEBUG    DLMS         dlms: meter returned capability for higher baudrate - try to change 4800 -- __init__.py:_update_values:83
    2013-11-23 22:26:57,479 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:26:58,645 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    [...]
    2013-11-23 22:26:59,702 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:27:00,713 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:27:01,731 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:27:02,743 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:27:03,757 DEBUG    DLMS         dlms: trying to switch baudrate -- __init__.py:_update_values:94
    2013-11-23 22:27:03,766 DEBUG    DLMS         dlms: got STX switching took: 0.00s -- __init__.py:_update_values:102
    2013-11-23 22:27:15,477 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:27:15,483 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:27:15,985 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:27:35+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:27:17,504 WARNING  DLMS         dlms: device reports readiness to read but returned no data (device disconnected?) -- __init__.py:_update_values:72
    2013-11-23 22:27:18,465 DEBUG    DLMS         dlms: got ETX rading took: 23.12s -- __init__.py:_update_values:109
    2013-11-23 22:27:18,474 DEBUG    DLMS         dlms: 0.0.0 = 05008901 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,482 DEBUG    DLMS         dlms: 0.0.1 = 797023 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,489 DEBUG    DLMS         dlms: 0.0.2 = 97983715 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,497 DEBUG    DLMS         dlms: 0.2.0 = G03 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,504 DEBUG    DLMS         dlms: 0.2.1 = 0A
    040 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,516 DEBUG    DLMS         dlms: 0.0.0 = 05008901 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,523 DEBUG    DLMS         dlms: 0.0.1 = 797023 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,530 DEBUG    DLMS         dlms: 0.0.2 = 97983715 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,538 DEBUG    DLMS         dlms: 0.2.0 = G03 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,545 DEBUG    DLMS         dlms: 0.2.1 = 0AM26 -- __init__.py:_update_values:132
    2013-11-23 22:27:18,552 DEBUG    DLMS         dlms: 1.8.1 = 0009611 kWh -- __init__.py:_update_values:135
    2013-11-23 22:27:18,560 INFO     DLMS         Item Stromzaehler.Bezug.Energie = 9611 via DLMS OBIS 1.8.1 None -- item.py:__update:363
    2013-11-23 22:27:18,580 DEBUG    DLMS         dlms: 2.8.1 = 0007206 kWh -- __init__.py:_update_values:135
    2013-11-23 22:27:18,589 INFO     DLMS         Item Stromzaehler.Lieferung.Energie = 7206 via DLMS OBIS 2.8.1 None -- item.py:__update:363
    [...]
    2013-11-23 22:27:35,104 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:27:35,125 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:27:35,614 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:27:55+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:27:55,230 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:27:55,237 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:27:55,739 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:28:15+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:28:15,348 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:28:15,355 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:28:15,864 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:28:35+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:28:35,479 DEBUG    DLMS         dlms: update -- __init__.py:_update_values:55
    2013-11-23 22:28:35,501 DEBUG    DLMS         Write init -- __init__.py:_update_values:58
    2013-11-23 22:28:35,990 DEBUG    Scheduler    DLMS next time: 2013-11-23 22:28:55+01:00 -- scheduler.py:_next_time:289
    2013-11-23 22:28:48,128 INFO     Main         Stop Plugins -- plugin.py:stop:70
    2013-11-23 22:28:48,153 DEBUG    Main         KNX: closing socket smartgate:6720 -- connection.py:close:302
    2013-11-23 22:28:49,072 INFO     Main         SmartHome.py stopped -- smarthome.py:stop:372
    Ein mal funktioniert es nach scheinbar einigen Baudraten-Wechseln.

    Ich schau da morgen noch mal drauf um raus zu kriegen wo es hakt.

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Probiere mal das hier ... wenn ich keinen Denkfehler habe sollte das Echo abgefangen sein. Die Checksumme hab ich mal auskommentiert, hatte keinen commit zum deaktivieren gefunden.

    Code:
    #!/usr/bin/env python3
    # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
    #########################################################################
    #  Copyright 2011 KNX-User-Forum e.V.           https://knx-user-forum.de/
    #########################################################################
    #  DLMS plugin for SmartHome.py.         http://mknx.github.io/smarthome/
    #
    #  This plugin is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This plugin is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this plugin. If not, see <http://www.gnu.org/licenses/>.
    #########################################################################
    
    import logging
    import time
    import serial
    import re
    
    logger = logging.getLogger('DLMS')
    
    
    class DLMS():
    
        def __init__(self, smarthome, serialport, baudrate="auto", update_cycle="60"):
            self._sh = smarthome
            self._update_cycle = int(update_cycle)
            if (baudrate.lower() == 'auto'):
                self._baudrate = -1
            else:
                self._baudrate = int(baudrate)
            self._obis_codes = {}
            self._serial = serial.Serial(
                serialport, 300, bytesize=serial.SEVENBITS, parity=serial.PARITY_EVEN, timeout=2)
            self._request = bytearray('\x06000\r\n', 'ascii')
    
        def run(self):
            self.alive = True
            self._sh.scheduler.add('DLMS', self._update_values,
                                   prio=5, cycle=self._update_cycle)
    
        def stop(self):
            self.alive = False
            self._serial.close()
            self._sh.scheduler.remove('DLMS')
    
        def _update_values(self):
            logger.debug("dlms: update")
            start = time.time()
            init_seq = bytes('/?!\r\n', 'ascii')
            logger.debug("Write init")
            self._serial.flushInput()
            self._serial.write(init_seq)
            response = bytes()
            prev_length = 0
            try:
                while self.alive:
                    response += self._serial.read()
                    length = len(response)
                    # break if timeout or newline-character
                    if (length == prev_length) or ((length > len(init_seq)) and (response[-1] == 0x0a)):
                        break
                    prev_length = length
            except Exception as e:
                logger.warning("dlms: {0}".format(e))
            # remove echoed chars if present
            if (init_seq == response[:len(init_seq)]):
                response = response[len(init_seq):]
            if (len(response) >= 5) and ((response[4] - 0x30) in range(6)):
                if (self._baudrate == -1):
                    baud_capable = 300 * (1 << (response[4] - 0x30))
                else:
                    baud_capable = self._baudrate
                if baud_capable > self._serial.baudrate:
                    try:
                        logger.debug("dlms: meter returned capability for higher baudrate - try to change {}".format(baud_capable))
                        stx = 'False'
                        while self.alive and stx == 'False':
                            response2 = bytes()
                            self._request[2] = response[4]
                            # set baudrate to 300 first
                            time.sleep(0.5)
                            self._serial.baudrate = 300
                            self._serial.write(self._request)
                            # change request to set higher baudrate
                            time.sleep(0.5)
                            logger.debug("dlms: trying to switch baudrate")
                            switch_start = time.time()
                            self._serial.baudrate = baud_capable
                            response2 += self._serial.read(1)
                            if 0x02 in response2:
                                if len(response2) >= len(self._request):
                                    response2 = response2[len(self_request):]
                                    logger.debug("dlms: cut echo")
                                logger.debug("dlms: got STX switching took: {:.2f}s".format(time.time() - switch_start))
                                etx = 'false'
                                while etx == 'false':
                                    response2 += self._serial.read()
                                    if (0x03 in response2) and (0x21 in response2):
                                        etx = 'true'
                                        stx = 'true'
                                        logger.debug("dlms: got ETX rading took: {:.2f}s".format(time.time() - start))
                                        response = response2
                    except Exception as e:
                        logger.warning("dlms: {0}".format(e))
                        return
    
            #checksum = 0
            #for i in response[1:]:
            #    checksum ^= i
            #if (len(response) < 5) or (response[0] != 0x02) or (response[-2] != 0x03) or (checksum != 0x00):
            #    logger.warning(
            #        "dlms: checksum/protocol error: response={} checksum={}".format(' '.join(hex(i) for i in response), checksum))
            #    return
            #print(str(response[1:-4], 'ascii'))
            for line in re.split('\r\n', str(response[1:-4], 'ascii')):
                # if re.match('[0-9]+\.[0-9]\.[0-9](.+)', line): # allows only
                # x.y.z(foo)
                if re.match('[0-9]+\.[0-9].+(.+)', line):  # allows also x.y(foo)
                    try:
                        #data = re.split('[(*)]', line)
                        data = line.split('(')
                        data[1:3] = data[1].strip(')').split('*')
                        if (len(data) == 2):
                            logger.debug("dlms: {} = {}".format(data[0], data[1]))
                        else:
                            logger.debug(
                                "dlms: {} = {} {}".format(data[0], data[1], data[2]))
                        if data[0] in self._obis_codes:
                            for item in self._obis_codes[data[0]]['items']:
                                item(data[1], 'DLMS', 'OBIS {}'.format(data[0]))
                    except Exception as e:
                        logger.warning(
                            "dlms: line={} exception={}".format(line, e))
    
        def parse_item(self, item):
            if 'dlms_obis_code' in item.conf:
                logger.debug("parse item: {0}".format(item))
                obis_code = item.conf['dlms_obis_code']
                if not obis_code in self._obis_codes:
                    self._obis_codes[obis_code] = {'items': [item], 'logics': []}
                else:
                    self._obis_codes[obis_code]['items'].append(item)
            return None

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Hallo Robert, gib mir mal ne Stunde, wenn ich mir Deinen Code jetzt ansehe komm ich durcheinander

    Ich hab das Problem verstanden ... nur ne kurze Frage. Erst kommt das Echo und dann die Antwort? Ich glaub dann pack ich das gerade.

    Einen Kommentar schreiben:


  • Robert
    antwortet
    @ Mirko:

    Wenn ich dich richtig verstehe willst du so etwas - das funktioniert bei mit leider (noch) nicht - würde das bei dir funktionieren?

    Code:
    #!/usr/bin/env python3
    # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
    #########################################################################
    #  Copyright 2011 KNX-User-Forum e.V.           https://knx-user-forum.de/
    #########################################################################
    #  DLMS plugin for SmartHome.py.         http://mknx.github.io/smarthome/
    #
    #  This plugin is free software: you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation, either version 3 of the License, or
    #  (at your option) any later version.
    #
    #  This plugin is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this plugin. If not, see <http://www.gnu.org/licenses/>.
    #########################################################################
    
    import logging
    import time
    import serial
    import re
    from time import sleep
    
    logger = logging.getLogger('DLMS')
    
    
    class DLMS():
    
        def __init__(self, smarthome, serialport, baudrate="auto", update_cycle="60", use_checksum = True):
            self._sh = smarthome
            self._update_cycle = int(update_cycle)
            self._use_checksum = use_checksum
            if (baudrate.lower() == 'auto'):
                self._baudrate = -1
            else:
                self._baudrate = int(baudrate)
            self._obis_codes = {}
            self._serial = serial.Serial(
                serialport, 300, bytesize=serial.SEVENBITS, parity=serial.PARITY_EVEN, timeout=2)
            self._request = bytearray('\x06000\r\n', 'ascii')
    
        def run(self):
            self.alive = True
            init_seq = bytes('/?!\r\n', 'ascii')
            self._serial.flushInput()
            self._serial.write(init_seq)
            response = bytes()
            prev_length = 0
            try:
                while self.alive:
                    response += self._serial.read()
                    length = len(response)
                    # break if timeout or newline-character
                    if (length == prev_length) or ((length > len(init_seq)) and (response[-1] == 0x0a)):
                        break
                    prev_length = length
            except Exception as e:
                logger.warning("dlms: {0}".format(e))
            # remove echoed chars if present
            if (init_seq == response[:len(init_seq)]):
                response = response[len(init_seq):]
            if (len(response) >= 5) and ((response[4] - 0x30) in range(6)):
                if (self._baudrate == -1):
                    self._baudrate = 300 * (1 << (response[4] - 0x30))
                    logger.debug("dlms: meter returned capability for higher baudrate {}".format(self._baudrate))
                pow2 = int(self._baudrate / 300)
                self._request[2] = 0x30 - 1
                while (pow2 > 0):
                    pow2 >>= 1
                    self._request[2] += 1
                self._sh.scheduler.add('DLMS', self._update_values, prio=5, cycle=self._update_cycle)
    
        def stop(self):
            self.alive = False
            self._serial.close()
            self._sh.scheduler.remove('DLMS')
    
        def _update_values(self):
            logger.debug("dlms: update")
            start = time.time()
            self._serial.baudrate = 300
            sleep(0.5)
            self._serial.write(self._request)
            sleep(1)
            self._serial.baudrate = self._baudrate
            response = bytes()
            prev_length = 0
            try:
                while self.alive:
                    response += self._serial.read()
                    length = len(response)
                    # break if timeout or "ETX"
                    if (length == prev_length) or ((length >= 2) and (response[-2] == 0x03)):
                        break
                    prev_length = length
            except Exception as e:
                logger.warning("dlms: {0}".format(e))
            logger.debug("dlms: Reading took: {:.2f}s".format(time.time() - start))
            # remove echoed chars if present
            if (self._request == response[:len(self._request)]):
                response = response[len(self._request):]
            if self._use_checksum:
                # perform checks (start with STX, end with ETX, checksum match)
                checksum = 0
                for i in response[1:]:
                    checksum ^= i
                if (len(response) < 5) or (response[0] != 0x02) or (response[-2] != 0x03) or (checksum != 0x00):
                    logger.warning(
                        "dlms: checksum/protocol error: response={} checksum={}".format(' '.join(hex(i) for i in response), checksum))
                    return
            #print(str(response[1:-4], 'ascii'))
            for line in re.split('\r\n', str(response[1:-4], 'ascii')):
                # if re.match('[0-9]+\.[0-9]\.[0-9](.+)', line): # allows only
                # x.y.z(foo)
                if re.match('[0-9]+\.[0-9].+(.+)', line):  # allows also x.y(foo)
                    try:
                        #data = re.split('[(*)]', line)
                        data = line.split('(')
                        data[1:3] = data[1].strip(')').split('*')
                        if (len(data) == 2):
                            logger.debug("dlms: {} = {}".format(data[0], data[1]))
                        else:
                            logger.debug(
                                "dlms: {} = {} {}".format(data[0], data[1], data[2]))
                        if data[0] in self._obis_codes:
                            for item in self._obis_codes[data[0]]['items']:
                                item(data[1], 'DLMS', 'OBIS {}'.format(data[0]))
                    except Exception as e:
                        logger.warning(
                            "dlms: line={} exception={}".format(line, e))
    
        def parse_item(self, item):
            if 'dlms_obis_code' in item.conf:
                logger.debug("parse item: {0}".format(item))
                obis_code = item.conf['dlms_obis_code']
                if not obis_code in self._obis_codes:
                    self._obis_codes[obis_code] = {'items': [item], 'logics': []}
                else:
                    self._obis_codes[obis_code]['items'].append(item)
            return None

    Einen Kommentar schreiben:


  • Robert
    antwortet
    Zitat von fanta2k Beitrag anzeigen
    bei mir läuft dieses hier aktuell:

    checksum und umschalten auskommentiert + typecast + \n vor dem string.
    das typecast nach float brauch ich wenn ich mit eval den kWk wert / 1000 dividiere.
    Ok, das ist das "aktuelle" Plugin.

    checksum: wie gesagt, ab jetzt per se optional im "develop"
    umschalten: per "baudrate = 300" kann das auch serienmäßig lahmgelegt werden
    typecast: hihi, könnte ein "bug" sein - denn eigentlich casten die Items ja auf den korrekten Typ - gut möglich, dass das bei einem eval noch nicht geschehen ist...
    \n - hm, könnte man optional machen

    Einen Kommentar schreiben:

Lädt...
X