1 """Config flow for Rainforest RAVEn devices."""
3 from __future__
import annotations
8 from aioraven.data
import MeterType
9 from aioraven.device
import RAVEnConnectionError
10 from aioraven.serial
import RAVEnSerialDevice
11 import serial.tools.list_ports
12 from serial.tools.list_ports_common
import ListPortInfo
13 import voluptuous
as vol
24 from .const
import DEFAULT_NAME, DOMAIN
28 if isinstance(value, str):
30 return f
"{value or 0:04X}"
34 """Generate unique id from usb attributes."""
36 f
"{_format_id(info.vid)}:{_format_id(info.pid)}_{info.serial_number}"
37 f
"_{info.manufacturer}_{info.description}"
42 """Handle a config flow for Rainforest RAVEn devices."""
45 """Set up flow instance."""
46 self.
_dev_path_dev_path: str |
None =
None
47 self._meter_macs: set[str] = set()
53 RAVEnSerialDevice(dev_path)
as raven_device,
55 await raven_device.synchronize()
56 meters = await raven_device.get_meter_list()
58 for meter
in meters.meter_mac_ids
or ():
59 meter_info = await raven_device.get_meter_info(meter=meter)
61 meter_info.meter_type
is None
62 or meter_info.meter_type == MeterType.ELECTRIC
64 self._meter_macs.
add(meter.hex())
68 self, user_input: dict[str, Any] |
None =
None
69 ) -> ConfigFlowResult:
70 """Connect to device and discover meters."""
71 errors: dict[str, str] = {}
72 if user_input
is not None:
74 for raw_mac
in user_input.get(CONF_MAC, ()):
75 mac = bytes.fromhex(raw_mac).hex()
76 if mac
not in meter_macs:
77 meter_macs.append(mac)
78 if meter_macs
and not errors:
80 title=user_input.get(CONF_NAME, DEFAULT_NAME),
91 options=sorted(self._meter_macs),
92 mode=SelectSelectorMode.DROPDOWN,
94 translation_key=CONF_MAC,
102 self, discovery_info: usb.UsbServiceInfo
103 ) -> ConfigFlowResult:
104 """Handle USB Discovery."""
105 device = discovery_info.device
106 dev_path = await self.hass.async_add_executor_job(usb.get_serial_by_id, device)
113 except RAVEnConnectionError:
118 self, user_input: dict[str, Any] |
None =
None
119 ) -> ConfigFlowResult:
120 """Handle a flow initiated by the user."""
123 ports = await self.hass.async_add_executor_job(serial.tools.list_ports.comports)
128 usb.human_readable_device_name(
137 if port.device
not in existing_devices
143 if user_input
is not None and user_input.get(CONF_DEVICE,
"").strip():
144 port = ports[unused_ports.index(
str(user_input[CONF_DEVICE]))]
145 dev_path = await self.hass.async_add_executor_job(
146 usb.get_serial_by_id, port.device
153 errors[CONF_DEVICE] =
"timeout_connect"
154 except RAVEnConnectionError:
155 errors[CONF_DEVICE] =
"cannot_connect"
159 schema = vol.Schema({vol.Required(CONF_DEVICE): vol.In(unused_ports)})
ConfigFlowResult async_step_meters(self, dict[str, Any]|None user_input=None)
None _validate_device(self, str dev_path)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_usb(self, usb.UsbServiceInfo discovery_info)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
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)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=None)
list[ConfigFlowResult] _async_in_progress(self, bool include_uninitialized=False, dict[str, Any]|None match_context=None)
ConfigFlowResult async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
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)
_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)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
bool add(self, _T matcher)
str _generate_unique_id(ListPortInfo|usb.UsbServiceInfo info)
str _format_id(str|int value)