Danke für den Tipp, die Zeit ist zu lang, kommen crc errors raus, kürzere sleeps bringen auch nichts. Durch zusammenfassen von reads habe ich zwar die last auf ca 10% reduziert aber weiter komme ich mit python nicht. Das schwierige ist das es ein Bus ist auf dem der Master permanent alle Geräte abfragt. Man muss also nach einem Frameanfang mit seiner Adresse lauschen und dann antworten mit ACK usw. Das alles läuft nicht gerade langsam ab. Werde es mit einem C Programm probieren und über Socket an sh anbinden, mal schauen ob es entschärft wird. C Programm hat eine last von 0,3.
LG
Eduard
Ankündigung
Einklappen
Keine Ankündigung bisher.
Pluginentwicklung, Trigger von serieller Schnittstelle
Einklappen
X
-
Hi,
ich würde noch ein time.sleep(0.01) in die Endlosschleife packen.
Das sollte die Last dramatisch drücken.
Bis bald
Marcus
Einen Kommentar schreiben:
-
Danke, mache ich wenn ich das Plugin verbessert habe ( wenns geht
). Momentan gefällt mir folgendes nicht: last beim Raspi von ca 13% bei diesem Plugin (habe nicht mit anderen Plugins verglichen) und das die Daten floaten (letzte Nachkommastelle bei Temperaturen springt z.B zwischen .5 und .6). Das erste kommt wohl vom byteweise lesen, habe aber keine andere Lösung dafür. Beim zweiten kommen die Werte vom Bus so, man müsste wohl ein dejitter einbauen damit man nicht alle paar Sekunden ein neuen Wert detektiert.
Einen Kommentar schreiben:
-
Hallo Eduard,
schönes Plugin. Auf den ersten Blick ist mir nichts aufgefallen.
Über ein Readme und einen Pull-Request (https://github.com/mknx/smarthome/tr...v#start-coding) würde ich mich freuen.
Bis bald
Marcus
Einen Kommentar schreiben:
-
Sehr schöne Sache.. da kann man schon den einen oder anderen Ansatz herausholen.
Wäre dennoch genial, wenn du mal in einer langweiligen Stunde noch ein paar Kommentare einfügen könntest. Dann wär's einfacher, die Sache generischer zu gestalten
Danke vielmals!
Einen Kommentar schreiben:
-
Vielen dank für die Antwort. Ich habe mir die Zeit genommen den ganzen sh Code rein zuziehen um zu verstehen wie alles Funktioniert. Ist einiges klar geworden. Schönes teil hast du da gebaut. Hier mein Plugin für die NIBE SPLIT WP. Ich aktualisiere die Items nur dann wenn sich was ändert. Einige Werte ändern sich relativ oft (Druck, Temperaturen und der WP) aber ich denke das ist ok.
Über Verbesserungen freue ich michCode:#!/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/ ######################################################################### # NIBE 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 serial import re import termios from struct import * logger = logging.getLogger('NIBE') class NIBE(): def __init__(self, smarthome, serialport): self._sh = smarthome self._nibe_regs = {} self._serial = serial.Serial(serialport, 19200, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE, timeout=2) iflag, oflag, cflag, lflag, ispeed, ospeed, cc = termios.tcgetattr(self._serial) CMSPAR = 0x40000000 cflag |= termios.PARENB | CMSPAR | termios.PARODD # to select MARK parity termios.tcsetattr(self._serial, termios.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) def run(self): self.alive = True try: while self.alive: if bytes(self._serial.read(1))[0] != 0x03: continue if bytes(self._serial.read(1))[0] != 0x00: continue if bytes(self._serial.read(1))[0] != 0x14: continue self._serial.write(b"\x06") self._serial.drainOutput() self._serial.flushInput() frm = bytes() frm += self._serial.read(1) #<C0> if frm[0] == 0x03: continue frm += self._serial.read(3) #<00> <59> <len> l = int(frm[3]) frm += self._serial.read(l+1) self._serial.write(b"\x06") self._serial.drainOutput() self._serial.flushInput() crc = 0 for i in frm[:-1]: crc ^= i if crc != frm[-1]: logger.warning("frame crc error") continue msg = frm[4:-1] l = len(msg) i=4 while i <= l: reg = msg[i-3] if i != l and (msg[i] == 0x00 or i == (l-1)): raw = bytes([msg[i-2],msg[i-1]]) i+=4 else: raw = bytes([msg[i-2]]) i+=3 if not reg in self._nibe_regs: continue if self._nibe_regs[reg]['raw'] == raw: continue value = self._decode(reg, raw) logger.debug("update_item: reg:{0} = {1}".format(reg,value)) self._nibe_regs[reg]['raw'] = raw for item in self._nibe_regs[reg]['items']: item(value, 'NIBE', 'REG {}'.format(reg)) except Exception as e: logger.warning("nibe: {0}".format(e)) def stop(self): self.alive = False self._serial.close() def parse_item(self, item): if 'nibe_reg' in item.conf: logger.debug("parse item: {0}".format(item)) nibe_reg = int(item.conf['nibe_reg']) if not nibe_reg in self._nibe_regs: self._nibe_regs[nibe_reg] = {'items': [item], 'logics': [], 'raw':0} else: self._nibe_regs[nibe_reg]['items'].append(item) return None def _decode(self, reg, raw): if len(raw) == 2: value = unpack('>H',raw)[0] else: value = unpack('B',raw)[0] if reg in [0,32,33,34,35,36,38,44,45,46,48,100,101,102,103,104,105]: #0 CPUID #32 Zusatzheizung erlaubt #33 Max dF Commpressor #34 Verd. Freq. regP #35 Min Startzeit Freq min #36 Minzeit konst. Freq min #38 Verd. Freq. GradMin #44 Pumpengeschwindigkeit % #45 Bw reg P #46 Bw reg Q #48 Bw reg Wert xP % #100 Datum - Jahr #101 Datum - Monat #102 Datum - Tag #103 Uhrzeit - Stunde #104 Uhrzeit - Minute #105 Uhrzeit - Sekunden return int(value) if reg == 31: #31 Status Heizung #1 Auto #3 Heizung #5 Brauchwasser #6 Zusatzheizung return int(value) if reg in [4,8]: #signed #4 Heizkurvenverschiebung #8 Gradminuten return int(unpack('h',pack('H',value))[0]/10) if reg == 25: #unsigned #25 Verdichterstarts return int(value/10) if reg in [1,5,6,7,11,12,13,14,15,16,17,18,21,23,27,37]: #signed #1 Aussentemp °C #5 Vorlauf Soll °C #6 Vorlauf Ist °C #7 Ruecklauf °C #11 Kondensator aus (MAX) °C #12 Brauchwasser oben °C #13 Brauchwasser unten °C #14 Verd. Temp. Tho-R1 °C #15 Verd. Temp. Tho-R2 °C #16 Sauggas Temp. Tho-S °C #17 Heissgas Temp. Tho-D °C #18 Fluessigkeitstemp AMS °C #21 Atemp. am AMS Tho-A °C #23 Invertertemp. Tho-IP °C #27 Vorlauf °C #37 Max Diff. soll-ber °C return float(unpack('h',pack('H',value))[0]/10) if reg in [9,10,19,20,22,24]: #unsigned #9 Verd. Freq. Soll Hz #10 Verd. Freq. Ist Hz #19 Hochdruck bar #20 Niederdruck bar #22 AMS Phase Ist A #24 Verdichterlaufzeit h return float(value/10) if reg in [40,47]: #unsigned #40 Hysterese °C #47 Bw reg xP return float(value/2) if reg in [43,49,50]: #43 Stopptemp. Heizen °C #49 Brauchwasser StartTemp °C 1.2 #50 Brauchwasser StopTemp °C 1.3 return float(value) #2 ? #3 ? #26 ? #28 ? #29 ? #30 ? #39 ? #41 ? #42 ? return value
LG
Eduard
Einen Kommentar schreiben:
-
Hallo,
ein Plugin darf seinen Thread behalten/blockieren. Anderes geht es momentan mit einer seriellen auch nicht.
Keine Ahnung was bei Dir passiert wenn Du die Items änderst. Prinzipiell ist das Backend ziemlich schnell. Die Frage ist wieso willst Du die Änderungen "reinpumpen". Ich würde das zeitlich wahrscheinlich entspannen, da ja auch Logiken durch Änderungen getriggert werden können.
Bis bald
Marcus
Einen Kommentar schreiben:
-
Hallo,
ich habe das gleiche Problem. Ich bastle gerade an einem Plugin für die NIBE Wärmepumpe. Es funktioniert auch soweit. Da ich permanent die serielle Schnittstelle abhören muss (es prasseln unaufhörlich Daten rein die ich filtere) ist meine Frage wie ich das am besten im Plugin einbaue. Ich brauche ja ein Thread der die Daten ausliest und einen der die Daten in die Items schaufelt oder ein Thread welcher beides macht.
Das Plugin, wie ich verstehe läuft im sh als Thread, darf die run Methode des Plugins blockieren? D.h wenn ich da die schleife mit dem serielle Schnittstelle Auslesen reinlege, so wie mode
es gemacht hat.
Was passiert wenn ich item(value, ...) aufrufe? Werden dabei viele Daten verarbeitet. Ich frage weil sehr viele Daten reinkommen in schnellen Intervallen. Wenn item(value,...) viel macht würde es Sinn machen die Daten lokal zu behalten und über den sheduler in kleineren Intervallen in Items zu schaufeln.
LG
eddso
Einen Kommentar schreiben:
-
Hallo,
Du kannst mehr Debug-Output in die lib/connection.py einbauen um den Fehler einzugrenzen. Ich vermute aber das Problem bei Deinem Plugin/Hardware.
Bis bald
Marcus
Einen Kommentar schreiben:
-
Danke für die Info. Wie gesagt löse ich die Sache derzeit so, dass jede Sekunde vom Arduino Daten geholt werden. Hat sich dort nichts geändert, gibt's aber auch keine neuen Info. Dadurch sollte die Kommunikation halbwegs im Zaum gehalten werden.
Dennoch gibt's immer wieder folgende Fehlermeldung:
Irgendeine Idee? Könnte das evtl. auch von nem anderen Plugin kommen? wie könnte ich da mehr Infos dazu raus kriegen..?Code:2014-06-30 21:44:35 ERROR Main Connection polling failed: [Errno 4] Unterbrechung während des Betriebssystemaufrufs Traceback (most recent call last): File "/usr/local/smarthome/bin/smarthome.py", line 357, in start self.connections.poll() File "/usr/local/smarthome/lib/connection.py", line 101, in poll for fileno, event in self._epoll.poll(timeout=1): IOError: [Errno 4] Unterbrechung während des Betriebssystemaufrufs 2014-06-30 21:44:38 ERROR Main Connection polling failed: [Errno 4] Unterbrechung während des Betriebssystemaufrufs Traceback (most recent call last): File "/usr/local/smarthome/bin/smarthome.py", line 357, in start self.connections.poll() File "/usr/local/smarthome/lib/connection.py", line 101, in poll for fileno, event in self._epoll.poll(timeout=1): IOError: [Errno 4] Unterbrechung während des Betriebssystemaufrufs
Dankeschööön!
Einen Kommentar schreiben:
-
Hallo,
Nein und Ja.Zitat von Onkelandy Beitrag anzeigenWollte kurz checken, ob sich in punkto serieller Schnittstelle schon was getan hat oder noch tun wird.
Bis bald
Marcus
Einen Kommentar schreiben:
-
Hallo zusammen!
Wollte kurz checken, ob sich in punkto serieller Schnittstelle schon was getan hat oder noch tun wird.
Ich möchte eine Verbindung mit einem Arduino herstellen. Letzterer soll bei einer Änderung der Daten diese an Smarthome.py schicken. Derzeit löse ich das über ein adaptiertes Roomla-Plugin, das jede Sekunde cyclet. Und somit auch immer beim Arduino nach den Daten frägt, der dann zurücksendet.
Das funktioniert zwar, ist aber sicher nicht die optimale Lösung. CPU-Last von Python ist dadurch 2,3% statt 0,7% und Memory ist bei 4,3%. Soweit kein Drama, aber doch klar ein Unterschied. Die TCP-Verbindung mit meinen anderen laufenden Plugins (adaptiertes Denon-Plugin, etc.) funktioniert einwandfrei ohne zusätzliche Last..
Einen Kommentar schreiben:
-
Hi Daniel,
ja das ist ok so.
Zu Deiner Exception kann ich nichts sagen, es fehlt der Code-Kontext.
Du solltest aber mehr try: except: einbauen. U.a. um das close()
Bis bald
Marcus
Einen Kommentar schreiben:
-
Hallo Marcus,
ich habe am Wochenende mit poll experimentiert. Dabei rausgekommen, dass die Systemlast mit einem blockierendem read() mit Timeout 1s noch geringer ist als mit mit poll(). Möchte daher vorerst so arbeiten.
Mein Plugin in dem ich die Daten vom EHz lese funktioniert auch schon. Ich bin mir aber nicht sicher, ob das Plugin sich beim beenden von sh.py korrekt verhält.
Ist das so ok?Code:def __init__(self, smarthome, port = '/dev/ttyUSB0', baudrate = 9600, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE, bytesize = serial.EIGHTBITS, \ timeout = 1, length_emh_frame = 392, max_bytes = 500): self._sh = smarthome self._tarif = {} self._port = port self._baudrate = baudrate self._parity = parity self._stopbits = stopbits self._bytesize = bytesize self._timeout = timeout self._length_emh_frame = length_emh_frame self._max_bytes = max_bytes self._ser = serial.Serial(port = self._port, baudrate = self._baudrate, parity = self._parity, stopbits = self._stopbits, bytesize = self._bytesize, timeout = self._timeout) logger.info("EHZ_EMH is connected to {0}".format(self._ser.portstr)) def run(self): self.alive = True while self.alive: self._ser.flushInput() dataset = self._ser.read(self._max_bytes) [...] weitere Verarbeitung und relevante items setzen def stop(self): self.alive = False self._ser.close()
Edit:
Gerade einer von vielen Stops nicht erfolgreich:
ConsoleLogCode:>>> Unhandled exception in thread started by <bound method Plugin._bootstrap of <Plugin(ehz, stopped 140047022003968)>>
Code:2013-11-17 00:29:02,754 INFO Main Stop Plugins -- plugin.py:stop:70 2013-11-17 00:29:02,758 DEBUG Main KNX: closing socket cgate.ts:6720 -- connection.py:close:302 2013-11-17 00:29:02,762 ERROR Dummy-7 Unhandled exception: 'utf-8' codec can't decode byte 0xe4 in position 2805: invalid continuation byte <class 'UnicodeDecodeError'> File "/usr/lib/python3.2/threading.py", line 713, in _bootstrap self._bootstrap_inner() File "/usr/lib/python3.2/threading.py", line 753, in _bootstrap_inner (self.name, _format_exc())) File "/usr/lib/python3.2/traceback.py", line 269, in format_exc format_exception(etype, value, tb, limit, chain)) File "/usr/lib/python3.2/traceback.py", line 186, in format_exception list.extend(format_tb(tb, limit)) File "/usr/lib/python3.2/traceback.py", line 75, in format_tb return format_list(extract_tb(tb, limit)) File "/usr/lib/python3.2/traceback.py", line 100, in extract_tb line = linecache.getline(filename, lineno, f.f_globals) File "/usr/lib/python3.2/linecache.py", line 15, in getline lines = getlines(filename, module_globals) File "/usr/lib/python3.2/linecache.py", line 41, in getlines return updatecache(filename, module_globals) File "/usr/lib/python3.2/linecache.py", line 132, in updatecache lines = fp.readlines() File "/usr/lib/python3.2/codecs.py", line 300, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) -- smarthome.py:_excepthook:494 2013-11-17 00:29:03,226 INFO Main Thread: Main, still alive -- smarthome.py:stop:370 2013-11-17 00:29:03,227 INFO Main Thread: Dummy-7, still alive -- smarthome.py:stop:370
Einen Kommentar schreiben:
-
Hallo Daniel,
das mit dem Triggern erzeugt unnötig Last. Ich würde das Plugin/den Thread selber loopen lassen und mit select/poll arbeiten.
Ich habe mir aber überlegt, ob ich serielle Schnittstellen etwas generischer über lib.connection einbinde. Mal sehen.
Bis bald
Marcus
Einen Kommentar schreiben:


Einen Kommentar schreiben: