Skip to content

Commit

Permalink
Merge pull request #674 from onkelandy/sdp
Browse files Browse the repository at this point in the history
smartdeviceplugin: fix and extend resend protocol (lists, custom_patterns)
  • Loading branch information
Morg42 authored Aug 18, 2024
2 parents 984364a + 83b81a7 commit df062d1
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 18 deletions.
23 changes: 13 additions & 10 deletions lib/model/sdp/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,24 +520,27 @@ def check_reply(self, command, value):
:return: False by default, True if received expected response
:rtype: bool
"""
returnvalue = False
if command in self._sending:
with self._sending_lock:
# getting current retries for current command
retry = self._sending_retries.get(command)
# compare the expected returnvalue with the received value after aligning the type of both values
compare = self._sending[command].get('returnvalue')
if type(compare)(value) == compare:
# if received value equals expexted value, remove command from _sending dict
self._sending.pop(command)
self._sending_retries.pop(command)
self.logger.debug(f'Got correct response for {command}, '
f'removing from send. Resending queue is {self._sending}')
returnvalue = True
elif retry is not None and retry <= self._send_retries:
compare = [compare] if not isinstance(compare, list) else compare
for c in compare:
self.logger.debug(f'Comparing expected reply {c} ({type(c)}) with value {value} ({type(value)})')
if type(c)(value) == c:
# if received value equals expexted value, remove command from _sending dict
self._sending.pop(command)
self._sending_retries.pop(command)
self.logger.debug(f'Got correct response for {command}, '
f'removing from send. Resending queue is {self._sending}')
return True
if retry is not None and retry <= self._send_retries:
# return False and log info if response is not the same as the expected response
self.logger.debug(f'Should send again {self._sending}...')
return returnvalue
return False
return False

def resend(self):
"""
Expand Down
38 changes: 30 additions & 8 deletions lib/model/smartdeviceplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
update, PLUGIN_ATTR_SEND_TIMEOUT, ATTR_NAMES, CMD_ATTR_CMD_SETTINGS, CMD_ATTR_ITEM_ATTRS,
CMD_ATTR_ITEM_TYPE, CMD_ATTR_LOOKUP, CMD_ATTR_OPCODE, CMD_ATTR_PARAMS,
CMD_ATTR_READ, CMD_ATTR_READ_CMD, CMD_ATTR_WRITE, CMD_IATTR_ATTRIBUTES,
CMD_IATTR_CYCLE, CMD_IATTR_ENFORCE, CMD_IATTR_INITIAL,
CMD_IATTR_CYCLE, CMD_IATTR_ENFORCE, CMD_IATTR_INITIAL, CMD_ATTR_REPLY_PATTERN,
CMD_IATTR_LOOKUP_ITEM, CMD_IATTR_READ_GROUPS, CMD_IATTR_RG_LEVELS,
CMD_IATTR_CUSTOM1, CMD_IATTR_CUSTOM2, CMD_IATTR_CUSTOM3,
CMD_IATTR_CUSTOM1, CMD_IATTR_CUSTOM2, CMD_IATTR_CUSTOM3, PATTERN_CUSTOM_PATTERN,
CMD_IATTR_TEMPLATE, COMMAND_READ, COMMAND_SEP, COMMAND_WRITE, CUSTOM_SEP,
INDEX_GENERIC, INDEX_MODEL, ITEM_ATTR_COMMAND, ITEM_ATTR_CUSTOM1,
ITEM_ATTR_CYCLE, ITEM_ATTR_GROUP, ITEM_ATTR_LOOKUP, ITEM_ATTR_READ,
Expand Down Expand Up @@ -709,6 +709,7 @@ def send_command(self, command, value=None, return_result=False, **kwargs):
:return: True if send was successful, False otherwise
:rtype: bool
"""

if not self.alive:
self.logger.warning(f'trying to send command {command} with value {value}, but plugin is not active.')
return False
Expand All @@ -722,6 +723,7 @@ def send_command(self, command, value=None, return_result=False, **kwargs):
return False

kwargs.update(self._parameters)
custom_value = None
if self.custom_commands:
try:
command, custom_value = command.split(CUSTOM_SEP)
Expand Down Expand Up @@ -760,17 +762,37 @@ def send_command(self, command, value=None, return_result=False, **kwargs):

# creating resend info, necessary for resend protocol
result = None
reply_pattern = self._commands.get_commandlist(command).get('reply_pattern')
read_cmd = self._transform_send_data(self._commands.get_send_data(command, None))
reply_pattern = self._commands.get_commandlist(command).get(CMD_ATTR_REPLY_PATTERN)
# replace custom patterns in reply_pattern by the current result
if custom_value:
for index in (1, 2, 3):
custom_replacement = kwargs['custom'].get(index)
if custom_replacement is not None:
pattern = "{" + PATTERN_CUSTOM_PATTERN + str(index) + "}"

if isinstance(reply_pattern, list):
reply_pattern = [r.replace(pattern, custom_replacement) for r in reply_pattern]
else:
reply_pattern = reply_pattern.replace(pattern, custom_replacement)
read_cmd = self._transform_send_data(self._commands.get_send_data(command, None, **kwargs), **kwargs)
resend_command = command if custom_value is None else f'{command}#{custom_value}'
# if no reply_pattern given, no response is expected
if reply_pattern is None:
resend_info = {'command': command, 'returnvalue': None, 'read_cmd': read_cmd}
resend_info = {'command': resend_command, 'returnvalue': None, 'read_cmd': read_cmd}
# if no reply_pattern has lookup or capture group, put it in resend_info
elif '(' not in reply_pattern and '{' not in reply_pattern:
resend_info = {'command': command, 'returnvalue': reply_pattern, 'read_cmd': read_cmd}
elif not isinstance(reply_pattern, list) and '(' not in reply_pattern and '{' not in reply_pattern:
resend_info = {'command': resend_command, 'returnvalue': reply_pattern, 'read_cmd': read_cmd}
# if reply_pattern is list, check if one of the entries has capture group
elif isinstance(reply_pattern, list):
return_list = []
for r in reply_pattern:
if '(' not in r and '{' not in r:
return_list.append(r)
reply_pattern = return_list if return_list else None
resend_info = {'command': resend_command, 'returnvalue': reply_pattern, 'read_cmd': read_cmd}
# if reply pattern does not expect a specific value, use value as expected reply
else:
resend_info = {'command': command, 'returnvalue': value, 'read_cmd': read_cmd}
resend_info = {'command': resend_command, 'returnvalue': value, 'read_cmd': read_cmd}
# if an error occurs on sending, an exception is thrown "below"
try:
result = self._send(data_dict, resend_info=resend_info)
Expand Down

0 comments on commit df062d1

Please sign in to comment.