aioccl 2024.10__py3-none-any.whl → 2024.12.2__py3-none-any.whl
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.
- aioccl/device.py +33 -31
- aioccl/server.py +31 -53
- {aioccl-2024.10.dist-info → aioccl-2024.12.2.dist-info}/METADATA +3 -3
- aioccl-2024.12.2.dist-info/RECORD +9 -0
- {aioccl-2024.10.dist-info → aioccl-2024.12.2.dist-info}/WHEEL +1 -1
- aioccl-2024.10.dist-info/RECORD +0 -9
- {aioccl-2024.10.dist-info → aioccl-2024.12.2.dist-info}/LICENSE +0 -0
- {aioccl-2024.10.dist-info → aioccl-2024.12.2.dist-info}/top_level.txt +0 -0
aioccl/device.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""CCL device mapping."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
import logging
|
@@ -11,72 +12,73 @@ _LOGGER = logging.getLogger(__name__)
|
|
11
12
|
|
12
13
|
CCL_DEVICE_INFO_TYPES = ("serial_no", "mac_address", "model", "fw_ver")
|
13
14
|
|
15
|
+
|
14
16
|
class CCLDevice:
|
17
|
+
"""Mapping for a CCL device."""
|
18
|
+
_binary_sensors: dict[str, CCLSensor] | None = {}
|
19
|
+
_fw_ver: str | None
|
20
|
+
_last_updated_time: float | None
|
21
|
+
_mac_address: str | None
|
22
|
+
_model: str | None
|
23
|
+
_new_binary_sensor_callbacks = set()
|
24
|
+
_new_sensors: list[CCLSensor] | None = []
|
25
|
+
_new_sensor_callbacks = set()
|
26
|
+
_sensors: dict[str, CCLSensor] | None = {}
|
27
|
+
_serial_no: str | None
|
28
|
+
_update_callbacks = set()
|
29
|
+
|
30
|
+
|
15
31
|
def __init__(self, passkey: str):
|
16
32
|
"""Initialize a CCL device."""
|
17
|
-
_LOGGER.debug(
|
33
|
+
_LOGGER.debug("Initializing CCL Device: %s", self)
|
18
34
|
self._passkey = passkey
|
19
|
-
|
20
|
-
self._serial_no: str | None
|
21
|
-
self._mac_address: str | None
|
22
|
-
self._model: str | None
|
23
|
-
self._fw_ver: str | None
|
24
|
-
self._binary_sensors: dict[str, CCLSensor] | None = {}
|
25
|
-
self._sensors: dict[str, CCLSensor] | None = {}
|
26
|
-
self._last_updated_time: float | None
|
27
|
-
|
28
|
-
self._new_sensors: list[CCLSensor] | None = []
|
29
|
-
|
30
|
-
self._update_callbacks = set()
|
31
|
-
self._new_binary_sensor_callbacks = set()
|
32
|
-
self._new_sensor_callbacks = set()
|
33
|
-
|
35
|
+
|
34
36
|
@property
|
35
37
|
def passkey(self) -> str:
|
36
38
|
"""Return the passkey."""
|
37
39
|
return self._passkey
|
38
|
-
|
40
|
+
|
39
41
|
@property
|
40
42
|
def device_id(self) -> str | None:
|
41
43
|
"""Return the device ID."""
|
42
44
|
return self._mac_address.replace(":", "").lower()[-6:]
|
43
|
-
|
45
|
+
|
44
46
|
@property
|
45
47
|
def name(self) -> str | None:
|
46
48
|
"""Return the display name."""
|
47
49
|
return self._model + " - " + self.device_id
|
48
|
-
|
50
|
+
|
49
51
|
@property
|
50
52
|
def mac_address(self) -> str | None:
|
51
53
|
"""Return the MAC address."""
|
52
54
|
return self._mac_address
|
53
|
-
|
55
|
+
|
54
56
|
@property
|
55
57
|
def model(self) -> str | None:
|
56
58
|
"""Return the model."""
|
57
59
|
return self._model
|
58
|
-
|
60
|
+
|
59
61
|
@property
|
60
62
|
def fw_ver(self) -> str | None:
|
61
63
|
"""Return the firmware version."""
|
62
64
|
return self._fw_ver
|
63
|
-
|
65
|
+
|
64
66
|
@property
|
65
67
|
def binary_sensors(self) -> dict[str, CCLSensor] | None:
|
66
68
|
"""Store binary sensor data under this device."""
|
67
69
|
return self._binary_sensors
|
68
|
-
|
70
|
+
|
69
71
|
@property
|
70
72
|
def sensors(self) -> dict[str, CCLSensor] | None:
|
71
73
|
"""Store sensor data under this device."""
|
72
74
|
return self._sensors
|
73
|
-
|
75
|
+
|
74
76
|
def update_info(self, info: dict[str, None | str]) -> None:
|
75
77
|
"""Add or update device info."""
|
76
|
-
self._mac_address = info.get(
|
77
|
-
self._model = info.get(
|
78
|
-
self._fw_ver = info.get(
|
79
|
-
|
78
|
+
self._mac_address = info.get("mac_address")
|
79
|
+
self._model = info.get("model")
|
80
|
+
self._fw_ver = info.get("fw_ver")
|
81
|
+
|
80
82
|
def update_sensors(self, sensors: dict[str, None | str | int | float]) -> None:
|
81
83
|
"""Add or update all sensor values."""
|
82
84
|
for key, value in sensors.items():
|
@@ -108,7 +110,7 @@ class CCLDevice:
|
|
108
110
|
try:
|
109
111
|
for callback in self._update_callbacks:
|
110
112
|
callback()
|
111
|
-
except Exception as err:
|
113
|
+
except Exception as err: # pylint: disable=broad-exception-caught
|
112
114
|
_LOGGER.warning("Error while publishing sensor updates: %s", err)
|
113
115
|
|
114
116
|
def register_new_binary_sensor_cb(self, callback: Callable[[], None]) -> None:
|
@@ -139,5 +141,5 @@ class CCLDevice:
|
|
139
141
|
for callback in self._new_sensor_callbacks:
|
140
142
|
callback(sensor)
|
141
143
|
self._new_sensors.remove(sensor)
|
142
|
-
except Exception as err:
|
143
|
-
_LOGGER.warning("Error while publishing new sensors: %s", err)
|
144
|
+
except Exception as err: # pylint: disable=broad-exception-caught
|
145
|
+
_LOGGER.warning("Error while publishing new sensors: %s", err)
|
aioccl/server.py
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
import logging
|
6
|
+
from typing import Callable
|
6
7
|
|
7
8
|
from aiohttp import web
|
8
|
-
import aiohttp_cors
|
9
9
|
|
10
10
|
from .device import CCLDevice, CCL_DEVICE_INFO_TYPES
|
11
11
|
from .sensor import CCL_SENSORS
|
@@ -21,47 +21,38 @@ class CCLServer:
|
|
21
21
|
devices: dict[str, CCLDevice] = {}
|
22
22
|
|
23
23
|
@staticmethod
|
24
|
-
def
|
25
|
-
"""
|
24
|
+
def register(device: CCLDevice) -> None:
|
25
|
+
"""Register a device with a passkey."""
|
26
26
|
CCLServer.devices.setdefault(device.passkey, device)
|
27
|
-
_LOGGER.debug(CCLServer.devices)
|
28
|
-
|
29
|
-
# routes = web.RouteTableDef()
|
27
|
+
_LOGGER.debug("Device registered: %s", CCLServer.devices)
|
30
28
|
|
29
|
+
@staticmethod
|
30
|
+
def get_handler() -> Callable[[web.BaseRequest], web.Response]:
|
31
|
+
"""Get the handler."""
|
32
|
+
return CCLServer._handler
|
33
|
+
|
31
34
|
@staticmethod
|
32
35
|
async def _handler(request: web.BaseRequest) -> web.Response:
|
33
36
|
"""Handle POST requests for data updating."""
|
34
|
-
|
35
|
-
class HandlerStorage:
|
36
|
-
"""Store data for a single request."""
|
37
|
-
|
38
|
-
body: dict[str, None | str | int | float]
|
39
|
-
info: dict[str, None | str]
|
40
|
-
sensors: dict[str, None | str | int | float]
|
41
|
-
|
42
|
-
_LOGGER.debug("Request received.")
|
43
|
-
|
44
|
-
# Resetting variables
|
37
|
+
_body: dict[str, None | str | int | float] = {}
|
45
38
|
_device: CCLDevice = None
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
HandlerStorage.sensors = {}
|
50
|
-
|
39
|
+
_info: dict[str, None | str] = {}
|
40
|
+
_passkey: str = ''
|
41
|
+
_sensors: dict[str, None | str | int | float] = {}
|
51
42
|
_status: None | int = None
|
52
43
|
_text: None | str = None
|
53
44
|
|
54
45
|
try:
|
55
46
|
for passkey, _device in CCLServer.devices.items():
|
56
47
|
if passkey == request.match_info["passkey"]:
|
48
|
+
_passkey = passkey
|
57
49
|
break
|
58
50
|
assert _device, 404
|
59
51
|
|
60
52
|
assert request.content_type == "application/json", 400
|
61
53
|
assert 0 < request.content_length <= 5000, 400
|
62
54
|
|
63
|
-
|
64
|
-
_LOGGER.debug(HandlerStorage.body)
|
55
|
+
_body = await request.json()
|
65
56
|
|
66
57
|
except Exception as err: # pylint: disable=broad-exception-caught
|
67
58
|
_status = err.args[0]
|
@@ -75,42 +66,29 @@ class CCLServer:
|
|
75
66
|
_LOGGER.debug("Request exception occured: %s", err)
|
76
67
|
return web.Response(status=_status, text=_text)
|
77
68
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
_device.update_info(HandlerStorage.info)
|
86
|
-
_device.update_sensors(HandlerStorage.sensors)
|
87
|
-
_status = 200
|
88
|
-
_text = "200 OK"
|
89
|
-
_LOGGER.debug("Request processed.")
|
90
|
-
return web.Response(status=_status, text=_text)
|
91
|
-
|
92
|
-
app = web.Application()
|
69
|
+
|
70
|
+
for key, value in _body.items():
|
71
|
+
if key in CCL_DEVICE_INFO_TYPES:
|
72
|
+
_info.setdefault(key, value)
|
73
|
+
elif key in CCL_SENSORS:
|
74
|
+
_sensors.setdefault(key, value)
|
93
75
|
|
94
|
-
|
76
|
+
_device.update_info(_info)
|
77
|
+
_device.update_sensors(_sensors)
|
78
|
+
_status = 200
|
79
|
+
_text = "200 OK"
|
80
|
+
_LOGGER.debug("Request processed: %s", _passkey)
|
81
|
+
return web.Response(status=_status, text=_text)
|
95
82
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
{
|
100
|
-
"*": aiohttp_cors.ResourceOptions(
|
101
|
-
allow_credentials=True,
|
102
|
-
expose_headers="*",
|
103
|
-
allow_headers="*",
|
104
|
-
)
|
105
|
-
},
|
106
|
-
)
|
83
|
+
app = web.Application()
|
84
|
+
app.add_routes([web.get('/{passkey}', _handler)])
|
85
|
+
runner = web.AppRunner(app)
|
107
86
|
|
108
87
|
@staticmethod
|
109
88
|
async def run() -> None:
|
110
|
-
"""Try to run the API server
|
89
|
+
"""Try to run the API server."""
|
111
90
|
try:
|
112
91
|
_LOGGER.debug("Trying to start the API server.")
|
113
|
-
CCLServer.runner = web.AppRunner(CCLServer.app)
|
114
92
|
await CCLServer.runner.setup()
|
115
93
|
site = web.TCPSite(CCLServer.runner, port=CCLServer.LISTEN_PORT)
|
116
94
|
await site.start()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: aioccl
|
3
|
-
Version: 2024.
|
3
|
+
Version: 2024.12.2
|
4
4
|
Summary: A Python library for CCL API server
|
5
5
|
Home-page: https://github.com/fkiscd/aioccl
|
6
6
|
Download-URL: https://github.com/fkiscd/aioccl
|
@@ -16,8 +16,8 @@ Classifier: Programming Language :: Python :: 3
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
17
17
|
Description-Content-Type: text/markdown
|
18
18
|
License-File: LICENSE
|
19
|
-
Requires-Dist: aiohttp
|
20
|
-
Requires-Dist:
|
19
|
+
Requires-Dist: aiohttp>3
|
20
|
+
Requires-Dist: aiohttp_cors>=0.7.0
|
21
21
|
|
22
22
|
# aioCCL
|
23
23
|
A Python library for CCL API server
|
@@ -0,0 +1,9 @@
|
|
1
|
+
aioccl/__init__.py,sha256=XnegKtbvHvUTwVuuWNLb4LB9ZuGGar0xrZYOqk7scyg,133
|
2
|
+
aioccl/device.py,sha256=4TYkr3O4XI2l3XdTlGs62qXxsa0pA0_ig0d87nXwaSY,5278
|
3
|
+
aioccl/sensor.py,sha256=tMv_ypqsDIxWdghHQv91PUTOt2kUJGygZmFnJtzOx0k,16905
|
4
|
+
aioccl/server.py,sha256=k1YgFeNImxYILxalPIV23UDB3hvjaOH4pVWeB7cJkmM,3343
|
5
|
+
aioccl-2024.12.2.dist-info/LICENSE,sha256=PBRsTHchx7o0TQ2R2ktEAfFmn1iNHTxcOP_xaeuSAuo,11349
|
6
|
+
aioccl-2024.12.2.dist-info/METADATA,sha256=gYgnLScvW9u0xS60IzPWhLc0OqwKJrUQzMEDufl3w0E,768
|
7
|
+
aioccl-2024.12.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
8
|
+
aioccl-2024.12.2.dist-info/top_level.txt,sha256=-xIJfyfXTaW_EH7XCIHyxjSSSwjLmawa2qhsrHZH1vA,7
|
9
|
+
aioccl-2024.12.2.dist-info/RECORD,,
|
aioccl-2024.10.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
aioccl/__init__.py,sha256=XnegKtbvHvUTwVuuWNLb4LB9ZuGGar0xrZYOqk7scyg,133
|
2
|
-
aioccl/device.py,sha256=AjTlcIFysxPg57InXE8BEnRethEpypZsu5wf3tW5wuk,5390
|
3
|
-
aioccl/sensor.py,sha256=tMv_ypqsDIxWdghHQv91PUTOt2kUJGygZmFnJtzOx0k,16905
|
4
|
-
aioccl/server.py,sha256=2uilFTQ44SOoPG925K7lW9WJvGBgllaoR8QznK2LNe4,3916
|
5
|
-
aioccl-2024.10.dist-info/LICENSE,sha256=PBRsTHchx7o0TQ2R2ktEAfFmn1iNHTxcOP_xaeuSAuo,11349
|
6
|
-
aioccl-2024.10.dist-info/METADATA,sha256=FCuVzmEzJ9_tTnlPF6jGPVFq-JrIm3dZD4V4K8i75_E,768
|
7
|
-
aioccl-2024.10.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
8
|
-
aioccl-2024.10.dist-info/top_level.txt,sha256=-xIJfyfXTaW_EH7XCIHyxjSSSwjLmawa2qhsrHZH1vA,7
|
9
|
-
aioccl-2024.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|