Skip to content

Commit 31f52d4

Browse files
authored
Merge pull request #27 from Alexwijn/develop
Master
2 parents 3ea8238 + f77d3ff commit 31f52d4

5 files changed

Lines changed: 77 additions & 52 deletions

File tree

.github/workflows/pytest.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: [ "3.10" ]
14+
python-version: [ "3.11" ]
1515

1616
steps:
1717
- uses: actions/checkout@v2
@@ -22,8 +22,7 @@ jobs:
2222
- name: Install dependencies
2323
run: |
2424
python -m pip install --upgrade pip
25-
pip install pytest
26-
if [ -f requirements_test.txt ]; then pip install -r requirements_test.txt; fi
25+
pip install -r requirements_test.txt
2726
- name: Test with pytest
2827
run: |
2928
pytest

custom_components/sat/config_flow.py

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@
3535
class SatFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
3636
"""Config flow for SAT."""
3737
VERSION = 5
38+
MINOR_VERSION = 0
39+
3840
calibration = None
3941
overshoot_protection_value = None
4042

4143
def __init__(self):
4244
"""Initialize."""
43-
self._data = {}
44-
self._errors = {}
45+
self.data = {}
46+
self.errors = {}
4547

4648
@staticmethod
4749
@callback
@@ -58,7 +60,7 @@ async def async_step_user(self, _user_input=None) -> FlowResult:
5860
menu_options = []
5961

6062
# Since we rely on the availability logic in 2023.5, we do not support below it.
61-
if MAJOR_VERSION >= 2023 and MINOR_VERSION >= 5:
63+
if MAJOR_VERSION >= 2023 and (MINOR_VERSION >= 5 or MAJOR_VERSION > 2023):
6264
menu_options.append("mosquitto")
6365

6466
menu_options.append("serial")
@@ -72,12 +74,12 @@ async def async_step_user(self, _user_input=None) -> FlowResult:
7274
async def async_step_dhcp(self, discovery_info: DhcpServiceInfo) -> FlowResult:
7375
"""Handle dhcp discovery."""
7476
_LOGGER.debug("Discovered OTGW at [socket://%s]", discovery_info.hostname)
75-
self._data[CONF_DEVICE] = f"socket://{discovery_info.hostname}:25238"
77+
self.data[CONF_DEVICE] = f"socket://{discovery_info.hostname}:25238"
7678

7779
# abort if we already have exactly this gateway id/host
7880
# reload the integration if the host got updated
7981
await self.async_set_unique_id(discovery_info.hostname)
80-
self._abort_if_unique_id_configured(updates=self._data, reload_on_update=True)
82+
self._abort_if_unique_id_configured(updates=self.data, reload_on_update=True)
8183

8284
return await self.async_step_serial()
8385

@@ -88,77 +90,77 @@ async def async_step_mqtt(self, discovery_info: MqttServiceInfo):
8890
)
8991

9092
_LOGGER.debug("Discovered OTGW at [mqtt://%s]", discovery_info.topic)
91-
self._data[CONF_DEVICE] = device.id
93+
self.data[CONF_DEVICE] = device.id
9294

9395
# abort if we already have exactly this gateway id/host
9496
# reload the integration if the host got updated
9597
await self.async_set_unique_id(device.id)
96-
self._abort_if_unique_id_configured(updates=self._data, reload_on_update=True)
98+
self._abort_if_unique_id_configured(updates=self.data, reload_on_update=True)
9799

98100
return await self.async_step_mosquitto()
99101

100102
async def async_step_mosquitto(self, _user_input=None):
101-
self._errors = {}
103+
self.errors = {}
102104

103105
if _user_input is not None:
104-
self._data.update(_user_input)
105-
self._data[CONF_MODE] = MODE_MQTT
106+
self.data.update(_user_input)
107+
self.data[CONF_MODE] = MODE_MQTT
106108

107109
if not await mqtt.async_wait_for_mqtt_client(self.hass):
108-
self._errors["base"] = "mqtt_component"
110+
self.errors["base"] = "mqtt_component"
109111
return await self.async_step_mosquitto()
110112

111113
return await self.async_step_sensors()
112114

113115
return self.async_show_form(
114116
step_id="mosquitto",
115117
last_step=False,
116-
errors=self._errors,
118+
errors=self.errors,
117119
data_schema=vol.Schema({
118120
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
119121
vol.Required(CONF_MQTT_TOPIC, default=OPTIONS_DEFAULTS[CONF_MQTT_TOPIC]): str,
120-
vol.Required(CONF_DEVICE, default=self._data.get(CONF_DEVICE)): selector.DeviceSelector(
122+
vol.Required(CONF_DEVICE, default=self.data.get(CONF_DEVICE)): selector.DeviceSelector(
121123
selector.DeviceSelectorConfig(model="otgw-nodo")
122124
),
123125
}),
124126
)
125127

126128
async def async_step_serial(self, _user_input=None):
127-
self._errors = {}
129+
self.errors = {}
128130

129131
if _user_input is not None:
130-
self._data.update(_user_input)
131-
self._data[CONF_MODE] = MODE_SERIAL
132+
self.data.update(_user_input)
133+
self.data[CONF_MODE] = MODE_SERIAL
132134

133135
gateway = OpenThermGateway()
134-
if not await gateway.connect(port=self._data[CONF_DEVICE], skip_init=True, timeout=5):
136+
if not await gateway.connect(port=self.data[CONF_DEVICE], skip_init=True, timeout=5):
135137
await gateway.disconnect()
136-
self._errors["base"] = "connection"
138+
self.errors["base"] = "connection"
137139
return await self.async_step_serial()
138140

139141
return await self.async_step_sensors()
140142

141143
return self.async_show_form(
142144
step_id="serial",
143145
last_step=False,
144-
errors=self._errors,
146+
errors=self.errors,
145147
data_schema=vol.Schema({
146148
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
147-
vol.Required(CONF_DEVICE, default=self._data.get(CONF_DEVICE, "socket://otgw.local:25238")): str,
149+
vol.Required(CONF_DEVICE, default=self.data.get(CONF_DEVICE, "socket://otgw.local:25238")): str,
148150
}),
149151
)
150152

151153
async def async_step_switch(self, _user_input=None):
152154
if _user_input is not None:
153-
self._data.update(_user_input)
154-
self._data[CONF_MODE] = MODE_SWITCH
155+
self.data.update(_user_input)
156+
self.data[CONF_MODE] = MODE_SWITCH
155157

156158
return await self.async_step_sensors()
157159

158160
return self.async_show_form(
159161
step_id="switch",
160162
last_step=False,
161-
errors=self._errors,
163+
errors=self.errors,
162164
data_schema=vol.Schema({
163165
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
164166
vol.Required(CONF_DEVICE): selector.EntitySelector(
@@ -172,16 +174,16 @@ async def async_step_switch(self, _user_input=None):
172174

173175
async def async_step_simulator(self, _user_input=None):
174176
if _user_input is not None:
175-
self._data.update(_user_input)
176-
self._data[CONF_MODE] = MODE_SIMULATOR
177-
self._data[CONF_DEVICE] = f"%s_%s".format(MODE_SIMULATOR, snake_case(_user_input.get(CONF_NAME)))
177+
self.data.update(_user_input)
178+
self.data[CONF_MODE] = MODE_SIMULATOR
179+
self.data[CONF_DEVICE] = f"%s_%s".format(MODE_SIMULATOR, snake_case(_user_input.get(CONF_NAME)))
178180

179181
return await self.async_step_sensors()
180182

181183
return self.async_show_form(
182184
step_id="simulator",
183185
last_step=False,
184-
errors=self._errors,
186+
errors=self.errors,
185187
data_schema=vol.Schema({
186188
vol.Required(CONF_NAME, default=DEFAULT_NAME): str,
187189
vol.Required(CONF_SIMULATED_HEATING, default=OPTIONS_DEFAULTS[CONF_SIMULATED_HEATING]): selector.NumberSelector(
@@ -198,13 +200,13 @@ async def async_step_simulator(self, _user_input=None):
198200
)
199201

200202
async def async_step_sensors(self, _user_input=None):
201-
await self.async_set_unique_id(self._data[CONF_DEVICE], raise_on_progress=False)
203+
await self.async_set_unique_id(self.data[CONF_DEVICE], raise_on_progress=False)
202204
self._abort_if_unique_id_configured()
203205

204206
if _user_input is not None:
205-
self._data.update(_user_input)
207+
self.data.update(_user_input)
206208

207-
if self._data[CONF_MODE] in [MODE_MQTT, MODE_SERIAL, MODE_SIMULATOR]:
209+
if self.data[CONF_MODE] in [MODE_MQTT, MODE_SERIAL, MODE_SIMULATOR]:
208210
return await self.async_step_heating_system()
209211

210212
return await self.async_step_areas()
@@ -236,7 +238,7 @@ async def async_step_sensors(self, _user_input=None):
236238

237239
async def async_step_heating_system(self, _user_input=None):
238240
if _user_input is not None:
239-
self._data.update(_user_input)
241+
self.data.update(_user_input)
240242

241243
return await self.async_step_areas()
242244

@@ -256,9 +258,9 @@ async def async_step_heating_system(self, _user_input=None):
256258

257259
async def async_step_areas(self, _user_input=None):
258260
if _user_input is not None:
259-
self._data.update(_user_input)
261+
self.data.update(_user_input)
260262

261-
if (await self._create_coordinator()).supports_setpoint_management:
263+
if (await self.async_create_coordinator()).supports_setpoint_management:
262264
return await self.async_step_calibrate_system()
263265

264266
return await self.async_step_automatic_gains()
@@ -277,9 +279,9 @@ async def async_step_areas(self, _user_input=None):
277279

278280
async def async_step_automatic_gains(self, _user_input=None):
279281
if _user_input is not None:
280-
self._data.update(_user_input)
282+
self.data.update(_user_input)
281283

282-
if not self._data[CONF_AUTOMATIC_GAINS]:
284+
if not self.data[CONF_AUTOMATIC_GAINS]:
283285
return await self.async_step_pid_controller()
284286

285287
return await self.async_step_finish()
@@ -297,7 +299,7 @@ async def async_step_calibrate_system(self, _user_input=None):
297299
)
298300

299301
async def async_step_calibrate(self, _user_input=None):
300-
coordinator = await self._create_coordinator()
302+
coordinator = await self.async_create_coordinator()
301303

302304
async def start_calibration():
303305
try:
@@ -341,7 +343,7 @@ async def start_calibration():
341343
async def async_step_calibrated(self, _user_input=None):
342344
return self.async_show_menu(
343345
step_id="calibrated",
344-
description_placeholders=self._data,
346+
description_placeholders=self.data,
345347
menu_options=["calibrate", "finish"],
346348
)
347349

@@ -363,10 +365,10 @@ async def async_step_overshoot_protection(self, _user_input=None):
363365
)
364366

365367
async def async_step_pid_controller(self, _user_input=None):
366-
self._data[CONF_AUTOMATIC_GAINS] = False
368+
self.data[CONF_AUTOMATIC_GAINS] = False
367369

368370
if _user_input is not None:
369-
self._data.update(_user_input)
371+
self.data.update(_user_input)
370372
return await self.async_step_finish()
371373

372374
return self.async_show_form(
@@ -379,22 +381,33 @@ async def async_step_pid_controller(self, _user_input=None):
379381
)
380382

381383
async def async_step_finish(self, _user_input=None):
382-
return self.async_create_entry(title=self._data[CONF_NAME], data=self._data)
384+
return self.async_create_entry(title=self.data[CONF_NAME], data=self.data)
385+
386+
async def async_create_coordinator(self) -> SatDataUpdateCoordinator:
387+
# Set up the config entry parameters, since they differ per version
388+
config_params = {
389+
"version": self.VERSION,
390+
"domain": DOMAIN,
391+
"title": self.data[CONF_NAME],
392+
"data": self.data,
393+
"source": SOURCE_USER,
394+
}
395+
396+
# Check Home Assistant version and add parameters accordingly
397+
if MAJOR_VERSION >= 2024:
398+
config_params["minor_version"] = self.MINOR_VERSION
383399

384-
async def _create_coordinator(self) -> SatDataUpdateCoordinator:
385400
# Create a new config to use
386-
config = ConfigEntry(
387-
version=self.VERSION, domain=DOMAIN, title=self._data[CONF_NAME], data=self._data, source=SOURCE_USER
388-
)
401+
config = ConfigEntry(**config_params)
389402

390403
# Resolve the coordinator by using the factory according to the mode
391404
return await SatDataUpdateCoordinatorFactory().resolve(
392-
hass=self.hass, config_entry=config, mode=self._data[CONF_MODE], device=self._data[CONF_DEVICE]
405+
hass=self.hass, config_entry=config, mode=self.data[CONF_MODE], device=self.data[CONF_DEVICE]
393406
)
394407

395408
async def _enable_overshoot_protection(self, overshoot_protection_value: float):
396-
self._data[CONF_OVERSHOOT_PROTECTION] = True
397-
self._data[CONF_MINIMUM_SETPOINT] = overshoot_protection_value
409+
self.data[CONF_OVERSHOOT_PROTECTION] = True
410+
self.data[CONF_MINIMUM_SETPOINT] = overshoot_protection_value
398411

399412

400413
class SatOptionsFlowHandler(config_entries.OptionsFlow):

custom_components/sat/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@
2222
"requirements": [
2323
"pyotgw==2.1.3"
2424
],
25-
"version": "2.1.0"
25+
"version": "3.0.1"
2626
}

requirements_test.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pytest
22
pytest-cov
33
pytest-asyncio
44
pytest-homeassistant-custom-component
5-
homeassistant==2023.5.3
5+
homeassistant
66
aiohttp_cors
77
aiodiscover
88
freezegun

tests/test_config_flow.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from custom_components.sat import MODE_FAKE
2+
from custom_components.sat.config_flow import SatFlowHandler
3+
4+
5+
async def test_create_coordinator(hass):
6+
flow_handler = SatFlowHandler()
7+
flow_handler.data = {
8+
"name": "Test",
9+
"mode": MODE_FAKE,
10+
"device": "test_device",
11+
}
12+
13+
await flow_handler.async_create_coordinator()

0 commit comments

Comments
 (0)