Skip to content

Commit

Permalink
Merge pull request #10 from pwitab/7-not-able-to-enter-programming-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Krolken committed May 18, 2020
2 parents f435d3d + d09071e commit 09d9acf
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 73 deletions.
42 changes: 27 additions & 15 deletions iec62056_21/client.py
Expand Up @@ -55,17 +55,24 @@ def __init__(
self.password = password
self.battery_powered = battery_powered
self.identification = None
self.switchover_baudrate_char = None
self._switchover_baudrate_char = None
self.manufacturer_id = None
self.use_short_reaction_time = False
self.error_parser = error_parser_class()
self._current_baudrate: int = 300

if self.transport.TRANSPORT_REQUIRES_ADDRESS and not self.device_address:
raise exceptions.Iec6205621ClientError(
f"The transported used ({self.transport}) requires a device address "
f"and none was supplied."
)

@property
def switchover_baudrate(self):
"""
Shoirtcut to get the baud rate for the switchover.
Shortcut to get the baud rate for the switchover.
"""
return self.BAUDRATES_MODE_C.get(self.switchover_baudrate_char)
return self.BAUDRATES_MODE_C.get(self._switchover_baudrate_char)

def read_single_value(self, address, additional_data="1"):
"""
Expand All @@ -76,6 +83,10 @@ def read_single_value(self, address, additional_data="1"):
:return:
"""
# TODO Can't find documentation on why the additional_data of 1 is needed.
# LIS-200 Specific?

# TODO: When not using the additional data on an EMH meter we get an ack back.
# a bit later we get the break message. Is the device waiting?

request = messages.CommandMessage.for_single_read(address, additional_data)
logger.info(f"Sending read request: {request}")
Expand Down Expand Up @@ -145,8 +156,7 @@ def startup(self):
ident_msg = self.read_identification()

# Setting the baudrate to the one propsed by the device.
self.switchover_baudrate_char = str(ident_msg.switchover_baudrate_char)

self._switchover_baudrate_char = ident_msg.switchover_baudrate_char
self.identification = ident_msg.identification
self.manufacturer_id = ident_msg.manufacturer

Expand All @@ -165,8 +175,6 @@ def access_programming_mode(self):

self.ack_with_option_select("programming")

self.transport.switch_baudrate(self.switchover_baudrate)

# receive password request
pw_req = self.read_response()

Expand All @@ -178,7 +186,6 @@ def standard_readout(self):
"""
self.startup()
self.ack_with_option_select("readout")
self.transport.switch_baudrate(self.switchover_baudrate)
logger.info(f"Reading standard readout from device.")
response = self.read_response()
return response
Expand All @@ -201,7 +208,9 @@ def send_break(self):
communication.
"""
logger.info("Sending BREAK message to end communication")
break_msg = messages.CommandMessage(command="B", command_type=0, data_set=None)
break_msg = messages.CommandMessage(
command="B", command_type="0", data_set=None
)
self.transport.send(break_msg.to_bytes())

def ack_with_option_select(self, mode):
Expand All @@ -213,13 +222,20 @@ def ack_with_option_select(self, mode):
:param mode:
"""
# TODO: allow the client to suggest a new baudrate to the devices instead of
# the devices proposed one.

mode_char = self.MODE_CONTROL_CHARACTER[mode]

ack_message = messages.AckOptionSelectMessage(
mode_char=mode_char, baud_char=self.switchover_baudrate_char
mode_char=mode_char, baud_char=self._switchover_baudrate_char
)
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]
)

def send_init_request(self):
"""
Expand All @@ -230,11 +246,7 @@ def send_init_request(self):
you want to talk to by adding the address in the request.
"""
if self.transport.TRANSPORT_REQUIRES_ADDRESS:
request = messages.RequestMessage(device_address=self.device_address)
else:
request = messages.RequestMessage()

request = messages.RequestMessage(device_address=self.device_address)
logger.info(f"Sending request message: {request}")
self.transport.send(request.to_bytes())
self.rest()
Expand Down
4 changes: 4 additions & 0 deletions iec62056_21/exceptions.py
Expand Up @@ -2,6 +2,10 @@ class Iec6205621Exception(Exception):
"""General IEC62056-21 Exception"""


class Iec6205621ClientError(Iec6205621Exception):
"""Client error"""


class Iec6205621ParseError(Iec6205621Exception):
"""Error in parsing IEC62056-21 data"""

Expand Down
37 changes: 23 additions & 14 deletions iec62056_21/messages.py
Expand Up @@ -50,19 +50,24 @@ class DataSet(Iec6205621Data):

EXCLUDE_CHARS = ["(", ")", "/", "!"]

def __init__(self, address, value, unit=None, no_address=False):
def __init__(self, value: str, address: str = None, unit: str = None):

# TODO: in programming mode, protocol mode C the value can be up to 128 chars

self.address = address
self.value = value
self.unit = unit

def to_representation(self):
if self.unit:
def to_representation(self) -> str:
if self.unit is not None and self.address is not None:
return f"{self.address}({self.value}*{self.unit})"
else:
elif self.address is not None and self.unit is None:
return f"{self.address}({self.value})"
else:
if self.value is None:
return f"()"
else:
return f"({self.value})"

@classmethod
def from_representation(cls, data_set_string):
Expand Down Expand Up @@ -90,8 +95,8 @@ def from_representation(cls, data_set_string):
def __repr__(self):
return (
f"{self.__class__.__name__}("
f"address={self.address!r}, "
f"value={self.value!r}, "
f"address={self.address!r}, "
f"unit={self.unit!r}"
f")"
)
Expand Down Expand Up @@ -187,9 +192,11 @@ def __repr__(self):

class CommandMessage(Iec6205621Data):
allowed_commands = ["P", "W", "R", "E", "B"]
allowed_command_types = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
allowed_command_types = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]

def __init__(self, command, command_type, data_set):
def __init__(
self, command: str, command_type: str, data_set: typing.Optional[DataSet]
):
self.command = command
self.command_type = command_type
self.data_set = data_set
Expand Down Expand Up @@ -219,7 +226,7 @@ def from_representation(cls, string_data):
body = _message[3:]

command = header[1]
command_type = int(header[2])
command_type = header[2]
data_set = DataSet.from_representation(body[1:-1])

return cls(command, command_type, data_set)
Expand All @@ -231,12 +238,12 @@ def for_single_read(cls, address, additional_data=None):
else:
_add_data = ""
data_set = DataSet(value=_add_data, address=address)
return cls(command="R", command_type=1, data_set=data_set)
return cls(command="R", command_type="1", data_set=data_set)

@classmethod
def for_single_write(cls, address, value):
data_set = DataSet(value=value, address=address)
return cls(command="W", command_type=1, data_set=data_set)
return cls(command="W", command_type="1", data_set=data_set)

def __repr__(self):
return (
Expand Down Expand Up @@ -339,10 +346,12 @@ def __repr__(self):


class IdentificationMessage(Iec6205621Data):
def __init__(self, identification, manufacturer, switchover_baudrate_char):
self.identification = identification
self.manufacturer = manufacturer
self.switchover_baudrate_char = switchover_baudrate_char
def __init__(
self, identification: str, manufacturer: str, switchover_baudrate_char: str
):
self.identification: str = identification
self.manufacturer: str = manufacturer
self.switchover_baudrate_char: str = switchover_baudrate_char

def to_representation(self):
return (
Expand Down

0 comments on commit 09d9acf

Please sign in to comment.