Hallo,
ich habe ein Plugin zum interpretieren von EMH Stromzählerdaten geschrieben. Die Daten werden über die serielle Schnittstelle gelesen.
Wird dieses Plugin genutzt kann ich zu 30% smarthome.py aus dem interaktiven Mode nicht mit CTRL+C beenden. Die Shell des interaktiven Modes friert dann ein und die sh Instanz läuft fröhlich weiter. Auch ein kill <PID> hilft dann nicht. Erst ein kill -9 <PID> beendet die Instanz. Dann wird die Shell in der der interactive Modus gelaufen ist auch wieder frei. Manchmal sind danach die Terminaleinstellungen verstellt (kein Keyboard echo mehr, keine Newline bei enter etc).
Ganz selten bekomme ich diese Fehlermeldung:
Aufgrund dieser Probleme gibt es dieses Plugin auch noch nicht im GIT - da ich selbst im Dev Branach nichts veröffentlichen möchte was die Stabilität des ganzen Systems beeinträchtigen könnte.
Anbei der Quellcode von dem Plugin:
Wäre super wenn jemand eine Idee hätte wie das beenden sauber umgesetzt werden kann.
LG
Mode
ich habe ein Plugin zum interpretieren von EMH Stromzählerdaten geschrieben. Die Daten werden über die serielle Schnittstelle gelesen.
Wird dieses Plugin genutzt kann ich zu 30% smarthome.py aus dem interaktiven Mode nicht mit CTRL+C beenden. Die Shell des interaktiven Modes friert dann ein und die sh Instanz läuft fröhlich weiter. Auch ein kill <PID> hilft dann nicht. Erst ein kill -9 <PID> beendet die Instanz. Dann wird die Shell in der der interactive Modus gelaufen ist auch wieder frei. Manchmal sind danach die Terminaleinstellungen verstellt (kein Keyboard echo mehr, keine Newline bei enter etc).
Ganz selten bekomme ich diese Fehlermeldung:
Code:
>>> Unhandled exception in thread started by <bound method Plugin._bootstrap of <Plugin(ehz, stopped 139903929153280)>>
Anbei der Quellcode von dem Plugin:
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/ ######################################################################### # 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 serial import struct logger = logging.getLogger('ehz_emh') class ehz_emh(): 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, length_tarif_data = 23, length_tarif_value = 5): 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._rx_buffer = rx_buffer self._length_tarif_data = length_tarif_data self._length_tarif_value = length_tarif_value self._ser = serial.Serial(port = self._port, baudrate = self._baudrate, parity = self._parity, stopbits = self._stopbits, \ bytesize = self._bytesize, timeout = self._timeout) if self._ser.isOpen(): logger.info("eHZ_EMH is connected to {0}".format(self._ser.portstr)) else: logger.error("Can not connect to {0}".format(self._ser.portstr)) def run(self): self.alive = True self._ser.flushInput() while self.alive: if not self._ser.isOpen(): self._ser = serial.Serial(port = self._port, baudrate = self._baudrate, parity = self._parity, stopbits = self._stopbits, \ bytesize = self._bytesize, timeout = self._timeout) logger.info("Reconnect needed, now connected to {0}".format(self._ser.portstr)) dataset = self._ser.read(self._length_emh_frame) if len(dataset) == 0: # logger.debug("No eHZ Data received from port ".format(self._ser.portstr)) continue if len(dataset) != self._length_emh_frame: logger.warning("Invalid eHZ Data. Len received: {0} Len expected: {1}".format(len(dataset), self._length_emh_frame)) self._ser.flushInput() continue # print (type(dataset)) # print (dataset) # for line in dataset: # print("{0:02X}".format(line), end = " ") # print("") crc = self._sml_crc16(dataset) if [dataset[-2],dataset[-1]] == [crc[-2],crc[-1]]: pass # logger.debug("CRC OK") else: logger.warning("CRC NOK") continue for tarif in self._tarif: value = self._get_tarif(dataset, tarif) self._tarif[tarif](value) def stop(self): self.alive = False self._ser.close() def parse_item(self, item): if 'ehz_emh_tarif' in item.conf: tarif = item.conf['ehz_emh_tarif'] logger.debug("parse item: {0}".format(item)) if tarif not in self._tarif: self._tarif[tarif] = item else: self._tarif[tarif].append(item) return None def parse_logic(self, logic): pass def update_item(self, item, caller=None, source=None, dest=None): if caller != 'plugin': logger.info("update item: {0}".format(item.id())) # CRC Berechnung mit Lookuptable def _sml_crc16(self, cp): crctab = [0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, \ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, \ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, \ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, \ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, \ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, \ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, \ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, \ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, \ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, \ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, \ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, \ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, \ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, \ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, \ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78] fcs = 0xFFFF index = 0 length = len(cp) - 2 while (length): length -= 1 fcs = (fcs >> 8) ^ crctab[(fcs ^ cp[index]) & 0xff] index += 1 fcs ^= 0xffff return struct.pack('H',fcs) def _get_tarif(self, dataset, tarif): result1 = None result2 = None # Auf Anfangssequenz von ZählerstandBlock <tarif> parsen und diesen Block in result1 vorhalten search = bytearray.fromhex('77 07 01 00') for n in tarif: search.append(int(n)) search.append(0xFF) cnt = dataset.find(search) if cnt >= 0: result1 = dataset[cnt:cnt+self._length_tarif_data] if result1 is None: logger.info("Tarif dataset {0} not Found!".format(tarif)) return # Auf Anfangssequenz von Zäherstand parsen und diesen in result2 vorhalten search = bytearray.fromhex('62 1E 52 FF 56') length = len(search) cnt = result1.find(search) if cnt >= 0: result2 = result1[cnt+length:cnt+length+self._length_tarif_value] if result2 is None: logger.info("Tarif value {0} not Found!".format(tarif)) return # Zäherstand konvertieren hex->int num = 0 for data in result2: num <<= 8 num |= data return num / 10000 if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) myplugin = Plugin('ehz_emh') myplugin.run()
LG
Mode
Kommentar