Skip to content

Commit

Permalink
added device unit configuration and dhcp configuration flow
Browse files Browse the repository at this point in the history
  • Loading branch information
toggm committed Nov 24, 2024
1 parent 777f143 commit 40c0993
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 9 deletions.
24 changes: 24 additions & 0 deletions custom_components/askoheat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
from homeassistant.loader import async_get_loaded_integration

from custom_components.askoheat.const import DeviceKey

from .api import AskoHeatModbusApiClient
from .const import (
CONF_ANALOG_INPUT_UNIT,
CONF_DEVICE_UNITS,
CONF_HEATPUMP_UNIT,
CONF_LEGIONELLA_PROTECTION_UNIT,
CONF_MODBUS_MASTER_UNIT,
)
from .coordinator import (
AskoheatConfigDataUpdateCoordinator,
AskoheatEMADataUpdateCoordinator,
Expand Down Expand Up @@ -50,6 +59,20 @@ async def async_setup_entry(
)
config_coordinator = AskoheatConfigDataUpdateCoordinator(hass=hass)
data_coordinator = AskoheatOperationDataUpdateCoordinator(hass=hass)

# default devices
supported_devices = [DeviceKey.WATER_HEATER_CONTROL_UNIT, DeviceKey.ENERGY_MANAGER]
# add devices based on configuration
additional_devices = entry.data[CONF_DEVICE_UNITS]
if additional_devices[CONF_LEGIONELLA_PROTECTION_UNIT]:
supported_devices.append(DeviceKey.LEGIO_PROTECTION_CONTROL_UNIT)
if additional_devices[CONF_ANALOG_INPUT_UNIT]:
supported_devices.append(DeviceKey.ANALOG_INPUT_CONTROL_UNIT)
if additional_devices[CONF_MODBUS_MASTER_UNIT]:
supported_devices.append(DeviceKey.MODBUS_MASTER)
if additional_devices[CONF_HEATPUMP_UNIT]:
supported_devices.append(DeviceKey.HEATPUMP_CONTROL_UNIT)

entry.runtime_data = AskoheatData(
client=AskoHeatModbusApiClient(
host=entry.data[CONF_HOST],
Expand All @@ -60,6 +83,7 @@ async def async_setup_entry(
config_coordinator=config_coordinator,
par_coordinator=par_coordinator,
data_coordinator=data_coordinator,
supported_devices=supported_devices,
)
await entry.runtime_data.client.connect()

Expand Down
2 changes: 1 addition & 1 deletion custom_components/askoheat/api_conf_desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
),
AskoheatNumberEntityDescription(
key=NumberAttrKey.CON_RTU_SLAVE_ID,
device_key=DeviceKey.ENERGY_MANAGER,
device_key=DeviceKey.MODBUS_MASTER,
native_min_value=0,
native_max_value=240,
entity_category=EntityCategory.CONFIG,
Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ async def async_setup_entry(
for entity_description in DATA_REGISTER_BLOCK_DESCRIPTOR.binary_sensors
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
94 changes: 88 additions & 6 deletions custom_components/askoheat/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

from __future__ import annotations

from types import MappingProxyType
from typing import TYPE_CHECKING, Any

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant import config_entries, data_entry_flow
from homeassistant.const import CONF_HOST, CONF_PORT
Expand All @@ -17,13 +21,21 @@
AskoheatModbusApiClientError,
)
from .const import (
CONF_ANALOG_INPUT_UNIT,
CONF_DEVICE_UNITS,
CONF_HEATPUMP_UNIT,
CONF_LEGIONELLA_PROTECTION_UNIT,
CONF_MODBUS_MASTER_UNIT,
DEFAULT_HOST,
DEFAULT_PORT,
DOMAIN,
LOGGER,
SensorAttrKey,
)

if TYPE_CHECKING:
from homeassistant.components.dhcp import DhcpServiceInfo

PORT_SELECTOR = vol.All(
selector.NumberSelector(
selector.NumberSelectorConfig(
Expand All @@ -33,12 +45,62 @@
vol.Coerce(int),
)

STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST, default=DEFAULT_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_PORT): PORT_SELECTOR,
}
)

def _step_user_data_schema(
data: MappingProxyType[str, Any] | None = None,
) -> vol.Schema:
return vol.Schema(
{
vol.Required(
CONF_HOST, default=data[CONF_HOST] if data else DEFAULT_HOST
): cv.string,
vol.Required(
CONF_PORT, default=data[CONF_PORT] if data else DEFAULT_PORT
): PORT_SELECTOR,
CONF_DEVICE_UNITS: data_entry_flow.section(
vol.Schema(
{
vol.Required(
CONF_LEGIONELLA_PROTECTION_UNIT,
default=data[CONF_DEVICE_UNITS][
CONF_LEGIONELLA_PROTECTION_UNIT
]
if data
else True,
): cv.boolean,
vol.Required(
CONF_HEATPUMP_UNIT,
default=data[CONF_DEVICE_UNITS][
CONF_LEGIONELLA_PROTECTION_UNIT
]
if data
else False,
): cv.boolean,
vol.Required(
CONF_ANALOG_INPUT_UNIT,
default=data[CONF_DEVICE_UNITS][
CONF_LEGIONELLA_PROTECTION_UNIT
]
if data
else False,
): cv.boolean,
vol.Required(
CONF_MODBUS_MASTER_UNIT,
default=data[CONF_DEVICE_UNITS][
CONF_LEGIONELLA_PROTECTION_UNIT
]
if data
else False,
): cv.boolean,
}
),
{"collapsed": False},
),
}
)


STEP_USER_DATA_SCHEMA = _step_user_data_schema()


class AskoheatFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
Expand Down Expand Up @@ -101,3 +163,23 @@ async def async_step_user(
data_schema=STEP_USER_DATA_SCHEMA,
errors=_errors,
)

async def async_step_dhcp(
self, discovery_info: DhcpServiceInfo
) -> data_entry_flow.FlowResult:
"""Prepare configuration for a DHCP discovered Askoheat device."""
LOGGER.info(
"Found device with hostname '%s' IP '%s'",
discovery_info.hostname,
discovery_info.ip,
)
# Validate dhcp result with socket broadcast:
config = dict[str, Any]()
config[CONF_HOST] = discovery_info.ip
config[CONF_PORT] = DEFAULT_PORT

return self.async_show_form(
step_id="user",
data_schema=_step_user_data_schema(MappingProxyType(config)),
errors={},
)
6 changes: 5 additions & 1 deletion custom_components/askoheat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
SCAN_INTERVAL_CONFIG = timedelta(hours=1)
SCAN_INTERVAL_OP_DATA = timedelta(minutes=1)

CONF_DEVICE_UNIQUE_ID = "device_unique_id"
CONF_DEVICE_UNITS = "devices"
CONF_ANALOG_INPUT_UNIT = "analog_input_unit"
CONF_LEGIONELLA_PROTECTION_UNIT = "legionella_protection_unit"
CONF_MODBUS_MASTER_UNIT = "modbus_master_unit"
CONF_HEATPUMP_UNIT = "heatpump_unit"


class NumberAttrKey(StrEnum):
Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from custom_components.askoheat.const import (
BinarySensorAttrKey,
DeviceKey,
NumberAttrKey,
SelectAttrKey,
SensorAttrKey,
Expand Down Expand Up @@ -45,6 +46,7 @@ class AskoheatData:
par_coordinator: AskoheatParameterDataUpdateCoordinator
data_coordinator: AskoheatOperationDataUpdateCoordinator
integration: Integration
supported_devices: list[DeviceKey]


@dataclass
Expand Down
6 changes: 5 additions & 1 deletion custom_components/askoheat/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
"@toggm"
],
"config_flow": true,
"dhcp": [
{ "hostname": "askoheat" },
{ "hostname": "askoheat.local" }
],
"documentation": "https://github.com/toggm/askoheat",
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/toggm/askoheat/issues",
"version": "0.0.0"
"version": "0.0.1-beta"
}
2 changes: 2 additions & 0 deletions custom_components/askoheat/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ async def async_setup_entry(
for entity_description in CONF_REGISTER_BLOCK_DESCRIPTOR.number_inputs
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ async def async_setup_entry(
for entity_description in CONF_REGISTER_BLOCK_DESCRIPTOR.select_inputs
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ async def async_setup_entry(
for entity_description in DATA_REGISTER_BLOCK_DESCRIPTOR.sensors
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ async def async_setup_entry(
for entity_description in CONF_REGISTER_BLOCK_DESCRIPTOR.switches
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ async def async_setup_entry(
for entity_description in CONF_REGISTER_BLOCK_DESCRIPTOR.text_inputs
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
2 changes: 2 additions & 0 deletions custom_components/askoheat/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ async def async_setup_entry(
for entity_description in CONF_REGISTER_BLOCK_DESCRIPTOR.time_inputs
},
}.items()
if entity_description.device_key is None
or entity_description.device_key in entry.runtime_data.supported_devices
)


Expand Down
11 changes: 11 additions & 0 deletions custom_components/askoheat/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
"data": {
"host": "host",
"port": "port"
},
"sections": {
"devices": {
"name": "Enable additional device units",
"data": {
"legionella_protection_unit": "Legionella protection",
"heatpump_unit": "Heatpump control",
"analog_input_unit": "Analog input control",
"modbus_master_unit": "Modbus master"
}
}
}
}
},
Expand Down

0 comments on commit 40c0993

Please sign in to comment.