Add opentherm_gw options flow. (#27316)
This commit is contained in:
parent
0888098718
commit
489340160b
6 changed files with 149 additions and 12 deletions
|
@ -19,5 +19,16 @@
|
|||
}
|
||||
},
|
||||
"title": "OpenTherm Gateway"
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"description": "Options for the OpenTherm Gateway",
|
||||
"data": {
|
||||
"floor_temperature": "Floor Temperature",
|
||||
"precision": "Precision"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,6 +75,12 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
)
|
||||
|
||||
|
||||
async def options_updated(hass, entry):
|
||||
"""Handle options update."""
|
||||
gateway = hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][entry.data[CONF_ID]]
|
||||
async_dispatcher_send(hass, gateway.options_update_signal, entry)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry):
|
||||
"""Set up the OpenTherm Gateway component."""
|
||||
if DATA_OPENTHERM_GW not in hass.data:
|
||||
|
@ -83,6 +89,8 @@ async def async_setup_entry(hass, config_entry):
|
|||
gateway = OpenThermGatewayDevice(hass, config_entry)
|
||||
hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][config_entry.data[CONF_ID]] = gateway
|
||||
|
||||
config_entry.add_update_listener(options_updated)
|
||||
|
||||
# Schedule directly on the loop to avoid blocking HA startup.
|
||||
hass.loop.create_task(gateway.connect_and_subscribe())
|
||||
|
||||
|
@ -348,6 +356,7 @@ class OpenThermGatewayDevice:
|
|||
self.climate_config = config_entry.options
|
||||
self.status = {}
|
||||
self.update_signal = f"{DATA_OPENTHERM_GW}_{self.gw_id}_update"
|
||||
self.options_update_signal = f"{DATA_OPENTHERM_GW}_{self.gw_id}_options_update"
|
||||
self.gateway = pyotgw.pyotgw()
|
||||
|
||||
async def connect_and_subscribe(self):
|
||||
|
|
|
@ -39,7 +39,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
ents = []
|
||||
ents.append(
|
||||
OpenThermClimate(
|
||||
hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][config_entry.data[CONF_ID]]
|
||||
hass.data[DATA_OPENTHERM_GW][DATA_GATEWAYS][config_entry.data[CONF_ID]],
|
||||
config_entry.options,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -49,12 +50,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
class OpenThermClimate(ClimateDevice):
|
||||
"""Representation of a climate device."""
|
||||
|
||||
def __init__(self, gw_dev):
|
||||
def __init__(self, gw_dev, options):
|
||||
"""Initialize the device."""
|
||||
self._gateway = gw_dev
|
||||
self.friendly_name = gw_dev.name
|
||||
self.floor_temp = gw_dev.climate_config.get(CONF_FLOOR_TEMP)
|
||||
self.temp_precision = gw_dev.climate_config.get(CONF_PRECISION)
|
||||
self.floor_temp = options[CONF_FLOOR_TEMP]
|
||||
self.temp_precision = options.get(CONF_PRECISION)
|
||||
self._current_operation = None
|
||||
self._current_temperature = None
|
||||
self._hvac_mode = HVAC_MODE_HEAT
|
||||
|
@ -65,12 +66,22 @@ class OpenThermClimate(ClimateDevice):
|
|||
self._away_state_a = False
|
||||
self._away_state_b = False
|
||||
|
||||
@callback
|
||||
def update_options(self, entry):
|
||||
"""Update climate entity options."""
|
||||
self.floor_temp = entry.options[CONF_FLOOR_TEMP]
|
||||
self.temp_precision = entry.options.get(CONF_PRECISION)
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Connect to the OpenTherm Gateway device."""
|
||||
_LOGGER.debug("Added OpenTherm Gateway climate device %s", self.friendly_name)
|
||||
async_dispatcher_connect(
|
||||
self.hass, self._gateway.update_signal, self.receive_report
|
||||
)
|
||||
async_dispatcher_connect(
|
||||
self.hass, self._gateway.options_update_signal, self.update_options
|
||||
)
|
||||
|
||||
@callback
|
||||
def receive_report(self, status):
|
||||
|
|
|
@ -6,11 +6,20 @@ import pyotgw
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_DEVICE, CONF_ID, CONF_NAME
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE,
|
||||
CONF_ID,
|
||||
CONF_NAME,
|
||||
PRECISION_HALVES,
|
||||
PRECISION_TENTHS,
|
||||
PRECISION_WHOLE,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import DOMAIN
|
||||
from .const import CONF_FLOOR_TEMP, CONF_PRECISION
|
||||
|
||||
|
||||
class OpenThermGwConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
@ -19,6 +28,12 @@ class OpenThermGwConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry):
|
||||
"""Get the options flow for this handler."""
|
||||
return OpenThermGwOptionsFlow(config_entry)
|
||||
|
||||
async def async_step_init(self, info=None):
|
||||
"""Handle config flow initiation."""
|
||||
if info:
|
||||
|
@ -89,3 +104,39 @@ class OpenThermGwConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
return self.async_create_entry(
|
||||
title=name, data={CONF_ID: gw_id, CONF_DEVICE: device, CONF_NAME: name}
|
||||
)
|
||||
|
||||
|
||||
class OpenThermGwOptionsFlow(config_entries.OptionsFlow):
|
||||
"""Handle opentherm_gw options."""
|
||||
|
||||
def __init__(self, config_entry):
|
||||
"""Initialize the options flow."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
"""Manage the opentherm_gw options."""
|
||||
if user_input is not None:
|
||||
if user_input.get(CONF_PRECISION) == 0:
|
||||
user_input[CONF_PRECISION] = None
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_PRECISION,
|
||||
default=self.config_entry.options.get(CONF_PRECISION, 0),
|
||||
): vol.All(
|
||||
vol.Coerce(float),
|
||||
vol.In(
|
||||
[0, PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]
|
||||
),
|
||||
),
|
||||
vol.Optional(
|
||||
CONF_FLOOR_TEMP,
|
||||
default=self.config_entry.options.get(CONF_FLOOR_TEMP, False),
|
||||
): bool,
|
||||
}
|
||||
),
|
||||
)
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
"data": {
|
||||
"name": "Name",
|
||||
"device": "Path or URL",
|
||||
"id": "ID",
|
||||
"precision": "Climate temperature precision",
|
||||
"floor_temperature": "Floor climate temperature"
|
||||
"id": "ID"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -19,5 +17,16 @@
|
|||
"serial_error": "Error connecting to device",
|
||||
"timeout": "Connection attempt timed out"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"description": "Options for the OpenTherm Gateway",
|
||||
"data": {
|
||||
"floor_temperature": "Floor Temperature",
|
||||
"precision": "Precision"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,12 +3,16 @@ import asyncio
|
|||
from serial import SerialException
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.const import CONF_DEVICE, CONF_ID, CONF_NAME
|
||||
from homeassistant.components.opentherm_gw.const import DOMAIN
|
||||
from homeassistant import config_entries, data_entry_flow, setup
|
||||
from homeassistant.const import CONF_DEVICE, CONF_ID, CONF_NAME, PRECISION_HALVES
|
||||
from homeassistant.components.opentherm_gw.const import (
|
||||
DOMAIN,
|
||||
CONF_FLOOR_TEMP,
|
||||
CONF_PRECISION,
|
||||
)
|
||||
|
||||
from pyotgw import OTGW_ABOUT
|
||||
from tests.common import mock_coro
|
||||
from tests.common import mock_coro, MockConfigEntry
|
||||
|
||||
|
||||
async def test_form_user(hass):
|
||||
|
@ -161,3 +165,45 @@ async def test_form_connection_error(hass):
|
|||
assert result2["type"] == "form"
|
||||
assert result2["errors"] == {"base": "serial_error"}
|
||||
assert len(mock_connect.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_options_form(hass):
|
||||
"""Test the options form."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="Mock Gateway",
|
||||
data={
|
||||
CONF_NAME: "Mock Gateway",
|
||||
CONF_DEVICE: "/dev/null",
|
||||
CONF_ID: "mock_gateway",
|
||||
},
|
||||
options={},
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.options.flow.async_init(
|
||||
entry.entry_id, context={"source": "test"}, data=None
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "init"
|
||||
|
||||
result = await hass.config_entries.options.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_FLOOR_TEMP: True, CONF_PRECISION: PRECISION_HALVES},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["data"][CONF_PRECISION] == PRECISION_HALVES
|
||||
assert result["data"][CONF_FLOOR_TEMP] is True
|
||||
|
||||
result = await hass.config_entries.options.flow.async_init(
|
||||
entry.entry_id, context={"source": "test"}, data=None
|
||||
)
|
||||
|
||||
result = await hass.config_entries.options.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_PRECISION: 0}
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["data"][CONF_PRECISION] is None
|
||||
assert result["data"][CONF_FLOOR_TEMP] is True
|
||||
|
|
Loading…
Add table
Reference in a new issue