From b0fe361486349c4a73979f3a8a1f0ceffbe9fed1 Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Thu, 29 Dec 2022 21:49:42 +0000 Subject: [PATCH 01/10] Make RTS setting configurable --- smeterd/meter.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index 740e009..70d6fe4 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -20,10 +20,15 @@ class SmartMeter(object): 'xonxoff': False, 'timeout': 10, } + serial_rts = False def __init__(self, port, **kwargs): config = {} config.update(self.serial_defaults) + + # This is quite uggly. The config part should probably be rewritten. + self.serial_rts = kwargs['rts'] + del kwargs['rts'] config.update(kwargs) log.debug('Open serial connect to {} with: {}'.format(port, ', '.join('{}={}'.format(key, value) for key, value in config.items()))) @@ -33,7 +38,7 @@ def __init__(self, port, **kwargs): except (serial.SerialException, OSError) as e: raise SmartMeterError(e) else: - self.serial.setRTS(False) + self.serial.setRTS(self.serial_rts) self.port = self.serial.name log.info('New serial connection opened to %s', self.port) @@ -42,7 +47,7 @@ def connect(self): if not self.serial.isOpen(): log.info('Opening connection to `%s`', self.serial.name) self.serial.open() - self.serial.setRTS(False) + self.serial.setRTS(self.serial_rts) else: log.debug('`%s` was already open.', self.serial.name) From f8b2e890526d51a487cda8f2218d158fa770800f Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Thu, 29 Dec 2022 21:50:23 +0000 Subject: [PATCH 02/10] Add option to set RTS configuration --- smeterd/cli/read_meter.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/smeterd/cli/read_meter.py b/smeterd/cli/read_meter.py index 06d9064..be87d83 100644 --- a/smeterd/cli/read_meter.py +++ b/smeterd/cli/read_meter.py @@ -16,9 +16,10 @@ @click.option('--serial-stopbits', help='number of stop bits', default=str(serial.STOPBITS_ONE), type=click.Choice(['1', '1.5', '2'])) @click.option('--serial-timeout', help='set a read timeout value in seconds', default=10, type=int) @click.option('--serial-xonxoff', help='enable software flow control. By default software flow control is disabled', is_flag=True) +@click.option('--serial-rts', help='Enable RTS flow control.', is_flag=True) @click.option('--show-output', help='choose output to display', default=('time', 'consumed', 'tariff', 'gas_measured_at'), multiple=True, type=click.Choice(['time', 'kwh_eid', 'gas_eid', 'consumed', 'tariff', 'gas_measured_at', 'produced', 'current'])) @click.option('--tsv', help='display packet in tab separated value form', is_flag=True) -def read_meter(elec_unit, gas_unit, raw, serial_baudrate, serial_bytesize, serial_parity, serial_port, serial_stopbits, serial_timeout, serial_xonxoff, show_output, tsv): +def read_meter(elec_unit, gas_unit, raw, serial_baudrate, serial_bytesize, serial_parity, serial_port, serial_stopbits, serial_timeout, serial_xonxoff, serial_rts, show_output, tsv): ''' read a single P1 packet to stdout. @@ -38,6 +39,7 @@ def read_meter(elec_unit, gas_unit, raw, serial_baudrate, serial_bytesize, seria stopbits=float(serial_stopbits), xonxoff=serial_xonxoff, timeout=serial_timeout, + rts=serial_rts, ) with meter: From 0859505d81c3e2bb1920765a62ebe85ac1e462cd Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Thu, 29 Dec 2022 21:54:29 +0000 Subject: [PATCH 03/10] setRTS is deprecated, use new syntax --- smeterd/meter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index 70d6fe4..6b03f0d 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -38,7 +38,7 @@ def __init__(self, port, **kwargs): except (serial.SerialException, OSError) as e: raise SmartMeterError(e) else: - self.serial.setRTS(self.serial_rts) + self.serial.rts = self.serial_rts self.port = self.serial.name log.info('New serial connection opened to %s', self.port) @@ -47,7 +47,7 @@ def connect(self): if not self.serial.isOpen(): log.info('Opening connection to `%s`', self.serial.name) self.serial.open() - self.serial.setRTS(self.serial_rts) + self.serial.rts = self.serial_rts else: log.debug('`%s` was already open.', self.serial.name) From 64cd319148b76cdc2b82e1f57d1055348bfa289c Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Thu, 29 Dec 2022 22:04:43 +0000 Subject: [PATCH 04/10] Adding support to parse the total meter readings for incomming and outgoing energy. --- smeterd/meter.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index 6b03f0d..b85e6a0 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -6,8 +6,10 @@ from time import mktime from datetime import datetime - log = logging.getLogger(__name__) +# Uncomment this line to enable debug logging: +# logging.basicConfig(level=logging.DEBUG) + crc16 = crcmod.predefined.mkPredefinedCrcFun('crc16') @@ -139,6 +141,14 @@ def __init__(self, datagram): keys['kwh']['switch'] = self.get_int(rb'^0-0:96\.3\.10\((\d)\)\r\n') keys['kwh']['treshold'] = self.get_float(rb'^0-0:17\.0\.0\(([0-9]{4}\.[0-9]{2})\*kW\)\r\n') + keys['kwh']['total_consumed'] = {} + keys['kwh']['total_consumed']['active'] = self.get_float(rb'^1-0:1\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['total_consumed']['reactive'] = self.get_float(rb'^1-0:3\.8\.0\(([0-9]+\.[0-9]+)\*kvarh\)\r\n') + + keys['kwh']['total_input'] = {} + keys['kwh']['total_input']['active'] = self.get_float(rb'^1-0:2\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['total_input']['reactive'] = self.get_float(rb'^1-0:4\.8\.0\(([0-9]+\.[0-9]+)\*kvarh\)\r\n') + keys['kwh']['low'] = {} keys['kwh']['low']['consumed'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') keys['kwh']['low']['produced'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') From 9dbf4f531655796aa86f57e803eb016f65fe092e Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Thu, 29 Dec 2022 22:13:19 +0000 Subject: [PATCH 05/10] Current (apms) is a float --- smeterd/meter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index b85e6a0..2b73458 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -163,15 +163,15 @@ def __init__(self, datagram): keys['instantaneous'] = {} keys['instantaneous']['l1'] = {} keys['instantaneous']['l1']['volts'] = self.get_float(rb'^1-0:32\.7\.0\((\d+\.\d+)\*V\)\r\n') - keys['instantaneous']['l1']['amps'] = self.get_int(rb'^1-0:31\.7\.0\((\d+)\*A\)\r\n') + keys['instantaneous']['l1']['amps'] = self.get_float(rb'^1-0:31\.7\.0\((\d+\.\d+)\*A\)\r\n') keys['instantaneous']['l1']['watts'] = self.get_float(rb'^1-0:21\.7\.0\((\d+\.\d+)\*kW\)\r\n', 0) * 1000 keys['instantaneous']['l2'] = {} keys['instantaneous']['l2']['volts'] = self.get_float(rb'^1-0:52\.7\.0\((\d+\.\d+)\*V\)\r\n') - keys['instantaneous']['l2']['amps'] = self.get_int(rb'^1-0:51\.7\.0\((\d+)\*A\)\r\n') + keys['instantaneous']['l2']['amps'] = self.get_float(rb'^1-0:51\.7\.0\((\d+\.\d+)\*A\)\r\n') keys['instantaneous']['l2']['watts'] = self.get_float(rb'^1-0:41\.7\.0\((\d+\.\d+)\*kW\)\r\n', 0) * 1000 keys['instantaneous']['l3'] = {} keys['instantaneous']['l3']['volts'] = self.get_float(rb'^1-0:72\.7\.0\((\d+\.\d+)\*V\)\r\n') - keys['instantaneous']['l3']['amps'] = self.get_int(rb'^1-0:71\.7\.0\((\d+)\*A\)\r\n') + keys['instantaneous']['l3']['amps'] = self.get_float(rb'^1-0:71\.7\.0\((\d+\.\d+)\*A\)\r\n') keys['instantaneous']['l3']['watts'] = self.get_float(rb'^1-0:61\.7\.0\((\d+\.\d+)\*kW\)\r\n', 0) * 1000 keys['gas'] = {} From 384ef67db0afa66223723d607622105ea7b3ca13 Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Thu, 29 Dec 2022 22:47:16 +0000 Subject: [PATCH 06/10] Only remove rts if defined --- smeterd/meter.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index 6b03f0d..a04e73d 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -27,8 +27,9 @@ def __init__(self, port, **kwargs): config.update(self.serial_defaults) # This is quite uggly. The config part should probably be rewritten. - self.serial_rts = kwargs['rts'] - del kwargs['rts'] + if 'rts' in kwargs: + self.serial_rts = kwargs['rts'] + del kwargs['rts'] config.update(kwargs) log.debug('Open serial connect to {} with: {}'.format(port, ', '.join('{}={}'.format(key, value) for key, value in config.items()))) From a995ecc71d461fef9846e002959291f29659afc6 Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Sat, 7 Jan 2023 00:11:04 +0100 Subject: [PATCH 07/10] New structure of consumed/produced data --- smeterd/meter.py | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index 02f4bc9..a4830a3 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -142,24 +142,17 @@ def __init__(self, datagram): keys['kwh']['switch'] = self.get_int(rb'^0-0:96\.3\.10\((\d)\)\r\n') keys['kwh']['treshold'] = self.get_float(rb'^0-0:17\.0\.0\(([0-9]{4}\.[0-9]{2})\*kW\)\r\n') - keys['kwh']['total_consumed'] = {} - keys['kwh']['total_consumed']['active'] = self.get_float(rb'^1-0:1\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['total_consumed']['reactive'] = self.get_float(rb'^1-0:3\.8\.0\(([0-9]+\.[0-9]+)\*kvarh\)\r\n') - - keys['kwh']['total_input'] = {} - keys['kwh']['total_input']['active'] = self.get_float(rb'^1-0:2\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['total_input']['reactive'] = self.get_float(rb'^1-0:4\.8\.0\(([0-9]+\.[0-9]+)\*kvarh\)\r\n') - - keys['kwh']['low'] = {} - keys['kwh']['low']['consumed'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['low']['produced'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - - keys['kwh']['high'] = {} - keys['kwh']['high']['consumed'] = self.get_float(rb'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['high']['produced'] = self.get_float(rb'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - - keys['kwh']['current_consumed'] = self.get_float(rb'^1-0:1\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') - keys['kwh']['current_produced'] = self.get_float(rb'^1-0:2\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') + keys['kwh']['consumed'] = {} + keys['kwh']['consumed']['now'] = self.get_float(rb'^1-0:1\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') + keys['kwh']['consumed']['total'] = self.get_float(rb'^1-0:1\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['consumed']['low'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['consumed']['high'] = self.get_float(rb'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + + keys['kwh']['produced'] = {} + keys['kwh']['produced']['now'] = self.get_float(rb'^1-0:2\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') + keys['kwh']['produced']['total'] = self.get_float(rb'^1-0:2\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['produced']['low'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['produced']['high'] = self.get_float(rb'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') keys['instantaneous'] = {} keys['instantaneous']['l1'] = {} From e6b4e3e2aebd466ff63acb0085c6ecfbc98396cf Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Sat, 14 Jan 2023 21:48:50 +0000 Subject: [PATCH 08/10] Only add existing values to output data --- smeterd/cli/read_meter.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/smeterd/cli/read_meter.py b/smeterd/cli/read_meter.py index be87d83..8c78886 100644 --- a/smeterd/cli/read_meter.py +++ b/smeterd/cli/read_meter.py @@ -72,10 +72,14 @@ def read_meter(elec_unit, gas_unit, raw, serial_baudrate, serial_bytesize, seria if ('gas_eid' in show_output): data.append(('Gas serial', packet['gas']['eid'])) if ('consumed' in show_output): - data.extend([ - ('Total electricity consumed (high, {})'.format(elec_unit), int(packet['kwh']['high']['consumed'] * elec_unit_factor[elec_unit])), - ('Total electricity consumed (low, {})'.format(elec_unit), int(packet['kwh']['low']['consumed'] * elec_unit_factor[elec_unit])), - ('Total gas consumed ({})'.format(gas_unit), int(packet['gas']['total'] * gas_unit_factor[gas_unit]))]) + if packet['kwh']['consumed']['total']: + data.extend([('Total electricity consumed (total, {})'.format(elec_unit), float(packet['kwh']['consumed']['total'] * elec_unit_factor[elec_unit]))]) + if packet['kwh']['consumed']['high']: + data.extend([('Total electricity consumed (high, {})'.format(elec_unit), float(packet['kwh']['consumed']['high'] * elec_unit_factor[elec_unit]))]) + if packet['kwh']['consumed']['low']: + data.extend([('Total electricity consumed (low, {})'.format(elec_unit), float(packet['kwh']['consumed']['low'] * elec_unit_factor[elec_unit]))]) + if packet['gas']['total']: + data.extent([('Total gas consumed ({})'.format(gas_unit), int(packet['gas']['total'] * gas_unit_factor[gas_unit]))]) if ('produced' in show_output): data.extend([ ('Total electricity produced (high, {})'.format(elec_unit), int(packet['kwh']['high']['produced'] * elec_unit_factor[elec_unit])), From 5dc6670859796a75b569741ab99d75d6509a732a Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Sat, 21 Jan 2023 22:20:50 +0100 Subject: [PATCH 09/10] Adding tariff information as a comment --- smeterd/meter.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index a4830a3..db4b212 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -6,10 +6,8 @@ from time import mktime from datetime import datetime -log = logging.getLogger(__name__) -# Uncomment this line to enable debug logging: -# logging.basicConfig(level=logging.DEBUG) +log = logging.getLogger(__name__) crc16 = crcmod.predefined.mkPredefinedCrcFun('crc16') @@ -145,14 +143,14 @@ def __init__(self, datagram): keys['kwh']['consumed'] = {} keys['kwh']['consumed']['now'] = self.get_float(rb'^1-0:1\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') keys['kwh']['consumed']['total'] = self.get_float(rb'^1-0:1\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['consumed']['low'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['consumed']['high'] = self.get_float(rb'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['consumed']['low'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 1 + keys['kwh']['consumed']['high'] = self.get_float(rb'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 2 keys['kwh']['produced'] = {} keys['kwh']['produced']['now'] = self.get_float(rb'^1-0:2\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') keys['kwh']['produced']['total'] = self.get_float(rb'^1-0:2\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['produced']['low'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['produced']['high'] = self.get_float(rb'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') + keys['kwh']['produced']['low'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 1 + keys['kwh']['produced']['high'] = self.get_float(rb'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 2 keys['instantaneous'] = {} keys['instantaneous']['l1'] = {} From 3944313fb5f17e6e4898403912bfffc77971d497 Mon Sep 17 00:00:00 2001 From: Emil Sandnabba Date: Sat, 21 Jan 2023 23:02:51 +0100 Subject: [PATCH 10/10] Fixing linting according to flake8 --- smeterd/meter.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/smeterd/meter.py b/smeterd/meter.py index db4b212..d4df243 100644 --- a/smeterd/meter.py +++ b/smeterd/meter.py @@ -141,16 +141,16 @@ def __init__(self, datagram): keys['kwh']['treshold'] = self.get_float(rb'^0-0:17\.0\.0\(([0-9]{4}\.[0-9]{2})\*kW\)\r\n') keys['kwh']['consumed'] = {} - keys['kwh']['consumed']['now'] = self.get_float(rb'^1-0:1\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') + keys['kwh']['consumed']['now'] = self.get_float(rb'^1-0:1\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') keys['kwh']['consumed']['total'] = self.get_float(rb'^1-0:1\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['consumed']['low'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 1 - keys['kwh']['consumed']['high'] = self.get_float(rb'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 2 + keys['kwh']['consumed']['low'] = self.get_float(rb'^1-0:1\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 1 + keys['kwh']['consumed']['high'] = self.get_float(rb'^1-0:1\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 2 keys['kwh']['produced'] = {} - keys['kwh']['produced']['now'] = self.get_float(rb'^1-0:2\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') + keys['kwh']['produced']['now'] = self.get_float(rb'^1-0:2\.7\.0\(([0-9]+\.[0-9]+)\*kW\)\r\n') keys['kwh']['produced']['total'] = self.get_float(rb'^1-0:2\.8\.0\(([0-9]+\.[0-9]+)\*kWh\)\r\n') - keys['kwh']['produced']['low'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 1 - keys['kwh']['produced']['high'] = self.get_float(rb'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 2 + keys['kwh']['produced']['low'] = self.get_float(rb'^1-0:2\.8\.1\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 1 + keys['kwh']['produced']['high'] = self.get_float(rb'^1-0:2\.8\.2\(([0-9]+\.[0-9]+)\*kWh\)\r\n') # Tariff 2 keys['instantaneous'] = {} keys['instantaneous']['l1'] = {}