aioccl 2024.12.7__tar.gz → 2024.12.12__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aioccl
3
- Version: 2024.12.7
3
+ Version: 2024.12.12
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
@@ -17,7 +17,6 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: aiohttp>3
20
- Requires-Dist: aiohttp_cors>=0.7.0
21
20
 
22
21
  # aioCCL
23
22
  A Python library for CCL API server
@@ -0,0 +1,194 @@
1
+ """CCL device mapping."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import time
7
+ from typing import Callable, TypedDict
8
+
9
+ from .sensor import CCLSensor, CCL_SENSORS
10
+
11
+ _LOGGER = logging.getLogger(__name__)
12
+
13
+ CCL_DEVICE_INFO_TYPES = ("serial_no", "mac_address", "model", "fw_ver")
14
+
15
+
16
+ class CCLDevice:
17
+ """Mapping for a CCL device."""
18
+
19
+ def __init__(self, passkey: str):
20
+ """Initialize a CCL device."""
21
+
22
+ class Info(TypedDict):
23
+ """Store device information."""
24
+ fw_ver: str | None
25
+ last_update_time: float | None
26
+ mac_address: str | None
27
+ model: str | None
28
+ passkey: str
29
+ serial_no: str | None
30
+
31
+ self._info: Info = {
32
+ "fw_ver": None,
33
+ "last_update_time": None,
34
+ "mac_address": None,
35
+ "model": None,
36
+ "passkey": passkey,
37
+ "serial_no": None,
38
+ }
39
+
40
+ self._binary_sensors: dict[str, CCLSensor] | None = {}
41
+ self._sensors: dict[str, CCLSensor] | None = {}
42
+ self._update_callbacks = {}
43
+
44
+ self._new_binary_sensor_callbacks = set()
45
+ self._new_sensors: list[CCLSensor] | None = []
46
+ self._new_sensor_callbacks = set()
47
+
48
+ @property
49
+ def passkey(self) -> str:
50
+ """Return the passkey."""
51
+ return self._info["passkey"]
52
+
53
+ @property
54
+ def device_id(self) -> str | None:
55
+ """Return the device ID."""
56
+ if self.mac_address is None:
57
+ return None
58
+ return self.mac_address.replace(":", "").lower()[-6:]
59
+
60
+ @property
61
+ def last_update_time(self) -> str | None:
62
+ """Return the last update time."""
63
+ return self._info["last_update_time"]
64
+
65
+ @property
66
+ def name(self) -> str | None:
67
+ """Return the display name."""
68
+ if self.device_id is not None:
69
+ return self.model + " - " + self.device_id
70
+ return self._info["model"]
71
+
72
+ @property
73
+ def mac_address(self) -> str | None:
74
+ """Return the MAC address."""
75
+ return self._info["mac_address"]
76
+
77
+ @property
78
+ def model(self) -> str | None:
79
+ """Return the model."""
80
+ return self._info["model"]
81
+
82
+ @property
83
+ def fw_ver(self) -> str | None:
84
+ """Return the firmware version."""
85
+ return self._info["fw_ver"]
86
+
87
+ @property
88
+ def binary_sensors(self) -> dict[str, CCLSensor] | None:
89
+ """Store binary sensor data under this device."""
90
+ return self._binary_sensors
91
+
92
+ @property
93
+ def sensors(self) -> dict[str, CCLSensor] | None:
94
+ """Store sensor data under this device."""
95
+ return self._sensors
96
+
97
+ def update_info(self, new_info: dict[str, None | str]) -> None:
98
+ """Add or update device info."""
99
+ for key, value in new_info.items():
100
+ if key in self._info:
101
+ self._info[key] = str(value)
102
+ self._info["last_update_time"] = time.monotonic()
103
+
104
+ def update_sensors(self, sensors: dict[str, None | str | int | float]) -> None:
105
+ """Add or update all sensor values."""
106
+ for key, value in sensors.items():
107
+ if CCL_SENSORS.get(key).binary:
108
+ if key not in self.binary_sensors:
109
+ self._binary_sensors[key] = CCLSensor(key)
110
+ self._new_sensors.append(self.binary_sensors[key])
111
+ self._binary_sensors[key].value = value
112
+ else:
113
+ if key not in self.sensors:
114
+ self._sensors[key] = CCLSensor(key)
115
+ self._new_sensors.append(self.sensors[key])
116
+ self._sensors[key].value = value
117
+
118
+ add_count = self._publish_new_sensors()
119
+ _LOGGER.debug(
120
+ "Added %s new sensors for device %s at %s.",
121
+ add_count,
122
+ self.device_id,
123
+ self.last_update_time,
124
+ )
125
+
126
+ update_count = self._publish_updates()
127
+ _LOGGER.debug(
128
+ "Updated %s sensors in total for device %s at %s.",
129
+ update_count,
130
+ self.device_id,
131
+ self.last_update_time,
132
+ )
133
+
134
+ def register_update_cb(self, sensor_key, callback: Callable[[], None]) -> None:
135
+ """Register callback, called when Sensor changes state."""
136
+ self._update_callbacks[sensor_key] = callback
137
+
138
+ def remove_update_cb(self, sensor_key, callback: Callable[[], None]) -> None:
139
+ """Remove previously registered callback."""
140
+ self._update_callbacks.pop(sensor_key, None)
141
+
142
+ def _publish_updates(self) -> int:
143
+ """Schedule call all registered callbacks."""
144
+ count = 0
145
+ for sensor_key, callback in self._update_callbacks.items():
146
+ try:
147
+ callback()
148
+ count += 1
149
+ except Exception as err: # pylint: disable=broad-exception-caught
150
+ _LOGGER.warning(
151
+ "Error while updating sensor %s for device %s: %s",
152
+ sensor_key,
153
+ self.device_id,
154
+ err,
155
+ )
156
+ return count
157
+
158
+ def register_new_binary_sensor_cb(self, callback: Callable[[], None]) -> None:
159
+ """Register callback, called when Sensor changes state."""
160
+ self._new_binary_sensor_callbacks.add(callback)
161
+
162
+ def remove_new_binary_sensor_cb(self, callback: Callable[[], None]) -> None:
163
+ """Remove previously registered callback."""
164
+ self._new_binary_sensor_callbacks.discard(callback)
165
+
166
+ def register_new_sensor_cb(self, callback: Callable[[], None]) -> None:
167
+ """Register callback, called when Sensor changes state."""
168
+ self._new_sensor_callbacks.add(callback)
169
+
170
+ def remove_new_sensor_cb(self, callback: Callable[[], None]) -> None:
171
+ """Remove previously registered callback."""
172
+ self._new_sensor_callbacks.discard(callback)
173
+
174
+ def _publish_new_sensors(self) -> None:
175
+ """Schedule call all registered callbacks."""
176
+ count = 0
177
+ for sensor in self._new_sensors[:]:
178
+ try:
179
+ if sensor.binary:
180
+ for callback in self._new_binary_sensor_callbacks:
181
+ callback(sensor)
182
+ else:
183
+ for callback in self._new_sensor_callbacks:
184
+ callback(sensor)
185
+ self._new_sensors.remove(sensor)
186
+ count += 1
187
+ except Exception as err: # pylint: disable=broad-exception-caught
188
+ _LOGGER.warning(
189
+ "Error while adding sensor %s for device %s: %s",
190
+ sensor.key,
191
+ self.device_id,
192
+ err,
193
+ )
194
+ return count
@@ -23,60 +23,60 @@ class CCLServer:
23
23
  def register(device: CCLDevice) -> None:
24
24
  """Register a device with a passkey."""
25
25
  CCLServer.devices.setdefault(device.passkey, device)
26
- _LOGGER.debug("Device registered: %s", device)
27
-
26
+ _LOGGER.debug("Device registered: %s", device.passkey)
27
+
28
28
  @staticmethod
29
29
  async def handler(request: web.BaseRequest | web.Request) -> web.Response:
30
30
  """Handle POST requests for data updating."""
31
- _body: dict[str, None | str | int | float] = {}
32
- _device: CCLDevice = None
33
- _info: dict[str, None | str] = {}
34
- _passkey: str = ''
35
- _sensors: dict[str, None | str | int | float] = {}
36
- _status: None | int = None
37
- _text: None | str = None
38
-
31
+ body: dict[str, None | str | int | float] = {}
32
+ device: CCLDevice = None
33
+ info: dict[str, None | str] = {}
34
+ passkey: str = ""
35
+ sensors: dict[str, None | str | int | float] = {}
36
+ status: None | int = None
37
+ text: None | str = None
38
+
39
+ _LOGGER.debug("Request received: %s", passkey)
39
40
  try:
40
- _passkey = request.path[-8:]
41
- for passkey in CCLServer.devices:
42
- if passkey == _passkey:
43
- _device = CCLServer.devices[_passkey]
41
+ passkey = request.path[-8:]
42
+ for ref_passkey, ref_device in CCLServer.devices.items():
43
+ if passkey == ref_passkey:
44
+ device = ref_device
44
45
  break
45
- assert isinstance(_device, CCLDevice), 404
46
+ assert isinstance(device, CCLDevice), 404
46
47
 
47
48
  assert request.content_type == "application/json", 400
48
49
  assert 0 < request.content_length <= 5000, 400
49
50
 
50
- _body = await request.json()
51
+ body = await request.json()
51
52
 
52
53
  except Exception as err: # pylint: disable=broad-exception-caught
53
- _status = err.args[0]
54
- if _status == 400:
55
- _text = "400 Bad Request"
56
- elif _status == 404:
57
- _text = "404 Not Found"
54
+ status = err.args[0]
55
+ if status == 400:
56
+ text = "400 Bad Request"
57
+ elif status == 404:
58
+ text = "404 Not Found"
58
59
  else:
59
- _status = 500
60
- _text = "500 Internal Server Error"
60
+ status = 500
61
+ text = "500 Internal Server Error"
61
62
  _LOGGER.debug("Request exception occured: %s", err)
62
- return web.Response(status=_status, text=_text)
63
+ return web.Response(status=status, text=text)
63
64
 
64
-
65
- for key, value in _body.items():
65
+ for key, value in body.items():
66
66
  if key in CCL_DEVICE_INFO_TYPES:
67
- _info.setdefault(key, value)
67
+ info.setdefault(key, value)
68
68
  elif key in CCL_SENSORS:
69
- _sensors.setdefault(key, value)
69
+ sensors.setdefault(key, value)
70
70
 
71
- _device.update_info(_info)
72
- _device.update_sensors(_sensors)
73
- _status = 200
74
- _text = "200 OK"
75
- _LOGGER.debug("Request processed: %s", _passkey)
76
- return web.Response(status=_status, text=_text)
71
+ device.update_info(info)
72
+ device.update_sensors(sensors)
73
+ status = 200
74
+ text = "200 OK"
75
+ _LOGGER.debug("Request processed: %s", passkey)
76
+ return web.Response(status=status, text=text)
77
77
 
78
78
  app = web.Application()
79
- app.add_routes([web.get('/{passkey}', handler)])
79
+ app.add_routes([web.get("/{passkey}", handler)])
80
80
  runner = web.AppRunner(app)
81
81
 
82
82
  @staticmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: aioccl
3
- Version: 2024.12.7
3
+ Version: 2024.12.12
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
@@ -17,7 +17,6 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: aiohttp>3
20
- Requires-Dist: aiohttp_cors>=0.7.0
21
20
 
22
21
  # aioCCL
23
22
  A Python library for CCL API server
@@ -0,0 +1 @@
1
+ aiohttp>3
@@ -3,7 +3,7 @@
3
3
  from pathlib import Path
4
4
  from setuptools import find_packages, setup
5
5
 
6
- VERSION = "2024.12.7"
6
+ VERSION = "2024.12.12"
7
7
 
8
8
  ROOT_DIR = Path(__file__).parent.resolve()
9
9
 
@@ -20,8 +20,7 @@ setup(
20
20
  url="https://github.com/fkiscd/aioccl",
21
21
  download_url="https://github.com/fkiscd/aioccl",
22
22
  install_requires=[
23
- "aiohttp>3",
24
- "aiohttp_cors>=0.7.0"
23
+ "aiohttp>3"
25
24
  ],
26
25
  include_package_data=True,
27
26
  classifiers=[
@@ -1,150 +0,0 @@
1
- """CCL device mapping."""
2
-
3
- from __future__ import annotations
4
-
5
- import logging
6
- import time
7
- from typing import Callable
8
-
9
- from .sensor import CCLSensor, CCL_SENSORS
10
-
11
- _LOGGER = logging.getLogger(__name__)
12
-
13
- CCL_DEVICE_INFO_TYPES = ("serial_no", "mac_address", "model", "fw_ver")
14
-
15
-
16
- class CCLDevice:
17
- """Mapping for a CCL device."""
18
- _binary_sensors: dict[str, CCLSensor] | None = {}
19
- _device_id: str | None = None
20
- _fw_ver: str | None = None
21
- _last_updated_time: float | None = None
22
- _mac_address: str | None = None
23
- _model: str | None = None
24
- _new_binary_sensor_callbacks = set()
25
- _new_sensors: list[CCLSensor] | None = []
26
- _new_sensor_callbacks = set()
27
- _passkey = ''
28
- _sensors: dict[str, CCLSensor] | None = {}
29
- _serial_no: str | None = None
30
- _update_callbacks = set()
31
-
32
- def __init__(self, passkey: str):
33
- """Initialize a CCL device."""
34
- self._passkey = passkey
35
-
36
- @property
37
- def passkey(self) -> str:
38
- """Return the passkey."""
39
- return self._passkey
40
-
41
- @property
42
- def device_id(self) -> str | None:
43
- """Return the device ID."""
44
- try:
45
- self._device_id = self._mac_address.replace(":", "").lower()[-6:]
46
- except Exception: # pylint: disable=broad-exception-caught
47
- return None
48
- return self._device_id
49
-
50
- @property
51
- def name(self) -> str | None:
52
- """Return the display name."""
53
- if self._device_id is not None:
54
- return self._model + " - " + self._device_id
55
- return self._model
56
-
57
- @property
58
- def mac_address(self) -> str | None:
59
- """Return the MAC address."""
60
- return self._mac_address
61
-
62
- @property
63
- def model(self) -> str | None:
64
- """Return the model."""
65
- return self._model
66
-
67
- @property
68
- def fw_ver(self) -> str | None:
69
- """Return the firmware version."""
70
- return self._fw_ver
71
-
72
- @property
73
- def binary_sensors(self) -> dict[str, CCLSensor] | None:
74
- """Store binary sensor data under this device."""
75
- return self._binary_sensors
76
-
77
- @property
78
- def sensors(self) -> dict[str, CCLSensor] | None:
79
- """Store sensor data under this device."""
80
- return self._sensors
81
-
82
- def update_info(self, info: dict[str, None | str]) -> None:
83
- """Add or update device info."""
84
- self._mac_address = info.get("mac_address")
85
- self._model = info.get("model")
86
- self._fw_ver = info.get("fw_ver")
87
-
88
- def update_sensors(self, sensors: dict[str, None | str | int | float]) -> None:
89
- """Add or update all sensor values."""
90
- for key, value in sensors.items():
91
- if CCL_SENSORS.get(key).binary:
92
- if key not in self._binary_sensors:
93
- self._binary_sensors[key] = CCLSensor(key)
94
- self._new_sensors.append(self._binary_sensors[key])
95
- self._binary_sensors[key].value = value
96
- else:
97
- if key not in self._sensors:
98
- self._sensors[key] = CCLSensor(key)
99
- self._new_sensors.append(self._sensors[key])
100
- self._sensors[key].value = value
101
- self._publish_new_sensors()
102
- self._publish_updates()
103
- self._last_updated_time = time.monotonic()
104
- _LOGGER.debug("Sensors Updated: %s", self._last_updated_time)
105
-
106
- def register_update_cb(self, callback: Callable[[], None]) -> None:
107
- """Register callback, called when Sensor changes state."""
108
- self._update_callbacks.add(callback)
109
-
110
- def remove_update_cb(self, callback: Callable[[], None]) -> None:
111
- """Remove previously registered callback."""
112
- self._update_callbacks.discard(callback)
113
-
114
- def _publish_updates(self) -> None:
115
- """Schedule call all registered callbacks."""
116
- try:
117
- for callback in self._update_callbacks:
118
- callback()
119
- except Exception as err: # pylint: disable=broad-exception-caught
120
- _LOGGER.warning("Error while publishing sensor updates: %s", err)
121
-
122
- def register_new_binary_sensor_cb(self, callback: Callable[[], None]) -> None:
123
- """Register callback, called when Sensor changes state."""
124
- self._new_binary_sensor_callbacks.add(callback)
125
-
126
- def remove_new_binary_sensor_cb(self, callback: Callable[[], None]) -> None:
127
- """Remove previously registered callback."""
128
- self._new_binary_sensor_callbacks.discard(callback)
129
-
130
- def register_new_sensor_cb(self, callback: Callable[[], None]) -> None:
131
- """Register callback, called when Sensor changes state."""
132
- self._new_sensor_callbacks.add(callback)
133
-
134
- def remove_new_sensor_cb(self, callback: Callable[[], None]) -> None:
135
- """Remove previously registered callback."""
136
- self._new_sensor_callbacks.discard(callback)
137
-
138
- def _publish_new_sensors(self) -> None:
139
- """Schedule call all registered callbacks."""
140
- for sensor in self._new_sensors[:]:
141
- try:
142
- if sensor.binary:
143
- for callback in self._new_binary_sensor_callbacks:
144
- callback(sensor)
145
- else:
146
- for callback in self._new_sensor_callbacks:
147
- callback(sensor)
148
- self._new_sensors.remove(sensor)
149
- except Exception as err: # pylint: disable=broad-exception-caught
150
- _LOGGER.warning("Error while publishing new sensors: %s", err)
@@ -1,2 +0,0 @@
1
- aiohttp>3
2
- aiohttp_cors>=0.7.0
File without changes
File without changes
File without changes
File without changes