Skip to content

Commit cc7d693

Browse files
authored
Merge pull request #14 from siku2/dev
Modernize project
2 parents fc354b5 + 0748939 commit cc7d693

File tree

16 files changed

+866
-105
lines changed

16 files changed

+866
-105
lines changed

.devcontainer/devcontainer.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// For format details, see https://aka.ms/devcontainer.json.
2+
{
3+
"name": "Python 3",
4+
"image": "mcr.microsoft.com/devcontainers/python:1-3-bookworm",
5+
"runArgs": [
6+
// Use host network for discovery
7+
"--network=host"
8+
],
9+
"features": {
10+
"ghcr.io/va-h/devcontainers-features/uv:1": {}
11+
},
12+
"customizations": {
13+
"vscode": {
14+
"extensions": [
15+
"charliermarsh.ruff",
16+
"tamasfe.even-better-toml",
17+
]
18+
}
19+
}
20+
}

.github/workflows/python.yml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Python lint and packages
22

33
on:
44
push:
5-
branches: [ master ]
5+
branches: [ master, dev ]
66
pull_request:
7-
branches: [ master ]
7+
branches: [ master, dev ]
88

99
jobs:
1010
build:
@@ -22,10 +22,8 @@ jobs:
2222
with:
2323
python-version: ${{ matrix.python-version }}
2424

25-
- name: Install dependencies
26-
run: |
27-
python -m pip install --upgrade pip
28-
python setup.py install
25+
- uses: astral-sh/ruff-action@v3
2926

30-
- name: Black Code Formatter
31-
uses: jpetrucciani/black-check@22.12.0
27+
- uses: astral-sh/ruff-action@v3
28+
with:
29+
args: "format --check --diff"

MANIFEST.in

Lines changed: 0 additions & 1 deletion
This file was deleted.

dingz/__init__.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
"""Base details for the dingz Python bindings."""
2+
23
import asyncio
34
import socket
45
from typing import Any, Mapping, Optional
56

67
import aiohttp
78
import sys
9+
810
if sys.version_info >= (3, 11):
911
import asyncio as async_timeout
1012
else:
1113
import async_timeout
1214

13-
from .constants import TIMEOUT, USER_AGENT, CONTENT_TYPE_JSON, CONTENT_TYPE, CONTENT_TYPE_TEXT_PLAIN
15+
from .constants import (
16+
TIMEOUT,
17+
USER_AGENT,
18+
CONTENT_TYPE_JSON,
19+
CONTENT_TYPE,
20+
CONTENT_TYPE_TEXT_PLAIN,
21+
)
1422
from .exceptions import DingzConnectionError
1523

1624

@@ -38,14 +46,23 @@ async def make_call(
3846
self._close_session = True
3947

4048
try:
41-
with async_timeout.timeout(TIMEOUT):
49+
async with async_timeout.timeout(TIMEOUT):
4250
response = await self._session.request(
43-
method, uri, data=data, json=json_data, params=parameters, headers=headers,
51+
method,
52+
uri,
53+
data=data,
54+
json=json_data,
55+
params=parameters,
56+
headers=headers,
4457
)
4558
except asyncio.TimeoutError as exception:
46-
raise DingzConnectionError("Timeout occurred while connecting to dingz unit") from exception
59+
raise DingzConnectionError(
60+
"Timeout occurred while connecting to dingz unit"
61+
) from exception
4762
except (aiohttp.ClientError, socket.gaierror) as exception:
48-
raise DingzConnectionError("Error occurred while communicating with dingz") from exception
63+
raise DingzConnectionError(
64+
"Error occurred while communicating with dingz"
65+
) from exception
4966

5067
if CONTENT_TYPE_JSON in response.headers.get(CONTENT_TYPE, ""):
5168
response_json = await response.json()

dingz/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Command-line interface to interact with dingz devices."""
2+
23
import asyncio
34
from functools import wraps
45

dingz/constants.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Constants used by the Python API for interacting with dingz units."""
2-
import pkg_resources
2+
3+
import importlib.metadata
34

45
try:
5-
__version__ = pkg_resources.get_distribution("setuptools").version
6+
__version__ = importlib.metadata.version("dingz")
67
except Exception:
78
__version__ = "unknown"
89

dingz/dimmer.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ async def toggle(self, brightness_pct=100):
2727
await self.operate_light(action, brightness_pct)
2828

2929
async def turn_on(self, brightness_pct=100):
30-
""" Turn light on.
30+
"""Turn light on.
3131
:param brightness_pct: brightness in percent, or None.
3232
"""
3333
await self.operate_light("on", brightness_pct)
3434

3535
async def turn_off(self):
36-
""" Rurn light off."""
36+
"""Rurn light off."""
3737
await self.operate_light("off")
3838

39-
VALID_OPERATIONS = ('on', 'off')
39+
VALID_OPERATIONS = ("on", "off")
4040

4141
async def operate_light(self, action, brightness_pct=None):
4242
"""
@@ -46,14 +46,20 @@ async def operate_light(self, action, brightness_pct=None):
4646
:return:
4747
"""
4848
if action not in Dimmer.VALID_OPERATIONS:
49-
raise ValueError("invalid action %s, expected one of %s" %
50-
(repr(action), repr(Dimmer.VALID_OPERATIONS)))
49+
raise ValueError(
50+
"invalid action %s, expected one of %s"
51+
% (repr(action), repr(Dimmer.VALID_OPERATIONS))
52+
)
5153

5254
if brightness_pct is not None and (brightness_pct > 100 or brightness_pct < 0):
53-
raise ValueError("invalid brightness_pct %s, expected value between 0 and 100" %
54-
(repr(brightness_pct)))
55-
56-
url = URL(self.dingz.uri).join(URL("%s/%s/%s" % (DIMMER, self.index_relative, action)))
55+
raise ValueError(
56+
"invalid brightness_pct %s, expected value between 0 and 100"
57+
% (repr(brightness_pct))
58+
)
59+
60+
url = URL(self.dingz.uri).join(
61+
URL("%s/%s/%s" % (DIMMER, self.index_relative, action))
62+
)
5763
params = {}
5864
if brightness_pct is not None:
5965
params["value"] = str(brightness_pct)
@@ -73,18 +79,18 @@ def _consume_state(self, state_details):
7379
:param state_details:
7480
:return:
7581
"""
76-
assert self.absolute_index == state_details['index']['absolute']
82+
assert self.absolute_index == state_details["index"]["absolute"]
7783
self.seen_state = True
78-
self.index_relative = state_details['index']['relative']
79-
self.on = state_details['on']
80-
self.brightness_pct = state_details['output']
84+
self.index_relative = state_details["index"]["relative"]
85+
self.on = state_details["on"]
86+
self.brightness_pct = state_details["output"]
8187

8288
def _consume_config(self, config):
8389
# "output": "halogen", "name": "Dimmable 3", "feedback": null, "feedback_intensity": 10
84-
self.output = config['output']
85-
self.enabled = config['output'] != 'not_connected'
86-
self.dimmable = config['output'] != 'non_dimmable'
87-
self.name = config['name']
90+
self.output = config["output"]
91+
self.enabled = config["output"] != "not_connected"
92+
self.dimmable = config["output"] != "non_dimmable"
93+
self.name = config["name"]
8894

8995

9096
class DimmerRegistry(BaseRegistry[Dimmer]):

dingz/dingz.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Python client/wrapper to interact with dingz devices."""
2+
23
import logging
34

45
import aiohttp
@@ -25,7 +26,8 @@
2526
STATE,
2627
SYSTEM_CONFIG,
2728
BLIND_CONFIGURATION,
28-
DIMMER_CONFIGURATION, SHADE,
29+
DIMMER_CONFIGURATION,
30+
SHADE,
2931
)
3032
from .dimmer import DimmerRegistry
3133
from .shade import ShadeRegistry
@@ -154,9 +156,9 @@ async def get_state(self) -> None:
154156
# first fetch the device state
155157
url = URL(self.uri).join(URL(STATE))
156158
device_state = await make_call(self, uri=url)
157-
self._consume_sensor_state(device_state['sensors'])
158-
self._dimmers._consume_dimmer_state(device_state['dimmers'])
159-
self._shades._consume_device_state(device_state['blinds'])
159+
self._consume_sensor_state(device_state["sensors"])
160+
self._dimmers._consume_dimmer_state(device_state["dimmers"])
161+
self._shades._consume_device_state(device_state["blinds"])
160162
self._state = device_state
161163

162164
if len(self._shades.all()) > 0:
@@ -169,13 +171,13 @@ async def get_blind_config(self) -> None:
169171
"""Get the configuration of the blinds."""
170172
url = URL(self.uri).join(URL(BLIND_CONFIGURATION))
171173
response = await make_call(self, uri=url)
172-
self._blind_config = response['blinds']
174+
self._blind_config = response["blinds"]
173175

174176
async def get_dimmer_config(self) -> None:
175177
"""Get the configuration of the dimmer/lights."""
176178
url = URL(self.uri).join(URL(DIMMER_CONFIGURATION))
177179
response = await make_call(self, uri=url)
178-
self._dimmer_config = response['dimmers']
180+
self._dimmer_config = response["dimmers"]
179181

180182
async def get_system_config(self) -> None:
181183
"""Get the system configuration of a dingz."""

dingz/discovery.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Discover dingz devices in a network."""
2+
23
import asyncio
34
import logging
45
from typing import Optional, List
@@ -66,7 +67,7 @@ class DiscoveryProtocol(asyncio.DatagramProtocol):
6667
"""Representation of the discovery protocol."""
6768

6869
def __init__(self, registry: DeviceRegistry):
69-
""""Initialize the discovery protocol."""
70+
""" "Initialize the discovery protocol."""
7071
super().__init__()
7172
self.registry = registry
7273

@@ -108,6 +109,9 @@ async def discover_dingz_devices(timeout: int = 7) -> List[DiscoveredDevice]:
108109
devices = registry.devices()
109110
for device in devices:
110111
_LOGGER.debug(
111-
"Discovered dingz %s (%s) (MAC address: %s)", device.host, device.type, device.mac
112+
"Discovered dingz %s (%s) (MAC address: %s)",
113+
device.host,
114+
device.type,
115+
device.mac,
112116
)
113117
return devices

dingz/registry.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
def organize_by_absolute_index(items):
55
result = []
66
for item in items:
7-
result.append((item['index']['absolute'], item))
7+
result.append((item["index"]["absolute"], item))
88

99
return result
1010

@@ -21,6 +21,7 @@ class BaseRegistry(Generic[T]):
2121
Note, the absolute index remains the same, regardless of deactivation by the dip switch.
2222
So shade 1 is always the shade operated by output 2&3, even if it is the only shade.
2323
"""
24+
2425
_registry: Dict[int, T]
2526

2627
def __init__(self, factory):

0 commit comments

Comments
 (0)