tinytoolslib 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/PKG-INFO +1 -1
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/pyproject.toml +1 -1
- tinytoolslib-0.5.0/tinytoolslib/__version__.py +1 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/models.py +368 -290
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib.egg-info/PKG-INFO +1 -1
- tinytoolslib-0.4.0/tinytoolslib/__version__.py +0 -1
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/README.md +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/setup.cfg +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/__init__.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/constants.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/discovery.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/exceptions.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/flash.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/parsers.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib/requests.py +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib.egg-info/SOURCES.txt +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib.egg-info/dependency_links.txt +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib.egg-info/requires.txt +0 -0
- {tinytoolslib-0.4.0 → tinytoolslib-0.5.0}/tinytoolslib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tinytoolslib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Set of tools for use with Tinycontrol devices like LK2.X, LK3.X, LK4.X or tcPDU.
|
|
5
5
|
Author-email: Bartek Barszczewski <tinycontrol.software@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.5.0'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Device definitions along with methods for communicating with them."""
|
|
2
2
|
|
|
3
|
+
import operator
|
|
3
4
|
import re
|
|
4
5
|
import warnings
|
|
5
6
|
from abc import ABC, abstractmethod
|
|
@@ -8,27 +9,18 @@ from typing import Any, ClassVar, Dict, List, Tuple, Union
|
|
|
8
9
|
|
|
9
10
|
from aiohttp import ClientSession
|
|
10
11
|
|
|
11
|
-
from tinytoolslib.constants import FW_URL_TEMPLATE, DeviceFamily,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
float_div100,
|
|
24
|
-
float_div1000,
|
|
25
|
-
int_inverted,
|
|
26
|
-
list_map,
|
|
27
|
-
name_list,
|
|
28
|
-
parse_version,
|
|
29
|
-
strint_to_int_list,
|
|
30
|
-
up_to_int,
|
|
31
|
-
)
|
|
12
|
+
from tinytoolslib.constants import (FW_URL_TEMPLATE, DeviceFamily,
|
|
13
|
+
FWUpdateMethod)
|
|
14
|
+
from tinytoolslib.exceptions import (TinyToolsRequestConnectionError,
|
|
15
|
+
TinyToolsRequestError,
|
|
16
|
+
TinyToolsRequestInternalServerError,
|
|
17
|
+
TinyToolsRequestNotFound,
|
|
18
|
+
TinyToolsRequestSSLError,
|
|
19
|
+
TinyToolsRequestTimeout,
|
|
20
|
+
TinyToolsUnsupported)
|
|
21
|
+
from tinytoolslib.parsers import (float_div10, float_div100, float_div1000,
|
|
22
|
+
int_inverted, list_map, name_list,
|
|
23
|
+
parse_version, strint_to_int_list, up_to_int)
|
|
32
24
|
from tinytoolslib.requests import async_get, get
|
|
33
25
|
|
|
34
26
|
|
|
@@ -108,7 +100,11 @@ class DeviceModel(ABC):
|
|
|
108
100
|
if remove_mapped_keys:
|
|
109
101
|
# Remove keys that were parsed/mapped
|
|
110
102
|
for key, val in self.mapping.items():
|
|
111
|
-
if
|
|
103
|
+
if (
|
|
104
|
+
isinstance(val["name"], str)
|
|
105
|
+
and key != val["name"]
|
|
106
|
+
and (skip_keys is None or key not in skip_keys)
|
|
107
|
+
):
|
|
112
108
|
data.pop(key, None)
|
|
113
109
|
# Run extra parsers, that need to work on whole response.
|
|
114
110
|
for parser in self.parsers:
|
|
@@ -183,12 +179,12 @@ class DeviceModel(ABC):
|
|
|
183
179
|
f"{self.__class__.__name__} does not support setting DSs"
|
|
184
180
|
)
|
|
185
181
|
|
|
186
|
-
def get_all(self) -> Dict[str, Any]:
|
|
182
|
+
def get_all(self, remove_mapped_keys: bool = False) -> Dict[str, Any]:
|
|
187
183
|
"""Get set of all sensor/readings."""
|
|
188
184
|
if callable(getattr(self, "_get_all", None)):
|
|
189
185
|
data = {}
|
|
190
186
|
for url in self._get_all():
|
|
191
|
-
data.update(self.get(url))
|
|
187
|
+
data.update(self.get(url, remove_mapped_keys=remove_mapped_keys))
|
|
192
188
|
return data
|
|
193
189
|
raise TinyToolsUnsupported(
|
|
194
190
|
f"{self.__class__.__name__} does not support get_all command"
|
|
@@ -258,12 +254,12 @@ class DeviceModel(ABC):
|
|
|
258
254
|
f"{self.__class__.__name__} does not support controlling VARs"
|
|
259
255
|
)
|
|
260
256
|
|
|
261
|
-
async def async_get_all(self) -> Dict[str, Any]:
|
|
257
|
+
async def async_get_all(self, remove_mapped_keys: bool = False) -> Dict[str, Any]:
|
|
262
258
|
"""Async get_all."""
|
|
263
259
|
if callable(getattr(self, "_get_all", None)):
|
|
264
260
|
data = {}
|
|
265
261
|
for url in self._get_all():
|
|
266
|
-
data.update(await self.async_get(url))
|
|
262
|
+
data.update(await self.async_get(url, remove_mapped_keys=remove_mapped_keys))
|
|
267
263
|
return data
|
|
268
264
|
raise TinyToolsUnsupported(
|
|
269
265
|
f"{self.__class__.__name__} does not support get_all command"
|
|
@@ -296,6 +292,82 @@ class DeviceModel(ABC):
|
|
|
296
292
|
# endregion
|
|
297
293
|
|
|
298
294
|
|
|
295
|
+
def set_cmd_helper(
|
|
296
|
+
caller: DeviceModel,
|
|
297
|
+
cmd_prefix: str,
|
|
298
|
+
cmd_param: str,
|
|
299
|
+
index: Union[int, List[int]],
|
|
300
|
+
value: Union[int, List[int], None],
|
|
301
|
+
negation=False,
|
|
302
|
+
toggle_available=True,
|
|
303
|
+
cmd_set_format="{cmd_param}{index}={value}",
|
|
304
|
+
cmd_toggle_format="{cmd_param}={cmd_param}{index}",
|
|
305
|
+
):
|
|
306
|
+
"""Helper for building GET query for setting, eg OUTs, PWMs, VARs.
|
|
307
|
+
|
|
308
|
+
It handles negation (or forced inversion of state, eg. when device
|
|
309
|
+
uses 0 for on and 1 for off), toggle commands (only chainable mode,
|
|
310
|
+
eg. out=out1&out=out2), and also mixed combination of index+value.
|
|
311
|
+
|
|
312
|
+
Example output (for single index and single value, set command):
|
|
313
|
+
`{cmd_prefix}{cmd_param}{index}={value}`
|
|
314
|
+
"""
|
|
315
|
+
cmd = cmd_prefix
|
|
316
|
+
# Invert states for negation or forced inversion.
|
|
317
|
+
if negation and value is not None:
|
|
318
|
+
if isinstance(value, list):
|
|
319
|
+
value = [int_inverted(val) for val in value]
|
|
320
|
+
else:
|
|
321
|
+
value = int_inverted(value)
|
|
322
|
+
# Handle case when value is missing but toggle is not available.
|
|
323
|
+
if toggle_available is False and value is None:
|
|
324
|
+
raise TinyToolsUnsupported(
|
|
325
|
+
f"{caller.__class__.__name__} does not support toggle for command {cmd_param}"
|
|
326
|
+
)
|
|
327
|
+
# Handle combinations of index + value: int + int/None, [int] + int/[int]/None.
|
|
328
|
+
if isinstance(index, list):
|
|
329
|
+
if toggle_available and value is None:
|
|
330
|
+
cmd += "&".join(
|
|
331
|
+
[
|
|
332
|
+
cmd_toggle_format.format(cmd_param=cmd_param, index=ix)
|
|
333
|
+
for ix in index
|
|
334
|
+
]
|
|
335
|
+
)
|
|
336
|
+
elif isinstance(value, list):
|
|
337
|
+
cmd += "&".join(
|
|
338
|
+
[
|
|
339
|
+
cmd_set_format.format(cmd_param=cmd_param, index=ix, value=val)
|
|
340
|
+
for ix, val in zip(index, value)
|
|
341
|
+
]
|
|
342
|
+
)
|
|
343
|
+
else:
|
|
344
|
+
cmd += "&".join(
|
|
345
|
+
[
|
|
346
|
+
cmd_set_format.format(cmd_param=cmd_param, index=ix, value=value)
|
|
347
|
+
for ix in index
|
|
348
|
+
]
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
if toggle_available and value is None:
|
|
352
|
+
cmd += cmd_toggle_format.format(cmd_param=cmd_param, index=index)
|
|
353
|
+
else:
|
|
354
|
+
cmd += cmd_set_format.format(cmd_param=cmd_param, index=index, value=value)
|
|
355
|
+
return cmd
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def apply_index_offset(
|
|
359
|
+
index: Union[int, List[int]], offset: int = 0, func=operator.add
|
|
360
|
+
) -> Union[int, List[int]]:
|
|
361
|
+
"""Apply an integer offset to a single index or list of indices.
|
|
362
|
+
|
|
363
|
+
Use offset=-1 to convert 1-based → 0-based, offset=+1 to convert 0-based → 1-based.
|
|
364
|
+
Might change how it processes by providing func, which will be given 2 params: index and offset.
|
|
365
|
+
"""
|
|
366
|
+
if isinstance(index, list):
|
|
367
|
+
return [func(i, offset) for i in index]
|
|
368
|
+
return func(index, offset)
|
|
369
|
+
|
|
370
|
+
|
|
299
371
|
@dataclass
|
|
300
372
|
class LK_HW_20_PS(DeviceModel):
|
|
301
373
|
"""Methods for working with Power Socket on LK2.0.
|
|
@@ -307,6 +379,7 @@ class LK_HW_20_PS(DeviceModel):
|
|
|
307
379
|
"IP Power Socket v1 (LK2.0)", # 5G10A/6G10A
|
|
308
380
|
DeviceFamily.PS,
|
|
309
381
|
fw_update_method=FWUpdateMethod.TFTP,
|
|
382
|
+
extras={"number_of_outputs": 6, "outputs_inverted": True}, # or 5 for SW 6.12a
|
|
310
383
|
)
|
|
311
384
|
mapping: ClassVar[Dict[str, Dict]] = {
|
|
312
385
|
# --- st0.xml
|
|
@@ -396,6 +469,9 @@ class LK_HW_20_PS(DeviceModel):
|
|
|
396
469
|
"b28": {"name": "snmp_trap_active", "format": bool}, # 'true' or ''
|
|
397
470
|
# r0, r1, r2 - remote control
|
|
398
471
|
}
|
|
472
|
+
parsers: ClassVar[List[str]] = [
|
|
473
|
+
"_parse_outs",
|
|
474
|
+
]
|
|
399
475
|
|
|
400
476
|
@classmethod
|
|
401
477
|
def check_version(
|
|
@@ -409,6 +485,27 @@ class LK_HW_20_PS(DeviceModel):
|
|
|
409
485
|
"6.12",
|
|
410
486
|
]
|
|
411
487
|
|
|
488
|
+
def is_5_socket_ps(self):
|
|
489
|
+
"""Helper check whether it's version of LK 2.0 PS with 5 sockets."""
|
|
490
|
+
return type(self) == LK_HW_20_PS and self.software_version == "6.12a"
|
|
491
|
+
|
|
492
|
+
# region Parser methods that modifies data in _get()
|
|
493
|
+
def _parse_outs(self, data: Dict[str, Any], path: str) -> None:
|
|
494
|
+
"""Parse outputs OUT with including negation."""
|
|
495
|
+
# Parser is called post mapping so original keys might be missing already.
|
|
496
|
+
if "out_negation" in data:
|
|
497
|
+
self._context["out_negation"] = int(data.get("out_negation"))
|
|
498
|
+
if "out0" in data:
|
|
499
|
+
out_negation = self._context.get("out_negation")
|
|
500
|
+
number_of_outputs = self.info.extras["number_of_outputs"]
|
|
501
|
+
if self.is_5_socket_ps():
|
|
502
|
+
number_of_outputs = 5
|
|
503
|
+
for name in name_list("out", number_of_outputs, 0):
|
|
504
|
+
data[name] = (
|
|
505
|
+
int_inverted(data[name]) if out_negation else int(data[name])
|
|
506
|
+
)
|
|
507
|
+
# endregion
|
|
508
|
+
|
|
412
509
|
def _get(
|
|
413
510
|
self,
|
|
414
511
|
data: Dict[str, Any],
|
|
@@ -416,13 +513,38 @@ class LK_HW_20_PS(DeviceModel):
|
|
|
416
513
|
skip_keys: Union[List[str], None] = None,
|
|
417
514
|
remove_mapped_keys: bool = False,
|
|
418
515
|
) -> Dict[str, Any]:
|
|
419
|
-
|
|
516
|
+
"""Manage properties depending on path.
|
|
517
|
+
|
|
518
|
+
Remove problematic keys, or do extra mapping for some keys.
|
|
519
|
+
"""
|
|
520
|
+
if self.is_5_socket_ps() and path == "/st2.xml":
|
|
521
|
+
# For PS HW 2.0 SW 6.12a (5 socket)
|
|
420
522
|
if skip_keys is None:
|
|
421
523
|
skip_keys = set()
|
|
524
|
+
# Ignore r5-r11 from normal mapping - process that post _get()
|
|
525
|
+
skip_keys.update(["r5", "r6", "r7", "r8", "r9", "r10", "r11"])
|
|
526
|
+
elif path == "/board.xml":
|
|
422
527
|
# Ignore few variables for /board.xml as they overlap in /st2.xml and /board.xml,
|
|
423
528
|
# but with different meaning (out reset time instead of remote control).
|
|
529
|
+
if skip_keys is None:
|
|
530
|
+
skip_keys = set()
|
|
424
531
|
skip_keys.update({"r0", "r1", "r2", "r3", "r4"})
|
|
425
|
-
|
|
532
|
+
get_result = super()._get(data, path, skip_keys, remove_mapped_keys)
|
|
533
|
+
if self.is_5_socket_ps() and path == "/st2.xml":
|
|
534
|
+
# For PS HW 2.0 SW 6.12a (5 socket) apply parsing for r5-r9
|
|
535
|
+
mapping = {
|
|
536
|
+
"r5": {"name": "out0_name", "format": str},
|
|
537
|
+
"r6": {"name": "out1_name", "format": str},
|
|
538
|
+
"r7": {"name": "out2_name", "format": str},
|
|
539
|
+
"r8": {"name": "out3_name", "format": str},
|
|
540
|
+
"r9": {"name": "out4_name", "format": str},
|
|
541
|
+
}
|
|
542
|
+
for key, mapper in mapping.items():
|
|
543
|
+
get_result[mapper["name"]] = mapper["format"](get_result[key])
|
|
544
|
+
if remove_mapped_keys:
|
|
545
|
+
for key in mapping:
|
|
546
|
+
get_result.pop(key)
|
|
547
|
+
return get_result
|
|
426
548
|
|
|
427
549
|
def _set_out(
|
|
428
550
|
self, index: Union[int, List[int]], value: Union[int, List[int], None]
|
|
@@ -434,28 +556,27 @@ class LK_HW_20_PS(DeviceModel):
|
|
|
434
556
|
value: 0-1 (single or list)
|
|
435
557
|
"""
|
|
436
558
|
cmd = "/outs.cgi?"
|
|
437
|
-
if
|
|
438
|
-
|
|
559
|
+
if value is None:
|
|
560
|
+
# Handle different toggle command
|
|
561
|
+
if isinstance(index, list):
|
|
439
562
|
cmd += "out=" + "".join(map(str, index))
|
|
440
|
-
elif isinstance(value, list):
|
|
441
|
-
cmd += "&".join(
|
|
442
|
-
[
|
|
443
|
-
"out{}={}".format(ix, int_inverted(val))
|
|
444
|
-
for ix, val in zip(index, value)
|
|
445
|
-
]
|
|
446
|
-
)
|
|
447
563
|
else:
|
|
448
|
-
cmd += "
|
|
449
|
-
["out{}={}".format(ix, int_inverted(value)) for ix in index]
|
|
450
|
-
)
|
|
564
|
+
cmd += f"out={index}"
|
|
451
565
|
else:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
566
|
+
cmd = set_cmd_helper(
|
|
567
|
+
self,
|
|
568
|
+
cmd,
|
|
569
|
+
"out",
|
|
570
|
+
index,
|
|
571
|
+
value,
|
|
572
|
+
operator.xor(
|
|
573
|
+
self._context["out_negation"], self.info.extras["outputs_inverted"]
|
|
574
|
+
),
|
|
575
|
+
False,
|
|
576
|
+
)
|
|
577
|
+
# Fix command for OUT5 (non-inverted) is only for LK HW 2.0 PS 6G (HW=2.0, SW=6.12),
|
|
578
|
+
# but PS 5G simply doesn't have OUT5, so for simplicity checks for LK_HW_20_PS.
|
|
579
|
+
if type(self) == LK_HW_20_PS:
|
|
459
580
|
if "out5=0" in cmd:
|
|
460
581
|
cmd = cmd.replace("out5=0", "out5=1")
|
|
461
582
|
elif "out5=1" in cmd:
|
|
@@ -480,6 +601,7 @@ class LK_HW_20(LK_HW_20_PS):
|
|
|
480
601
|
"lc20",
|
|
481
602
|
"https://tinycontrol.pl/en/archives/lan-controller-20/#firmware",
|
|
482
603
|
fw_update_method=FWUpdateMethod.TFTP,
|
|
604
|
+
extras={"number_of_outputs": 6, "outputs_inverted": True},
|
|
483
605
|
)
|
|
484
606
|
mapping: ClassVar[Dict[str, Dict]] = {
|
|
485
607
|
# Overwrite PS mapping (there will be extra b30, b31)
|
|
@@ -532,7 +654,7 @@ class LK_HW_20(LK_HW_20_PS):
|
|
|
532
654
|
"dz": {"name": "power2_iD4_divisor", "format": int},
|
|
533
655
|
"mm": {"name": "power2_iD4_unit", "format": str},
|
|
534
656
|
"mh": {"name": "power2_iD4_divisor2", "format": int},
|
|
535
|
-
# Negation of iD (int with bin 0000)
|
|
657
|
+
# Negation of iD (int with bin 0000) - it does not change visual state of inputs.
|
|
536
658
|
"db": {"name": "iD_negation", "format": str},
|
|
537
659
|
# --- board.xml
|
|
538
660
|
"ds": {"name": "ds_read_id", "format": str},
|
|
@@ -542,62 +664,30 @@ class LK_HW_20(LK_HW_20_PS):
|
|
|
542
664
|
def check_version(
|
|
543
665
|
cls, hardware_version: Union[str, None], software_version: str
|
|
544
666
|
) -> bool:
|
|
545
|
-
return
|
|
546
|
-
"
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
"6.12a",
|
|
550
|
-
"6.12",
|
|
551
|
-
]
|
|
667
|
+
return (
|
|
668
|
+
hardware_version == "2.0"
|
|
669
|
+
and LK_HW_20_PS.check_version(hardware_version, software_version) is False
|
|
670
|
+
)
|
|
552
671
|
|
|
553
|
-
def _set_pwm(
|
|
554
|
-
|
|
555
|
-
) -> str:
|
|
556
|
-
"""Prepare command for setting PWM.
|
|
672
|
+
def _set_pwm(self, index: int, value: int) -> str:
|
|
673
|
+
"""Prepare command for setting PWM(0).
|
|
557
674
|
|
|
558
675
|
Arguments:
|
|
559
|
-
index: 0
|
|
560
|
-
value: 0-1 (single
|
|
561
|
-
NOTE: 1-3 can be only set, not read
|
|
676
|
+
index: 0 (single int)
|
|
677
|
+
value: 0-1 (single int)
|
|
562
678
|
"""
|
|
563
|
-
cmd = "/ind.cgi?"
|
|
564
|
-
if isinstance(index, list):
|
|
565
|
-
if isinstance(value, list):
|
|
566
|
-
cmd += "&".join(
|
|
567
|
-
["pwm{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
568
|
-
)
|
|
569
|
-
else:
|
|
570
|
-
cmd += "&".join(["pwm{}={}".format(ix, value) for ix in index])
|
|
571
|
-
else:
|
|
572
|
-
cmd += "pwm{}={}".format(index, value)
|
|
679
|
+
cmd = set_cmd_helper(self, "/ind.cgi?", "pwm", index, value, False, False)
|
|
573
680
|
cmd = cmd.replace("pwm0", "pwm")
|
|
574
681
|
return cmd
|
|
575
682
|
|
|
576
|
-
def _set_pwm_duty(
|
|
577
|
-
|
|
578
|
-
) -> str:
|
|
579
|
-
"""Prepare command for setting PWM duty.
|
|
683
|
+
def _set_pwm_duty(self, index: int, value: int) -> str:
|
|
684
|
+
"""Prepare command for setting PWM(0) duty.
|
|
580
685
|
|
|
581
686
|
Arguments:
|
|
582
|
-
index: 0
|
|
583
|
-
value: 0-100 (single
|
|
584
|
-
NOTE: 1-3 can be only set, not read
|
|
687
|
+
index: 0 (single int)
|
|
688
|
+
value: 0-100 (single int)
|
|
585
689
|
"""
|
|
586
|
-
cmd = "/ind.cgi?"
|
|
587
|
-
if isinstance(index, list):
|
|
588
|
-
if isinstance(value, list):
|
|
589
|
-
cmd += "&".join(
|
|
590
|
-
[
|
|
591
|
-
"pwmd{}={}".format(ix, int(val * 10))
|
|
592
|
-
for ix, val in zip(index, value)
|
|
593
|
-
]
|
|
594
|
-
)
|
|
595
|
-
else:
|
|
596
|
-
cmd += "&".join(
|
|
597
|
-
["pwmd{}={}".format(ix, int(value * 10)) for ix in index]
|
|
598
|
-
)
|
|
599
|
-
else:
|
|
600
|
-
cmd += "pwmd{}={}".format(index, int(value * 10))
|
|
690
|
+
cmd = set_cmd_helper(self, "/ind.cgi?", "pwmd", index, value*10, False, False)
|
|
601
691
|
cmd = cmd.replace("pwmd0", "pwmd")
|
|
602
692
|
return cmd
|
|
603
693
|
|
|
@@ -617,7 +707,7 @@ class LK_HW_20(LK_HW_20_PS):
|
|
|
617
707
|
index - 1-6
|
|
618
708
|
value - not used for LK2.X
|
|
619
709
|
"""
|
|
620
|
-
cmd = "/ind.cgi?ds={}"
|
|
710
|
+
cmd = f"/ind.cgi?ds={index}"
|
|
621
711
|
return cmd
|
|
622
712
|
|
|
623
713
|
def get_ds_id(self) -> str:
|
|
@@ -628,10 +718,7 @@ class LK_HW_20(LK_HW_20_PS):
|
|
|
628
718
|
|
|
629
719
|
@dataclass
|
|
630
720
|
class LK_HW_25(LK_HW_20):
|
|
631
|
-
"""Methods for working with LK2.5.
|
|
632
|
-
|
|
633
|
-
Note: for outputs it uses unified values 0 - off, 1 - on.
|
|
634
|
-
"""
|
|
721
|
+
"""Methods for working with LK2.5."""
|
|
635
722
|
|
|
636
723
|
info: ClassVar[Union[DeviceInfo, None]] = DeviceInfo(
|
|
637
724
|
"LK HW 2.5",
|
|
@@ -639,13 +726,43 @@ class LK_HW_25(LK_HW_20):
|
|
|
639
726
|
"lc25",
|
|
640
727
|
"https://tinycontrol.pl/en/lan-controller-25/firmware-docs/#firmware",
|
|
641
728
|
fw_update_method=FWUpdateMethod.TFTP,
|
|
729
|
+
extras={"number_of_outputs": 6, "outputs_inverted": True},
|
|
642
730
|
)
|
|
643
731
|
|
|
644
732
|
@classmethod
|
|
645
733
|
def check_version(
|
|
646
734
|
cls, hardware_version: Union[str, None], software_version: str
|
|
647
735
|
) -> bool:
|
|
648
|
-
return
|
|
736
|
+
return (
|
|
737
|
+
hardware_version == "2.5"
|
|
738
|
+
and LK_HW_25_PS.check_version(hardware_version, software_version) is False
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
# pylint: disable=useless-super-delegation, useless-parent-delegation
|
|
742
|
+
def _set_pwm(
|
|
743
|
+
self, index: Union[int, List[int]], value: Union[int, List[int]]
|
|
744
|
+
) -> str:
|
|
745
|
+
"""Prepare command for setting PWM.
|
|
746
|
+
|
|
747
|
+
Arguments:
|
|
748
|
+
index: 0-3 (single or list)
|
|
749
|
+
value: 0-1 (single or list)
|
|
750
|
+
NOTE: 1-3 can be only set, not read
|
|
751
|
+
"""
|
|
752
|
+
return super()._set_pwm(index, value)
|
|
753
|
+
|
|
754
|
+
# pylint: disable=useless-super-delegation, useless-parent-delegation
|
|
755
|
+
def _set_pwm_duty(
|
|
756
|
+
self, index: Union[int, List[int]], value: Union[int, List[int]]
|
|
757
|
+
) -> str:
|
|
758
|
+
"""Prepare command for setting PWM duty.
|
|
759
|
+
|
|
760
|
+
Arguments:
|
|
761
|
+
index: 0-3 (single or list)
|
|
762
|
+
value: 0-100 (single or list)
|
|
763
|
+
NOTE: 1-3 can be only set, not read
|
|
764
|
+
"""
|
|
765
|
+
return super()._set_pwm_duty(index, value)
|
|
649
766
|
|
|
650
767
|
|
|
651
768
|
@dataclass
|
|
@@ -654,13 +771,31 @@ class LK_HW_25_PS(LK_HW_20_PS):
|
|
|
654
771
|
"IP Power Socket v2 (LK2.5)",
|
|
655
772
|
DeviceFamily.PS,
|
|
656
773
|
fw_update_method=FWUpdateMethod.TFTP,
|
|
774
|
+
extras={"number_of_outputs": 6, "outputs_inverted": False},
|
|
657
775
|
)
|
|
776
|
+
mapping: ClassVar[Dict[str, Dict]] = {
|
|
777
|
+
**LK_HW_20_PS.mapping,
|
|
778
|
+
"out0": {"name": "out0", "format": int},
|
|
779
|
+
"out1": {"name": "out1", "format": int},
|
|
780
|
+
"out2": {"name": "out2", "format": int},
|
|
781
|
+
"out3": {"name": "out3", "format": int},
|
|
782
|
+
"out4": {"name": "out4", "format": int},
|
|
783
|
+
"out5": {"name": "out5", "format": int},
|
|
784
|
+
# There are 6 DS instead of 4
|
|
785
|
+
"ia5": {"name": "ds5", "format": float_div10},
|
|
786
|
+
"ia6": {"name": "ds6", "format": float_div10},
|
|
787
|
+
"ia7": {"name": "iAValue1", "format": float_div100}, # Voltage input
|
|
788
|
+
"ia8": {"name": "boardVoltage", "format": float_div10},
|
|
789
|
+
# Names divided with *
|
|
790
|
+
"d": {"name": "dsName1-6_iAName1_iDName1-2", "format": str},
|
|
791
|
+
}
|
|
658
792
|
|
|
659
793
|
@classmethod
|
|
660
794
|
def check_version(
|
|
661
795
|
cls, hardware_version: Union[str, None], software_version: str
|
|
662
796
|
) -> bool:
|
|
663
|
-
|
|
797
|
+
# Tested FW 6.15 on LK2.5 and it returns HW 2.0, so include it.
|
|
798
|
+
return hardware_version in ["2.0", "2.5"] and software_version == "6.15"
|
|
664
799
|
|
|
665
800
|
|
|
666
801
|
@dataclass
|
|
@@ -677,7 +812,7 @@ class LK_HW_30(DeviceModel):
|
|
|
677
812
|
"lc30",
|
|
678
813
|
"https://tinycontrol.pl/en/archives/lan-controller-30/#firmware",
|
|
679
814
|
fw_update_method=FWUpdateMethod.TFTP,
|
|
680
|
-
extras={"number_of_outputs": 6},
|
|
815
|
+
extras={"number_of_outputs": 6, "number_of_digital_inputs": 4},
|
|
681
816
|
)
|
|
682
817
|
mapping: ClassVar[Dict[str, Dict]] = {
|
|
683
818
|
# OUTs - further parsed with _parse_outs
|
|
@@ -779,6 +914,7 @@ class LK_HW_30(DeviceModel):
|
|
|
779
914
|
"_parse_outs",
|
|
780
915
|
"_parse_diffs",
|
|
781
916
|
"_parse_custom_readings",
|
|
917
|
+
"_parse_inpd",
|
|
782
918
|
]
|
|
783
919
|
|
|
784
920
|
@classmethod
|
|
@@ -915,6 +1051,21 @@ class LK_HW_30(DeviceModel):
|
|
|
915
1051
|
int_inverted(data[name]) if out_negation else int(data[name])
|
|
916
1052
|
)
|
|
917
1053
|
|
|
1054
|
+
def _parse_inpd(self, data: Dict[str, Any], path: str):
|
|
1055
|
+
"""Parse digital inputs and include negation in returned values."""
|
|
1056
|
+
if "iDNegation1" in data:
|
|
1057
|
+
for name in name_list(
|
|
1058
|
+
"iDNegation", self.info.extras["number_of_digital_inputs"]
|
|
1059
|
+
):
|
|
1060
|
+
self._context[name] = data[name]
|
|
1061
|
+
if "iDValue1" in data and "iDNegation1" in self._context:
|
|
1062
|
+
for name1, name2 in zip(
|
|
1063
|
+
name_list("iDValue", self.info.extras["number_of_digital_inputs"]),
|
|
1064
|
+
name_list("iDNegation", self.info.extras["number_of_digital_inputs"]),
|
|
1065
|
+
):
|
|
1066
|
+
if self._context.get(name2):
|
|
1067
|
+
data[name1] = int_inverted(data[name1])
|
|
1068
|
+
|
|
918
1069
|
# endregion
|
|
919
1070
|
|
|
920
1071
|
def _set_out(
|
|
@@ -928,26 +1079,9 @@ class LK_HW_30(DeviceModel):
|
|
|
928
1079
|
NOTE: When out is negated it will negate passed value,
|
|
929
1080
|
so value=1 will actually set 0 and value=0 set 1.
|
|
930
1081
|
"""
|
|
931
|
-
cmd =
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
value = [int_inverted(val) for val in value]
|
|
935
|
-
else:
|
|
936
|
-
value = int_inverted(value)
|
|
937
|
-
if isinstance(index, list):
|
|
938
|
-
if value is None:
|
|
939
|
-
cmd += "&".join(["out=out{}".format(ix) for ix in index])
|
|
940
|
-
elif isinstance(value, list):
|
|
941
|
-
cmd += "&".join(
|
|
942
|
-
["out{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
943
|
-
)
|
|
944
|
-
else:
|
|
945
|
-
cmd += "&".join(["out{}={}".format(ix, value) for ix in index])
|
|
946
|
-
else:
|
|
947
|
-
if value is None:
|
|
948
|
-
cmd += "out=out{}".format(index)
|
|
949
|
-
else:
|
|
950
|
-
cmd += "out{}={}".format(index, value)
|
|
1082
|
+
cmd = set_cmd_helper(
|
|
1083
|
+
self, "/outs.cgi?", "out", index, value, self._context["out_negation"], True
|
|
1084
|
+
)
|
|
951
1085
|
return cmd
|
|
952
1086
|
|
|
953
1087
|
def _set_pwm(
|
|
@@ -959,21 +1093,7 @@ class LK_HW_30(DeviceModel):
|
|
|
959
1093
|
index: 0-3 (single or list)
|
|
960
1094
|
value: 0-1 (single or list)
|
|
961
1095
|
"""
|
|
962
|
-
cmd = "/outs.cgi?"
|
|
963
|
-
if isinstance(index, list):
|
|
964
|
-
if value is None:
|
|
965
|
-
cmd += "&".join(["pwm=pwm{}".format(ix) for ix in index])
|
|
966
|
-
elif isinstance(value, list):
|
|
967
|
-
cmd += "&".join(
|
|
968
|
-
["pwm{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
969
|
-
)
|
|
970
|
-
else:
|
|
971
|
-
cmd += "&".join(["pwm{}={}".format(ix, value) for ix in index])
|
|
972
|
-
else:
|
|
973
|
-
if value is None:
|
|
974
|
-
cmd += "pwm=pwm{}".format(index)
|
|
975
|
-
else:
|
|
976
|
-
cmd += "pwm{}={}".format(index, value)
|
|
1096
|
+
cmd = set_cmd_helper(self, "/outs.cgi?", "pwm", index, value, False, True)
|
|
977
1097
|
return cmd
|
|
978
1098
|
|
|
979
1099
|
def _set_pwm_duty(
|
|
@@ -985,16 +1105,16 @@ class LK_HW_30(DeviceModel):
|
|
|
985
1105
|
index: 0-3 (single or list)
|
|
986
1106
|
value: 0-100 (single or list)
|
|
987
1107
|
"""
|
|
988
|
-
cmd =
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1108
|
+
cmd = set_cmd_helper(
|
|
1109
|
+
self,
|
|
1110
|
+
"/stm.cgi?",
|
|
1111
|
+
"pwmd",
|
|
1112
|
+
index,
|
|
1113
|
+
value,
|
|
1114
|
+
False,
|
|
1115
|
+
False,
|
|
1116
|
+
"{cmd_param}={index}{value}",
|
|
1117
|
+
)
|
|
998
1118
|
return cmd
|
|
999
1119
|
|
|
1000
1120
|
def _set_pwm_freq(
|
|
@@ -1006,16 +1126,16 @@ class LK_HW_30(DeviceModel):
|
|
|
1006
1126
|
index: 0-1 (single or list; 0 - pwm0, 1 - pwm1-3 shared)
|
|
1007
1127
|
value: 1-1_000_000
|
|
1008
1128
|
"""
|
|
1009
|
-
cmd =
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1129
|
+
cmd = set_cmd_helper(
|
|
1130
|
+
self,
|
|
1131
|
+
"/stm.cgi?",
|
|
1132
|
+
"pwmf",
|
|
1133
|
+
index,
|
|
1134
|
+
value,
|
|
1135
|
+
False,
|
|
1136
|
+
False,
|
|
1137
|
+
"{cmd_param}={index}{value}",
|
|
1138
|
+
)
|
|
1019
1139
|
return cmd
|
|
1020
1140
|
|
|
1021
1141
|
def _set_ds(
|
|
@@ -1027,16 +1147,16 @@ class LK_HW_30(DeviceModel):
|
|
|
1027
1147
|
index: 1-8
|
|
1028
1148
|
value: DS ID
|
|
1029
1149
|
"""
|
|
1030
|
-
cmd =
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1150
|
+
cmd = set_cmd_helper(
|
|
1151
|
+
self,
|
|
1152
|
+
"/stm.cgi?",
|
|
1153
|
+
"dswrite",
|
|
1154
|
+
index,
|
|
1155
|
+
value,
|
|
1156
|
+
False,
|
|
1157
|
+
False,
|
|
1158
|
+
"{cmd_param}={index}:{value}",
|
|
1159
|
+
)
|
|
1040
1160
|
return cmd
|
|
1041
1161
|
|
|
1042
1162
|
def get_ds_id(self) -> str:
|
|
@@ -1047,8 +1167,10 @@ class LK_HW_30(DeviceModel):
|
|
|
1047
1167
|
def _get_all(self) -> List[str]:
|
|
1048
1168
|
"""Prepare list of URLs to fetch data from."""
|
|
1049
1169
|
urls = ["/json/all.json", "/json/pwmpid.json"]
|
|
1050
|
-
|
|
1051
|
-
|
|
1170
|
+
# For LK3.0 add few extra paths, as all.json is incomplete there.
|
|
1171
|
+
if LK_HW_30.check_version(self.hardware_version, self.software_version):
|
|
1172
|
+
urls.insert(0, "/json/inputs.json")
|
|
1173
|
+
urls.insert(0, "/json/outputs.json")
|
|
1052
1174
|
return urls
|
|
1053
1175
|
|
|
1054
1176
|
def _reset_to_defaults(self):
|
|
@@ -1074,48 +1196,40 @@ class LK_HW_30(DeviceModel):
|
|
|
1074
1196
|
calibration: -32768 - 32767 (calibration offset)
|
|
1075
1197
|
multiplier: 0.01 - 327.67 (before sending it will be int(X*100)
|
|
1076
1198
|
"""
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
]
|
|
1112
|
-
)
|
|
1113
|
-
else:
|
|
1114
|
-
cmd += "sensor={}{}".format(index - 1, sensor)
|
|
1115
|
-
if calibration is not None:
|
|
1116
|
-
cmd += "&calibration={}{}".format(index - 1, calibration)
|
|
1117
|
-
if multiplier is not None:
|
|
1118
|
-
cmd += "&multiplier={}{}".format(index - 1, int(multiplier * 100))
|
|
1199
|
+
index = apply_index_offset(index, -1) # -1 each index
|
|
1200
|
+
cmd = set_cmd_helper(
|
|
1201
|
+
self,
|
|
1202
|
+
"/inpa.cgi?",
|
|
1203
|
+
"sensor",
|
|
1204
|
+
index,
|
|
1205
|
+
sensor,
|
|
1206
|
+
False,
|
|
1207
|
+
False,
|
|
1208
|
+
"{cmd_param}={index}{value}",
|
|
1209
|
+
)
|
|
1210
|
+
if calibration is not None:
|
|
1211
|
+
cmd = set_cmd_helper(
|
|
1212
|
+
self,
|
|
1213
|
+
cmd,
|
|
1214
|
+
"calibration",
|
|
1215
|
+
index,
|
|
1216
|
+
calibration,
|
|
1217
|
+
False,
|
|
1218
|
+
False,
|
|
1219
|
+
"{cmd_param}={index}{value}",
|
|
1220
|
+
)
|
|
1221
|
+
if multiplier is not None:
|
|
1222
|
+
multiplier = apply_index_offset(multiplier, 100, lambda a, b: int(a * b))
|
|
1223
|
+
cmd = set_cmd_helper(
|
|
1224
|
+
self,
|
|
1225
|
+
cmd,
|
|
1226
|
+
"multiplier",
|
|
1227
|
+
index,
|
|
1228
|
+
multiplier,
|
|
1229
|
+
False,
|
|
1230
|
+
False,
|
|
1231
|
+
"{cmd_param}={index}{value}",
|
|
1232
|
+
)
|
|
1119
1233
|
return self.get(cmd)
|
|
1120
1234
|
|
|
1121
1235
|
|
|
@@ -1129,7 +1243,7 @@ class LK_HW_35(LK_HW_30):
|
|
|
1129
1243
|
"lc35",
|
|
1130
1244
|
"https://tinycontrol.pl/en/lan-controller-35/firmware/#firmware",
|
|
1131
1245
|
fw_update_method=FWUpdateMethod.TFTP,
|
|
1132
|
-
extras={"number_of_outputs": 6},
|
|
1246
|
+
extras={"number_of_outputs": 6, "number_of_digital_inputs": 4},
|
|
1133
1247
|
)
|
|
1134
1248
|
|
|
1135
1249
|
@classmethod
|
|
@@ -1142,6 +1256,20 @@ class LK_HW_35(LK_HW_30):
|
|
|
1142
1256
|
and not software_version.endswith("dcdc")
|
|
1143
1257
|
)
|
|
1144
1258
|
|
|
1259
|
+
# region Parser methods that modifies data in _get()
|
|
1260
|
+
def _parse_inpd(self, data: Dict[str, Any], path: str):
|
|
1261
|
+
"""Apply fix for negation of digital inputs for earlier SW.
|
|
1262
|
+
|
|
1263
|
+
Since SW 1.49, LK 3.5 automatically applies negation to readings,
|
|
1264
|
+
but older SWs works like LK3.0, so for those use inherited parsing.
|
|
1265
|
+
"""
|
|
1266
|
+
if (
|
|
1267
|
+
LK_HW_35.check_version(self.hardware_version, self.software_version)
|
|
1268
|
+
and self.software_version < "1.49"
|
|
1269
|
+
):
|
|
1270
|
+
super()._parse_inpd(data, path)
|
|
1271
|
+
# endregion
|
|
1272
|
+
|
|
1145
1273
|
def _set_var(
|
|
1146
1274
|
self, index: Union[int, List[int]], value: Union[int, List[int]]
|
|
1147
1275
|
) -> str:
|
|
@@ -1151,18 +1279,19 @@ class LK_HW_35(LK_HW_30):
|
|
|
1151
1279
|
index: 1-8 (single or list)
|
|
1152
1280
|
value: 0-1 (single or list)
|
|
1153
1281
|
"""
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
cmd += "&".join(
|
|
1158
|
-
["vout{}={}".format(ix - 1, val) for ix, val in zip(index, value)]
|
|
1159
|
-
)
|
|
1160
|
-
else:
|
|
1161
|
-
cmd += "&".join(["vout{}={}".format(ix - 1, value) for ix in index])
|
|
1162
|
-
else:
|
|
1163
|
-
cmd += "vout{}={}".format(index - 1, value)
|
|
1282
|
+
# Fix indexes to be 0-based, as outside we use 1-based indexes/names for VARs.
|
|
1283
|
+
index = apply_index_offset(index, -1)
|
|
1284
|
+
cmd = set_cmd_helper(self, "/outs.cgi?", "vout", index, value, False, False)
|
|
1164
1285
|
return cmd
|
|
1165
1286
|
|
|
1287
|
+
def _get_all(self) -> List[str]:
|
|
1288
|
+
"""Prepare list of URLs to fetch data from."""
|
|
1289
|
+
urls = super()._get_all()
|
|
1290
|
+
# Early SWs for LK3.5 require extra path to get state of EVENT.
|
|
1291
|
+
if LK_HW_35.check_version(self.hardware_version, self.software_version) and "1.50" > self.software_version >= "1.22b":
|
|
1292
|
+
urls.append("/json/events_per.json")
|
|
1293
|
+
return urls
|
|
1294
|
+
|
|
1166
1295
|
|
|
1167
1296
|
@dataclass
|
|
1168
1297
|
class LK_HW_39(LK_HW_35):
|
|
@@ -1242,6 +1371,10 @@ class LK_HW_40(DeviceModel):
|
|
|
1242
1371
|
"netMac": {"name": "mac", "format": str},
|
|
1243
1372
|
"softwareVersion": {"name": "software_version", "format": str},
|
|
1244
1373
|
"hardwareVersion": {"name": "hardware_version", "format": str},
|
|
1374
|
+
"pm1": {"name": "pm1.0", "format": float},
|
|
1375
|
+
"pm2": {"name": "pm2.5", "format": float},
|
|
1376
|
+
"pm4": {"name": "pm4.0", "format": float},
|
|
1377
|
+
"pm10": {"name": "pm10.0", "format": float},
|
|
1245
1378
|
}
|
|
1246
1379
|
parsers: ClassVar[List[str]] = ["_parse_outs"]
|
|
1247
1380
|
|
|
@@ -1273,26 +1406,15 @@ class LK_HW_40(DeviceModel):
|
|
|
1273
1406
|
NOTE: When out is negated it will negate passed value,
|
|
1274
1407
|
so value=1 will actually set 0 and value=0 set 1.
|
|
1275
1408
|
"""
|
|
1276
|
-
cmd =
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
elif isinstance(value, list):
|
|
1286
|
-
cmd += "&".join(
|
|
1287
|
-
["out{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
1288
|
-
)
|
|
1289
|
-
else:
|
|
1290
|
-
cmd += "&".join(["out{}={}".format(ix, value) for ix in index])
|
|
1291
|
-
else:
|
|
1292
|
-
if value is None:
|
|
1293
|
-
cmd += "out=out{}".format(index)
|
|
1294
|
-
else:
|
|
1295
|
-
cmd += "out{}={}".format(index, value)
|
|
1409
|
+
cmd = set_cmd_helper(
|
|
1410
|
+
self,
|
|
1411
|
+
"/api/v1/save/?",
|
|
1412
|
+
"out",
|
|
1413
|
+
index,
|
|
1414
|
+
value,
|
|
1415
|
+
self._context["out_negation"],
|
|
1416
|
+
True,
|
|
1417
|
+
)
|
|
1296
1418
|
return cmd
|
|
1297
1419
|
|
|
1298
1420
|
def _set_pwm(
|
|
@@ -1304,21 +1426,7 @@ class LK_HW_40(DeviceModel):
|
|
|
1304
1426
|
index: 1-3 (single or list)
|
|
1305
1427
|
value: 0-1 (single or list)
|
|
1306
1428
|
"""
|
|
1307
|
-
cmd = "/api/v1/save/?"
|
|
1308
|
-
if isinstance(index, list):
|
|
1309
|
-
if value is None:
|
|
1310
|
-
cmd += "&".join(["pwm=pwm{}".format(ix) for ix in index])
|
|
1311
|
-
elif isinstance(value, list):
|
|
1312
|
-
cmd += "&".join(
|
|
1313
|
-
["pwm{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
1314
|
-
)
|
|
1315
|
-
else:
|
|
1316
|
-
cmd += "&".join(["pwm{}={}".format(ix, value) for ix in index])
|
|
1317
|
-
else:
|
|
1318
|
-
if value is None:
|
|
1319
|
-
cmd += "pwm=pwm{}".format(index)
|
|
1320
|
-
else:
|
|
1321
|
-
cmd += "pwm{}={}".format(index, value)
|
|
1429
|
+
cmd = set_cmd_helper(self, "/api/v1/save/?", "pwm", index, value, False, True)
|
|
1322
1430
|
return cmd
|
|
1323
1431
|
|
|
1324
1432
|
def _set_pwm_duty(
|
|
@@ -1330,19 +1438,7 @@ class LK_HW_40(DeviceModel):
|
|
|
1330
1438
|
index: 1-3 (single or list)
|
|
1331
1439
|
value: 0-100 (single or list)
|
|
1332
1440
|
"""
|
|
1333
|
-
cmd = "/api/v1/save/?"
|
|
1334
|
-
if isinstance(index, list):
|
|
1335
|
-
if isinstance(value, list):
|
|
1336
|
-
cmd += "&".join(
|
|
1337
|
-
[
|
|
1338
|
-
"pwmDuty{}={}".format(ix, int(val))
|
|
1339
|
-
for ix, val in zip(index, value)
|
|
1340
|
-
]
|
|
1341
|
-
)
|
|
1342
|
-
else:
|
|
1343
|
-
cmd += "&".join(["pwmDuty{}={}".format(ix, int(value)) for ix in index])
|
|
1344
|
-
else:
|
|
1345
|
-
cmd += "pwmDuty{}={}".format(index, int(value))
|
|
1441
|
+
cmd = set_cmd_helper(self, "/api/v1/save/?", "pwmDuty", index, value, False, False)
|
|
1346
1442
|
return cmd
|
|
1347
1443
|
|
|
1348
1444
|
def _set_pwm_freq(self, index: Any, value: int) -> str:
|
|
@@ -1364,16 +1460,7 @@ class LK_HW_40(DeviceModel):
|
|
|
1364
1460
|
index: 1-8 (single or list)
|
|
1365
1461
|
value: 0-1 (single or list)
|
|
1366
1462
|
"""
|
|
1367
|
-
cmd = "/api/v1/save/?"
|
|
1368
|
-
if isinstance(index, list):
|
|
1369
|
-
if isinstance(value, list):
|
|
1370
|
-
cmd += "&".join(
|
|
1371
|
-
["var{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
1372
|
-
)
|
|
1373
|
-
else:
|
|
1374
|
-
cmd += "&".join(["var{}={}".format(ix, value) for ix in index])
|
|
1375
|
-
else:
|
|
1376
|
-
cmd += "var{}={}".format(index, value)
|
|
1463
|
+
cmd = set_cmd_helper(self, "/api/v1/save/?", "var", index, value, False, False)
|
|
1377
1464
|
return cmd
|
|
1378
1465
|
|
|
1379
1466
|
def _set_ds(
|
|
@@ -1385,16 +1472,7 @@ class LK_HW_40(DeviceModel):
|
|
|
1385
1472
|
index: 1-8
|
|
1386
1473
|
value: DS ID
|
|
1387
1474
|
"""
|
|
1388
|
-
cmd = "/api/v1/save/?"
|
|
1389
|
-
if isinstance(index, list):
|
|
1390
|
-
if isinstance(value, list):
|
|
1391
|
-
cmd += "&".join(
|
|
1392
|
-
["dsID{}={}".format(ix, val) for ix, val in zip(index, value)]
|
|
1393
|
-
)
|
|
1394
|
-
else:
|
|
1395
|
-
cmd += "&".join(["dsID{}={}".format(ix, value) for ix in index])
|
|
1396
|
-
else:
|
|
1397
|
-
cmd += "dsID{}={}".format(index, value)
|
|
1475
|
+
cmd = set_cmd_helper(self, "/api/v1/save/?", "dsID", index, value, False, False)
|
|
1398
1476
|
return cmd
|
|
1399
1477
|
|
|
1400
1478
|
def get_ds_id(self) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tinytoolslib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Set of tools for use with Tinycontrol devices like LK2.X, LK3.X, LK4.X or tcPDU.
|
|
5
5
|
Author-email: Bartek Barszczewski <tinycontrol.software@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.4.0'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|