Update nibe library to 2.0.0 (#88769)
parent
aaa5bb9f86
commit
8c7b29db25
|
@ -8,11 +8,11 @@ from datetime import timedelta
|
|||
from functools import cached_property
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
from nibe.connection import Connection
|
||||
from nibe.connection.modbus import Modbus
|
||||
from nibe.connection.nibegw import NibeGW, ProductInfo
|
||||
from nibe.exceptions import CoilNotFoundException, CoilReadException
|
||||
from nibe.exceptions import CoilNotFoundException, ReadException
|
||||
from nibe.heatpump import HeatPump, Model, Series
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -182,7 +182,7 @@ class ContextCoordinator(
|
|||
return release_update
|
||||
|
||||
|
||||
class Coordinator(ContextCoordinator[dict[int, Coil], int]):
|
||||
class Coordinator(ContextCoordinator[dict[int, CoilData], int]):
|
||||
"""Update coordinator for nibe heat pumps."""
|
||||
|
||||
config_entry: ConfigEntry
|
||||
|
@ -199,17 +199,18 @@ class Coordinator(ContextCoordinator[dict[int, Coil], int]):
|
|||
)
|
||||
|
||||
self.data = {}
|
||||
self.seed: dict[int, Coil] = {}
|
||||
self.seed: dict[int, CoilData] = {}
|
||||
self.connection = connection
|
||||
self.heatpump = heatpump
|
||||
self.task: asyncio.Task | None = None
|
||||
|
||||
heatpump.subscribe(heatpump.COIL_UPDATE_EVENT, self._on_coil_update)
|
||||
|
||||
def _on_coil_update(self, coil: Coil):
|
||||
def _on_coil_update(self, data: CoilData):
|
||||
"""Handle callback on coil updates."""
|
||||
self.data[coil.address] = coil
|
||||
self.seed[coil.address] = coil
|
||||
coil = data.coil
|
||||
self.data[coil.address] = data
|
||||
self.seed[coil.address] = data
|
||||
self.async_update_context_listeners([coil.address])
|
||||
|
||||
@property
|
||||
|
@ -246,26 +247,26 @@ class Coordinator(ContextCoordinator[dict[int, Coil], int]):
|
|||
|
||||
async def async_write_coil(self, coil: Coil, value: int | float | str) -> None:
|
||||
"""Write coil and update state."""
|
||||
coil.value = value
|
||||
coil = await self.connection.write_coil(coil)
|
||||
data = CoilData(coil, value)
|
||||
await self.connection.write_coil(data)
|
||||
|
||||
self.data[coil.address] = coil
|
||||
self.data[coil.address] = data
|
||||
|
||||
self.async_update_context_listeners([coil.address])
|
||||
|
||||
async def async_read_coil(self, coil: Coil) -> Coil:
|
||||
async def async_read_coil(self, coil: Coil) -> CoilData:
|
||||
"""Read coil and update state using callbacks."""
|
||||
return await self.connection.read_coil(coil)
|
||||
|
||||
async def _async_update_data(self) -> dict[int, Coil]:
|
||||
async def _async_update_data(self) -> dict[int, CoilData]:
|
||||
self.task = asyncio.current_task()
|
||||
try:
|
||||
return await self._async_update_data_internal()
|
||||
finally:
|
||||
self.task = None
|
||||
|
||||
async def _async_update_data_internal(self) -> dict[int, Coil]:
|
||||
result: dict[int, Coil] = {}
|
||||
async def _async_update_data_internal(self) -> dict[int, CoilData]:
|
||||
result: dict[int, CoilData] = {}
|
||||
|
||||
def _get_coils() -> Iterable[Coil]:
|
||||
for address in sorted(self.context_callbacks.keys()):
|
||||
|
@ -282,10 +283,10 @@ class Coordinator(ContextCoordinator[dict[int, Coil], int]):
|
|||
yield coil
|
||||
|
||||
try:
|
||||
async for coil in self.connection.read_coils(_get_coils()):
|
||||
result[coil.address] = coil
|
||||
self.seed.pop(coil.address, None)
|
||||
except CoilReadException as exception:
|
||||
async for data in self.connection.read_coils(_get_coils()):
|
||||
result[data.coil.address] = data
|
||||
self.seed.pop(data.coil.address, None)
|
||||
except ReadException as exception:
|
||||
if not result:
|
||||
raise UpdateFailed(f"Failed to update: {exception}") from exception
|
||||
self.logger.debug(
|
||||
|
@ -329,7 +330,7 @@ class CoilEntity(CoordinatorEntity[Coordinator]):
|
|||
self.coordinator.data or {}
|
||||
)
|
||||
|
||||
def _async_read_coil(self, coil: Coil):
|
||||
def _async_read_coil(self, data: CoilData):
|
||||
"""Update state of entity based on coil data."""
|
||||
|
||||
async def _async_write_coil(self, value: int | float | str):
|
||||
|
@ -337,10 +338,9 @@ class CoilEntity(CoordinatorEntity[Coordinator]):
|
|||
await self.coordinator.async_write_coil(self._coil, value)
|
||||
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
coil = self.coordinator.data.get(self._coil.address)
|
||||
if coil is None:
|
||||
data = self.coordinator.data.get(self._coil.address)
|
||||
if data is None:
|
||||
return
|
||||
|
||||
self._coil = coil
|
||||
self._async_read_coil(coil)
|
||||
self._async_read_coil(data)
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""The Nibe Heat Pump binary sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
|
||||
from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT, BinarySensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -37,5 +37,5 @@ class BinarySensor(CoilEntity, BinarySensorEntity):
|
|||
"""Initialize entity."""
|
||||
super().__init__(coordinator, coil, ENTITY_ID_FORMAT)
|
||||
|
||||
def _async_read_coil(self, coil: Coil) -> None:
|
||||
self._attr_is_on = coil.value == "ON"
|
||||
def _async_read_coil(self, data: CoilData) -> None:
|
||||
self._attr_is_on = data.value == "ON"
|
||||
|
|
|
@ -8,10 +8,10 @@ from nibe.connection.nibegw import NibeGW
|
|||
from nibe.exceptions import (
|
||||
AddressInUseException,
|
||||
CoilNotFoundException,
|
||||
CoilReadException,
|
||||
CoilReadSendException,
|
||||
CoilWriteException,
|
||||
CoilWriteSendException,
|
||||
ReadException,
|
||||
ReadSendException,
|
||||
WriteException,
|
||||
)
|
||||
from nibe.heatpump import HeatPump, Model
|
||||
import voluptuous as vol
|
||||
|
@ -108,13 +108,13 @@ async def validate_nibegw_input(
|
|||
|
||||
try:
|
||||
await connection.verify_connectivity()
|
||||
except (CoilReadSendException, CoilWriteSendException) as exception:
|
||||
except (ReadSendException, CoilWriteSendException) as exception:
|
||||
raise FieldError(str(exception), CONF_IP_ADDRESS, "address") from exception
|
||||
except CoilNotFoundException as exception:
|
||||
raise FieldError("Coils not found", "base", "model") from exception
|
||||
except CoilReadException as exception:
|
||||
except ReadException as exception:
|
||||
raise FieldError("Timeout on read from pump", "base", "read") from exception
|
||||
except CoilWriteException as exception:
|
||||
except WriteException as exception:
|
||||
raise FieldError("Timeout on writing to pump", "base", "write") from exception
|
||||
finally:
|
||||
await connection.stop()
|
||||
|
@ -147,13 +147,13 @@ async def validate_modbus_input(
|
|||
|
||||
try:
|
||||
await connection.verify_connectivity()
|
||||
except (CoilReadSendException, CoilWriteSendException) as exception:
|
||||
except (ReadSendException, CoilWriteSendException) as exception:
|
||||
raise FieldError(str(exception), CONF_MODBUS_URL, "address") from exception
|
||||
except CoilNotFoundException as exception:
|
||||
raise FieldError("Coils not found", "base", "model") from exception
|
||||
except CoilReadException as exception:
|
||||
except ReadException as exception:
|
||||
raise FieldError("Timeout on read from pump", "base", "read") from exception
|
||||
except CoilWriteException as exception:
|
||||
except WriteException as exception:
|
||||
raise FieldError("Timeout on writing to pump", "base", "write") from exception
|
||||
finally:
|
||||
await connection.stop()
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/nibe_heatpump",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["nibe==1.6.0"]
|
||||
"requirements": ["nibe==2.0.0"]
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""The Nibe Heat Pump numbers."""
|
||||
from __future__ import annotations
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
|
||||
from homeassistant.components.number import ENTITY_ID_FORMAT, NumberEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -58,13 +58,13 @@ class Number(CoilEntity, NumberEntity):
|
|||
self._attr_native_unit_of_measurement = coil.unit
|
||||
self._attr_native_value = None
|
||||
|
||||
def _async_read_coil(self, coil: Coil) -> None:
|
||||
if coil.value is None:
|
||||
def _async_read_coil(self, data: CoilData) -> None:
|
||||
if data.value is None:
|
||||
self._attr_native_value = None
|
||||
return
|
||||
|
||||
try:
|
||||
self._attr_native_value = float(coil.value)
|
||||
self._attr_native_value = float(data.value)
|
||||
except ValueError:
|
||||
self._attr_native_value = None
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""The Nibe Heat Pump select."""
|
||||
from __future__ import annotations
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
|
||||
from homeassistant.components.select import ENTITY_ID_FORMAT, SelectEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -40,12 +40,12 @@ class Select(CoilEntity, SelectEntity):
|
|||
self._attr_options = list(coil.mappings.values())
|
||||
self._attr_current_option = None
|
||||
|
||||
def _async_read_coil(self, coil: Coil) -> None:
|
||||
if not isinstance(coil.value, str):
|
||||
def _async_read_coil(self, data: CoilData) -> None:
|
||||
if not isinstance(data.value, str):
|
||||
self._attr_current_option = None
|
||||
return
|
||||
|
||||
self._attr_current_option = coil.value
|
||||
self._attr_current_option = data.value
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Support writing value."""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""The Nibe Heat Pump sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
ENTITY_ID_FORMAT,
|
||||
|
@ -146,5 +146,5 @@ class Sensor(CoilEntity, SensorEntity):
|
|||
self._attr_native_unit_of_measurement = coil.unit
|
||||
self._attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
def _async_read_coil(self, coil: Coil):
|
||||
self._attr_native_value = coil.value
|
||||
def _async_read_coil(self, data: CoilData):
|
||||
self._attr_native_value = data.value
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
|
||||
from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -40,8 +40,8 @@ class Switch(CoilEntity, SwitchEntity):
|
|||
super().__init__(coordinator, coil, ENTITY_ID_FORMAT)
|
||||
self._attr_is_on = None
|
||||
|
||||
def _async_read_coil(self, coil: Coil) -> None:
|
||||
self._attr_is_on = coil.value == "ON"
|
||||
def _async_read_coil(self, data: CoilData) -> None:
|
||||
self._attr_is_on = data.value == "ON"
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the entity on."""
|
||||
|
|
|
@ -1201,7 +1201,7 @@ nextcord==2.0.0a8
|
|||
nextdns==1.3.0
|
||||
|
||||
# homeassistant.components.nibe_heatpump
|
||||
nibe==1.6.0
|
||||
nibe==2.0.0
|
||||
|
||||
# homeassistant.components.niko_home_control
|
||||
niko-home-control==0.2.1
|
||||
|
|
|
@ -891,7 +891,7 @@ nextcord==2.0.0a8
|
|||
nextdns==1.3.0
|
||||
|
||||
# homeassistant.components.nibe_heatpump
|
||||
nibe==1.6.0
|
||||
nibe==2.0.0
|
||||
|
||||
# homeassistant.components.nfandroidtv
|
||||
notifications-android-tv==0.1.5
|
||||
|
|
|
@ -4,9 +4,9 @@ from contextlib import ExitStack
|
|||
from typing import Any
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import Coil, CoilData
|
||||
from nibe.connection import Connection
|
||||
from nibe.exceptions import CoilReadException
|
||||
from nibe.exceptions import ReadException
|
||||
import pytest
|
||||
|
||||
|
||||
|
@ -39,12 +39,11 @@ async def fixture_coils(mock_connection):
|
|||
"""Return a dict with coil data."""
|
||||
coils: dict[int, Any] = {}
|
||||
|
||||
async def read_coil(coil: Coil, timeout: float = 0) -> Coil:
|
||||
async def read_coil(coil: Coil, timeout: float = 0) -> CoilData:
|
||||
nonlocal coils
|
||||
if (data := coils.get(coil.address, None)) is None:
|
||||
raise CoilReadException()
|
||||
coil.value = data
|
||||
return coil
|
||||
raise ReadException()
|
||||
return CoilData(coil, data)
|
||||
|
||||
async def read_coils(
|
||||
coils: Iterable[Coil], timeout: float = 0
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import Any
|
|||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from nibe.coil import Coil
|
||||
from nibe.coil import CoilData
|
||||
from nibe.coil_groups import UNIT_COILGROUPS
|
||||
from nibe.heatpump import Model
|
||||
import pytest
|
||||
|
@ -91,6 +91,6 @@ async def test_reset_button(
|
|||
# Verify reset was written
|
||||
args = mock_connection.write_coil.call_args
|
||||
assert args
|
||||
coil: Coil = args.args[0]
|
||||
assert coil.address == unit.alarm_reset
|
||||
coil: CoilData = args.args[0]
|
||||
assert coil.coil.address == unit.alarm_reset
|
||||
assert coil.value == 1
|
||||
|
|
|
@ -5,9 +5,9 @@ from nibe.coil import Coil
|
|||
from nibe.exceptions import (
|
||||
AddressInUseException,
|
||||
CoilNotFoundException,
|
||||
CoilReadException,
|
||||
CoilReadSendException,
|
||||
CoilWriteException,
|
||||
ReadException,
|
||||
ReadSendException,
|
||||
WriteException,
|
||||
)
|
||||
import pytest
|
||||
|
||||
|
@ -169,7 +169,7 @@ async def test_read_timeout(
|
|||
"""Test we handle cannot connect error."""
|
||||
result = await _get_connection_form(hass, connection_type)
|
||||
|
||||
mock_connection.verify_connectivity.side_effect = CoilReadException()
|
||||
mock_connection.verify_connectivity.side_effect = ReadException()
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], data)
|
||||
|
||||
|
@ -190,7 +190,7 @@ async def test_write_timeout(
|
|||
"""Test we handle cannot connect error."""
|
||||
result = await _get_connection_form(hass, connection_type)
|
||||
|
||||
mock_connection.verify_connectivity.side_effect = CoilWriteException()
|
||||
mock_connection.verify_connectivity.side_effect = WriteException()
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], data)
|
||||
|
||||
|
@ -232,7 +232,7 @@ async def test_nibegw_invalid_host(
|
|||
"""Test we handle cannot connect error."""
|
||||
result = await _get_connection_form(hass, connection_type)
|
||||
|
||||
mock_connection.verify_connectivity.side_effect = CoilReadSendException()
|
||||
mock_connection.verify_connectivity.side_effect = ReadSendException()
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], data)
|
||||
|
||||
|
|
Loading…
Reference in New Issue