zcc-helper 3.3.1.dev2__tar.gz → 3.4.dev2__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.
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/PKG-INFO +12 -7
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/setup.py +1 -1
- zcc_helper-3.4.dev2/tests/test_controller.py +59 -0
- zcc_helper-3.4.dev2/tests/test_device.py +42 -0
- zcc_helper-3.4.dev2/tests/test_server.py +11 -0
- zcc_helper-3.4.dev2/tests/test_socket.py +52 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/__main__.py +9 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/constants.py +1 -1
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/controller.py +8 -4
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/discovery.py +70 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/protocol.py +4 -2
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc_helper.egg-info/PKG-INFO +13 -8
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc_helper.egg-info/SOURCES.txt +4 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/LICENSE.txt +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/README.md +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/setup.cfg +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/__init__.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/description.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/device.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/errors.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/manufacture_info.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/socket.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/trace.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc/watchdog.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc.py +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc_helper.egg-info/dependency_links.txt +0 -0
- {zcc_helper-3.3.1.dev2 → zcc_helper-3.4.dev2}/zcc_helper.egg-info/top_level.txt +0 -0
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: zcc_helper
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.dev2
|
|
4
4
|
Summary: ZIMI ZCC helper module
|
|
5
|
-
Home-page: UNKNOWN
|
|
6
5
|
Author: Mark Hannon
|
|
7
6
|
Author-email: mark.hannon@gmail.com
|
|
8
7
|
License: MIT
|
|
9
8
|
Project-URL: Source, https://bitbucket.org/mark_hannon/zcc
|
|
10
|
-
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
10
|
Description-Content-Type: text/markdown
|
|
13
11
|
License-File: LICENSE.txt
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: author-email
|
|
14
|
+
Dynamic: classifier
|
|
15
|
+
Dynamic: description
|
|
16
|
+
Dynamic: description-content-type
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
Dynamic: project-url
|
|
20
|
+
Dynamic: summary
|
|
14
21
|
|
|
15
22
|
# ZCC-HELPER
|
|
16
23
|
|
|
@@ -274,5 +281,3 @@ python -m zcc --execute --device 'bddf0500-4d15-4457-b063-c12ed208a0b0_3' --acti
|
|
|
274
281
|
```
|
|
275
282
|
|
|
276
283
|
This version of the command is relatively slow as it first of all discovers the ZCC on the local LAN, builds a device inventory and then executes the action.
|
|
277
|
-
|
|
278
|
-
|
|
@@ -19,7 +19,7 @@ setup(
|
|
|
19
19
|
author_email="mark.hannon@gmail.com",
|
|
20
20
|
license="MIT",
|
|
21
21
|
classifiers=[
|
|
22
|
-
"Programming Language :: Python :: 3.
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
23
|
],
|
|
24
24
|
packages=find_packages(exclude=["contrib", "docs", "tests"]),
|
|
25
25
|
project_urls={"Source": "https://bitbucket.org/mark_hannon/zcc"},
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'''Test Basic Controller functionality.'''
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from zcc.controller import ControlPoint, ControlPointError
|
|
5
|
+
from zcc.device import ControlPointDevice
|
|
6
|
+
|
|
7
|
+
from tests.test_server import test_server
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_controller_discover(test_server):
|
|
11
|
+
'''Test for connection to a Controller connected to the Test Server'''
|
|
12
|
+
|
|
13
|
+
controller = ControlPoint(timeout=1)
|
|
14
|
+
|
|
15
|
+
assert controller.ready is True
|
|
16
|
+
assert controller.host is not None
|
|
17
|
+
assert controller.port == 5003
|
|
18
|
+
assert controller.brand == 'zimi'
|
|
19
|
+
assert len(controller.devices) == 31
|
|
20
|
+
assert len(controller.doors) == 0
|
|
21
|
+
assert len(controller.fans) == 0
|
|
22
|
+
assert len(controller.lights) == 20
|
|
23
|
+
assert len(controller.outlets) == 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_controller_discover_timeout():
|
|
27
|
+
'''Test if a UDP discovery times out - goes out over wire'''
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
ControlPoint(timeout=1)
|
|
31
|
+
assert False
|
|
32
|
+
except ControlPointError as error:
|
|
33
|
+
assert error.args[0] == '__init() failed - unable to discover and connect to ZCC'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_controller_device(test_server):
|
|
37
|
+
'''Test turn_on works for valid devices'''
|
|
38
|
+
|
|
39
|
+
controller = ControlPoint(timeout=1)
|
|
40
|
+
|
|
41
|
+
light = controller.lights[0]
|
|
42
|
+
|
|
43
|
+
assert light.is_off() is not True
|
|
44
|
+
assert light.is_on() is True
|
|
45
|
+
|
|
46
|
+
assert light.is_opening is not True
|
|
47
|
+
assert light.is_open is not True
|
|
48
|
+
assert light.location == "lounge LED strip/Lounge"
|
|
49
|
+
assert light.name == "lounge LED strip"
|
|
50
|
+
|
|
51
|
+
with pytest.raises(ControlPointDeviceError):
|
|
52
|
+
light.open_door()
|
|
53
|
+
|
|
54
|
+
with pytest.raises(ControlPointDeviceError):
|
|
55
|
+
light.close_door()
|
|
56
|
+
|
|
57
|
+
light.turn_on()
|
|
58
|
+
|
|
59
|
+
light.turn_off()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from zcc.device import ControlPointDevice
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DeviceTest(unittest.TestCase):
|
|
7
|
+
|
|
8
|
+
identifier = 'test_device_id'
|
|
9
|
+
|
|
10
|
+
def test_init(self):
|
|
11
|
+
device = ControlPointDevice(None, DeviceTest.identifier)
|
|
12
|
+
self.assertEqual(device.controller, None)
|
|
13
|
+
self.assertEqual(device.identifier, DeviceTest.identifier)
|
|
14
|
+
self.assertEqual(device.actions, {})
|
|
15
|
+
self.assertEqual(device.properties, {})
|
|
16
|
+
self.assertEqual(device.states, {})
|
|
17
|
+
|
|
18
|
+
def test_add_action(self):
|
|
19
|
+
device = ControlPointDevice(None, DeviceTest.identifier)
|
|
20
|
+
device.actions = {'TurnOn': {'actionParams': {}},
|
|
21
|
+
'TurnOff': {'actionParams': {}}}
|
|
22
|
+
print(device)
|
|
23
|
+
self.assertEqual(device.controller, None)
|
|
24
|
+
self.assertEqual(device.identifier, DeviceTest.identifier)
|
|
25
|
+
|
|
26
|
+
def test_add_properties(self):
|
|
27
|
+
device = ControlPointDevice(None, DeviceTest.identifier)
|
|
28
|
+
device.properties = {'name': 'Entry Pendant',
|
|
29
|
+
'controlPointType': 'switch', 'roomId': 2, 'roomName': 'Front Door '}
|
|
30
|
+
self.assertEqual(device.controller, None)
|
|
31
|
+
self.assertEqual(device.identifier, DeviceTest.identifier)
|
|
32
|
+
|
|
33
|
+
def test_add_states(self):
|
|
34
|
+
device = ControlPointDevice(None, DeviceTest.identifier)
|
|
35
|
+
device.states = {'controlState': {
|
|
36
|
+
'switch': {...}}, 'isConnected': True}
|
|
37
|
+
self.assertEqual(device.controller, None)
|
|
38
|
+
self.assertEqual(device.identifier, DeviceTest.identifier)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if __name__ == '__main__':
|
|
42
|
+
unittest.main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import pytest
|
|
3
|
+
from unittest.mock import Mock
|
|
4
|
+
from mockito import when, unstub
|
|
5
|
+
|
|
6
|
+
from zcc.socket import ControlPointSocket
|
|
7
|
+
|
|
8
|
+
TEST_HOST = '10.0.0.1'
|
|
9
|
+
TEST_PORT = 4567
|
|
10
|
+
TEST_TIMEOUT = 5
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def mock_tcp_socket():
|
|
15
|
+
mock_socket = Mock(spec=socket.socket)
|
|
16
|
+
return mock_socket
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_socket_create(mock_tcp_socket, when):
|
|
20
|
+
|
|
21
|
+
when(socket).socket(socket.AF_INET,
|
|
22
|
+
socket.SOCK_STREAM)\
|
|
23
|
+
.thenReturn(mock_tcp_socket)
|
|
24
|
+
|
|
25
|
+
controller_socket = ControlPointSocket(TEST_HOST, TEST_PORT)
|
|
26
|
+
|
|
27
|
+
assert controller_socket.host == TEST_HOST
|
|
28
|
+
assert controller_socket.port == TEST_PORT
|
|
29
|
+
assert controller_socket.sock == mock_tcp_socket
|
|
30
|
+
|
|
31
|
+
controller_socket.close()
|
|
32
|
+
assert controller_socket.sock == None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_socket_create_timeout(mock_tcp_socket, when):
|
|
36
|
+
|
|
37
|
+
when(socket).socket(socket.AF_INET,
|
|
38
|
+
socket.SOCK_STREAM)\
|
|
39
|
+
.thenReturn(mock_tcp_socket)
|
|
40
|
+
|
|
41
|
+
controller_socket = ControlPointSocket(
|
|
42
|
+
TEST_HOST, TEST_PORT, timeout=TEST_TIMEOUT)
|
|
43
|
+
|
|
44
|
+
assert controller_socket.host == TEST_HOST
|
|
45
|
+
assert controller_socket.port == TEST_PORT
|
|
46
|
+
assert controller_socket.sock == mock_tcp_socket
|
|
47
|
+
|
|
48
|
+
assert mock_tcp_socket.settimeout.call_count == 1
|
|
49
|
+
assert mock_tcp_socket.settimeout.call_args.args == (TEST_TIMEOUT,)
|
|
50
|
+
|
|
51
|
+
controller_socket.close()
|
|
52
|
+
assert controller_socket.sock == None
|
|
@@ -52,6 +52,9 @@ def __options(args):
|
|
|
52
52
|
cxg.add_argument(
|
|
53
53
|
"--execute", action="store_true", help="execute an action on a device"
|
|
54
54
|
)
|
|
55
|
+
cxg.add_argument(
|
|
56
|
+
"--test-connection", action="store_true", help="test the connection to a device"
|
|
57
|
+
)
|
|
55
58
|
|
|
56
59
|
host_group = parser.add_argument_group("host")
|
|
57
60
|
host_group.add_argument("--host", action="store", help="zcc host name|address")
|
|
@@ -96,6 +99,12 @@ async def main(args):
|
|
|
96
99
|
await ControlPointDiscoveryService(verbosity=options.verbosity).discover()
|
|
97
100
|
return
|
|
98
101
|
|
|
102
|
+
if options.test_connection and options.host and options.port:
|
|
103
|
+
await ControlPointDiscoveryService(
|
|
104
|
+
verbosity=options.verbosity
|
|
105
|
+
).validate_connection(host=options.host, port=options.port)
|
|
106
|
+
return
|
|
107
|
+
|
|
99
108
|
if options.host and options.port:
|
|
100
109
|
description = ControlPointDescription(host=options.host, port=options.port)
|
|
101
110
|
else:
|
|
@@ -313,9 +313,13 @@ class ControlPoint:
|
|
|
313
313
|
"""Get initial control point data from controller."""
|
|
314
314
|
|
|
315
315
|
self.manufacture_info_ready = self.loop.create_future()
|
|
316
|
+
self.manufacture_info_received = 0
|
|
316
317
|
self.properties_ready = self.loop.create_future()
|
|
318
|
+
self.properties_received = 0
|
|
317
319
|
self.actions_ready = self.loop.create_future()
|
|
320
|
+
self.actions_received = 0
|
|
318
321
|
self.states_ready = self.loop.create_future()
|
|
322
|
+
self.states_received = 0
|
|
319
323
|
|
|
320
324
|
self.logger.debug("Getting manufacture_info")
|
|
321
325
|
await self.socket.sendall(
|
|
@@ -332,7 +336,7 @@ class ControlPoint:
|
|
|
332
336
|
"ZCC connection failed - didn't receive manufacture_info."
|
|
333
337
|
) from error
|
|
334
338
|
|
|
335
|
-
await asyncio.sleep(ControlPointProtocol.
|
|
339
|
+
await asyncio.sleep(ControlPointProtocol.STEP_TIMEOUT)
|
|
336
340
|
|
|
337
341
|
self.logger.debug("Getting initial device properties")
|
|
338
342
|
await self.socket.sendall(
|
|
@@ -348,7 +352,7 @@ class ControlPoint:
|
|
|
348
352
|
"ZCC connection failed - didn't receive any properties."
|
|
349
353
|
) from error
|
|
350
354
|
|
|
351
|
-
await asyncio.sleep(ControlPointProtocol.
|
|
355
|
+
await asyncio.sleep(ControlPointProtocol.STEP_TIMEOUT)
|
|
352
356
|
|
|
353
357
|
self.logger.debug("Getting initial device actions")
|
|
354
358
|
await self.socket.sendall(
|
|
@@ -364,7 +368,7 @@ class ControlPoint:
|
|
|
364
368
|
"ZCC connection failed - didn't receive any actions."
|
|
365
369
|
) from error
|
|
366
370
|
|
|
367
|
-
await asyncio.sleep(ControlPointProtocol.
|
|
371
|
+
await asyncio.sleep(ControlPointProtocol.STEP_TIMEOUT)
|
|
368
372
|
|
|
369
373
|
self.logger.debug("Getting initial device states")
|
|
370
374
|
await self.socket.sendall(
|
|
@@ -380,7 +384,7 @@ class ControlPoint:
|
|
|
380
384
|
"ZCC connection failed - didn't receive any states."
|
|
381
385
|
) from error
|
|
382
386
|
|
|
383
|
-
await asyncio.sleep(ControlPointProtocol.
|
|
387
|
+
await asyncio.sleep(ControlPointProtocol.STEP_TIMEOUT)
|
|
384
388
|
|
|
385
389
|
for key in self.devices.keys():
|
|
386
390
|
identifier_msb = self.devices[key].identifier.split("_")[0]
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
+
from enum import StrEnum
|
|
6
7
|
import json
|
|
7
8
|
from json.decoder import JSONDecodeError
|
|
8
9
|
import logging
|
|
@@ -10,11 +11,25 @@ import socket
|
|
|
10
11
|
from typing import Tuple
|
|
11
12
|
|
|
12
13
|
from zcc.constants import LEVEL_BY_VERBOSITY
|
|
14
|
+
from zcc.controller import ControlPoint
|
|
13
15
|
from zcc.description import ControlPointDescription
|
|
14
16
|
from zcc.errors import ControlPointError
|
|
15
17
|
from zcc.protocol import ControlPointProtocol
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
class ControlPointDiscoveryErrors(StrEnum):
|
|
21
|
+
"""Discovery errors."""
|
|
22
|
+
|
|
23
|
+
ALREADY_CONFIGURED = "already_configured"
|
|
24
|
+
CANNOT_CONNECT = "cannot_connect"
|
|
25
|
+
CONNECTION_REFUSED = "connection_refused"
|
|
26
|
+
DISCOVERY_FAILURE = "discovery_failure"
|
|
27
|
+
INVALID_HOST = "invalid_host"
|
|
28
|
+
INVALID_PORT = "invalid_port"
|
|
29
|
+
TIMEOUT = "timeout"
|
|
30
|
+
UNKNOWN = "unknown"
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
class ControlPointDiscoveryProtocol(asyncio.DatagramProtocol):
|
|
19
34
|
"""Listens for ZCC announcements on the defined UDP port."""
|
|
20
35
|
|
|
@@ -76,6 +91,7 @@ class ControlPointDiscoveryService:
|
|
|
76
91
|
self.discovery_complete = self.loop.create_future()
|
|
77
92
|
self.discovery_result: list[ControlPointDescription] = []
|
|
78
93
|
self.never_completes = self.loop.create_future()
|
|
94
|
+
self.validation_result: ControlPointDescription
|
|
79
95
|
|
|
80
96
|
async def discover(
|
|
81
97
|
self, wait_for_all: bool = False
|
|
@@ -135,3 +151,57 @@ class ControlPointDiscoveryService:
|
|
|
135
151
|
async def discovers(self) -> list[ControlPointDescription]:
|
|
136
152
|
"""Discover all local zimi controllers."""
|
|
137
153
|
return await self.discover(wait_for_all=True)
|
|
154
|
+
|
|
155
|
+
async def validate_connection(
|
|
156
|
+
self, host: str, port: int
|
|
157
|
+
) -> ControlPointDescription | dict[str, str]:
|
|
158
|
+
"""Validate ability to connect and close a connection.
|
|
159
|
+
|
|
160
|
+
Return a ControlPointDescription if OK or error dictionary if not.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
error = None
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
socket.gethostbyname(host)
|
|
167
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
168
|
+
s.settimeout(10)
|
|
169
|
+
try:
|
|
170
|
+
s.connect((host, port))
|
|
171
|
+
s.close()
|
|
172
|
+
except ConnectionRefusedError:
|
|
173
|
+
error = {"error": ControlPointDiscoveryErrors.CONNECTION_REFUSED}
|
|
174
|
+
except TimeoutError:
|
|
175
|
+
error = {"error": ControlPointDiscoveryErrors.TIMEOUT}
|
|
176
|
+
except socket.gaierror:
|
|
177
|
+
error = {"error": ControlPointDiscoveryErrors.CANNOT_CONNECT}
|
|
178
|
+
except socket.gaierror:
|
|
179
|
+
error = {"error": ControlPointDiscoveryErrors.INVALID_HOST}
|
|
180
|
+
|
|
181
|
+
if error:
|
|
182
|
+
self.logger.error(error)
|
|
183
|
+
return error
|
|
184
|
+
|
|
185
|
+
api = ControlPoint(ControlPointDescription(host=host, port=port))
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
await api.connect(fast=True)
|
|
189
|
+
except ControlPointError:
|
|
190
|
+
return {"error": ControlPointDiscoveryErrors.CANNOT_CONNECT}
|
|
191
|
+
|
|
192
|
+
self.validation_result = ControlPointDescription(
|
|
193
|
+
brand=api.brand,
|
|
194
|
+
product=api.product,
|
|
195
|
+
host=host,
|
|
196
|
+
port=port,
|
|
197
|
+
mac=api.mac,
|
|
198
|
+
available_tcps=api.available_tcps,
|
|
199
|
+
api_version=api.api_version,
|
|
200
|
+
firmware_version=api.firmware_version
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
api.disconnect()
|
|
204
|
+
|
|
205
|
+
self.logger.info(self.validation_result)
|
|
206
|
+
|
|
207
|
+
return self.validation_result
|
|
@@ -23,9 +23,11 @@ class ControlPointProtocol:
|
|
|
23
23
|
CONTROLPOINT_STATES_EVENTS = "controlpoint_states_events"
|
|
24
24
|
ZCC_STATUS = "zcc_status"
|
|
25
25
|
|
|
26
|
-
SUBSCRIBE_TIMEOUT =
|
|
26
|
+
SUBSCRIBE_TIMEOUT = 2
|
|
27
27
|
GATEWAY_PROPERTIES = "gateway_properties"
|
|
28
|
-
|
|
28
|
+
GATEWAY_PROPERTIES_TIMEOUT = 10
|
|
29
|
+
|
|
30
|
+
STEP_TIMEOUT = 0
|
|
29
31
|
|
|
30
32
|
RETRY_TIMEOUT = 90
|
|
31
33
|
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version: 3.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zcc_helper
|
|
3
|
+
Version: 3.4.dev2
|
|
4
4
|
Summary: ZIMI ZCC helper module
|
|
5
|
-
Home-page: UNKNOWN
|
|
6
5
|
Author: Mark Hannon
|
|
7
6
|
Author-email: mark.hannon@gmail.com
|
|
8
7
|
License: MIT
|
|
9
8
|
Project-URL: Source, https://bitbucket.org/mark_hannon/zcc
|
|
10
|
-
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
10
|
Description-Content-Type: text/markdown
|
|
13
11
|
License-File: LICENSE.txt
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: author-email
|
|
14
|
+
Dynamic: classifier
|
|
15
|
+
Dynamic: description
|
|
16
|
+
Dynamic: description-content-type
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
Dynamic: project-url
|
|
20
|
+
Dynamic: summary
|
|
14
21
|
|
|
15
22
|
# ZCC-HELPER
|
|
16
23
|
|
|
@@ -274,5 +281,3 @@ python -m zcc --execute --device 'bddf0500-4d15-4457-b063-c12ed208a0b0_3' --acti
|
|
|
274
281
|
```
|
|
275
282
|
|
|
276
283
|
This version of the command is relatively slow as it first of all discovers the ZCC on the local LAN, builds a device inventory and then executes the action.
|
|
277
|
-
|
|
278
|
-
|
|
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
|
|
File without changes
|