class SerialReader(object): PORT_KEY = 'port' def __init__(self, device, serial_settings, telegram_specification): self.serial_settings = serial_settings self.serial_settings[self.PORT_KEY] = device self.telegram_parser = TelegramParser(telegram_specification) self.telegram_buffer = TelegramBuffer() def read_continuously(self): """ Read complete DSMR telegram's from the serial interface and parse it into CosemObject's and MbusObject's :rtype: generator """ with serial.Serial(**self.serial_settings) as serial_handle: while True: data = serial_handle.read( max(1, min(1024, serial_handle.in_waiting))) self.telegram_buffer.append(data.decode('ascii')) for telegram in self.telegram_buffer.get_all(): try: yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: logger.error('Failed to parse telegram: %s', e) def read(self): """ Read complete DSMR telegram's from the serial interface and parse it into CosemObject's and MbusObject's :rtype: generator """ with serial.Serial(**self.serial_settings) as serial_handle: data = serial_handle.read( max(1, min(1024, serial_handle.in_waiting))) self.telegram_buffer.append(data.decode('ascii')) for telegram in self.telegram_buffer.get_all(): try: yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: logger.error('Failed to parse telegram: %s', e)
def analyze(self): key = binascii.unhexlify(self._args.key) additional_data = binascii.unhexlify(self._args.aad) iv = binascii.unhexlify(self._system_title + self._frame_counter) payload = binascii.unhexlify(self._payload) gcm_tag = binascii.unhexlify(self._gcm_tag) try: decryption = self.decrypt(key, additional_data, iv, payload, gcm_tag) if has_dsmr_parser and self._args.parse: try: parser = TelegramParser(telegram_specifications.V5) telegram = parser.parse(decryption.decode()) for key in telegram: print("%s: %s" % (dsmr_parser.obis_name_mapping.EN[key], telegram[key])) except: print("ERROR: Cannot parse DSMR Telegram") print(decryption) else: print(decryption) if self._args.serial_output_port: self.write_to_serial_port(decryption) except InvalidTag: print("ERROR: Invalid Tag.")
def parse(user, telegram): """ Parse a DSMR telegram and log the values in the appropriate places in the database. :param django.contrib.auth.models.User user: :param str telegram: """ parser = TelegramParser(SPECIFICATION) parsed_telegram = parser.parse(telegram.split("\r\n")) log_consumed_electricity(user=user, parsed_telegram=parsed_telegram) log_produced_energy(user=user, parsed_telegram=parsed_telegram) log_consumed_gas(user=user, parsed_telegram=parsed_telegram)
def telegram_to_reading(data: str) -> DsmrReading: """ Converts a P1 telegram to a DSMR reading, which will be stored in database. """ params = get_dsmr_connection_parameters() parser = TelegramParser(params['specifications']) logger.debug("Received telegram:\n%s", data) try: parsed_telegram = parser.parse(data) except (InvalidChecksumError, ParseError) as error: # Hook to keep track of failed readings count. MeterStatistics.objects.all().update( rejected_telegrams=F('rejected_telegrams') + 1) logger.warning('Rejected telegram: %s', error) raise InvalidTelegramError(error) from error return _map_telegram_to_model(parsed_telegram=parsed_telegram, data=data)
def analyze(self): key = binascii.unhexlify(self._args.key) additional_data = binascii.unhexlify(self._args.aad) iv = binascii.unhexlify(self._system_title + self._frame_counter) payload = binascii.unhexlify(self._payload) gcm_tag = binascii.unhexlify(self._gcm_tag) try: decryption = self.decrypt(key, additional_data, iv, payload, gcm_tag) if has_dsmr_parser and self._args.parse: try: parser = TelegramParser(telegram_specifications.V5) telegram = parser.parse(decryption.decode()) for key in telegram: if key in dsmr_parser.obis_name_mapping.EN: print("%s: %s" % (dsmr_parser.obis_name_mapping.EN[key], telegram[key])) if has_mqtt: try: self._mqtt_client.publish( self._args.topic_prefix + '/' + dsmr_parser.obis_name_mapping.EN[key], str(telegram[key].value)) except: print("ERROR: cannot publish to MQTT") else: print("%s: %s" % (key, telegram[key])) except Exception as e: print("ERROR: Cannot parse DSMR Telegram") print("Exception: ", sys.exc_info()[0]) print(decryption) else: print(decryption) if self._args.serial_output_port: self.write_to_serial_port(decryption) except InvalidTag: print("ERROR: Invalid Tag.")
def telegram_to_reading(data): """ Converts a P1 telegram to a DSMR reading, which will be stored in database. """ params = get_dsmr_connection_parameters() parser = TelegramParser(params['specifications']) # We will log the telegrams in base64 for convenience and debugging. base64_data = base64.b64encode(data.encode()) if settings.DSMRREADER_LOG_TELEGRAMS: dsmrreader_logger.info('Received telegram (base64 encoded): %s', base64_data) try: parsed_telegram = parser.parse(data) except (InvalidChecksumError, ParseError) as error: # Hook to keep track of failed readings count. MeterStatistics.objects.all().update( rejected_telegrams=F('rejected_telegrams') + 1) dsmrreader_logger.warning( 'Rejected telegram (%s) (base64 encoded): %s', error, base64_data) dsmrreader_logger.exception(error) raise InvalidTelegramError(error) return _map_telegram_to_model(parsed_telegram=parsed_telegram, data=data)
class Terminal(object): def __init__( self, config, logger, hass_api, terminal_name, dsmr_serial_callback, dsmr_version, ): self.config = config self.logger = logger self.hass_api = hass_api self.terminal_name = terminal_name self.dsmr_serial_callback = dsmr_serial_callback self.mode = self.config.get(f"dsmr.{self.terminal_name}", "mode", "device") if self.mode not in ["tcp", "device"]: hybridlogger.ha_log( self.logger, self.hass_api, "ERROR", f"DSMR terminal {self.terminal_name} mode {self.mode} is not valid. " "Should be tcp or device. Ignoring DSMR configuration!", ) return self.device = self.config.get( f"dsmr.{self.terminal_name}", "device", "/dev/ttyUSB0" ) self.host = self.config.get(f"dsmr.{self.terminal_name}", "host", "localhost") self.port = self.config.get(f"dsmr.{self.terminal_name}", "port", "3333") self.dsmr_version = dsmr_version # start terminal self.stop = False hybridlogger.ha_log( self.logger, self.hass_api, "INFO", f"Initializing DSMR termimal '{terminal_name}'. Mode: {self.mode}.", ) if self.mode == "tcp": self.thr = threading.Thread( target=self._run_tcp_terminal, name=self.terminal_name ) elif self.mode == "device": self.thr = threading.Thread( target=self._run_serial_terminal, name=self.terminal_name ) self.thr.start() def terminate(self): self.stop = True # Wait for Thread to shutdown self.thr.join() def _get_dsmr_parser(self): dsmr_version = self.dsmr_version if dsmr_version == "2.2": specification = telegram_specifications.V2_2 serial_settings = SERIAL_SETTINGS_V2_2 elif dsmr_version == "4": specification = telegram_specifications.V4 serial_settings = SERIAL_SETTINGS_V4 elif dsmr_version == "5": specification = telegram_specifications.V5 serial_settings = SERIAL_SETTINGS_V5 elif dsmr_version == "5B": specification = telegram_specifications.BELGIUM_FLUVIUS serial_settings = SERIAL_SETTINGS_V5 else: raise NotImplementedError( "No telegram parser found for version: %s", dsmr_version ) self.telegram_parser = TelegramParser(specification) serial_settings["timeout"] = 10 self.serial_settings = serial_settings def _dsmr_data_received(self, data): """Add incoming data to buffer.""" data = data.decode("ascii") self.telegram_buffer.append(data) for telegram in self.telegram_buffer.get_all(): self._handle_telegram(telegram) def _handle_telegram(self, telegram): """Send off parsed telegram to handling callback.""" try: parsed_telegram = self.telegram_parser.parse(telegram) except InvalidChecksumError as e: self.logger.warning(str(e)) except ParseError: self.logger.exception("failed to parse telegram") else: self.dsmr_serial_callback(parsed_telegram) def _run_tcp_terminal(self): self._get_dsmr_parser() # buffer to keep incomplete incoming data while not self.stop: hybridlogger.ha_log( self.logger, self.hass_api, "INFO", f"DSMR terminal {self.terminal_name} was started.", ) try: self.telegram_buffer = TelegramBuffer() server_address = (self.host, self.port) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.settimeout(5) self.sock.connect(server_address) while not self.stop: data = self.sock.recv(1024) if not data and not self.stop: hybridlogger.ha_log( self.logger, self.hass_api, "INFO", f"DSMR terminal {self.terminal_name} was interrupted and will be restarted.", ) time.sleep(5) break elif data: self._dsmr_data_received(data) except Exception as e: if not self.stop: hybridlogger.ha_log( self.logger, self.hass_api, "WARNING", f"DSMR terminal {self.terminal_name} was interrupted " f"and will be restarted in a few moments: {e}", ) traceback.print_exception(*sys.exc_info()) time.sleep(5) finally: self.sock.close() def _run_serial_terminal(self): self._get_dsmr_parser() # buffer to keep incomplete incoming data while not self.stop: hybridlogger.ha_log( self.logger, self.hass_api, "INFO", f"DSMR terminal {self.terminal_name} was started.", ) try: self.telegram_buffer = TelegramBuffer() self.sock = serial.Serial(port=self.device, **self.serial_settings) while not self.stop: data = self.sock.read_until() if not data and not self.stop: hybridlogger.ha_log( self.logger, self.hass_api, "INFO", f"DSMR terminal {self.terminal_name} was interrupted and will be restarted.", ) time.sleep(5) break elif data: self._dsmr_data_received(data) except Exception as e: if not self.stop: hybridlogger.ha_log( self.logger, self.hass_api, "WARNING", f"DSMR terminal {self.terminal_name} was interrupted " f"and will be restarted in a few moments: {e.args}", ) time.sleep(5) finally: self.sock.close()
def test_parse(self): parser = TelegramParser(telegram_specifications.V5) result = parser.parse(TELEGRAM_V5) # P1_MESSAGE_HEADER (1-3:0.2.8) assert isinstance(result[obis.P1_MESSAGE_HEADER], CosemObject) assert result[obis.P1_MESSAGE_HEADER].unit is None assert isinstance(result[obis.P1_MESSAGE_HEADER].value, str) assert result[obis.P1_MESSAGE_HEADER].value == '50' # P1_MESSAGE_TIMESTAMP (0-0:1.0.0) assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP], CosemObject) assert result[obis.P1_MESSAGE_TIMESTAMP].unit is None assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP].value, datetime.datetime) assert result[obis.P1_MESSAGE_TIMESTAMP].value == \ datetime.datetime(2017, 1, 2, 18, 20, 2, tzinfo=datetime.timezone.utc) # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal('4.426') # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal('2.399') # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal( '2.444') # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal( '0') # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0) assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0002' # EQUIPMENT_IDENTIFIER (0-0:96.1.1) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str) assert result[ obis. EQUIPMENT_IDENTIFIER].value == '4B384547303034303436333935353037' # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject) assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('0.244') # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0') # LONG_POWER_FAILURE_COUNT (96.7.9) assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT], CosemObject) assert result[obis.LONG_POWER_FAILURE_COUNT].unit is None assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT].value, int) assert result[obis.LONG_POWER_FAILURE_COUNT].value == 0 # VOLTAGE_SAG_L1_COUNT (1-0:32.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L1_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L1_COUNT].value == 0 # VOLTAGE_SAG_L2_COUNT (1-0:52.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L2_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L2_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L2_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L2_COUNT].value == 0 # VOLTAGE_SAG_L3_COUNT (1-0:72.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L3_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L3_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L3_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L3_COUNT].value == 0 # VOLTAGE_SWELL_L1_COUNT (1-0:32.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L1_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L1_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L1_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L1_COUNT].value == 0 # VOLTAGE_SWELL_L2_COUNT (1-0:52.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L2_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L2_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L2_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L2_COUNT].value == 0 # VOLTAGE_SWELL_L3_COUNT (1-0:72.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L3_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L3_COUNT].value == 0 # TEXT_MESSAGE (0-0:96.13.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.TEXT_MESSAGE].unit is None assert result[obis.TEXT_MESSAGE].value is None # DEVICE_TYPE (0-x:24.1.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.DEVICE_TYPE].unit is None assert isinstance(result[obis.DEVICE_TYPE].value, int) assert result[obis.DEVICE_TYPE].value == 3 # INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value == Decimal( '0.070') # INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE (1-0:41.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value == Decimal( '0.032') # INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE (1-0:61.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value == Decimal( '0.142') # INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE (1-0:22.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value == Decimal('0') # INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE (1-0:42.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value == Decimal('0') # INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE (1-0:62.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value == Decimal('0') # EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS].value, str) assert result[ obis. EQUIPMENT_IDENTIFIER_GAS].value == '3232323241424344313233343536373839' # HOURLY_GAS_METER_READING (0-1:24.2.1) assert isinstance(result[obis.HOURLY_GAS_METER_READING], MBusObject) assert result[obis.HOURLY_GAS_METER_READING].unit == 'm3' assert isinstance(result[obis.HOURLY_GAS_METER_READING].value, Decimal) assert result[obis.HOURLY_GAS_METER_READING].value == Decimal('0.107')
def test_parse(self): parser = TelegramParser(telegram_specifications.V4) result = parser.parse(TELEGRAM_V4_2) # P1_MESSAGE_HEADER (1-3:0.2.8) assert isinstance(result[obis.P1_MESSAGE_HEADER], CosemObject) assert result[obis.P1_MESSAGE_HEADER].unit is None assert isinstance(result[obis.P1_MESSAGE_HEADER].value, str) assert result[obis.P1_MESSAGE_HEADER].value == '42' # P1_MESSAGE_TIMESTAMP (0-0:1.0.0) assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP], CosemObject) assert result[obis.P1_MESSAGE_TIMESTAMP].unit is None assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP].value, datetime.datetime) assert result[obis.P1_MESSAGE_TIMESTAMP].value == \ datetime.datetime(2016, 11, 13, 19, 57, 57, tzinfo=pytz.UTC) # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal('1511.267') # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal('1265.173') # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal('0') # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal('0') # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0) assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0001' # EQUIPMENT_IDENTIFIER (0-0:96.1.1) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str) assert result[obis.EQUIPMENT_IDENTIFIER].value == '1231231231231231231231231231231231' # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject) assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('0.235') # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0') # LONG_POWER_FAILURE_COUNT (96.7.9) assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT], CosemObject) assert result[obis.LONG_POWER_FAILURE_COUNT].unit is None assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT].value, int) assert result[obis.LONG_POWER_FAILURE_COUNT].value == 7 # VOLTAGE_SAG_L1_COUNT (1-0:32.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L1_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L1_COUNT].value == 0 # VOLTAGE_SAG_L2_COUNT (1-0:52.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L2_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L2_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L2_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L2_COUNT].value == 0 # VOLTAGE_SAG_L3_COUNT (1-0:72.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L3_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L3_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L3_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L3_COUNT].value == 0 # VOLTAGE_SWELL_L1_COUNT (1-0:32.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L1_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L1_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L1_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L1_COUNT].value == 0 # VOLTAGE_SWELL_L2_COUNT (1-0:52.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L2_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L2_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L2_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L2_COUNT].value == 0 # VOLTAGE_SWELL_L3_COUNT (1-0:72.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L3_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L3_COUNT].value == 0 # TEXT_MESSAGE_CODE (0-0:96.13.1) assert isinstance(result[obis.TEXT_MESSAGE_CODE], CosemObject) assert result[obis.TEXT_MESSAGE_CODE].unit is None assert result[obis.TEXT_MESSAGE_CODE].value is None # TEXT_MESSAGE (0-0:96.13.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.TEXT_MESSAGE].unit is None assert result[obis.TEXT_MESSAGE].value is None # DEVICE_TYPE (0-x:24.1.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.DEVICE_TYPE].unit is None assert isinstance(result[obis.DEVICE_TYPE].value, int) assert result[obis.DEVICE_TYPE].value == 3 # INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].unit == 'kW' assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value, Decimal) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value == Decimal('0.095') # INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE (1-0:41.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].unit == 'kW' assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value, Decimal) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value == Decimal('0.025') # INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE (1-0:61.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].unit == 'kW' assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value, Decimal) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value == Decimal('0.115') # INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE (1-0:22.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].unit == 'kW' assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value, Decimal) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value == Decimal('0') # INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE (1-0:42.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].unit == 'kW' assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value, Decimal) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value == Decimal('0') # INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE (1-0:62.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].unit == 'kW' assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value, Decimal) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value == Decimal('0') # EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS].value, str) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].value == '3404856892390357246729543587524029' # HOURLY_GAS_METER_READING (0-1:24.2.1) assert isinstance(result[obis.HOURLY_GAS_METER_READING], MBusObject) assert result[obis.HOURLY_GAS_METER_READING].unit == 'm3' assert isinstance(result[obis.HOURLY_GAS_METER_READING].value, Decimal) assert result[obis.HOURLY_GAS_METER_READING].value == Decimal('915.219')
def test_parse(self): parser = TelegramParser(telegram_specifications.V4) result = parser.parse(TELEGRAM_V4_2) # P1_MESSAGE_HEADER (1-3:0.2.8) assert isinstance(result[obis.P1_MESSAGE_HEADER], CosemObject) assert result[obis.P1_MESSAGE_HEADER].unit is None assert isinstance(result[obis.P1_MESSAGE_HEADER].value, str) assert result[obis.P1_MESSAGE_HEADER].value == '42' # P1_MESSAGE_TIMESTAMP (0-0:1.0.0) assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP], CosemObject) assert result[obis.P1_MESSAGE_TIMESTAMP].unit is None assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP].value, datetime.datetime) assert result[obis.P1_MESSAGE_TIMESTAMP].value == \ datetime.datetime(2016, 11, 13, 19, 57, 57, tzinfo=pytz.UTC) # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal( '1581.123') # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal( '1435.706') # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal( '0') # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal( '0') # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0) assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0002' # EQUIPMENT_IDENTIFIER (0-0:96.1.1) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str) assert result[ obis. EQUIPMENT_IDENTIFIER].value == '3960221976967177082151037881335713' # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject) assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('2.027') # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0') # LONG_POWER_FAILURE_COUNT (96.7.9) assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT], CosemObject) assert result[obis.LONG_POWER_FAILURE_COUNT].unit is None assert isinstance(result[obis.LONG_POWER_FAILURE_COUNT].value, int) assert result[obis.LONG_POWER_FAILURE_COUNT].value == 7 # VOLTAGE_SAG_L1_COUNT (1-0:32.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L1_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L1_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L1_COUNT].value == 0 # VOLTAGE_SAG_L2_COUNT (1-0:52.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L2_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L2_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L2_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L2_COUNT].value == 0 # VOLTAGE_SAG_L3_COUNT (1-0:72.32.0) assert isinstance(result[obis.VOLTAGE_SAG_L3_COUNT], CosemObject) assert result[obis.VOLTAGE_SAG_L3_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SAG_L3_COUNT].value, int) assert result[obis.VOLTAGE_SAG_L3_COUNT].value == 0 # VOLTAGE_SWELL_L1_COUNT (1-0:32.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L1_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L1_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L1_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L1_COUNT].value == 0 # VOLTAGE_SWELL_L2_COUNT (1-0:52.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L2_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L2_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L2_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L2_COUNT].value == 0 # VOLTAGE_SWELL_L3_COUNT (1-0:72.36.0) assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT], CosemObject) assert result[obis.VOLTAGE_SWELL_L3_COUNT].unit is None assert isinstance(result[obis.VOLTAGE_SWELL_L3_COUNT].value, int) assert result[obis.VOLTAGE_SWELL_L3_COUNT].value == 0 # TEXT_MESSAGE_CODE (0-0:96.13.1) assert isinstance(result[obis.TEXT_MESSAGE_CODE], CosemObject) assert result[obis.TEXT_MESSAGE_CODE].unit is None assert result[obis.TEXT_MESSAGE_CODE].value is None # TEXT_MESSAGE (0-0:96.13.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.TEXT_MESSAGE].unit is None assert result[obis.TEXT_MESSAGE].value is None # DEVICE_TYPE (0-x:24.1.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.DEVICE_TYPE].unit is None assert isinstance(result[obis.DEVICE_TYPE].value, int) assert result[obis.DEVICE_TYPE].value == 3 # INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value == Decimal( '0.170') # INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE (1-0:41.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value == Decimal( '1.247') # INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE (1-0:61.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value == Decimal( '0.209') # INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE (1-0:22.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value == Decimal('0') # INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE (1-0:42.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value == Decimal('0') # INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE (1-0:62.7.0) assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE], CosemObject) assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].unit == 'kW' assert isinstance( result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value, Decimal) assert result[ obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value == Decimal('0') # EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS].value, str) assert result[ obis. EQUIPMENT_IDENTIFIER_GAS].value == '4819243993373755377509728609491464' # HOURLY_GAS_METER_READING (0-1:24.2.1) assert isinstance(result[obis.HOURLY_GAS_METER_READING], MBusObject) assert result[obis.HOURLY_GAS_METER_READING].unit == 'm3' assert isinstance(result[obis.HOURLY_GAS_METER_READING].value, Decimal) assert result[obis.HOURLY_GAS_METER_READING].value == Decimal( '981.443')
class P1test(hass.Hass): def _logme(self, line): print(line) def initialize(self, *args, **kwargs): try: self.log("Using hass logger!") except Exception: self.log = self._logme self.log("Using test logger!") self.mode = 'tcp' self.host = 'homeassistant.fritz.box' self.port = 3333 self.device = 'COM3' self.dsmr_version = '5' self.terminal_name = 'test' self.stop = False self.transport = None self.log("Starting thread...") self.log("P1 test started") parser = self.test_serial # parser = self.tcp dsmr_version = self.dsmr_version if dsmr_version == '2.2': specification = telegram_specifications.V2_2 serial_settings = SERIAL_SETTINGS_V2_2 elif dsmr_version == '4': specification = telegram_specifications.V4 serial_settings = SERIAL_SETTINGS_V4 elif dsmr_version == '5': specification = telegram_specifications.V5 serial_settings = SERIAL_SETTINGS_V5 elif dsmr_version == '5B': specification = telegram_specifications.BELGIUM_FLUVIUS serial_settings = SERIAL_SETTINGS_V5 else: raise NotImplementedError( "No telegram parser found for version: %s", dsmr_version) self.telegram_parser = TelegramParser(specification) self.serial_settings = serial_settings # buffer to keep incomplete incoming data self.telegram_buffer = TelegramBuffer() self.thr = threading.Thread(target=parser, daemon=True) self.thr.start() self.log("Started!") # logging.basicConfig(level=logging.DEBUG) def dsmr_serial_callback(self, telegram): self.log('Telegram received') def terminate(self): self.stop = True self.log("Closing transport...") if self.transport: self.transport.close() self.thr.join(10) # Stopping loop the hard if self.thr.is_alive(): self.log( "Stopping the loop unfortunally did not stop the thread, waiting for completion..." ) else: self.log("Thread exited nicely") self.thr.join() self.log("Thread has stopped!") def test_serial(self): s = serial.Serial(port=self.device, **self.serial_settings) while not self.stop: data = s.read_until() print(f'{data}') self.data_received(data) s.close() def test_tcp(self): server_address = (self.host, self.port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(server_address) while not self.stop: data = sock.recv(1024) self.data_received(data) sock.close() def data_received(self, data): """Add incoming data to buffer.""" data = data.decode('ascii') self.telegram_buffer.append(data) for telegram in self.telegram_buffer.get_all(): self.handle_telegram(telegram) def handle_telegram(self, telegram): """Send off parsed telegram to handling callback.""" try: parsed_telegram = self.telegram_parser.parse(telegram) except InvalidChecksumError as e: self.log.warning(str(e)) except ParseError: self.log.exception("failed to parse telegram") else: self.dsmr_serial_callback(parsed_telegram)
def test_parse(self): parser = TelegramParser(telegram_specifications.V3) result = parser.parse(TELEGRAM_V3) # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal( '12345.678') # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal( '12345.678') # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal( '12345.678') # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal( '12345.678') # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0) assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0002' # EQUIPMENT_IDENTIFIER (0-0:96.1.1) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str) assert result[ obis. EQUIPMENT_IDENTIFIER].value == '4B384547303034303436333935353037' # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject) assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('1.19') # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0') # TEXT_MESSAGE_CODE (0-0:96.13.1) assert isinstance(result[obis.TEXT_MESSAGE_CODE], CosemObject) assert result[obis.TEXT_MESSAGE_CODE].unit is None assert isinstance(result[obis.TEXT_MESSAGE_CODE].value, int) assert result[obis.TEXT_MESSAGE_CODE].value == 303132333435363738 # TEXT_MESSAGE (0-0:96.13.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.TEXT_MESSAGE].unit is None assert isinstance(result[obis.TEXT_MESSAGE].value, str) assert result[obis.TEXT_MESSAGE].value == \ '303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E3F' \ '303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E3F' \ '303132333435363738393A3B3C3D3E3F' # DEVICE_TYPE (0-x:24.1.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.DEVICE_TYPE].unit is None assert isinstance(result[obis.DEVICE_TYPE].value, str) assert result[obis.DEVICE_TYPE].value == '03' # EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS].value, str) assert result[ obis. EQUIPMENT_IDENTIFIER_GAS].value == '3232323241424344313233343536373839' # GAS_METER_READING (0-1:24.3.0) assert isinstance(result[obis.GAS_METER_READING], MBusObject) assert result[obis.GAS_METER_READING].unit == 'm3' assert isinstance(result[obis.GAS_METER_READING].value, Decimal) assert result[obis.GAS_METER_READING].value == Decimal('1.001')
class SocketReader(object): BUFFER_SIZE = 256 def __init__(self, host, port, telegram_specification): self.host = host self.port = port self.telegram_parser = TelegramParser(telegram_specification) self.telegram_buffer = TelegramBuffer() self.telegram_specification = telegram_specification def read(self): """ Read complete DSMR telegram's from remote interface and parse it into CosemObject's and MbusObject's :rtype: generator """ buffer = b"" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_handle: socket_handle.connect((self.host, self.port)) while True: buffer += socket_handle.recv(self.BUFFER_SIZE) lines = buffer.splitlines(keepends=True) if len(lines) == 0: continue for data in lines: self.telegram_buffer.append(data.decode('ascii')) for telegram in self.telegram_buffer.get_all(): try: yield self.telegram_parser.parse(telegram) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: logger.error('Failed to parse telegram: %s', e) buffer = b"" def read_as_object(self): """ Read complete DSMR telegram's from remote and return a Telegram object. :rtype: generator """ buffer = b"" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_handle: socket_handle.connect((self.host, self.port)) while True: buffer += socket_handle.recv(self.BUFFER_SIZE) lines = buffer.splitlines(keepends=True) if len(lines) == 0: continue for data in lines: self.telegram_buffer.append(data.decode('ascii')) for telegram in self.telegram_buffer.get_all(): try: yield Telegram(telegram, self.telegram_parser, self.telegram_specification) except InvalidChecksumError as e: logger.warning(str(e)) except ParseError as e: logger.error('Failed to parse telegram: %s', e) buffer = b""
def test_parse(self): parser = TelegramParser(telegram_specifications.V2_2) result = parser.parse(TELEGRAM_V2_2) # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal('1.001') # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2) assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal('1.001') # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal( '1.001') # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2) assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh' assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal) assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal( '1.001') # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0) assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str) assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0001' # EQUIPMENT_IDENTIFIER (0-0:96.1.1) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str) assert result[obis.EQUIPMENT_IDENTIFIER].value == '00000000000000' # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject) assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('1.01') # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0) assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW' assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal) assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0') # TEXT_MESSAGE_CODE (0-0:96.13.1) assert isinstance(result[obis.TEXT_MESSAGE_CODE], CosemObject) assert result[obis.TEXT_MESSAGE_CODE].unit is None # TEXT_MESSAGE (0-0:96.13.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.TEXT_MESSAGE].unit is None assert result[obis.TEXT_MESSAGE].value is None # DEVICE_TYPE (0-x:24.1.0) assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) assert result[obis.DEVICE_TYPE].unit is None assert isinstance(result[obis.DEVICE_TYPE].value, str) assert result[obis.DEVICE_TYPE].value == '3' # EQUIPMENT_IDENTIFIER_GAS (0-x:96.1.0) assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS], CosemObject) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].unit is None assert isinstance(result[obis.EQUIPMENT_IDENTIFIER_GAS].value, str) assert result[obis.EQUIPMENT_IDENTIFIER_GAS].value == '000000000000' # GAS_METER_READING (0-1:24.3.0) assert isinstance(result[obis.GAS_METER_READING], MBusObject) assert result[obis.GAS_METER_READING].unit == 'm3' assert isinstance(result[obis.GAS_METER_READING].value, Decimal) assert result[obis.GAS_METER_READING].value == Decimal('1.001')