From 86b0d1c5c836b2bd6a0f00fb53938bf832caab11 Mon Sep 17 00:00:00 2001 From: Lukas Schulte Date: Fri, 11 Jul 2025 19:14:56 +0200 Subject: [PATCH 1/8] add support for climate --- README.md | 57 ++++++++++++++++++++++++++++++++ ha_mqtt_discoverable/sensors.py | 58 +++++++++++++++++++++++++++++++++ tests/test_climate.py | 41 +++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 tests/test_climate.py diff --git a/README.md b/README.md index f20e7a3..ad25a17 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Using MQTT discoverable devices lets us add new sensors and devices to HA withou - [Binary sensor](#binary-sensor) - [Button](#button) - [Camera](#camera) + - [Climate](#climate) - [Covers](#covers) - [Device](#device) - [Device trigger](#device-trigger) @@ -55,6 +56,7 @@ The following Home Assistant entities are currently implemented: - Button - Camera - Cover +- Climate - Device - Device trigger - Image @@ -164,6 +166,61 @@ my_camera = Camera(settings, my_callback, user_data) my_camera.set_topic("zanzito/shared_locations/my-device") # not needed if already defined ``` +### Climate + +The following example creates a climate entity with temperature control and mode selection: + +```py +from ha_mqtt_discoverable import Settings +from ha_mqtt_discoverable.sensors import Climate, ClimateInfo +from paho.mqtt.client import Client, MQTTMessage + +# Configure the required parameters for the MQTT broker +mqtt_settings = Settings.MQTT(host="localhost") + +# Information about the climate entity +climate_info = ClimateInfo( + name="MyThermostat", + temperature_unit="C", + min_temp=16, + max_temp=32, + modes=["off", "heat", "cool", "auto"], + current_temperature_topic="home/thermostat/temperature" +) + +settings = Settings(mqtt=mqtt_settings, entity=climate_info) + +# To receive commands from HA, define a callback function: +def my_callback(client: Client, user_data, message: MQTTMessage): + # Make sure received payload is JSON + try: + payload = json.loads(message.payload.decode()) + except ValueError: + print("Ony JSON schema is supported for climate entities!") + return + + # Handle the command (e.g., mode changes, temperature setpoints) + handle_climate_command(payload) + # Update the state in HA + my_climate.set_temperature(25.0) + my_climate.set_mode("heat") + +# Define an optional object to be passed back to the callback +user_data = "Some custom data" + +# Instantiate the climate entity +my_climate = Climate(settings, my_callback, user_data) + +# Update the current temperature reading +my_climate.update_current_temperature(24.5) + +# Set the target temperature +my_climate.set_temperature(25.0) + +# Change the HVAC mode +my_climate.set_mode("heat") +``` + ### Covers A cover has five possible states `open`, `closed`, `opening`, `closing` and `stopped`. Most other entities use the states as command payload, but covers differentiate on this. The HA user can either open, close or stop it in the covers current position. diff --git a/ha_mqtt_discoverable/sensors.py b/ha_mqtt_discoverable/sensors.py index d585e47..c6f0263 100644 --- a/ha_mqtt_discoverable/sensors.py +++ b/ha_mqtt_discoverable/sensors.py @@ -691,3 +691,61 @@ def select_option(self, option: str) -> None: logger.info(f"Changing selection of {self._entity.name} to {option} using {self.state_topic}") self._state_helper(option) + + +class ClimateInfo(EntityInfo): + """Climate specific information""" + + component: str = "climate" + state_schema: str = Field(default="json", alias="schema") # 'schema' is a reserved word by pydantic + optimistic: bool | None = None + temperature_unit: Literal["C", "F"] = "C" + min_temp: float = 7.0 + max_temp: float = 35.0 + current_temperature_topic: str | None = None + current_temperature_template: str | None = None + modes: list[str] = ["off", "heat", "cool", "auto", "dry", "fan_only"] + retain: bool | None = None + state_topic: str | None = None + + + +class Climate(Subscriber[ClimateInfo]): + """Implements an MQTT climate device: + https://www.home-assistant.io/integrations/climate.mqtt/ + """ + + def set_temperature(self, temperature: float) -> None: + """Set target temperature""" + if not self._entity.min_temp <= temperature <= self._entity.max_temp: + raise RuntimeError( + f"Temperature {temperature} is outside valid range " + f"[{self._entity.min_temp}, {self._entity.max_temp}]" + ) + state_payload = {"temperature": temperature} + self._update_state(state_payload) + + def set_mode(self, mode: str) -> None: + """Set HVAC mode""" + if mode not in self._entity.modes: + raise RuntimeError( + f"Mode {mode} is not in supported modes: {self._entity.modes}" + ) + state_payload = {"mode": mode} + self._update_state(state_payload) + + def update_current_temperature(self, temperature: float) -> None: + """Update current temperature reading""" + if not self._entity.current_temperature_topic: + raise RuntimeError("Current temperature topic not configured") + self._state_helper( + str(temperature), + topic=self._entity.current_temperature_topic, + retain=self._entity.retain + ) + + def _update_state(self, state: dict[str, Any]) -> None: + """Update climate state""" + logger.info(f"Setting {self._entity.name} to {state} using {self.state_topic}") + json_state = json.dumps(state) + self._state_helper(state=json_state, retain=self._entity.retain) diff --git a/tests/test_climate.py b/tests/test_climate.py new file mode 100644 index 0000000..d3700eb --- /dev/null +++ b/tests/test_climate.py @@ -0,0 +1,41 @@ +import pytest + +from ha_mqtt_discoverable import Settings +from ha_mqtt_discoverable.sensors import Climate, ClimateInfo + +# Test data +modes = ["off", "heat", "cool"] + +@pytest.fixture +def climate() -> Climate: + """Test climate temperature settings""" + mqtt_settings = Settings.MQTT(host="localhost") + climate_info = ClimateInfo( + name="test_climate", + temperature_unit="C", + min_temp=16, + max_temp=32, + modes=modes + ) + settings = Settings(mqtt=mqtt_settings, entity=climate_info) + return Climate(settings, lambda *_: None) + + +def test_set_temperature(climate: Climate): + """Test setting the temperature""" + climate.set_temperature(20.0) + + # Test with out-of-range temperature + with pytest.raises(RuntimeError): + climate.set_temperature(15.0) # Below min_temp + with pytest.raises(RuntimeError): + climate.set_temperature(33.0) # Above max_temp + +def test_climate_mode(climate: Climate): + """Test climate mode settings""" + # Valid mode + climate.set_mode("heat") + + # Invalid mode + with pytest.raises(RuntimeError): + climate.set_mode("invalid_mode") From 4ba0a021b589220382aca0660b2cb9e95797e22f Mon Sep 17 00:00:00 2001 From: Schluggi Date: Sun, 3 Aug 2025 17:58:59 +0200 Subject: [PATCH 2/8] add support for climate add support for climate Signed-off-by: Schluggi  This is the commit message #3: add support for climate Signed-off-by: Schluggi  This is the commit message #4: add support for climate Signed-off-by: Schluggi add support for climate Signed-off-by: Schluggi fix pytest --- ha_mqtt_discoverable/__init__.py | 73 +++++++++++++++++++++- ha_mqtt_discoverable/sensors.py | 101 +++++++++++++------------------ tests/test_climate.py | 13 ++-- 3 files changed, 124 insertions(+), 63 deletions(-) diff --git a/ha_mqtt_discoverable/__init__.py b/ha_mqtt_discoverable/__init__.py index 899f592..b26a967 100644 --- a/ha_mqtt_discoverable/__init__.py +++ b/ha_mqtt_discoverable/__init__.py @@ -849,7 +849,7 @@ def __del__(self): class Subscriber(Discoverable[EntityType]): """ - Specialized sub-lass that listens to commands coming from an MQTT topic + Specialized subclass that listens to commands coming from an MQTT topic """ T = TypeVar("T") # Used in the callback function @@ -898,3 +898,74 @@ def generate_config(self) -> dict[str, Any]: "command_topic": self._command_topic, } return config | topics + + +class ClimateSubscriber(Discoverable[EntityType]): + """ + Specialized subclass that listens to commands coming from an MQTT topic + """ + + T = TypeVar("T") # Used in the callback function + + def __init__( + self, + settings: Settings[EntityType], + command_callback: Callable[[mqtt.Client, T, mqtt.MQTTMessage], Any], + user_data: T = None, + ) -> None: + """ + Entity that listens to commands from an MQTT topic. + + Args: + settings: Settings for the entity we want to create in Home Assistant. + See the `Settings` class for the available options. + command_callback: Callback function invoked when there is a command + coming from the MQTT command topic + """ + + # Callback invoked when the MQTT connection is established + def on_client_connected(client: mqtt.Client, *args): + # Publish this button in Home Assistant + # Subscribe to the command topic + result_mode, _ = client.subscribe(self._mode_command_topic, qos=1) + result_temperature, _ = client.subscribe(self._temperature_command_topic, qos=1) + + if result_mode is not mqtt.MQTT_ERR_SUCCESS: + raise RuntimeError("Error subscribing to MQTT mode command topic") + + # Invoke the parent init + super().__init__(settings, on_client_connected) + # Define the command topic to receive commands from HA, using `hmd` topic prefix + self._mode_command_topic = f"{self._settings.mqtt.state_prefix}/{self._entity_topic}/mode_command" + self._mode_state_topic = f"{self._settings.mqtt.state_prefix}/{self._entity_topic}/mode_state" + self._current_temperature_topic = f"{self._settings.mqtt.state_prefix}/{self._entity_topic}/current_temperature" + self._temperature_command_topic = f"{self._settings.mqtt.state_prefix}/{self._entity_topic}/temperature_command" + self._temperature_state_topic = f"{self._settings.mqtt.state_prefix}/{self._entity_topic}/temperature_state" + + # Register the user-supplied callback function with its user_data + self.mqtt_client.user_data_set(user_data) + self.mqtt_client.on_message = command_callback + + # Manually connect the MQTT client + self._connect_client() + + def generate_config(self) -> dict[str, Any]: + """Override base config to add the command topic of this switch""" + config = super().generate_config() + # Add the MQTT command topic to the existing config object + topics = { + "mode_command_topic": self._mode_command_topic, + "mode_command_template": json.dumps({ + "command": "mode", + "value": "{{ value }}", + }), + "temperature_command_topic": self._temperature_command_topic, + "temperature_command_template": json.dumps({ + "command": "temperature", + "value": "{{ value }}", + }), + "mode_state_topic": self._mode_state_topic, + "current_temperature_topic": self._current_temperature_topic, + "temperature_state_topic": self._temperature_state_topic, + } + return config | topics diff --git a/ha_mqtt_discoverable/sensors.py b/ha_mqtt_discoverable/sensors.py index c6f0263..b284a84 100644 --- a/ha_mqtt_discoverable/sensors.py +++ b/ha_mqtt_discoverable/sensors.py @@ -27,6 +27,7 @@ Discoverable, EntityInfo, Subscriber, + ClimateSubscriber, ) logger = logging.getLogger(__name__) @@ -46,6 +47,18 @@ class BinarySensorInfo(EntityInfo): """Payload to send for the OFF state""" +class ClimateInfo(EntityInfo): + """Climate specific information""" + + component: str = "climate" + optimistic: bool | None = None + temperature_unit: Literal["C", "F"] = "C" + min_temp: float = 7.0 + max_temp: float = 35.0 + modes: list[str] = ["off", "heat"] # "cool", "auto", "dry", "fan_only" + retain: bool | None = True + + class SensorInfo(EntityInfo): """Sensor specific information""" @@ -370,6 +383,36 @@ def update_state(self, state: bool) -> None: self._state_helper(state=state_message) +class Climate(ClimateSubscriber[ClimateInfo]): + """Implements an MQTT climate device: + https://www.home-assistant.io/integrations/climate.mqtt/ + """ + + def set_current_temperature(self, temperature: float) -> None: + """Set target temperature""" + if temperature < self._entity.min_temp or temperature > self._entity.max_temp: + raise RuntimeError( + f"Temperature {temperature} is outside valid range " + f"[{self._entity.min_temp}, {self._entity.max_temp}]" + ) + self._state_helper(temperature, self._current_temperature_topic) + + def set_target_temperature(self, temperature: float) -> None: + """Set target temperature""" + if temperature < self._entity.min_temp or temperature > self._entity.max_temp: + raise RuntimeError( + f"Temperature {temperature} is outside valid range " + f"[{self._entity.min_temp}, {self._entity.max_temp}]" + ) + self._state_helper(temperature, self._temperature_state_topic) + + def set_mode(self, mode: str) -> None: + """Set HVAC mode""" + if mode not in self._entity.modes: + raise RuntimeError(f"Mode {mode} is not in supported modes: {self._entity.modes}") + self._state_helper(mode, self._mode_state_topic) + + class Sensor(Discoverable[SensorInfo]): def set_state(self, state: str | int | float, last_reset: str = None) -> None: """ @@ -691,61 +734,3 @@ def select_option(self, option: str) -> None: logger.info(f"Changing selection of {self._entity.name} to {option} using {self.state_topic}") self._state_helper(option) - - -class ClimateInfo(EntityInfo): - """Climate specific information""" - - component: str = "climate" - state_schema: str = Field(default="json", alias="schema") # 'schema' is a reserved word by pydantic - optimistic: bool | None = None - temperature_unit: Literal["C", "F"] = "C" - min_temp: float = 7.0 - max_temp: float = 35.0 - current_temperature_topic: str | None = None - current_temperature_template: str | None = None - modes: list[str] = ["off", "heat", "cool", "auto", "dry", "fan_only"] - retain: bool | None = None - state_topic: str | None = None - - - -class Climate(Subscriber[ClimateInfo]): - """Implements an MQTT climate device: - https://www.home-assistant.io/integrations/climate.mqtt/ - """ - - def set_temperature(self, temperature: float) -> None: - """Set target temperature""" - if not self._entity.min_temp <= temperature <= self._entity.max_temp: - raise RuntimeError( - f"Temperature {temperature} is outside valid range " - f"[{self._entity.min_temp}, {self._entity.max_temp}]" - ) - state_payload = {"temperature": temperature} - self._update_state(state_payload) - - def set_mode(self, mode: str) -> None: - """Set HVAC mode""" - if mode not in self._entity.modes: - raise RuntimeError( - f"Mode {mode} is not in supported modes: {self._entity.modes}" - ) - state_payload = {"mode": mode} - self._update_state(state_payload) - - def update_current_temperature(self, temperature: float) -> None: - """Update current temperature reading""" - if not self._entity.current_temperature_topic: - raise RuntimeError("Current temperature topic not configured") - self._state_helper( - str(temperature), - topic=self._entity.current_temperature_topic, - retain=self._entity.retain - ) - - def _update_state(self, state: dict[str, Any]) -> None: - """Update climate state""" - logger.info(f"Setting {self._entity.name} to {state} using {self.state_topic}") - json_state = json.dumps(state) - self._state_helper(state=json_state, retain=self._entity.retain) diff --git a/tests/test_climate.py b/tests/test_climate.py index d3700eb..bdf3297 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -4,7 +4,7 @@ from ha_mqtt_discoverable.sensors import Climate, ClimateInfo # Test data -modes = ["off", "heat", "cool"] +modes = ["off", "heat"] @pytest.fixture def climate() -> Climate: @@ -23,13 +23,18 @@ def climate() -> Climate: def test_set_temperature(climate: Climate): """Test setting the temperature""" - climate.set_temperature(20.0) + climate.set_current_temperature(20.0) + climate.set_target_temperature(25.0) # Test with out-of-range temperature with pytest.raises(RuntimeError): - climate.set_temperature(15.0) # Below min_temp + climate.set_current_temperature(15.0) # Below min_temp with pytest.raises(RuntimeError): - climate.set_temperature(33.0) # Above max_temp + climate.set_current_temperature(33.0) # Above max_temp + with pytest.raises(RuntimeError): + climate.set_target_temperature(15.0) # Below min_temp + with pytest.raises(RuntimeError): + climate.set_target_temperature(33.0) # Above max_temp def test_climate_mode(climate: Climate): """Test climate mode settings""" From 09631b3da6d0ce7bcd118f919ab755213162ccb4 Mon Sep 17 00:00:00 2001 From: Steffen Pankratz Date: Sat, 12 Jul 2025 12:35:43 +0200 Subject: [PATCH 3/8] Update ruff to version 0.12.3 Signed-off-by: Steffen Pankratz Signed-off-by: Schluggi --- .pre-commit-config.yaml | 2 +- poetry.lock | 40 ++++++++++++++++++++-------------------- pyproject.toml | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c15cfcf..16a6632 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.12.2 + rev: v0.12.3 hooks: # Run the linter. - id: ruff diff --git a/poetry.lock b/poetry.lock index b3654f5..6fea322 100644 --- a/poetry.lock +++ b/poetry.lock @@ -489,30 +489,30 @@ files = [ [[package]] name = "ruff" -version = "0.12.2" +version = "0.12.3" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.2-py3-none-linux_armv6l.whl", hash = "sha256:093ea2b221df1d2b8e7ad92fc6ffdca40a2cb10d8564477a987b44fd4008a7be"}, - {file = "ruff-0.12.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:09e4cf27cc10f96b1708100fa851e0daf21767e9709e1649175355280e0d950e"}, - {file = "ruff-0.12.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8ae64755b22f4ff85e9c52d1f82644abd0b6b6b6deedceb74bd71f35c24044cc"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eb3a6b2db4d6e2c77e682f0b988d4d61aff06860158fdb413118ca133d57922"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73448de992d05517170fc37169cbca857dfeaeaa8c2b9be494d7bcb0d36c8f4b"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b8b94317cbc2ae4a2771af641739f933934b03555e51515e6e021c64441532d"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45fc42c3bf1d30d2008023a0a9a0cfb06bf9835b147f11fe0679f21ae86d34b1"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce48f675c394c37e958bf229fb5c1e843e20945a6d962cf3ea20b7a107dcd9f4"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793d8859445ea47591272021a81391350205a4af65a9392401f418a95dfb75c9"}, - {file = "ruff-0.12.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6932323db80484dda89153da3d8e58164d01d6da86857c79f1961934354992da"}, - {file = "ruff-0.12.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6aa7e623a3a11538108f61e859ebf016c4f14a7e6e4eba1980190cacb57714ce"}, - {file = "ruff-0.12.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2a4a20aeed74671b2def096bdf2eac610c7d8ffcbf4fb0e627c06947a1d7078d"}, - {file = "ruff-0.12.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:71a4c550195612f486c9d1f2b045a600aeba851b298c667807ae933478fcef04"}, - {file = "ruff-0.12.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4987b8f4ceadf597c927beee65a5eaf994c6e2b631df963f86d8ad1bdea99342"}, - {file = "ruff-0.12.2-py3-none-win32.whl", hash = "sha256:369ffb69b70cd55b6c3fc453b9492d98aed98062db9fec828cdfd069555f5f1a"}, - {file = "ruff-0.12.2-py3-none-win_amd64.whl", hash = "sha256:dca8a3b6d6dc9810ed8f328d406516bf4d660c00caeaef36eb831cf4871b0639"}, - {file = "ruff-0.12.2-py3-none-win_arm64.whl", hash = "sha256:48d6c6bfb4761df68bc05ae630e24f506755e702d4fb08f08460be778c7ccb12"}, - {file = "ruff-0.12.2.tar.gz", hash = "sha256:d7b4f55cd6f325cb7621244f19c873c565a08aff5a4ba9c69aa7355f3f7afd3e"}, + {file = "ruff-0.12.3-py3-none-linux_armv6l.whl", hash = "sha256:47552138f7206454eaf0c4fe827e546e9ddac62c2a3d2585ca54d29a890137a2"}, + {file = "ruff-0.12.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0a9153b000c6fe169bb307f5bd1b691221c4286c133407b8827c406a55282041"}, + {file = "ruff-0.12.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fa6b24600cf3b750e48ddb6057e901dd5b9aa426e316addb2a1af185a7509882"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2506961bf6ead54887ba3562604d69cb430f59b42133d36976421bc8bd45901"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4faaff1f90cea9d3033cbbcdf1acf5d7fb11d8180758feb31337391691f3df0"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40dced4a79d7c264389de1c59467d5d5cefd79e7e06d1dfa2c75497b5269a5a6"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0262d50ba2767ed0fe212aa7e62112a1dcbfd46b858c5bf7bbd11f326998bafc"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12371aec33e1a3758597c5c631bae9a5286f3c963bdfb4d17acdd2d395406687"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:560f13b6baa49785665276c963edc363f8ad4b4fc910a883e2625bdb14a83a9e"}, + {file = "ruff-0.12.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023040a3499f6f974ae9091bcdd0385dd9e9eb4942f231c23c57708147b06311"}, + {file = "ruff-0.12.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:883d844967bffff5ab28bba1a4d246c1a1b2933f48cb9840f3fdc5111c603b07"}, + {file = "ruff-0.12.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2120d3aa855ff385e0e562fdee14d564c9675edbe41625c87eeab744a7830d12"}, + {file = "ruff-0.12.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b16647cbb470eaf4750d27dddc6ebf7758b918887b56d39e9c22cce2049082b"}, + {file = "ruff-0.12.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e1417051edb436230023575b149e8ff843a324557fe0a265863b7602df86722f"}, + {file = "ruff-0.12.3-py3-none-win32.whl", hash = "sha256:dfd45e6e926deb6409d0616078a666ebce93e55e07f0fb0228d4b2608b2c248d"}, + {file = "ruff-0.12.3-py3-none-win_amd64.whl", hash = "sha256:a946cf1e7ba3209bdef039eb97647f1c77f6f540e5845ec9c114d3af8df873e7"}, + {file = "ruff-0.12.3-py3-none-win_arm64.whl", hash = "sha256:5f9c7c9c8f84c2d7f27e93674d27136fbf489720251544c4da7fb3d742e011b1"}, + {file = "ruff-0.12.3.tar.gz", hash = "sha256:f1b5a4b6668fd7b7ea3697d8d98857390b40c1320a63a178eee6be0899ea2d77"}, ] [[package]] @@ -610,4 +610,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.10.0,<4.0" -content-hash = "c58893d01b992d6392db86076f72b529e137efae24286c18856f21c7ea247d1e" +content-hash = "6201835a4f11bc9c747ad58c7606edc045da6c170071ac5b00037163fac2c99c" diff --git a/pyproject.toml b/pyproject.toml index ba5d9fd..aa93db6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ packages = [{include = "ha_mqtt_discoverable"}] [tool.poetry.group.dev.dependencies] pytest = "^8.4.1" pre-commit = "^4.2.0" -ruff = "^0.12.2" +ruff = "^0.12.3" [tool.poetry.group.test.dependencies] From 71973bf4ad6447ee42108c3dba62b48c9a73d5a1 Mon Sep 17 00:00:00 2001 From: Steffen Pankratz Date: Sat, 12 Jul 2025 16:27:55 +0200 Subject: [PATCH 4/8] Update pyaml to version 25.7.0 Signed-off-by: Steffen Pankratz Signed-off-by: Schluggi fix README Signed-off-by: Schluggi [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: Schluggi --- README.md | 24 ++++++++++++------------ ha_mqtt_discoverable/__init__.py | 28 ++++++++++++++++------------ ha_mqtt_discoverable/sensors.py | 8 +++----- poetry.lock | 8 ++++---- pyproject.toml | 2 +- tests/test_climate.py | 10 +++------- 6 files changed, 39 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index ad25a17..c003731 100644 --- a/README.md +++ b/README.md @@ -180,12 +180,11 @@ mqtt_settings = Settings.MQTT(host="localhost") # Information about the climate entity climate_info = ClimateInfo( - name="MyThermostat", + name="MyClimate", temperature_unit="C", min_temp=16, max_temp=32, - modes=["off", "heat", "cool", "auto"], - current_temperature_topic="home/thermostat/temperature" + modes=["off", "heat"] ) settings = Settings(mqtt=mqtt_settings, entity=climate_info) @@ -198,12 +197,13 @@ def my_callback(client: Client, user_data, message: MQTTMessage): except ValueError: print("Ony JSON schema is supported for climate entities!") return - - # Handle the command (e.g., mode changes, temperature setpoints) - handle_climate_command(payload) - # Update the state in HA - my_climate.set_temperature(25.0) - my_climate.set_mode("heat") + + if payload['command'] == "mode": + set_my_custom_climate_mode(payload['value']) + elif payload['command'] == "temperature": + set_my_custom_climate_temperature(payload['value']) + else: + print("Unknown command") # Define an optional object to be passed back to the callback user_data = "Some custom data" @@ -211,11 +211,11 @@ user_data = "Some custom data" # Instantiate the climate entity my_climate = Climate(settings, my_callback, user_data) -# Update the current temperature reading -my_climate.update_current_temperature(24.5) +# Set the current temperature +my_climate.set_current_temperature(24.5) # Set the target temperature -my_climate.set_temperature(25.0) +my_climate.set_target_temperature(25.0) # Change the HVAC mode my_climate.set_mode("heat") diff --git a/ha_mqtt_discoverable/__init__.py b/ha_mqtt_discoverable/__init__.py index b26a967..75eb573 100644 --- a/ha_mqtt_discoverable/__init__.py +++ b/ha_mqtt_discoverable/__init__.py @@ -908,10 +908,10 @@ class ClimateSubscriber(Discoverable[EntityType]): T = TypeVar("T") # Used in the callback function def __init__( - self, - settings: Settings[EntityType], - command_callback: Callable[[mqtt.Client, T, mqtt.MQTTMessage], Any], - user_data: T = None, + self, + settings: Settings[EntityType], + command_callback: Callable[[mqtt.Client, T, mqtt.MQTTMessage], Any], + user_data: T = None, ) -> None: """ Entity that listens to commands from an MQTT topic. @@ -955,15 +955,19 @@ def generate_config(self) -> dict[str, Any]: # Add the MQTT command topic to the existing config object topics = { "mode_command_topic": self._mode_command_topic, - "mode_command_template": json.dumps({ - "command": "mode", - "value": "{{ value }}", - }), + "mode_command_template": json.dumps( + { + "command": "mode", + "value": "{{ value }}", + } + ), "temperature_command_topic": self._temperature_command_topic, - "temperature_command_template": json.dumps({ - "command": "temperature", - "value": "{{ value }}", - }), + "temperature_command_template": json.dumps( + { + "command": "temperature", + "value": "{{ value }}", + } + ), "mode_state_topic": self._mode_state_topic, "current_temperature_topic": self._current_temperature_topic, "temperature_state_topic": self._temperature_state_topic, diff --git a/ha_mqtt_discoverable/sensors.py b/ha_mqtt_discoverable/sensors.py index b284a84..a89bceb 100644 --- a/ha_mqtt_discoverable/sensors.py +++ b/ha_mqtt_discoverable/sensors.py @@ -23,11 +23,11 @@ from pydantic import Field, model_validator from ha_mqtt_discoverable import ( + ClimateSubscriber, DeviceInfo, Discoverable, EntityInfo, Subscriber, - ClimateSubscriber, ) logger = logging.getLogger(__name__) @@ -392,8 +392,7 @@ def set_current_temperature(self, temperature: float) -> None: """Set target temperature""" if temperature < self._entity.min_temp or temperature > self._entity.max_temp: raise RuntimeError( - f"Temperature {temperature} is outside valid range " - f"[{self._entity.min_temp}, {self._entity.max_temp}]" + f"Temperature {temperature} is outside valid range [{self._entity.min_temp}, {self._entity.max_temp}]" ) self._state_helper(temperature, self._current_temperature_topic) @@ -401,8 +400,7 @@ def set_target_temperature(self, temperature: float) -> None: """Set target temperature""" if temperature < self._entity.min_temp or temperature > self._entity.max_temp: raise RuntimeError( - f"Temperature {temperature} is outside valid range " - f"[{self._entity.min_temp}, {self._entity.max_temp}]" + f"Temperature {temperature} is outside valid range [{self._entity.min_temp}, {self._entity.max_temp}]" ) self._state_helper(temperature, self._temperature_state_topic) diff --git a/poetry.lock b/poetry.lock index 6fea322..ced8a8f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -217,14 +217,14 @@ virtualenv = ">=20.10.0" [[package]] name = "pyaml" -version = "25.5.0" +version = "25.7.0" description = "PyYAML-based module to produce a bit more pretty and readable YAML-serialized data" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "pyaml-25.5.0-py3-none-any.whl", hash = "sha256:b9e0c4e58a5e8003f8f18e802db49fd0563ada587209b13e429bdcbefa87d035"}, - {file = "pyaml-25.5.0.tar.gz", hash = "sha256:5799560c7b1c9daf35a7a4535f53e2c30323f74cbd7cb4f2e715b16dd681a58a"}, + {file = "pyaml-25.7.0-py3-none-any.whl", hash = "sha256:ce5d7867cc2b455efdb9b0448324ff7b9f74d99f64650f12ca570102db6b985f"}, + {file = "pyaml-25.7.0.tar.gz", hash = "sha256:e113a64ec16881bf2b092e2beb84b7dcf1bd98096ad17f5f14e8fb782a75d99b"}, ] [package.dependencies] @@ -610,4 +610,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.10.0,<4.0" -content-hash = "6201835a4f11bc9c747ad58c7606edc045da6c170071ac5b00037163fac2c99c" +content-hash = "e7852e84135c19fda0eab1087076a2b68639ac3ecfeece53485beada261c8964" diff --git a/pyproject.toml b/pyproject.toml index aa93db6..c1452ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{name = "Joe Block", email = "jpb@unixorn.net"}] readme = "README.md" requires-python = ">=3.10.0,<4.0" dependencies = [ - "pyaml==25.5.0", + "pyaml==25.7.0", "paho-mqtt==2.1.0", "gitlike-commands (>=0.2.1,<0.4.0)", "pydantic==2.11.7", diff --git a/tests/test_climate.py b/tests/test_climate.py index bdf3297..2177fa4 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -6,17 +6,12 @@ # Test data modes = ["off", "heat"] + @pytest.fixture def climate() -> Climate: """Test climate temperature settings""" mqtt_settings = Settings.MQTT(host="localhost") - climate_info = ClimateInfo( - name="test_climate", - temperature_unit="C", - min_temp=16, - max_temp=32, - modes=modes - ) + climate_info = ClimateInfo(name="test_climate", temperature_unit="C", min_temp=16, max_temp=32, modes=modes) settings = Settings(mqtt=mqtt_settings, entity=climate_info) return Climate(settings, lambda *_: None) @@ -36,6 +31,7 @@ def test_set_temperature(climate: Climate): with pytest.raises(RuntimeError): climate.set_target_temperature(33.0) # Above max_temp + def test_climate_mode(climate: Climate): """Test climate mode settings""" # Valid mode From 7c62041fd5aeb5c427bb93f26b19e81d207b9fff Mon Sep 17 00:00:00 2001 From: Joe Block Date: Sun, 13 Jul 2025 10:58:51 -0600 Subject: [PATCH 5/8] Ask how contributors want to be credited Ask for contributor mastodon account so we can credit them properly in release announcements. Also ask if there's a different way they'd prefer to be credited. Signed-off-by: Joe Block Signed-off-by: Schluggi --- .github/PULL_REQUEST_TEMPLATE.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6f68a2b..b3870ee 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,17 +3,24 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Description](#description) +- [Credit](#credit) - [License Acceptance](#license-acceptance) - [Type of changes](#type-of-changes) - [Checklist](#checklist) - + # Description - + + +# Credit + + + + # License Acceptance @@ -21,7 +28,7 @@ # Type of changes - + - [ ] Add/update a helper script - [ ] Add/update link to an external resource like a blog post or video @@ -33,8 +40,8 @@ # Checklist - - + + - [ ] I have read the [CONTRIBUTING](https://github.com/unixorn/ha-mqtt-discovery/blob/main/Contributing.md) document. - [ ] All new and existing tests pass. From 366f0ba9ce635b2dfb8e9f83da387264f9dab038 Mon Sep 17 00:00:00 2001 From: Steffen Pankratz Date: Fri, 18 Jul 2025 07:07:38 +0200 Subject: [PATCH 6/8] Update ruff to version 0.12.4 Signed-off-by: Steffen Pankratz Signed-off-by: Schluggi --- .pre-commit-config.yaml | 2 +- poetry.lock | 40 ++++++++++++++++++++-------------------- pyproject.toml | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 16a6632..d3ab26b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.12.3 + rev: v0.12.4 hooks: # Run the linter. - id: ruff diff --git a/poetry.lock b/poetry.lock index ced8a8f..0bc70b4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -489,30 +489,30 @@ files = [ [[package]] name = "ruff" -version = "0.12.3" +version = "0.12.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.3-py3-none-linux_armv6l.whl", hash = "sha256:47552138f7206454eaf0c4fe827e546e9ddac62c2a3d2585ca54d29a890137a2"}, - {file = "ruff-0.12.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0a9153b000c6fe169bb307f5bd1b691221c4286c133407b8827c406a55282041"}, - {file = "ruff-0.12.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fa6b24600cf3b750e48ddb6057e901dd5b9aa426e316addb2a1af185a7509882"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2506961bf6ead54887ba3562604d69cb430f59b42133d36976421bc8bd45901"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4faaff1f90cea9d3033cbbcdf1acf5d7fb11d8180758feb31337391691f3df0"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40dced4a79d7c264389de1c59467d5d5cefd79e7e06d1dfa2c75497b5269a5a6"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0262d50ba2767ed0fe212aa7e62112a1dcbfd46b858c5bf7bbd11f326998bafc"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12371aec33e1a3758597c5c631bae9a5286f3c963bdfb4d17acdd2d395406687"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:560f13b6baa49785665276c963edc363f8ad4b4fc910a883e2625bdb14a83a9e"}, - {file = "ruff-0.12.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023040a3499f6f974ae9091bcdd0385dd9e9eb4942f231c23c57708147b06311"}, - {file = "ruff-0.12.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:883d844967bffff5ab28bba1a4d246c1a1b2933f48cb9840f3fdc5111c603b07"}, - {file = "ruff-0.12.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2120d3aa855ff385e0e562fdee14d564c9675edbe41625c87eeab744a7830d12"}, - {file = "ruff-0.12.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b16647cbb470eaf4750d27dddc6ebf7758b918887b56d39e9c22cce2049082b"}, - {file = "ruff-0.12.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e1417051edb436230023575b149e8ff843a324557fe0a265863b7602df86722f"}, - {file = "ruff-0.12.3-py3-none-win32.whl", hash = "sha256:dfd45e6e926deb6409d0616078a666ebce93e55e07f0fb0228d4b2608b2c248d"}, - {file = "ruff-0.12.3-py3-none-win_amd64.whl", hash = "sha256:a946cf1e7ba3209bdef039eb97647f1c77f6f540e5845ec9c114d3af8df873e7"}, - {file = "ruff-0.12.3-py3-none-win_arm64.whl", hash = "sha256:5f9c7c9c8f84c2d7f27e93674d27136fbf489720251544c4da7fb3d742e011b1"}, - {file = "ruff-0.12.3.tar.gz", hash = "sha256:f1b5a4b6668fd7b7ea3697d8d98857390b40c1320a63a178eee6be0899ea2d77"}, + {file = "ruff-0.12.4-py3-none-linux_armv6l.whl", hash = "sha256:cb0d261dac457ab939aeb247e804125a5d521b21adf27e721895b0d3f83a0d0a"}, + {file = "ruff-0.12.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:55c0f4ca9769408d9b9bac530c30d3e66490bd2beb2d3dae3e4128a1f05c7442"}, + {file = "ruff-0.12.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a8224cc3722c9ad9044da7f89c4c1ec452aef2cfe3904365025dd2f51daeae0e"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9949d01d64fa3672449a51ddb5d7548b33e130240ad418884ee6efa7a229586"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:be0593c69df9ad1465e8a2d10e3defd111fdb62dcd5be23ae2c06da77e8fcffb"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7dea966bcb55d4ecc4cc3270bccb6f87a337326c9dcd3c07d5b97000dbff41c"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afcfa3ab5ab5dd0e1c39bf286d829e042a15e966b3726eea79528e2e24d8371a"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c057ce464b1413c926cdb203a0f858cd52f3e73dcb3270a3318d1630f6395bb3"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e64b90d1122dc2713330350626b10d60818930819623abbb56535c6466cce045"}, + {file = "ruff-0.12.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2abc48f3d9667fdc74022380b5c745873499ff827393a636f7a59da1515e7c57"}, + {file = "ruff-0.12.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2b2449dc0c138d877d629bea151bee8c0ae3b8e9c43f5fcaafcd0c0d0726b184"}, + {file = "ruff-0.12.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:56e45bb11f625db55f9b70477062e6a1a04d53628eda7784dce6e0f55fd549eb"}, + {file = "ruff-0.12.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:478fccdb82ca148a98a9ff43658944f7ab5ec41c3c49d77cd99d44da019371a1"}, + {file = "ruff-0.12.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0fc426bec2e4e5f4c4f182b9d2ce6a75c85ba9bcdbe5c6f2a74fcb8df437df4b"}, + {file = "ruff-0.12.4-py3-none-win32.whl", hash = "sha256:4de27977827893cdfb1211d42d84bc180fceb7b72471104671c59be37041cf93"}, + {file = "ruff-0.12.4-py3-none-win_amd64.whl", hash = "sha256:fe0b9e9eb23736b453143d72d2ceca5db323963330d5b7859d60d101147d461a"}, + {file = "ruff-0.12.4-py3-none-win_arm64.whl", hash = "sha256:0618ec4442a83ab545e5b71202a5c0ed7791e8471435b94e655b570a5031a98e"}, + {file = "ruff-0.12.4.tar.gz", hash = "sha256:13efa16df6c6eeb7d0f091abae50f58e9522f3843edb40d56ad52a5a4a4b6873"}, ] [[package]] @@ -610,4 +610,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.10.0,<4.0" -content-hash = "e7852e84135c19fda0eab1087076a2b68639ac3ecfeece53485beada261c8964" +content-hash = "cafd445d0c368048c1dc770c85e094217baf232cc40f8c64328b0787fd5a158f" diff --git a/pyproject.toml b/pyproject.toml index c1452ff..73cb9b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ packages = [{include = "ha_mqtt_discoverable"}] [tool.poetry.group.dev.dependencies] pytest = "^8.4.1" pre-commit = "^4.2.0" -ruff = "^0.12.3" +ruff = "^0.12.4" [tool.poetry.group.test.dependencies] From 5dbe4e8d6d335609d015bf37c645882ba418f233 Mon Sep 17 00:00:00 2001 From: Steffen Pankratz Date: Fri, 25 Jul 2025 07:40:41 +0200 Subject: [PATCH 7/8] Update ruff to version 0.12.5 Signed-off-by: Steffen Pankratz Signed-off-by: Schluggi --- .pre-commit-config.yaml | 2 +- poetry.lock | 40 ++++++++++++++++++++-------------------- pyproject.toml | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d3ab26b..441a8e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.12.4 + rev: v0.12.5 hooks: # Run the linter. - id: ruff diff --git a/poetry.lock b/poetry.lock index 0bc70b4..f304ff1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -489,30 +489,30 @@ files = [ [[package]] name = "ruff" -version = "0.12.4" +version = "0.12.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.4-py3-none-linux_armv6l.whl", hash = "sha256:cb0d261dac457ab939aeb247e804125a5d521b21adf27e721895b0d3f83a0d0a"}, - {file = "ruff-0.12.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:55c0f4ca9769408d9b9bac530c30d3e66490bd2beb2d3dae3e4128a1f05c7442"}, - {file = "ruff-0.12.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a8224cc3722c9ad9044da7f89c4c1ec452aef2cfe3904365025dd2f51daeae0e"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9949d01d64fa3672449a51ddb5d7548b33e130240ad418884ee6efa7a229586"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:be0593c69df9ad1465e8a2d10e3defd111fdb62dcd5be23ae2c06da77e8fcffb"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7dea966bcb55d4ecc4cc3270bccb6f87a337326c9dcd3c07d5b97000dbff41c"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afcfa3ab5ab5dd0e1c39bf286d829e042a15e966b3726eea79528e2e24d8371a"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c057ce464b1413c926cdb203a0f858cd52f3e73dcb3270a3318d1630f6395bb3"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e64b90d1122dc2713330350626b10d60818930819623abbb56535c6466cce045"}, - {file = "ruff-0.12.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2abc48f3d9667fdc74022380b5c745873499ff827393a636f7a59da1515e7c57"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2b2449dc0c138d877d629bea151bee8c0ae3b8e9c43f5fcaafcd0c0d0726b184"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:56e45bb11f625db55f9b70477062e6a1a04d53628eda7784dce6e0f55fd549eb"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:478fccdb82ca148a98a9ff43658944f7ab5ec41c3c49d77cd99d44da019371a1"}, - {file = "ruff-0.12.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0fc426bec2e4e5f4c4f182b9d2ce6a75c85ba9bcdbe5c6f2a74fcb8df437df4b"}, - {file = "ruff-0.12.4-py3-none-win32.whl", hash = "sha256:4de27977827893cdfb1211d42d84bc180fceb7b72471104671c59be37041cf93"}, - {file = "ruff-0.12.4-py3-none-win_amd64.whl", hash = "sha256:fe0b9e9eb23736b453143d72d2ceca5db323963330d5b7859d60d101147d461a"}, - {file = "ruff-0.12.4-py3-none-win_arm64.whl", hash = "sha256:0618ec4442a83ab545e5b71202a5c0ed7791e8471435b94e655b570a5031a98e"}, - {file = "ruff-0.12.4.tar.gz", hash = "sha256:13efa16df6c6eeb7d0f091abae50f58e9522f3843edb40d56ad52a5a4a4b6873"}, + {file = "ruff-0.12.5-py3-none-linux_armv6l.whl", hash = "sha256:1de2c887e9dec6cb31fcb9948299de5b2db38144e66403b9660c9548a67abd92"}, + {file = "ruff-0.12.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d1ab65e7d8152f519e7dea4de892317c9da7a108da1c56b6a3c1d5e7cf4c5e9a"}, + {file = "ruff-0.12.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:962775ed5b27c7aa3fdc0d8f4d4433deae7659ef99ea20f783d666e77338b8cf"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73b4cae449597e7195a49eb1cdca89fd9fbb16140c7579899e87f4c85bf82f73"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b13489c3dc50de5e2d40110c0cce371e00186b880842e245186ca862bf9a1ac"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1504fea81461cf4841778b3ef0a078757602a3b3ea4b008feb1308cb3f23e08"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c7da4129016ae26c32dfcbd5b671fe652b5ab7fc40095d80dcff78175e7eddd4"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca972c80f7ebcfd8af75a0f18b17c42d9f1ef203d163669150453f50ca98ab7b"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dbbf9f25dfb501f4237ae7501d6364b76a01341c6f1b2cd6764fe449124bb2a"}, + {file = "ruff-0.12.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c47dea6ae39421851685141ba9734767f960113d51e83fd7bb9958d5be8763a"}, + {file = "ruff-0.12.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5076aa0e61e30f848846f0265c873c249d4b558105b221be1828f9f79903dc5"}, + {file = "ruff-0.12.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a5a4c7830dadd3d8c39b1cc85386e2c1e62344f20766be6f173c22fb5f72f293"}, + {file = "ruff-0.12.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:46699f73c2b5b137b9dc0fc1a190b43e35b008b398c6066ea1350cce6326adcb"}, + {file = "ruff-0.12.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5a655a0a0d396f0f072faafc18ebd59adde8ca85fb848dc1b0d9f024b9c4d3bb"}, + {file = "ruff-0.12.5-py3-none-win32.whl", hash = "sha256:dfeb2627c459b0b78ca2bbdc38dd11cc9a0a88bf91db982058b26ce41714ffa9"}, + {file = "ruff-0.12.5-py3-none-win_amd64.whl", hash = "sha256:ae0d90cf5f49466c954991b9d8b953bd093c32c27608e409ae3564c63c5306a5"}, + {file = "ruff-0.12.5-py3-none-win_arm64.whl", hash = "sha256:48cdbfc633de2c5c37d9f090ba3b352d1576b0015bfc3bc98eaf230275b7e805"}, + {file = "ruff-0.12.5.tar.gz", hash = "sha256:b209db6102b66f13625940b7f8c7d0f18e20039bb7f6101fbdac935c9612057e"}, ] [[package]] @@ -610,4 +610,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.10.0,<4.0" -content-hash = "cafd445d0c368048c1dc770c85e094217baf232cc40f8c64328b0787fd5a158f" +content-hash = "7618bed73b14026fb5aeea37c1a2236a2e210a2620869d189588eb63aaf8483f" diff --git a/pyproject.toml b/pyproject.toml index 73cb9b8..4eb2494 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ packages = [{include = "ha_mqtt_discoverable"}] [tool.poetry.group.dev.dependencies] pytest = "^8.4.1" pre-commit = "^4.2.0" -ruff = "^0.12.4" +ruff = "^0.12.5" [tool.poetry.group.test.dependencies] From 11ca1af5f2d791d6b98e932ad4a0cbdd15a0bdca Mon Sep 17 00:00:00 2001 From: Steffen Pankratz Date: Wed, 30 Jul 2025 09:41:45 +0200 Subject: [PATCH 8/8] Update ruff to version 0.12.7 Signed-off-by: Steffen Pankratz Signed-off-by: Schluggi --- .pre-commit-config.yaml | 2 +- poetry.lock | 40 ++++++++++++++++++++-------------------- pyproject.toml | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 441a8e3..72e1df2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.12.5 + rev: v0.12.7 hooks: # Run the linter. - id: ruff diff --git a/poetry.lock b/poetry.lock index f304ff1..b832930 100644 --- a/poetry.lock +++ b/poetry.lock @@ -489,30 +489,30 @@ files = [ [[package]] name = "ruff" -version = "0.12.5" +version = "0.12.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.12.5-py3-none-linux_armv6l.whl", hash = "sha256:1de2c887e9dec6cb31fcb9948299de5b2db38144e66403b9660c9548a67abd92"}, - {file = "ruff-0.12.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d1ab65e7d8152f519e7dea4de892317c9da7a108da1c56b6a3c1d5e7cf4c5e9a"}, - {file = "ruff-0.12.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:962775ed5b27c7aa3fdc0d8f4d4433deae7659ef99ea20f783d666e77338b8cf"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73b4cae449597e7195a49eb1cdca89fd9fbb16140c7579899e87f4c85bf82f73"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b13489c3dc50de5e2d40110c0cce371e00186b880842e245186ca862bf9a1ac"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1504fea81461cf4841778b3ef0a078757602a3b3ea4b008feb1308cb3f23e08"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c7da4129016ae26c32dfcbd5b671fe652b5ab7fc40095d80dcff78175e7eddd4"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca972c80f7ebcfd8af75a0f18b17c42d9f1ef203d163669150453f50ca98ab7b"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dbbf9f25dfb501f4237ae7501d6364b76a01341c6f1b2cd6764fe449124bb2a"}, - {file = "ruff-0.12.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c47dea6ae39421851685141ba9734767f960113d51e83fd7bb9958d5be8763a"}, - {file = "ruff-0.12.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5076aa0e61e30f848846f0265c873c249d4b558105b221be1828f9f79903dc5"}, - {file = "ruff-0.12.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a5a4c7830dadd3d8c39b1cc85386e2c1e62344f20766be6f173c22fb5f72f293"}, - {file = "ruff-0.12.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:46699f73c2b5b137b9dc0fc1a190b43e35b008b398c6066ea1350cce6326adcb"}, - {file = "ruff-0.12.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5a655a0a0d396f0f072faafc18ebd59adde8ca85fb848dc1b0d9f024b9c4d3bb"}, - {file = "ruff-0.12.5-py3-none-win32.whl", hash = "sha256:dfeb2627c459b0b78ca2bbdc38dd11cc9a0a88bf91db982058b26ce41714ffa9"}, - {file = "ruff-0.12.5-py3-none-win_amd64.whl", hash = "sha256:ae0d90cf5f49466c954991b9d8b953bd093c32c27608e409ae3564c63c5306a5"}, - {file = "ruff-0.12.5-py3-none-win_arm64.whl", hash = "sha256:48cdbfc633de2c5c37d9f090ba3b352d1576b0015bfc3bc98eaf230275b7e805"}, - {file = "ruff-0.12.5.tar.gz", hash = "sha256:b209db6102b66f13625940b7f8c7d0f18e20039bb7f6101fbdac935c9612057e"}, + {file = "ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303"}, + {file = "ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb"}, + {file = "ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a828a5fc25a3efd3e1ff7b241fd392686c9386f20e5ac90aa9234a5faa12c423"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:69ffe0e5f9b2cf2b8e289a3f8945b402a1b19eff24ec389f45f23c42a3dd6fb5"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4"}, + {file = "ruff-0.12.7-py3-none-win32.whl", hash = "sha256:c928f1b2ec59fb77dfdf70e0419408898b63998789cc98197e15f560b9e77f77"}, + {file = "ruff-0.12.7-py3-none-win_amd64.whl", hash = "sha256:9c18f3d707ee9edf89da76131956aba1270c6348bfee8f6c647de841eac7194f"}, + {file = "ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69"}, + {file = "ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71"}, ] [[package]] @@ -610,4 +610,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.10.0,<4.0" -content-hash = "7618bed73b14026fb5aeea37c1a2236a2e210a2620869d189588eb63aaf8483f" +content-hash = "2213f6292851a3fc745a47d240226b4972062550d5c23d434561e2fcc830b6c1" diff --git a/pyproject.toml b/pyproject.toml index 4eb2494..5a1fb29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ packages = [{include = "ha_mqtt_discoverable"}] [tool.poetry.group.dev.dependencies] pytest = "^8.4.1" pre-commit = "^4.2.0" -ruff = "^0.12.5" +ruff = "^0.12.7" [tool.poetry.group.test.dependencies]