From 3122886a2a0ae1b5416da1625b0a4e7be965b1a7 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 18 Aug 2021 10:41:30 +0200 Subject: [PATCH 1/2] Add initial support for protocol mode B --- iec62056_21/client.py | 40 +++++++++++++++++++++++++++++++++------- iec62056_21/lis200.py | 2 +- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/iec62056_21/client.py b/iec62056_21/client.py index 9220167..8ba5d27 100644 --- a/iec62056_21/client.py +++ b/iec62056_21/client.py @@ -11,6 +11,14 @@ class Iec6205621Client: A client class for IEC 62056-21. Only validated with meters using mode C. """ + BAUDRATES_MODE_B = { + "A": 600, + "B": 1200, + "C": 2400, + "D": 4800, + "E": 9600, + "F": 19200, + } BAUDRATES_MODE_C = { "0": 300, "1": 600, @@ -48,6 +56,7 @@ def __init__( password="00000000", battery_powered=False, error_parser_class=exceptions.DummyErrorParser, + protocol_mode="C", ): self.transport = transport @@ -59,7 +68,7 @@ def __init__( self.manufacturer_id = None self.use_short_reaction_time = False self.error_parser = error_parser_class() - self._current_baudrate: int = 300 + self.protocol_mode = protocol_mode if self.transport.TRANSPORT_REQUIRES_ADDRESS and not self.device_address: raise exceptions.Iec6205621ClientError( @@ -72,7 +81,10 @@ def switchover_baudrate(self): """ Shortcut to get the baud rate for the switchover. """ - return self.BAUDRATES_MODE_C.get(self._switchover_baudrate_char) + if self.protocol_mode == "B": + return self.BAUDRATES_MODE_B[self._switchover_baudrate_char] + if self.protocol_mode == "C": + return self.BAUDRATES_MODE_C[self._switchover_baudrate_char] def read_single_value(self, address, additional_data="1"): """ @@ -155,8 +167,21 @@ def startup(self): ident_msg = self.read_identification() - # Setting the baudrate to the one propsed by the device. + # Setting the baudrate to the one proposed by the device. self._switchover_baudrate_char = ident_msg.switchover_baudrate_char + + if ( + self.protocol_mode == "B" + and self._switchover_baudrate_char not in self.BAUDRATES_MODE_B + ) or ( + self.protocol_mode == "C" + and self._switchover_baudrate_char not in self.BAUDRATES_MODE_C + ): + raise exceptions.Iec6205621ClientError( + f"The baudrate switchover character '{self._switchover_baudrate_char}' " + f"is not valid for protocol mode {self.protocol_mode}." + ) + self.identification = ident_msg.identification self.manufacturer_id = ident_msg.manufacturer @@ -185,7 +210,10 @@ def standard_readout(self): Goes through the steps to read the standard readout response from the device. """ self.startup() - self.ack_with_option_select("readout") + if self.protocol_mode == "C": + self.ack_with_option_select("readout") + else: + self.transport.switch_baudrate(self.switchover_baudrate) logger.info(f"Reading standard readout from device.") response = self.read_response() return response @@ -233,9 +261,7 @@ def ack_with_option_select(self, mode): logger.info(f"Sending AckOptionsSelect message: {ack_message}") self.transport.send(ack_message.to_bytes()) self.rest() - self.transport.switch_baudrate( - baud=self.BAUDRATES_MODE_C[self._switchover_baudrate_char] - ) + self.transport.switch_baudrate(self.switchover_baudrate) def send_init_request(self): """ diff --git a/iec62056_21/lis200.py b/iec62056_21/lis200.py index 29692b2..683dd45 100644 --- a/iec62056_21/lis200.py +++ b/iec62056_21/lis200.py @@ -224,7 +224,7 @@ class WrongInputError(Lis200ProtocolError): class UnknownUnitsError(Lis200ProtocolError): - """Code: 14, Unknown units code """ + """Code: 14, Unknown units code""" class WrongAccessCodeError(Lis200ProtocolError): From d3beabec8fb91977292e9bcab074e19faaad5901 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 18 Aug 2021 10:56:48 +0200 Subject: [PATCH 2/2] Minor improvements --- iec62056_21/client.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/iec62056_21/client.py b/iec62056_21/client.py index 8ba5d27..9477786 100644 --- a/iec62056_21/client.py +++ b/iec62056_21/client.py @@ -46,6 +46,7 @@ class Iec6205621Client: "manufacturer8": "8", "manufacturer9": "9", } + SUPPORTED_PROTOCOL_MODES = ["B", "C"] SHORT_REACTION_TIME = 0.02 REACTION_TIME = 0.2 @@ -76,6 +77,11 @@ def __init__( f"and none was supplied." ) + if self.protocol_mode not in self.SUPPORTED_PROTOCOL_MODES: + raise NotImplemented( + f"Protocol mode {self.protocol_mode} is not yet implemented" + ) + @property def switchover_baudrate(self): """ @@ -195,6 +201,10 @@ def access_programming_mode(self): Goes through the steps to set the meter in programming mode. Returns the password challenge request to be acted on. """ + if self.protocol_mode == "B": + raise NotImplemented( + f"Programming mode for protocol {self.protocol_mode} is not yet implemented" + ) self.startup() @@ -210,10 +220,10 @@ def standard_readout(self): Goes through the steps to read the standard readout response from the device. """ self.startup() - if self.protocol_mode == "C": - self.ack_with_option_select("readout") - else: + if self.protocol_mode == "B": self.transport.switch_baudrate(self.switchover_baudrate) + elif self.protocol_mode == "C": + self.ack_with_option_select("readout") logger.info(f"Reading standard readout from device.") response = self.read_response() return response