From f5305a1dec4322bf72942d822fd4edce4348e0f1 Mon Sep 17 00:00:00 2001 From: jamesjeffryes Date: Tue, 19 May 2020 14:54:07 -0500 Subject: [PATCH] Allow set by nickname for tags and update docs --- README.md | 15 ++++++++++++++- clickplc/driver.py | 10 +++++++--- clickplc/tests/bad_tags.csv | 3 +++ clickplc/tests/test_driver.py | 13 +++++++++++-- 4 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 clickplc/tests/bad_tags.csv diff --git a/README.md b/README.md index 8ad3157..619f7dd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -clickplc +clickplc [![Build Status](https://dev.azure.com/jjeffryes/jjeffryes/_apis/build/status/numat.clickplc?branchName=master)](https://dev.azure.com/jjeffryes/jjeffryes/_build/latest?definitionId=3&branchName=master) ======== Python ≥3.6 driver and command-line tool for [Koyo Ethernet ClickPLCs](https://www.automationdirect.com/adc/Overview/Catalog/Programmable_Controllers/CLICK_Series_PLCs_(Stackable_Micro_Brick)). @@ -57,11 +57,24 @@ The entire API is `get` and `set`, and takes a range of inputs: >>> await plc.set('y101', True) # Sets Y101 to true ``` +If a path is provided to a tags file when the driver is initialized, +tag nicknames can be used to set values and calling `.get()` without +arguments returns all named tags. +```python +async with ClickPLC('the-plc-ip-address', 'path-to-tags-csv') as plc: + await plc.set('Tag Nickname', True) + print(await plc.get()) +``` + Currently, only X, Y, C, DS, and DF are supported: + +| | | | +|---|---|---| | x | bool | Input point | | y | bool | Output point | | c | bool | (C)ontrol relay | | df | float | (D)ata register, (f)loating point | | ds | int16 | (D)ata register, (s)igned int | + I personally haven't needed to use the other categories, but they are straightforward to add if needed. diff --git a/clickplc/driver.py b/clickplc/driver.py index d9fdd27..8597225 100644 --- a/clickplc/driver.py +++ b/clickplc/driver.py @@ -115,11 +115,15 @@ async def set(self, address, data): >>> plc.set('df1', 0.0) # Sets DF1 to 0.0 >>> plc.set('df1', [0.0, 0.0, 0.0]) # Sets DF1-DF3 to 0.0. - >>> plc.set('y101', True) # Sets Y101 to true + >>> plc.set('AV-101', True) # Sets address nicknamed AV-101 to true This uses the ClickPLC's internal variable notation, which can be - found in the Address Picker of the ClickPLC software. + found in the Address Picker of the ClickPLC software. If a tags file + was loaded at driver initalization, nicknames can be used instead. """ + if address in self.tags: + address = self.tags[address]['id'] + if not isinstance(data, list): data = [data] @@ -464,7 +468,7 @@ def _load_tags(self, tag_filepath: str) -> dict: if not data['type']: raise TypeError( f"{data['id']} is an unsupported data type. Open a " - "github issue at numat/productivity to get it added." + "github issue at numat/clickplc to get it added." ) sorted_tags = {k: parsed[k] for k in sorted(parsed, key=lambda k: parsed[k]['address']['start'])} diff --git a/clickplc/tests/bad_tags.csv b/clickplc/tests/bad_tags.csv new file mode 100644 index 0000000..e95b27f --- /dev/null +++ b/clickplc/tests/bad_tags.csv @@ -0,0 +1,3 @@ +Address,Data Type,Modbus Address,Function Code,Nickname,Initial Value,Retentive,Address Comment +Y301,BIT,8289,"FC=01,05,15","P_101",0,No,"" +FOO1,BIT,16385,"FC=01,05,15","P_101_auto",0,No,"" diff --git a/clickplc/tests/test_driver.py b/clickplc/tests/test_driver.py index c75bd6e..d6b3faa 100644 --- a/clickplc/tests/test_driver.py +++ b/clickplc/tests/test_driver.py @@ -40,9 +40,18 @@ def test_get_tags(tagged_driver, expected_tags): assert expected_tags == tagged_driver.get_tags() +def test_unsupported_tags(): + with pytest.raises(TypeError, match='unsupported data type'): + ClickPLC('fake ip', 'tests/bad_tags.csv') + + @pytest.mark.asyncio -async def test_get_tagged_driver(tagged_driver, expected_tags): - assert expected_tags.keys() == (await tagged_driver.get()).keys() +async def test_tagged_driver(tagged_driver, expected_tags): + await tagged_driver.set('VAH_101_OK', True) + state = await tagged_driver.get() + assert state.get('VAH_101_OK') is True + assert expected_tags.keys() == state.keys() + @pytest.mark.asyncio