Skip to content

Commit 420c312

Browse files
committed
v0.0.2 - moving to uv, adding type data
1 parent a43c0cd commit 420c312

File tree

10 files changed

+523
-155
lines changed

10 files changed

+523
-155
lines changed

.github/workflows/mypy.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,5 @@ jobs:
1919
python-version: '3.9'
2020
- name: Running mypy
2121
run: |
22-
python --version
23-
python -m pip install --quiet --no-cache-dir --upgrade poetry
24-
poetry install
25-
poetry run mypy $(basename $(pwd)) test*.py
22+
python -m pip install --quiet --no-cache-dir --upgrade uv
23+
uv run mypy $(basename $(pwd)) test*.py

.github/workflows/pylint.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,5 @@ jobs:
1919
python-version: '3.9'
2020
- name: Running tests
2121
run: |
22-
python -m pip install --quiet --no-cache-dir --upgrade poetry
23-
poetry install
24-
poetry run pylint $(basename $(pwd))
25-
poetry run pylint test*.py
22+
python -m pip install --quiet --no-cache-dir --upgrade uv
23+
uv run ruff check mqttgpio tests

.github/workflows/pytest.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,5 @@ jobs:
1919
python-version: '3.9'
2020
- name: Running pytest
2121
run: |
22-
python --version
23-
python -m pip install --quiet --no-cache-dir --upgrade poetry
24-
poetry install
25-
poetry run python -m pytest
22+
python -m pip install --quiet --no-cache-dir --upgrade uv
23+
uv run pytest

mqttgpio.conf.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[Default]
2-
logging=foo # one of 'info', 'debug', 'warning', 'error'
2+
logging=info # one of 'info', 'debug', 'warning', 'error'
33

44
[MQTT]
55
MQTTBroker = mqtt.example.com

mqttgpio/__init__.py

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,129 @@
1-
""" mqttgpio - a shim between MQTT and GPIO on raspberry Pi """
1+
"""mqttgpio - a shim between MQTT and GPIO on raspberry Pi"""
22

3+
from configparser import ConfigParser
34
import json
45
import logging
56

6-
import gpiozero # type: ignore
7-
import paho.mqtt.client as mqtt # type: ignore
8-
9-
class GPIOSwitch(): #pylint: disable=too-many-instance-attributes
10-
""" a single pin controller """
11-
def __init__(self, name: str,
12-
pin: int,
13-
client: mqtt.Client,
14-
qos: int,
15-
logging_object: logging.Logger,
16-
initial_state: bool = False,
17-
mock_pins: bool = False,
18-
): #pylint: disable=too-many-arguments
7+
import gpiozero # type: ignore
8+
import paho.mqtt.client as mqtt
9+
from paho.mqtt.client import MQTTMessageInfo
10+
11+
CONFIG_FILES = ["/etc/mqttgpio.conf", "./mqttgpio.conf", "/opt/mqttgpio/mqttgpio.conf"]
12+
13+
LOG_LEVELS = {
14+
"info": logging.INFO,
15+
"debug": logging.DEBUG,
16+
"warning": logging.WARNING,
17+
"error": logging.ERROR,
18+
}
19+
20+
21+
def load_config(log_object: logging.Logger) -> ConfigParser:
22+
config = ConfigParser()
23+
parsed_files = config.read(CONFIG_FILES)
24+
25+
LOG_LEVEL = config.get("Default", "logging", fallback="info")
26+
27+
if LOG_LEVEL.lower() in LOG_LEVELS:
28+
log_object.setLevel(LOG_LEVELS[LOG_LEVEL.lower()])
29+
else:
30+
log_object.setLevel(logging.DEBUG)
31+
log_object.debug(
32+
"Configuration file had a misconfigured 'logging' setting (%s) - setting to DEBUG",
33+
LOG_LEVEL,
34+
) # pylint: disable=line-too-long
35+
36+
log_object.info("Loaded configuration from: %s", ",".join(parsed_files))
37+
38+
return config
39+
40+
41+
class GPIOSwitch:
42+
"""a single pin controller"""
43+
44+
def __init__(
45+
self,
46+
name: str,
47+
pin: int,
48+
client: mqtt.Client,
49+
qos: int,
50+
logging_object: logging.Logger,
51+
initial_state: bool = False,
52+
mock_pins: bool = False,
53+
) -> None:
1954
self.name = name
20-
self.device_class = 'switch'
55+
self.device_class = "switch"
2156
self.client = client
2257
self.mqtt_qos = qos
2358
self.logger = logging_object
2459
self.mock_pins = mock_pins
2560
if mock_pins:
2661
self.pin_io = gpiozero.Device.pin_factory.pin(pin)
2762
else:
28-
self.pin_io = gpiozero.LED(pin) # pylint: disable=undefined-variable
63+
self.pin_io = gpiozero.LED(pin) # pylint: disable=undefined-variable
2964

3065
# might as well say hello on startup
3166
self.announce_config()
3267
self._set_state(initial_state)
3368

34-
def str_state(self):
35-
""" returns the state in the home assistant version """
69+
def str_state(self) -> str:
70+
"""returns the state in the home assistant version"""
3671
if self.state:
3772
return "ON"
3873
return "OFF"
3974

40-
def config_topic(self):
41-
""" returns the config topic """
75+
def config_topic(self) -> str:
76+
"""returns the config topic"""
4277
return f"homeassistant/{self.device_class}/{self.name}/config"
4378

44-
def state_topic(self):
45-
""" returns the state topic as a string """
79+
def state_topic(self) -> str:
80+
"""returns the state topic as a string"""
4681
return f"{self.name}/state"
4782

48-
def command_topic(self):
49-
""" returns the command topic as a string """
83+
def command_topic(self) -> str:
84+
"""returns the command topic as a string"""
5085
return f"{self.name}/cmnd"
5186

52-
def _publish(self, topic, payload):
53-
""" publishes a message """
54-
return self.client.publish(topic,
55-
payload,
56-
qos=self.mqtt_qos,
57-
)
58-
87+
def _publish(self, topic: str, payload: str) -> MQTTMessageInfo:
88+
"""publishes a message"""
89+
return self.client.publish(
90+
topic,
91+
payload,
92+
qos=self.mqtt_qos,
93+
)
5994

60-
def announce_config(self):
61-
""" sends the MQTT message to configure
62-
home assistant
95+
def announce_config(self) -> None:
96+
"""sends the MQTT message to configure
97+
home assistant
6398
"""
6499
payload = {
65-
'name' : self.name,
66-
'state_topic' : self.state_topic(),
67-
'command_topic' : self.command_topic(),
68-
"val_tpl" : '{{value_json.POWER}}',
100+
"name": self.name,
101+
"state_topic": self.state_topic(),
102+
"command_topic": self.command_topic(),
103+
"val_tpl": "{{value_json.POWER}}",
69104
}
70105
self.logger.debug(
71106
"%s.announce_config(%s)",
72107
self.name,
73108
payload,
74-
)
109+
)
75110
self._publish(
76111
self.config_topic(),
77112
payload=json.dumps(payload),
78-
)
113+
)
79114

80-
def announce_state(self):
81-
""" sends the MQTT message about the current state """
82-
payload = {'POWER' : self.str_state()}
115+
def announce_state(self) -> None:
116+
"""sends the MQTT message about the current state"""
117+
payload = {"POWER": self.str_state()}
83118

84119
self.logger.debug("%s.announce_state(%s)", self.name, payload)
85120
self._publish(self.state_topic(), payload=json.dumps(payload))
86121

87-
def _set_state(self, state):
88-
""" Does a few things:
89-
- sets the internal state variable
90-
- sets the GPIO
91-
- announces via MQTT the current state
122+
def _set_state(self, state: bool) -> None:
123+
"""Does a few things:
124+
- sets the internal state variable
125+
- sets the GPIO
126+
- announces via MQTT the current state
92127
"""
93128
if self.mock_pins:
94129
if state:
@@ -105,12 +140,16 @@ def _set_state(self, state):
105140
self.state = state
106141
self.announce_state()
107142

108-
def handle_command(self, payload):
109-
""" takes actions based on incoming commands """
143+
def handle_command(self, payload: bytes) -> None:
144+
"""takes actions based on incoming commands"""
110145
self.logger.debug("%s.handle_command(%s)", self.name, payload)
111-
if payload == b'ON':
146+
if payload == b"ON":
112147
self._set_state(True)
113-
elif payload == b'OFF':
148+
elif payload == b"OFF":
114149
self._set_state(False)
115150
else:
116-
self.logger.WARN("%s.handle_command(%s) is weird - should match '(ON|OFF)'", self.name, payload) # pylint: disable=line-too-long
151+
self.logger.warning(
152+
"%s.handle_command(%s) is weird - should match '(ON|OFF)'",
153+
self.name,
154+
payload,
155+
) # pylint: disable=line-too-long

0 commit comments

Comments
 (0)