1 """Config flow for La Marzocco integration."""
3 from __future__
import annotations
5 from collections.abc
import Mapping
9 from httpx
import AsyncClient
10 from pylamarzocco.client_cloud
import LaMarzoccoCloudClient
11 from pylamarzocco.client_local
import LaMarzoccoLocalClient
12 from pylamarzocco.exceptions
import AuthFail, RequestNotSuccessful
13 from pylamarzocco.models
import LaMarzoccoDeviceInfo
14 import voluptuous
as vol
18 async_discovered_service_info,
49 from .const
import CONF_USE_BLUETOOTH, DOMAIN
51 CONF_MACHINE =
"machine"
53 _LOGGER = logging.getLogger(__name__)
57 """Handle a config flow for La Marzocco."""
64 """Initialize the config flow."""
65 self.
_config_config: dict[str, Any] = {}
66 self.
_fleet_fleet: dict[str, LaMarzoccoDeviceInfo] = {}
67 self._discovered: dict[str, str] = {}
70 self, user_input: dict[str, Any] |
None =
None
71 ) -> ConfigFlowResult:
72 """Handle the initial step."""
77 data: dict[str, Any] = {}
87 cloud_client = LaMarzoccoCloudClient(
88 username=data[CONF_USERNAME],
89 password=data[CONF_PASSWORD],
93 self.
_fleet_fleet = await cloud_client.get_customer_fleet()
95 _LOGGER.debug(
"Server rejected login credentials")
96 errors[
"base"] =
"invalid_auth"
97 except RequestNotSuccessful
as exc:
98 _LOGGER.error(
"Error connecting to server: %s", exc)
99 errors[
"base"] =
"cannot_connect"
102 errors[
"base"] =
"no_machines"
110 if self._discovered[CONF_MACHINE]
not in self.
_fleet_fleet:
111 errors[
"base"] =
"machine_not_found"
115 if CONF_HOST
in self._discovered:
118 CONF_HOST: self._discovered[CONF_HOST],
119 CONF_MACHINE: self._discovered[CONF_MACHINE],
124 step_id=
"machine_selection",
125 data_schema=vol.Schema(
126 {vol.Optional(CONF_HOST): cv.string}
134 placeholders: dict[str, str] |
None =
None
136 self.context[
"title_placeholders"] = placeholders = {
137 CONF_NAME: self._discovered[CONF_MACHINE]
142 data_schema=vol.Schema(
144 vol.Required(CONF_USERNAME): str,
145 vol.Required(CONF_PASSWORD): str,
149 description_placeholders=placeholders,
153 self, user_input: dict[str, Any] |
None =
None
154 ) -> ConfigFlowResult:
155 """Let user select machine to connect to."""
156 errors: dict[str, str] = {}
158 if not self._discovered:
159 serial_number = user_input[CONF_MACHINE]
164 serial_number = self._discovered[CONF_MACHINE]
166 selected_device = self.
_fleet_fleet[serial_number]
169 if user_input.get(CONF_HOST):
170 if not await LaMarzoccoLocalClient.validate_connection(
172 host=user_input[CONF_HOST],
173 token=selected_device.communication_key,
175 errors[CONF_HOST] =
"cannot_connect"
177 self.
_config_config[CONF_HOST] = user_input[CONF_HOST]
182 self._discovered[service_info.name] = service_info.address
188 title=selected_device.name,
191 CONF_NAME: selected_device.name,
192 CONF_MODEL: selected_device.model,
193 CONF_TOKEN: selected_device.communication_key,
199 value=device.serial_number,
200 label=f
"{device.model} ({device.serial_number})",
202 for device
in self.
_fleet_fleet.values()
205 machine_selection_schema = vol.Schema(
208 CONF_MACHINE, default=machine_options[0][
"value"]
211 options=machine_options,
212 mode=SelectSelectorMode.DROPDOWN,
215 vol.Optional(CONF_HOST): cv.string,
220 step_id=
"machine_selection",
221 data_schema=machine_selection_schema,
226 self, user_input: dict[str, Any] |
None =
None
227 ) -> ConfigFlowResult:
228 """Handle Bluetooth device selection."""
230 if user_input
is not None:
235 CONF_MAC: user_input[CONF_MAC],
242 label=f
"{device_name} ({device_mac})",
244 for device_name, device_mac
in self._discovered.items()
248 step_id=
"bluetooth_selection",
249 data_schema=vol.Schema(
254 mode=SelectSelectorMode.DROPDOWN,
262 self, discovery_info: BluetoothServiceInfo
263 ) -> ConfigFlowResult:
264 """Handle a flow initialized by discovery over Bluetooth."""
265 address = discovery_info.address
266 name = discovery_info.name
269 "Discovered La Marzocco machine %s through Bluetooth at address %s",
274 self._discovered[CONF_NAME] = name
275 self._discovered[CONF_MAC] = address
277 serial = name.split(
"_")[1]
278 self._discovered[CONF_MACHINE] = serial
286 self, discovery_info: DhcpServiceInfo
287 ) -> ConfigFlowResult:
288 """Handle discovery via dhcp."""
290 serial = discovery_info.hostname.upper()
295 CONF_HOST: discovery_info.ip,
296 CONF_ADDRESS: discovery_info.macaddress,
302 "Discovered La Marzocco machine %s through DHCP at address %s",
303 discovery_info.hostname,
307 self._discovered[CONF_MACHINE] = serial
308 self._discovered[CONF_HOST] = discovery_info.ip
309 self._discovered[CONF_ADDRESS] = discovery_info.macaddress
314 self, entry_data: Mapping[str, Any]
315 ) -> ConfigFlowResult:
316 """Perform reauth upon an API authentication error."""
320 self, user_input: dict[str, Any] |
None =
None
321 ) -> ConfigFlowResult:
322 """Dialog that informs the user that reauth is required."""
325 step_id=
"reauth_confirm",
326 data_schema=vol.Schema(
328 vol.Required(CONF_PASSWORD): str,
336 self, user_input: dict[str, Any] |
None =
None
337 ) -> ConfigFlowResult:
338 """Perform reconfiguration of the config entry."""
342 step_id=
"reconfigure",
343 data_schema=vol.Schema(
347 default=reconfigure_entry.data[CONF_USERNAME],
351 default=reconfigure_entry.data[CONF_PASSWORD],
362 config_entry: ConfigEntry,
363 ) -> LmOptionsFlowHandler:
364 """Create the options flow."""
369 """Handles options flow for the component."""
372 self, user_input: dict[str, Any] |
None =
None
373 ) -> ConfigFlowResult:
374 """Manage the options for the custom component."""
378 options_schema = vol.Schema(
389 data_schema=options_schema,
ConfigFlowResult async_step_dhcp(self, DhcpServiceInfo discovery_info)
LmOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult async_step_reauth_confirm(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_machine_selection(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_bluetooth_selection(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_bluetooth(self, BluetoothServiceInfo discovery_info)
ConfigFlowResult async_step_reconfigure(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry _get_reauth_entry(self)
ConfigEntry|None async_set_unique_id(self, str|None unique_id=None, *bool raise_on_progress=True)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
ConfigFlowResult async_update_reload_and_abort(self, ConfigEntry entry, *str|None|UndefinedType unique_id=UNDEFINED, str|UndefinedType title=UNDEFINED, Mapping[str, Any]|UndefinedType data=UNDEFINED, Mapping[str, Any]|UndefinedType data_updates=UNDEFINED, Mapping[str, Any]|UndefinedType options=UNDEFINED, str|UndefinedType reason=UNDEFINED, bool reload_even_if_entry_is_unchanged=True)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
None _async_abort_entries_match(self, dict[str, Any]|None match_dict=None)
ConfigEntry _get_reconfigure_entry(self)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
ConfigEntry config_entry(self)
None config_entry(self, ConfigEntry value)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
Iterable[BluetoothServiceInfoBleak] async_discovered_service_info(HomeAssistant hass, bool connectable=True)
httpx.AsyncClient create_async_httpx_client(HomeAssistant hass, bool verify_ssl=True, bool auto_cleanup=True, SSLCipherList ssl_cipher_list=SSLCipherList.PYTHON_DEFAULT, **Any kwargs)