diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 5d0b7de6..6f035024 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -3,7 +3,7 @@ name: Publish 📦 to PyPI on: push: tags: - - 'v*' + - "v*" jobs: build-n-publish: @@ -24,11 +24,11 @@ jobs: - name: Build a binary wheel and a source tarball run: >- python -m build . -# - name: Publish 📦 to Test PyPI -# uses: pypa/gh-action-pypi-publish@master -# with: -# password: ${{ secrets.PYPI_TEST_TOKEN }} -# repository_url: https://test.pypi.org/legacy/ + # - name: Publish 📦 to Test PyPI + # uses: pypa/gh-action-pypi-publish@master + # with: + # password: ${{ secrets.PYPI_TEST_TOKEN }} + # repository-url: https://test.pypi.org/legacy/ - name: Publish 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index 2d1cdd02..1f9be7fe 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -5,7 +5,6 @@ on: branches: - development - jobs: build-n-publish: name: Build and publish 📦 to TestPyPI @@ -30,4 +29,4 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_TEST_TOKEN }} - repository_url: https://test.pypi.org/legacy/ + repository-url: https://test.pypi.org/legacy/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 165c750b..8aa8efec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,39 +5,20 @@ exclude: ^(fixtures/) repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.9 + rev: v0.6.1 hooks: - id: ruff args: - --fix - - repo: https://github.com/asottile/pyupgrade - rev: v3.16.0 - hooks: - - id: pyupgrade - args: [--py310-plus] - exclude: "external_src/int-tools" - - - repo: https://github.com/asottile/add-trailing-comma - rev: v3.1.0 - hooks: - - id: add-trailing-comma - args: [--py36-plus] - exclude: "external_src/int-tools" - - - repo: https://github.com/asottile/yesqa - rev: v1.5.0 - hooks: - - id: yesqa - - repo: https://github.com/psf/black - rev: 24.4.2 + rev: 24.8.0 hooks: - id: black language_version: python3 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.11.1 hooks: - id: mypy name: mypy diff --git a/CHANGELOG.md b/CHANGELOG.md index d261e77d..313f13a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Security -- + +## [8.1.0] + +### Added + +- Expose camera person status +- Add NLE support +- Add proper energy support +- Add cooler support +- Add BNS support + +## [8.0.3] + +### Added + +- Add NLLF centralized ventilation controller + +### Fixed + +- Add BNSC switch capability ## [8.0.3] diff --git a/fixtures/homesdata.json b/fixtures/homesdata.json index 7e7e753e..e5623ad4 100644 --- a/fixtures/homesdata.json +++ b/fixtures/homesdata.json @@ -805,6 +805,8 @@ } ], "therm_setpoint_default_duration": 120, + "temperature_control_mode": "cooling", + "cooling_mode": "schedule", "persons": [ { "id": "91827374-7e04-5298-83ad-a0cb8372dff1", diff --git a/pyproject.toml b/pyproject.toml index b5e0935e..30880cf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,9 @@ minversion = "7.0" asyncio_mode = "auto" [tool.ruff] +target-version = "py310" + +[tool.ruff.lint] select = [ "B002", # Python does not support the unary prefix increment "B007", # Loop control variable {name} not used within loop body @@ -23,17 +26,13 @@ select = [ "G", # flake8-logging-format "I", # isort "ICN001", # import concentions; {name} should be imported as {asname} - "ISC001", # Implicitly concatenated string literals on one line "N804", # First argument of a class method should be named cls "N805", # First argument of a method should be named self "N815", # Variable {name} in class scope should not be mixedCase - "PGH001", # No builtin eval() allowed + "S307", # No builtin eval() allowed "PGH004", # Use specific rule codes when using noqa "PLC0414", # Useless import alias. Import alias does not rename original package. - "PLC", # pylint - "PLE", # pylint - "PLR", # pylint - "PLW", # pylint + "PL", # pylint "Q000", # Double quotes found but single quotes preferred "RUF006", # Store a reference to the return value of asyncio.create_task "S102", # Use of exec detected @@ -66,7 +65,7 @@ select = [ "T20", # flake8-print "TID251", # Banned imports "TRY004", # Prefer TypeError exception for invalid type - "TRY200", # Use raise from to specify exception cause + "B904", # Use raise from to specify exception cause "TRY302", # Remove exception handler; error is immediately re-raised "UP", # pyupgrade "W", # pycodestyle @@ -94,25 +93,25 @@ ignore = [ "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` ] -[tool.ruff.flake8-pytest-style] +[tool.ruff.lint.flake8-pytest-style] fixture-parentheses = false -[tool.ruff.flake8-tidy-imports.banned-api] +[tool.ruff.lint.flake8-tidy-imports.banned-api] "pytz".msg = "use zoneinfo instead" -[tool.ruff.isort] +[tool.ruff.lint.isort] force-sort-within-sections = true combine-as-imports = true split-on-trailing-comma = false -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] # Allow for main entry & scripts to write to stdout "src/pyatmo/__main__.py" = ["T201"] # Exceptions for tests "tests/*" = ["D10"] -[tool.ruff.mccabe] +[tool.ruff.lint.mccabe] max-complexity = 25 [tool.setuptools_scm] diff --git a/src/pyatmo/account.py b/src/pyatmo/account.py index 466337cc..ff871573 100644 --- a/src/pyatmo/account.py +++ b/src/pyatmo/account.py @@ -57,7 +57,6 @@ def process_topology(self, disabled_homes_ids: list[str] | None = None) -> None: disabled_homes_ids = [] for home in self.raw_data["homes"]: - home_id = home.get("id", "Unknown") home_name = home.get("name", "Unknown") self.all_homes_id[home_id] = home_name @@ -237,7 +236,7 @@ async def update_devices( {HOME: {"modules": [normalize_weather_attributes(device_data)]}}, ) else: - LOG.debug("No home %s found.", home_id) + LOG.debug("No home %s (%s) found.", home_id, home_id) for module_data in device_data.get("modules", []): module_data["home_id"] = home_id diff --git a/src/pyatmo/const.py b/src/pyatmo/const.py index 1a471d67..0b141743 100644 --- a/src/pyatmo/const.py +++ b/src/pyatmo/const.py @@ -88,7 +88,6 @@ SCHEDULES = "schedules" EVENTS = "events" - STATION_TEMPERATURE_TYPE = "temperature" STATION_PRESSURE_TYPE = "pressure" STATION_HUMIDITY_TYPE = "humidity" @@ -105,3 +104,5 @@ # 2 days of dynamic historical data stored MAX_HISTORY_TIME_FRAME = 24 * 2 * 3600 + +UNKNOWN = "unknown" diff --git a/src/pyatmo/home.py b/src/pyatmo/home.py index aed14ade..fe286182 100644 --- a/src/pyatmo/home.py +++ b/src/pyatmo/home.py @@ -49,6 +49,11 @@ class Home: persons: dict[str, Person] events: dict[str, Event] + temperature_control_mode: str | None = None + therm_mode: str | None = None + therm_setpoint_default_duration: int | None = None + cooling_mode: str | None = None + def __init__(self, auth: AbstractAsyncAuth, raw_data: RawData) -> None: """Initialize a Netatmo home instance.""" @@ -76,6 +81,13 @@ def __init__(self, auth: AbstractAsyncAuth, raw_data: RawData) -> None: } self.events = {} + self.temperature_control_mode = raw_data.get("temperature_control_mode") + self.therm_mode = raw_data.get("therm_mode") + self.therm_setpoint_default_duration = raw_data.get( + "therm_setpoint_default_duration", + ) + self.cooling_mode = raw_data.get("cooling_mode") + def get_module(self, module: dict) -> Module: """Return module.""" @@ -97,6 +109,14 @@ def update_topology(self, raw_data: RawData) -> None: self.name = raw_data.get("name", "Unknown") raw_modules = raw_data.get("modules", []) + + self.temperature_control_mode = raw_data.get("temperature_control_mode") + self.therm_mode = raw_data.get("therm_mode") + self.therm_setpoint_default_duration = raw_data.get( + "therm_setpoint_default_duration", + ) + self.cooling_mode = raw_data.get("cooling_mode") + for module in raw_modules: if (module_id := module["id"]) not in self.modules: self.modules[module_id] = self.get_module(module) @@ -128,7 +148,9 @@ def update_topology(self, raw_data: RawData) -> None: } async def update( - self, raw_data: RawData, do_raise_for_reachability_error=False + self, + raw_data: RawData, + do_raise_for_reachability_error=False, ) -> None: """Update home with the latest data.""" has_error = False @@ -204,6 +226,11 @@ def has_otm(self) -> bool: return any("OTM" in room.device_types for room in self.rooms.values()) + def has_bns(self) -> bool: + """Check if any room has a BNS device.""" + + return any("BNS" in room.device_types for room in self.rooms.values()) + def get_hg_temp(self) -> float | None: """Return frost guard temperature value for given home.""" diff --git a/src/pyatmo/modules/module.py b/src/pyatmo/modules/module.py index 64901659..0e202ca4 100644 --- a/src/pyatmo/modules/module.py +++ b/src/pyatmo/modules/module.py @@ -228,6 +228,16 @@ def __init__(self, home: Home, module: ModuleT): self.boiler_status: bool | None = None +class CoolerMixin(EntityBase): + """Mixin for cooler data.""" + + def __init__(self, home: Home, module: ModuleT): + """Initialize cooler mixin.""" + + super().__init__(home, module) # type: ignore # mypy issue 4335 + self.cooler_status: bool | None = None + + class BatteryMixin(EntityBase): """Mixin for battery data.""" @@ -492,7 +502,7 @@ async def async_update_camera_urls(self) -> None: self.local_url = await self._async_check_url( temp_local_url, ) - except ClientConnectorError as exc: + except (TimeoutError, ClientConnectorError) as exc: LOG.debug("Cannot connect to %s - reason: %s", temp_local_url, exc) self.is_local = False self.local_url = None @@ -643,19 +653,18 @@ class MeasureType(Enum): def compute_riemann_sum( - power_data: list[tuple[int, float]], conservative: bool = False + power_data: list[tuple[int, float]], + conservative: bool = False, ): """Compute energy from power with a rieman sum.""" delta_energy = 0 if power_data and len(power_data) > 1: - # compute a rieman sum, as best as possible , trapezoidal, taking pessimistic asumption # as we don't want to artifically go up the previous one # (except in rare exceptions like reset, 0 , etc) for i in range(len(power_data) - 1): - dt_h = float(power_data[i + 1][0] - power_data[i][0]) / 3600.0 if conservative: @@ -702,7 +711,9 @@ def reset_measures(self, start_power_time, in_reset=True): self.sum_energy_elec_off_peak = 0 def get_sum_energy_elec_power_adapted( - self, to_ts: int | float | None = None, conservative: bool = False + self, + to_ts: int | float | None = None, + conservative: bool = False, ): """Compute proper energy value with adaptation from power.""" v = self.sum_energy_elec @@ -713,7 +724,6 @@ def get_sum_energy_elec_power_adapted( delta_energy = 0 if not self.in_reset: - if to_ts is None: to_ts = int(time()) @@ -726,10 +736,13 @@ def get_sum_energy_elec_power_adapted( and isinstance(self, NetatmoBase) ): power_data = self.get_history_data( - "power", from_ts=from_ts, to_ts=to_ts + "power", + from_ts=from_ts, + to_ts=to_ts, ) if isinstance( - self, EnergyHistoryMixin + self, + EnergyHistoryMixin, ): # well to please the linter.... delta_energy = compute_riemann_sum(power_data, conservative) @@ -784,7 +797,10 @@ async def async_update_measures( filters, raw_data = await self._energy_API_calls(start_time, end_time, interval) hist_good_vals = await self._get_aligned_energy_values_and_mode( - start_time, end_time, delta_range, raw_data + start_time, + end_time, + delta_range, + raw_data, ) self.historical_data = [] @@ -811,7 +827,6 @@ async def async_update_measures( prev_sum_energy_elec if prev_sum_energy_elec is not None else "NOTHING", ) else: - await self._prepare_exported_historical_data( start_time, end_time, @@ -836,7 +851,6 @@ async def _prepare_exported_historical_data( computed_end = 0 computed_end_for_calculus = 0 for cur_start_time, val, vals in hist_good_vals: - self.sum_energy_elec += val modes = [] @@ -915,7 +929,11 @@ async def _prepare_exported_historical_data( self._anchor_for_power_adjustment = computed_end_for_calculus async def _get_aligned_energy_values_and_mode( - self, start_time, end_time, delta_range, raw_data + self, + start_time, + end_time, + delta_range, + raw_data, ): hist_good_vals = [] values_lots = raw_data @@ -932,7 +950,7 @@ async def _get_aligned_energy_values_and_mode( ) raise ApiError( f"Energy badly formed resp beg_time missing: {values_lots} - " - f"module: {self.name}" + f"module: {self.name}", ) from None interval_sec = values_lot.get("step_time") @@ -971,7 +989,6 @@ def _get_energy_filers(self): return ENERGY_FILTERS async def _energy_API_calls(self, start_time, end_time, interval): - filters = self._get_energy_filers() params = { @@ -993,12 +1010,15 @@ async def _energy_API_calls(self, start_time, end_time, interval): if rw_dt is None: self._log_energy_error( - start_time, end_time, msg=f"direct from {filters}", body=rw_dt_f + start_time, + end_time, + msg=f"direct from {filters}", + body=rw_dt_f, ) raise ApiError( f"Energy badly formed resp: {rw_dt_f} - " f"module: {self.name} - " - f"when accessing '{filters}'" + f"when accessing '{filters}'", ) raw_data = rw_dt diff --git a/src/pyatmo/modules/smarther.py b/src/pyatmo/modules/smarther.py index 09aaffa5..871365ee 100644 --- a/src/pyatmo/modules/smarther.py +++ b/src/pyatmo/modules/smarther.py @@ -4,10 +4,16 @@ import logging -from pyatmo.modules.module import BoilerMixin, FirmwareMixin, Module, WifiMixin +from pyatmo.modules.module import ( + BoilerMixin, + CoolerMixin, + FirmwareMixin, + Module, + WifiMixin, +) LOG = logging.getLogger(__name__) -class BNS(FirmwareMixin, BoilerMixin, WifiMixin, Module): +class BNS(FirmwareMixin, BoilerMixin, CoolerMixin, WifiMixin, Module): """Smarther thermostat.""" diff --git a/src/pyatmo/room.py b/src/pyatmo/room.py index 28578bb0..a07d0077 100644 --- a/src/pyatmo/room.py +++ b/src/pyatmo/room.py @@ -6,7 +6,14 @@ import logging from typing import TYPE_CHECKING, Any -from pyatmo.const import FROSTGUARD, HOME, MANUAL, SETROOMTHERMPOINT_ENDPOINT, RawData +from pyatmo.const import ( + FROSTGUARD, + HOME, + MANUAL, + SETROOMTHERMPOINT_ENDPOINT, + UNKNOWN, + RawData, +) from pyatmo.modules.base_class import NetatmoBase from pyatmo.modules.device_types import DeviceType @@ -29,15 +36,25 @@ class Room(NetatmoBase): climate_type: DeviceType | None = None - heating_power_request: int | None = None humidity: int | None = None + therm_measured_temperature: float | None = None + reachable: bool | None = None + + heating_power_request: int | None = None therm_setpoint_temperature: float | None = None therm_setpoint_mode: str | None = None - therm_measured_temperature: float | None = None therm_setpoint_start_time: int | None = None therm_setpoint_end_time: int | None = None + anticipating: bool | None = None + open_window: bool | None = None + + cooling_setpoint_temperature: float | None = None + cooling_setpoint_start_time: int | None = None + cooling_setpoint_end_time: int | None = None + cooling_setpoint_mode: str | None = None + def __init__( self, home: Home, @@ -60,7 +77,7 @@ def __init__( def update_topology(self, raw_data: RawData) -> None: """Update room topology.""" - self.name = raw_data["name"] + self.name = raw_data.get("name", UNKNOWN) self.modules = { m_id: m for m_id, m in self.home.modules.items() @@ -91,19 +108,31 @@ def evaluate_device_type(self) -> None: def update(self, raw_data: RawData) -> None: """Update room data.""" - self.heating_power_request = raw_data.get("heating_power_request") self.humidity = raw_data.get("humidity") if self.climate_type == DeviceType.BNTH: # BNTH is wired, so the room is always reachable self.reachable = True else: self.reachable = raw_data.get("reachable") + self.therm_measured_temperature = raw_data.get("therm_measured_temperature") + + self.reachable = raw_data.get("reachable") + + self.heating_power_request = raw_data.get("heating_power_request") self.therm_setpoint_mode = raw_data.get("therm_setpoint_mode") self.therm_setpoint_temperature = raw_data.get("therm_setpoint_temperature") self.therm_setpoint_start_time = raw_data.get("therm_setpoint_start_time") self.therm_setpoint_end_time = raw_data.get("therm_setpoint_end_time") + self.anticipating = raw_data.get("anticipating") + self.open_window = raw_data.get("open_window") + + self.cooling_setpoint_temperature = raw_data.get("cooling_setpoint_temperature") + self.cooling_setpoint_start_time = raw_data.get("cooling_setpoint_start_time") + self.cooling_setpoint_end_time = raw_data.get("cooling_setpoint_end_time") + self.cooling_setpoint_mode = raw_data.get("cooling_setpoint_mode") + async def async_therm_manual( self, temp: float | None = None, @@ -134,7 +163,9 @@ async def async_therm_set( mode = MODE_MAP.get(mode, mode) if "NATherm1" in self.device_types or ( - "NRV" in self.device_types and not self.home.has_otm() + "NRV" in self.device_types + and not self.home.has_otm() + and not self.home.has_bns() ): await self._async_set_thermpoint(mode, temp, end_time) diff --git a/tests/conftest.py b/tests/conftest.py index bd9bfdea..6b7c53a7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,9 +4,10 @@ from contextlib import contextmanager from unittest.mock import AsyncMock, patch -import pyatmo import pytest +import pyatmo + from .common import fake_post_request, fake_post_request_multi @@ -27,12 +28,15 @@ async def async_account(async_auth): """AsyncAccount fixture.""" account = pyatmo.AsyncAccount(async_auth) - with patch( - "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", - fake_post_request, - ), patch( - "pyatmo.auth.AbstractAsyncAuth.async_post_request", - fake_post_request, + with ( + patch( + "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", + fake_post_request, + ), + patch( + "pyatmo.auth.AbstractAsyncAuth.async_post_request", + fake_post_request, + ), ): await account.async_update_topology() yield account @@ -51,15 +55,18 @@ async def async_account_multi(async_auth): """AsyncAccount fixture.""" account = pyatmo.AsyncAccount(async_auth) - with patch( - "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", - fake_post_request_multi, - ), patch( - "pyatmo.auth.AbstractAsyncAuth.async_post_request", - fake_post_request_multi, + with ( + patch( + "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", + fake_post_request_multi, + ), + patch( + "pyatmo.auth.AbstractAsyncAuth.async_post_request", + fake_post_request_multi, + ), ): await account.async_update_topology( - disabled_homes_ids=["eeeeeeeeeffffffffffaaaaa"] + disabled_homes_ids=["eeeeeeeeeffffffffffaaaaa"], ) yield account diff --git a/tests/test_camera.py b/tests/test_camera.py index d0d19100..79b7c01e 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -3,9 +3,9 @@ import json from unittest.mock import AsyncMock, patch -from pyatmo import DeviceType import pytest +from pyatmo import DeviceType from tests.common import MockResponse # pylint: disable=F6401 diff --git a/tests/test_climate.py b/tests/test_climate.py index 45f9d628..e0303840 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -3,11 +3,11 @@ import json from unittest.mock import AsyncMock, patch +import pytest + from pyatmo import DeviceType, NoSchedule from pyatmo.modules import NATherm1 from pyatmo.modules.device_types import DeviceCategory -import pytest - from tests.common import MockResponse, fake_post_request from tests.conftest import does_not_raise @@ -200,10 +200,13 @@ async def test_async_climate_switch_schedule( with open("fixtures/status_ok.json", encoding="utf-8") as json_file: response = json.load(json_file) - with patch( - "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", - AsyncMock(return_value=MockResponse(response, 200)), - ), expected: + with ( + patch( + "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", + AsyncMock(return_value=MockResponse(response, 200)), + ), + expected, + ): await async_home.async_switch_schedule( schedule_id=t_sched_id, ) @@ -351,10 +354,13 @@ async def test_async_climate_set_thermmode( with open(f"fixtures/{json_fixture}", encoding="utf-8") as json_file: response = json.load(json_file) - with patch( - "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", - AsyncMock(return_value=MockResponse(response, 200)), - ), exception: + with ( + patch( + "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", + AsyncMock(return_value=MockResponse(response, 200)), + ), + exception, + ): resp = await async_home.async_set_thermmode( mode=mode, end_time=end_time, diff --git a/tests/test_energy.py b/tests/test_energy.py index 511bf815..735d34f6 100644 --- a/tests/test_energy.py +++ b/tests/test_energy.py @@ -4,11 +4,11 @@ import json from unittest.mock import AsyncMock, patch -from pyatmo import ApiHomeReachabilityError, DeviceType -from pyatmo.modules.module import EnergyHistoryMixin, MeasureInterval import pytest import time_machine +from pyatmo import ApiHomeReachabilityError, DeviceType +from pyatmo.modules.module import EnergyHistoryMixin, MeasureInterval from tests.common import MockResponse # pylint: disable=F6401 @@ -139,7 +139,7 @@ async def test_disconnected_main_bridge(async_account_multi): with patch( "pyatmo.auth.AbstractAsyncAuth.async_post_api_request", AsyncMock(return_value=mock_home_status_resp), - ) as mock_request: + ): try: await async_account_multi.async_update_status(home_id) except ApiHomeReachabilityError: diff --git a/tests/test_fan.py b/tests/test_fan.py index 6c3a2c0c..a6e5535f 100644 --- a/tests/test_fan.py +++ b/tests/test_fan.py @@ -1,8 +1,9 @@ """Define tests for fan module.""" -from pyatmo import DeviceType import pytest +from pyatmo import DeviceType + # pylint: disable=F6401 diff --git a/tests/test_home.py b/tests/test_home.py index 70e85b6c..dc77d8cb 100644 --- a/tests/test_home.py +++ b/tests/test_home.py @@ -4,10 +4,10 @@ import json from unittest.mock import AsyncMock, patch -import pyatmo -from pyatmo import DeviceType, NoDevice import pytest +import pyatmo +from pyatmo import DeviceType, NoDevice from tests.common import MockResponse # pylint: disable=F6401 @@ -39,6 +39,8 @@ async def test_async_home(async_home): module = async_home.modules[module_id] assert module.device_type == DeviceType.NOC + assert async_home.temperature_control_mode == "cooling" + @pytest.mark.asyncio async def test_async_home_set_schedule(async_home): diff --git a/tests/test_shutter.py b/tests/test_shutter.py index f1a26ee3..004f9648 100644 --- a/tests/test_shutter.py +++ b/tests/test_shutter.py @@ -3,9 +3,9 @@ import json from unittest.mock import AsyncMock, patch -from pyatmo import DeviceType import pytest +from pyatmo import DeviceType from tests.common import MockResponse # pylint: disable=F6401 diff --git a/tests/test_switch.py b/tests/test_switch.py index af5034ce..846bd57f 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -1,8 +1,9 @@ """Define tests for switch module.""" -from pyatmo import DeviceType import pytest +from pyatmo import DeviceType + # pylint: disable=F6401 diff --git a/tests/test_weather.py b/tests/test_weather.py index fac69461..c83fb0d1 100644 --- a/tests/test_weather.py +++ b/tests/test_weather.py @@ -1,9 +1,10 @@ """Define tests for weaather module.""" +import pytest + import pyatmo from pyatmo import DeviceType from pyatmo.modules.base_class import Location, Place -import pytest # pylint: disable=F6401 diff --git a/tests/testing_main_template.py b/tests/testing_main_template.py index 5d17423a..329ace5b 100644 --- a/tests/testing_main_template.py +++ b/tests/testing_main_template.py @@ -1,6 +1,7 @@ import asyncio from aiohttp import ClientSession + import pyatmo from pyatmo.auth import AbstractAsyncAuth from pyatmo.modules.module import MeasureInterval @@ -9,9 +10,7 @@ class MyAuth(AbstractAsyncAuth): - async def async_get_access_token(self): - return MY_TOKEN_FROM_NETATMO @@ -42,7 +41,6 @@ async def main(): if __name__ == "__main__": - topology = asyncio.run(main()) # print(topology)