def __parse(sml_frame: SmlFrame) -> tp.Optional[Sample]: """ Internal helper to extract relevant information :param sml_frame: SmlFrame from parser """ sample = None for sml_mesage in sml_frame: if 'messageBody' in sml_mesage: sml_list: tp.List[SmlListEntry] = sml_mesage[ 'messageBody'].get('valList', []) for sml_entry in sml_list: if sample is None: sample = Sample() obis_code: str = sml_entry.get('objName', '') value = sml_entry.get('value', '') # Differentiate SML Messages based on whether they contain a unit if 'unit' in sml_entry: sample.channels.append( ChannelValue(obis_code, value, sml_entry.get('unit'))) else: # Determine the meter_id from OBIS code if obis_code in SmlReader.OBIS_CODES_METER_ID: sample.meter_id = value # Add Channels without unit else: sample.channels.append( ChannelValue(obis_code, value)) return sample
def __init__(self) -> None: test_data = SerialTestData( binary= b'\x1b\x1b\x1b\x1b\x01\x01\x01\x01v\x07\x00\x07\r\xf8\xb2\xd7b\x00b\x00rc\x01\x01v\x01\x01\x07\x00\x07\x0b?;\x9d\x0b\t\x01EMH\x00\x00K\x18\xe2\x01\x01cXk\x00v\x07\x00\x07\r\xf8\xb2\xd8b\x00b\x00rc\x07\x01w\x01\x0b\t\x01EMH\x00\x00K\x18\xe2\x07\x01\x00b\n\xff\xffrb\x01e\x0b?\xeejzw\x07\x81\x81\xc7\x82\x03\xff\x01\x01\x01\x01\x04EMH\x01w\x07\x01\x00\x00\x00\t\xff\x01\x01\x01\x01\x0b\t\x01EMH\x00\x00K\x18\xe2\x01w\x07\x01\x00\x01\x08\x00\xffd\x01\x01\xa2\x01b\x1eR\xffV\x00\x10T\xf2\xfe\x01w\x07\x01\x00\x02\x08\x00\xffd\x01\x01\xa2\x01b\x1eR\xffV\x00\x0bHz\xf0\x01w\x07\x01\x00\x01\x08\x01\xff\x01\x01b\x1eR\xffV\x00\x10T\xf2\xfe\x01w\x07\x01\x00\x02\x08\x01\xff\x01\x01b\x1eR\xffV\x00\x0bHz\xf0\x01w\x07\x01\x00\x01\x08\x02\xff\x01\x01b\x1eR\xffV\x00\x00\x00\x00\x00\x01w\x07\x01\x00\x02\x08\x02\xff\x01\x01b\x1eR\xffV\x00\x00\x00\x00\x00\x01w\x07\x01\x00\x10\x07\x00\xff\x01\x01b\x1bR\xffU\xff\xff\xf3\xfa\x01w\x07\x81\x81\xc7\x82\x05\xff\x01rb\x01e\x0b?\xeej\x01\x01\x83\x02X\xaf(\x9aa\x13R\x98L\xf8R\x95#~\xf2fp\xcb=6~!\x8bH\xd9Rx\x9f\xc4\xa5\x88\x86\x04\x01+24\x90\xce\xd3\xd9m4\x1c\x9e\x9c\xcfw\x01\x01\x01c[\x12\x00v\x07\x00\x07\r\xf8\xb2\xdbb\x00b\x00rc\x02\x01q\x01c;\x15\x00\x00\x1b\x1b\x1b\x1b\x1a\x01\x1b\xe1', meter_id='1 EMH 00 4921570', channels=[ ChannelValue(channel_name='129-129:199.130.3*255', value='EMH', unit=None), ChannelValue(channel_name='1-0:1.8.0*255', value=27400268.6, unit='Wh'), ChannelValue(channel_name='1-0:2.8.0*255', value=18929944.0, unit='Wh'), ChannelValue(channel_name='1-0:1.8.1*255', value=27400268.6, unit='Wh'), ChannelValue(channel_name='1-0:2.8.1*255', value=18929944.0, unit='Wh'), ChannelValue(channel_name='1-0:1.8.2*255', value=0, unit='Wh'), ChannelValue(channel_name='1-0:2.8.2*255', value=0, unit='Wh'), ChannelValue(channel_name='1-0:16.7.0*255', value=-307.8, unit='W'), ChannelValue( channel_name='129-129:199.130.5*255', value= '58af289a611352984cf85295237ef26670cb3d367e218b48d952789fc4a5888604012b323490ced3d96d341c9e9ccf77', unit=None) ]) super().__init__(test_data)
def __init__(self) -> None: start_sequence = b"/?!\x0D\x0A" test_frame = b'\x026.8(0006047*kWh)6.26(00428.35*m3)9.21(99999999)\r\n' test_data = SerialTestData(binary=start_sequence + test_frame, meter_id='99999999', channels=[ ChannelValue(channel_name='6.8', value=6047.0, unit='kWh'), ChannelValue(channel_name='6.26', value=428.35, unit='m3') ]) super().__init__(test_data)
def _fetch_untracked(self) -> tp.Optional[Sample]: with self.__access_lock: if self.__fetch_possible: self.counter += 1 return Sample(meter_id=self.sample_meter_id, channels=[ChannelValue("COUNTER", self.counter)]) return None
def __init__(self) -> None: test_data = SerialTestData( binary= b'\x1b\x1b\x1b\x1b\x01\x01\x01\x01v\x05\tLN\x1db\x00b\x00rc\x01\x01v\x01\x01\x05\x03\x19o_\x0b\n\x01ISK\x00\x045\xa9.rb\x01e\x03\x19p#b\x01c\xfe\x90\x00v\x05\tLN\x1eb\x00b\x00rc\x07\x01w\x01\x0b\n\x01ISK\x00\x045\xa9.\x07\x01\x00b\n\xff\xffrb\x01e\x03\x19p#uw\x07\x01\x00`2\x01\x01\x01\x01\x01\x01\x04ISK\x01w\x07\x01\x00`\x01\x00\xff\x01\x01\x01\x01\x0b\n\x01ISK\x00\x045\xa9.\x01w\x07\x01\x00\x01\x08\x00\xffe\x00\x1c)\x04\x01b\x1eR\xffe\x01"\xd9\x15\x01w\x07\x01\x00\x02\x08\x00\xff\x01\x01b\x1eR\xffe\x02\x8d\x94\x85\x01w\x07\x01\x00\x10\x07\x00\xff\x01\x01b\x1bR\x00S\xfe\xe4\x01\x01\x01c\xd6\xd5\x00v\x05\tLN\x1fb\x00b\x00rc\x02\x01q\x01cW\xe6\x00\x00\x1b\x1b\x1b\x1b\x1a\x01\x0b\x83', meter_id='1 ISK 00 70625582', channels=[ ChannelValue(channel_name='1-0:96.50.1*1', value=b'ISK', unit=None), ChannelValue(channel_name='1-0:1.8.0*255', value=1906101.3, unit='Wh'), ChannelValue(channel_name='1-0:2.8.0*255', value=4283302.9, unit='Wh'), ChannelValue(channel_name='1-0:16.7.0*255', value=-284, unit='W') ]) super().__init__(test_data)
def __parse(response: str) -> tp.Optional[Sample]: """ Internal helper to extract relevant information :param response: decoded line """ parsed = None for ident, value, unit in re.findall(r"([\d.]+)\(([\d.]+)\*?([\w\d.]+)?\)", response): if parsed is None: parsed = Sample() if not unit and ident == "9.21": parsed.meter_id = value else: parsed.channels.append(ChannelValue(ident, float(value), unit)) return parsed
def __exit__(self, exit_type, value, traceback) -> None: self.open = False REG_ADDR_CHIP_ID = 0xD0 REG_ADDR_MEASUREMENT_START = 0xF7 REG_ADDR_CALIBRATION1_START = 0x88 REG_ADDR_CALIBRATION2_START = 0xE1 REG_ADDR_STATUS = 0xF3 bm280_testdata = I2CTestData( meter_id= "BME280-078fc53ee157b535d787a94e8ac2f05ed6083c8d21ef77389021ae97961d7d0a", channels=[ ChannelValue(channel_name="TEMPERATURE", value=19.272266477266385, unit="°C"), ChannelValue(channel_name="PRESSURE", value=99855.59723964224, unit="Pa"), ChannelValue(channel_name="HUMIDITY", value=50.935725617532256, unit="%") ], static_registers={ REG_ADDR_CHIP_ID: 0x60, REG_ADDR_STATUS: 0b00000000, REG_ADDR_MEASUREMENT_START + 0: 83, REG_ADDR_MEASUREMENT_START + 1: 224, REG_ADDR_MEASUREMENT_START + 2: 0, REG_ADDR_MEASUREMENT_START + 3: 126,
} }, 'id': 118, 'protocol': 'BME280' } }, 'middleware': { 'type': 'volkszaehler', 'middleware_url': 'http://localhost/middleware.php' } } SAMPLE_BME = Sample() SAMPLE_BME.meter_id = '0x76' SAMPLE_BME.channels = [ ChannelValue('TEMPERATURE', 20.0, 'C'), ChannelValue('HUMIDITY', 50.0, '%'), ChannelValue('PRESSURE', 1000.0, 'hPa') ] SAMPLE_SML = Sample() SAMPLE_SML.meter_id = '1 EMH00 12345678' SAMPLE_SML.channels = [ChannelValue('1.8.0*255', 10000, 'kWh')] SAMPLE_PLAIN = Sample() SAMPLE_PLAIN.meter_id = '888777666' SAMPLE_PLAIN.channels = [ChannelValue('6.8', 20000, 'kWh')] class MockedGateway(VolkszaehlerGateway): def post(self, channel, value, sample_timestamp, poll_timestamp):
def _fetch_untracked(self) -> tp.Optional[Sample]: # pylint: disable=too-many-locals try: with Bme280Reader.I2C_BUS_LOCK: with SMBus(self.i2c_bus) as bus: # Read Chip ID chip_id = bus.read_byte_data(self.i2c_address, Bme280Reader.REG_ADDR_CHIP_ID) if self.__calibration_data is None or not self.cache_calibration: self.__calibration_data = self.__read_calibration_data(bus) else: logger.debug("Using cached calibration data") calibration_data = self.__calibration_data # Reconfigure sensor if self.__reconfiguration_required or self.mode is Bme280SensorMode.FORCED: # Reset sensor to sleep mode for reconfiguration self.__reset(bus) logger.debug("Reconfiguring sensor") # Configure humidity self.__set_register_ctrl_hum(bus, self.humidity_oversampling) # Configure other measurement parameters self.__set_register_config(bus, self.standby_time, self.irr_filter_coefficient) # Activate configuration self.__set_register_ctrl_meas(bus, self.mode, self.temperature_oversampling, self.pressure_oversampling) self.__reconfiguration_required = False # Wait for the measurement if running in forced mode if self.mode is Bme280SensorMode.FORCED: logger.debug("Waiting for measurement to complete in forced mode") osrs_t_time = 2.3 * self.temperature_oversampling osrs_p_time = 2.3 * self.pressure_oversampling + 0.575 osrs_h_time = 2.3 * self.humidity_oversampling + 0.575 measurement_time = 1.25 + osrs_t_time + osrs_p_time + osrs_h_time # Wait for measurement to complete time.sleep(measurement_time / 1000) # Read measuring status measuring, _ = self.__read_status(bus) if measuring: logger.error("Measurement is still in progress after maximum measurement time! Aborting...") return None # Read measurement registers logger.debug("Reading measurement registers") measurement = bus.read_i2c_block_data(self.i2c_address, Bme280Reader.REG_ADDR_MEASUREMENT_START, 8) # Parse measurement logger.debug("Parsing measurement") measurement_container = Bme280Reader.STRUCT_MEASUREMENT.parse(bytes(measurement)) # Calculate fine temperature to enable temperature compensation for the other measurements fine_temperature = Bme280Reader.calculate_fine_temperature(calibration_data, measurement_container.temp_raw) # Calculate measurement results temperature = Bme280Reader.calculate_temperature(fine_temperature) pressure = Bme280Reader.calculate_pressure(calibration_data, measurement_container.press_raw, fine_temperature) humidity = Bme280Reader.calculate_humidity(calibration_data, measurement_container.hum_raw, fine_temperature) # Determine meter_id meter_id = Bme280Reader.derive_meter_id(calibration_data, chip_id) # Return Sample return Sample(meter_id=meter_id, channels=[ChannelValue('TEMPERATURE', temperature, '°C'), ChannelValue('PRESSURE', pressure, 'Pa'), ChannelValue('HUMIDITY', humidity, '%')]) except OSError as err: logger.error(f"Accessing the smbus faild: {err}") except ConstructError as err: logger.error(f"Parsing the binary data failed: {err}") return None