Skip to content

Commit

Permalink
Fixes for config flow
Browse files Browse the repository at this point in the history
  • Loading branch information
bergdahl committed Dec 9, 2023
1 parent 119ed2f commit 83fef14
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 44 deletions.
4 changes: 2 additions & 2 deletions custom_components/growcube/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: dict):
device_entry = registry.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, data_coordinator.model.device_id)},
name=f"Growcube " + data_coordinator.device_id,
name=f"GrowCube " + data_coordinator.device_id,
manufacturer="Elecrow",
model="Growcube",
model="GrowCube",
sw_version=data_coordinator.model.version
)

Expand Down
68 changes: 35 additions & 33 deletions custom_components/growcube/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,58 @@
"""Config flow for the Growcube integration."""
from typing import Optional, Dict

import voluptuous as vol
import asyncio
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.const import CONF_HOST
from growcube_client import GrowcubeClient

from . import GrowcubeDataCoordinator
from .const import DOMAIN

DATA_SCHEMA = {
vol.Required(CONF_HOST): str,
}


class GrowcubeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Growcube config flow."""
VERSION = 1

async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""

if user_input is not None:
# Validate the user input.
errors = await self._async_validate_user_input(user_input)
if not errors:
# User input is valid, create a new config entry.
return self.async_create_entry(title=user_input[CONF_HOST], data=user_input)
else:
# User input is invalid, show an error message.
return self._show_error(errors)
if not user_input:
return await self._show_form()

# Validate the user input.
errors, device_id = await self._async_validate_user_input(user_input)
if errors:
# return self._show_form(errors)
return await self._show_form(errors)

# Show the form to the user.
return self._show_form()
await self.async_set_unique_id(device_id)
self._abort_if_unique_id_configured(updates=user_input)

async def _async_validate_user_input(self, user_input):
return self.async_create_entry(title=user_input[CONF_HOST],
data=user_input)

async def _async_validate_user_input(self, user_input) -> tuple[Dict, Optional[str]]:
"""Validate the user input."""
errors = {}
try:
client = GrowcubeClient(user_input[CONF_HOST], None)
await asyncio.wait_for(client.connect(), timeout=10)
client.disconnect()
except asyncio.TimeoutError:
errors[CONF_HOST] = "Connection timed out"
except OSError:
errors[CONF_HOST] = "Unable to connect to host"

return errors

def _show_form(self, errors=None):
device_id = ""
result, value = await asyncio.wait_for(GrowcubeDataCoordinator.get_device_id(user_input[CONF_HOST]), timeout=4)
if not result:
errors[CONF_HOST] = value
else:
device_id = value

return errors, device_id

async def _show_form(self, errors=None):
"""Show the form to the user."""
return self.async_show_form(
step_id="user",
data_schema=vol.Schema({
vol.Required(CONF_HOST): str
}),
errors=errors
data_schema=vol.Schema(DATA_SCHEMA),
errors=errors if errors else {}
)

def _show_error(self, errors):
"""Show an error message to the user."""
return self._show_form(errors)
39 changes: 36 additions & 3 deletions custom_components/growcube/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import asyncio
from typing import Optional, List
from typing import Optional, List, Tuple

from growcube_client import GrowcubeClient, GrowcubeReport, Channel
from growcube_client import (WaterStateGrowcubeReport,
Expand Down Expand Up @@ -65,12 +65,45 @@ def set_device_id(self, device_id: str) -> None:
async def _async_update_data(self):
return self.model

async def connect(self):
await self.client.connect()
async def connect(self) -> Tuple[bool, str]:
result, error = await self.client.connect()
if not result:
return False, error

# Wait for the device to send back the DeviceVersionGrowcubeReport
while not self.model.device_id:
await asyncio.sleep(0.1)
_LOGGER.debug("Growcube device id: %s", self.model.device_id)
return True, ""

@staticmethod
async def get_device_id(host: str) -> tuple[bool, str]:
""" This is used in the config flow to check for a valid device """
device_id = ""

def _handle_device_id_report(report: GrowcubeReport):
if isinstance(report, DeviceVersionGrowcubeReport):
nonlocal device_id
device_id = report.device_id

async def _check_device_id_assigned():
nonlocal device_id
while not device_id:
await asyncio.sleep(0.1)

client = GrowcubeClient(host, _handle_device_id_report)
result, error = await client.connect()
if not result:
return False, error

try:
await asyncio.wait_for(_check_device_id_assigned(), timeout=2)
client.disconnect()
except asyncio.TimeoutError:
client.disconnect()
return False, 'Timed out waiting for device ID'

return True, device_id

def on_connected(self, host: str) -> None:
_LOGGER.debug(f"Connection to {host} established")
Expand Down
2 changes: 1 addition & 1 deletion custom_components/growcube/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"issue_tracker": "https://github.com/jonnybergdahl/homeassistant_growcube/issues",
"iot_class": "local_push",
"requirements": [
"growcube-client==1.0.11"
"growcube-client==1.0.13"
],
"version": "0.9.0"
}
11 changes: 6 additions & 5 deletions custom_components/growcube/strings.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"title": "GrowCube",
"config": {
"step": {
"init": {
"title": "Select GrowCube device",
"user": {
"description": "Select GrowCube device",
"data": {
"host": "Host"
"host": "[%key:common::config_flow::data::host%]"
},
"data_description": {
"host": "The hostname or IP address of the GrowCube device."
}
}
},
"error": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"unknown": "Unexpected error"
},
"abort": {
Expand Down
23 changes: 23 additions & 0 deletions custom_components/growcube/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"title": "GrowCube",
"config": {
"step": {
"user": {
"description": "Select GrowCube device",
"data": {
"host": "[%key:common::config_flow::data::host%]"
},
"data_description": {
"host": "The hostname or IP address of the GrowCube device."
}
}
},
"error": {
"cannot_connect": "Failed to connect",
"unknown": "Unexpected error"
},
"abort": {
"already_configured": "Device is already configured"
}
}
}

0 comments on commit 83fef14

Please sign in to comment.