Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cooler support #504

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

-
- Expose camera person status
- Add NLE support
- Add proper energy support
- Add cooler support
- Add BNS support

### Changed

Expand Down
2 changes: 2 additions & 0 deletions fixtures/homesdata.json
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,8 @@
}
],
"therm_setpoint_default_duration": 120,
"temperature_control_mode": "cooling",
"cooling_mode": "schedule",
"persons": [
{
"id": "91827374-7e04-5298-83ad-a0cb8372dff1",
Expand Down
3 changes: 1 addition & 2 deletions src/pyatmo/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/pyatmo/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
SCHEDULES = "schedules"
EVENTS = "events"


STATION_TEMPERATURE_TYPE = "temperature"
STATION_PRESSURE_TYPE = "pressure"
STATION_HUMIDITY_TYPE = "humidity"
Expand All @@ -105,3 +104,5 @@

# 2 days of dynamic historical data stored
MAX_HISTORY_TIME_FRAME = 24 * 2 * 3600

UNKNOWN = "unknown"
20 changes: 20 additions & 0 deletions src/pyatmo/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""

Expand Down Expand Up @@ -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")
cgtobi marked this conversation as resolved.
Show resolved Hide resolved
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."""

Expand All @@ -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)
Expand Down
16 changes: 10 additions & 6 deletions src/pyatmo/modules/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ def __init__(self, home: Home, module: ModuleT):
self.boiler_status: bool | None = None


class CoolerMixin(EntityBase):
cgtobi marked this conversation as resolved.
Show resolved Hide resolved
"""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."""

Expand Down Expand Up @@ -649,13 +659,11 @@ def compute_riemann_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:
Expand Down Expand Up @@ -713,7 +721,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())

Expand Down Expand Up @@ -811,7 +818,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,
Expand All @@ -836,7 +842,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 = []
Expand Down Expand Up @@ -971,7 +976,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 = {
Expand Down
10 changes: 8 additions & 2 deletions src/pyatmo/modules/smarther.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
cgtobi marked this conversation as resolved.
Show resolved Hide resolved
"""Smarther thermostat."""
39 changes: 34 additions & 5 deletions src/pyatmo/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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,
Expand All @@ -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()
Expand Down Expand Up @@ -91,19 +108,31 @@ def evaluate_device_type(self) -> None:
def update(self, raw_data: RawData) -> None:
cgtobi marked this conversation as resolved.
Show resolved Hide resolved
"""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,
Expand Down
2 changes: 2 additions & 0 deletions tests/test_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
cgtobi marked this conversation as resolved.
Show resolved Hide resolved


@pytest.mark.asyncio
async def test_async_home_set_schedule(async_home):
Expand Down