Upload files to "custom_components/aguaiot"

This commit is contained in:
2026-01-08 13:27:00 +00:00
parent 64dbb8d4ad
commit 5de189287e
5 changed files with 296 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
"""Support for Micronova Agua IOT heating devices."""
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.core import Event, HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from .coordinator import AguaIOTDataUpdateCoordinator
from .const import DOMAIN, PLATFORMS
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the AguaIOT integration."""
if DOMAIN in config:
for entry_config in config[DOMAIN]:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=entry_config
)
)
return True
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up AguaIOT entry."""
coordinator = AguaIOTDataUpdateCoordinator(
hass=hass,
config_entry=config_entry,
)
config_entry.runtime_data = coordinator
await coordinator.async_config_entry_first_refresh()
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
# Services
async def async_close_connection(event: Event) -> None:
"""Close AguaIOT connection on HA Stop."""
# await agua.close()
config_entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_close_connection)
)
return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)

View File

@@ -0,0 +1,116 @@
"""Update coordinator"""
from __future__ import annotations
import logging
from datetime import timedelta
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.helpers.httpx_client import get_async_client
from .aguaiot import (
AguaIOTConnectionError,
AguaIOTError,
AguaIOTUnauthorized,
AguaIOTUpdateError,
aguaiot,
)
from .const import (
CONF_API_URL,
CONF_CUSTOMER_CODE,
CONF_LOGIN_API_URL,
CONF_UUID,
CONF_BRAND_ID,
CONF_BRAND,
CONF_LANGUAGE,
CONF_AIR_TEMP_FIX,
CONF_READING_ERROR_FIX,
CONF_UPDATE_INTERVAL,
CONF_HTTP_TIMEOUT,
CONF_BUFFER_READ_TIMEOUT,
DOMAIN,
)
_LOGGER = logging.getLogger(__name__)
class AguaIOTDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""
def __init__(
self,
hass: HomeAssistant,
config_entry: ConfigEntry,
) -> None:
"""Initialize."""
update_interval = config_entry.options.get(CONF_UPDATE_INTERVAL, 60)
super().__init__(
hass=hass,
logger=_LOGGER,
name=DOMAIN,
update_interval=timedelta(seconds=update_interval),
config_entry=config_entry,
)
"""Set up AguaIOT entry."""
api_url = config_entry.data[CONF_API_URL]
customer_code = config_entry.data[CONF_CUSTOMER_CODE]
email = config_entry.data[CONF_EMAIL]
password = config_entry.data[CONF_PASSWORD]
gen_uuid = config_entry.data[CONF_UUID]
login_api_url = config_entry.data.get(CONF_LOGIN_API_URL)
brand_id = config_entry.data.get(CONF_BRAND_ID)
brand = config_entry.data.get(CONF_BRAND)
air_temp_fix = config_entry.options.get(CONF_AIR_TEMP_FIX, False)
reading_error_fix = config_entry.options.get(CONF_READING_ERROR_FIX, False)
language = config_entry.options.get(CONF_LANGUAGE)
http_timeout = config_entry.options.get(CONF_HTTP_TIMEOUT)
buffer_read_timeout = config_entry.options.get(CONF_BUFFER_READ_TIMEOUT)
self.agua = aguaiot(
api_url=api_url,
customer_code=customer_code,
email=email,
password=password,
unique_id=gen_uuid,
login_api_url=login_api_url,
brand_id=brand_id,
brand=brand,
async_client=get_async_client(hass),
air_temp_fix=air_temp_fix,
reading_error_fix=reading_error_fix,
language=language,
http_timeout=http_timeout,
buffer_read_timeout=buffer_read_timeout,
)
async def _async_setup(self) -> None:
"""Connect to the AguaIOT platform"""
try:
await self.agua.connect()
except AguaIOTUpdateError as e:
_LOGGER.error("Agua IOT Update error: %s", e)
except AguaIOTUnauthorized as e:
raise UpdateFailed(f"Agua IOT Unauthorized: {e}") from e
except AguaIOTConnectionError as e:
raise UpdateFailed(f"Agua IOT Connection error: {e}") from e
except AguaIOTError as e:
raise UpdateFailed(f"Agua IOT error: {e}") from e
async def _async_update_data(self) -> None:
"""Get the latest data."""
try:
await self.agua.update()
except AguaIOTUpdateError as e:
_LOGGER.error("Agua IOT Update error: %s", e)
except AguaIOTUnauthorized as e:
raise UpdateFailed(f"Agua IOT Unauthorized: {e}") from e
except AguaIOTConnectionError as e:
raise UpdateFailed(f"Agua IOT Connection error: {e}") from e
except AguaIOTError as e:
raise UpdateFailed(f"Agua IOT error: {e}") from e

View File

@@ -0,0 +1,33 @@
from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
TO_REDACT = {
CONF_PASSWORD,
CONF_EMAIL,
}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator = config_entry.runtime_data
agua = coordinator.agua
devices = {}
for device in agua.devices:
devices[device.name] = {}
for reg in device.registers:
devices[device.name][reg] = device.get_register(reg)
return {
"entry": async_redact_data(config_entry.as_dict(), TO_REDACT),
"devices": devices,
}

View File

@@ -0,0 +1,13 @@
{
"domain": "aguaiot",
"name": "Micronova Agua IOT",
"codeowners": ["@vincentwolsink"],
"config_flow": true,
"dependencies": [],
"documentation": "https://github.com/vincentwolsink/home_assistant_micronova_agua_iot/",
"integration_type": "hub",
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/vincentwolsink/home_assistant_micronova_agua_iot/issues",
"requirements": ["httpx", "simpleeval"],
"version": "0.9.2"
}

View File

@@ -0,0 +1,85 @@
import logging
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
)
from homeassistant.components.number import NumberEntity
from homeassistant.helpers.entity import DeviceInfo
from .const import NUMBERS, DOMAIN
from .aguaiot import AguaIOTError
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
coordinator = config_entry.runtime_data
agua = coordinator.agua
numbers = []
for device in agua.devices:
hybrid = "power_wood_set" in device.registers
for number in NUMBERS:
if (
number.key in device.registers
and (number.force_enabled or device.get_register_enabled(number.key))
and (
(number.hybrid_only and hybrid)
or (number.hybrid_exclude and not hybrid)
or (not number.hybrid_only and not number.hybrid_exclude)
)
):
numbers.append(AguaIOTHeatingNumber(coordinator, device, number))
async_add_entities(numbers, True)
class AguaIOTHeatingNumber(CoordinatorEntity, NumberEntity):
"""Number entity"""
_attr_has_entity_name = True
def __init__(self, coordinator, device, description):
"""Initialize the thermostat."""
super().__init__(coordinator)
self._device = device
self.entity_description = description
@property
def unique_id(self):
"""Return a unique ID."""
return f"{self._device.id_device}_{self.entity_description.key}"
@property
def name(self):
"""Return the name of the device, if any."""
return self.entity_description.name
@property
def device_info(self):
"""Return the device info."""
return DeviceInfo(
identifiers={(DOMAIN, self._device.id_device)},
name=self._device.name,
manufacturer="Micronova",
model=self._device.name_product,
)
@property
def native_value(self):
"""Return the state of the sensor."""
return self._device.get_register_value(self.entity_description.key)
@property
def native_min_value(self):
return self._device.get_register_value_min(self.entity_description.key)
@property
def native_max_value(self):
return self._device.get_register_value_max(self.entity_description.key)
async def async_set_native_value(self, value):
try:
await self._device.set_register_value(self.entity_description.key, value)
await self.coordinator.async_request_refresh()
except (ValueError, AguaIOTError) as err:
_LOGGER.error("Failed to set value, error: %s", err)