Skip to content

Commit

Permalink
Merge pull request #187 from pylipp/feature/structure-support-for-rea…
Browse files Browse the repository at this point in the history
…d-list-by-name

Support structured variables in read_list_by_name
  • Loading branch information
stlehmann authored Feb 18, 2021
2 parents 463ca32 + d21e32b commit 372c9b2
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 3.3.4 [unreleased]

### Added
* [#187](https://github.com/stlehmann/pyads/pull/187) Support structured data types in `read_list_by_name`
* [#195](https://github.com/stlehmann/pyads/pull/195) Read/write by name without passing the datatype
* [#200](https://github.com/stlehmann/pyads/pull/200) Split read write by list into max-ads-sub-comands chunks
* [#206](https://github.com/stlehmann/pyads/pull/206) AdsSymbol now supports DT, DATE_TIME and TIME datatypes
Expand Down
18 changes: 16 additions & 2 deletions pyads/ads.py
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,7 @@ def read_list_by_name(
data_names: List[str],
cache_symbol_info: bool = True,
ads_sub_commands: int = MAX_ADS_SUB_COMMANDS,
structure_defs: Optional[Dict[str, StructureDef]] = None,
) -> Dict[str, Any]:
"""Read a list of variables.
Expand All @@ -869,6 +870,9 @@ def read_list_by_name(
:param bool cache_symbol_info: when True, symbol info will be cached for future reading
:param int ads_sub_commands: Max number of ADS-Sub commands used to read the variables in a single ADS call.
A larger number can be used but may jitter the PLC execution!
:param dict structure_defs: for structured variables, optional mapping of
data name to special tuple defining the structure and
types contained within it according to PLCTYPE constants
:return adsSumRead: A dictionary containing variable names from data_names as keys and values read from PLC for each variable
:rtype dict(str, Any)
Expand All @@ -886,13 +890,23 @@ def read_list_by_name(
i: adsGetSymbolInfo(self._port, self._adr, i) for i in data_names
}

structure_defs = structure_defs or {}
def sum_read(port, adr, data_names, data_symbols):
result = adsSumRead(port, adr, data_names, data_symbols,
list(structure_defs.keys()))

for data_name, structure_def in structure_defs.items():
result[data_name] = dict_from_bytes(result[data_name], structure_def)

return result

if len(data_names) <= ads_sub_commands:
return adsSumRead(self._port, self._adr, data_names, data_symbols)
return sum_read(self._port, self._adr, data_names, data_symbols)

return_data: Dict[str, Any] = {}
for data_names_slice in _list_slice_generator(data_names, ads_sub_commands):
return_data.update(
adsSumRead(self._port, self._adr, data_names_slice, data_symbols)
sum_read(self._port, self._adr, data_names_slice, data_symbols)
)
return return_data

Expand Down
10 changes: 8 additions & 2 deletions pyads/pyads_ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,8 @@ def adsGetSymbolInfo(port: int, address: AmsAddr, data_name: str) -> SAdsSymbolE


def adsSumRead(
port: int, address: AmsAddr, data_names: List[str], data_symbols
port: int, address: AmsAddr, data_names: List[str], data_symbols,
structured_data_names: List[str]
) -> Dict[str, Any]:
"""Perform a sum read to get the value of multiple variables
Expand All @@ -855,6 +856,7 @@ def adsSumRead(
:param data_names: list of variables names to read
:param data_symbols: list of dictionaries of ADS Symbol Info
:type data_symbols: dict[str, ADSSymbolInfo]
:param structured_data_names: list of structured variable names
:return: result: dict of variable names and values
:rtype: dict[str, Any]
"""
Expand Down Expand Up @@ -889,7 +891,11 @@ def adsSumRead(
if error:
result[data_name] = ERROR_CODES[error]
else:
if (
if data_name in structured_data_names:
value = sum_response[
data_start + offset :
data_start + offset + data_symbols[data_name].size]
elif (
data_symbols[data_name].dataType != ADST_STRING
and data_symbols[data_name].dataType != ADST_WSTRING
):
Expand Down
21 changes: 21 additions & 0 deletions tests/test_connection_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,27 @@ def test_write_list_without_cache(self):
self.assertEqual(errors, expected_result)
self.assertEqual(errors2, expected_result)

def test_read_structure_list(self):
variables = ["TestStructure", "TestVar"]
structure_defs = {"TestStructure": (("xVar", pyads.PLCTYPE_BYTE, 1),)}

with self.plc:
actual_result = self.plc.read_list_by_name(variables, cache_symbol_info=False,
structure_defs=structure_defs)

requests = self.test_server.request_history
self.assertEqual(len(requests), 3)

# Assert that all commands are read write - 2x symbol info, 1x sum write
for request in requests:
self.assert_command_id(request, constants.ADSCOMMAND_READWRITE)

expected_result = {
"TestStructure": {"xVar": 1},
"TestVar": 2,
}
self.assertEqual(actual_result, expected_result)

def test_write_list(self):
variables = {
"i1": 1,
Expand Down

0 comments on commit 372c9b2

Please sign in to comment.