Skip to content

Commit

Permalink
Create Devices
Browse files Browse the repository at this point in the history
  • Loading branch information
Snuffy2 committed Nov 3, 2024
1 parent 5e83bb9 commit d15c235
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 13 deletions.
1 change: 0 additions & 1 deletion custom_components/__init__.py

This file was deleted.

13 changes: 13 additions & 0 deletions custom_components/variable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
CONF_DEVICE,
CONF_DEVICE_ID,
CONF_ENTITY_ID,
CONF_FRIENDLY_NAME,
Expand Down Expand Up @@ -44,6 +45,7 @@
PLATFORMS,
SERVICE_UPDATE_SENSOR,
)
from .device import create_device, remove_device

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -236,19 +238,30 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await hass.config_entries.async_forward_entry_setups(
entry, [hass_data.get(CONF_ENTITY_PLATFORM)]
)
elif hass_data.get(CONF_ENTITY_PLATFORM) == CONF_DEVICE:
await create_device(hass, entry)
return True


async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Handle an options update."""
_LOGGER.debug(f"[init async_reload_entry] entry: {entry}")
await hass.config_entries.async_reload(entry.entry_id)


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""

_LOGGER.info(f"Unloading: {entry.data}")
_LOGGER.debug(f"[init async_unload_entry] entry: {entry}")
hass_data = dict(entry.data)
unload_ok = False
if hass_data.get(CONF_ENTITY_PLATFORM) in PLATFORMS:
unload_ok = await hass.config_entries.async_unload_platforms(
entry, [hass_data.get(CONF_ENTITY_PLATFORM)]
)
elif hass_data.get(CONF_ENTITY_PLATFORM) == CONF_DEVICE:
unload_ok = await remove_device(hass, entry)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)

Expand Down
152 changes: 143 additions & 9 deletions custom_components/variable/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@
from homeassistant.components.device_tracker import ATTR_LOCATION_NAME
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
ATTR_CONFIGURATION_URL,
ATTR_GPS_ACCURACY,
ATTR_HW_VERSION,
ATTR_LATITUDE,
ATTR_LONGITUDE,
ATTR_MANUFACTURER,
ATTR_MODEL,
ATTR_MODEL_ID,
ATTR_SERIAL_NUMBER,
ATTR_SW_VERSION,
CONF_DEVICE,
CONF_DEVICE_CLASS,
CONF_DEVICE_ID,
CONF_ENTITY_ID,
Expand Down Expand Up @@ -60,6 +68,7 @@
SERVICE_UPDATE_DEVICE_TRACKER,
SERVICE_UPDATE_SENSOR,
)
from .device import update_device
from .helpers import value_to_type

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -223,6 +232,19 @@
}
)

ADD_DEVICE_SCHEMA = vol.Schema(
{
vol.Required(CONF_NAME): cv.string,
vol.Optional(ATTR_CONFIGURATION_URL): cv.string,
vol.Optional(ATTR_MANUFACTURER): cv.string,
vol.Optional(ATTR_HW_VERSION): cv.string,
vol.Optional(ATTR_MODEL): cv.string,
vol.Optional(ATTR_MODEL_ID): cv.string,
vol.Optional(ATTR_SERIAL_NUMBER): cv.string,
vol.Optional(ATTR_SW_VERSION): cv.string,
}
)


async def validate_sensor_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
"""Validate the user input"""
Expand All @@ -239,15 +261,16 @@ class VariableConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):

async def async_step_user(self, user_input=None) -> FlowResult:
"""Handle the initial step."""

platforms_w_device: list = PLATFORMS + [CONF_DEVICE]
return self.async_show_menu(
step_id="user",
menu_options=["add_" + p for p in PLATFORMS],
menu_options=["add_" + p for p in platforms_w_device],
)

async def async_step_add_sensor(
self, user_input=None, errors=None, yaml_variable=False
):
errors = {} if errors is None else errors
if user_input is not None:
user_input.update({CONF_ENTITY_PLATFORM: Platform.SENSOR})
user_input.update({CONF_YAML_VARIABLE: yaml_variable})
Expand All @@ -267,8 +290,8 @@ async def async_step_add_sensor(
},
)

async def async_step_sensor_page_2(self, user_input=None):
errors = {}
async def async_step_sensor_page_2(self, user_input=None, errors=None):
errors = {} if errors is None else errors
if (
user_input is not None
or self.add_sensor_input.get(CONF_YAML_VARIABLE) is True
Expand Down Expand Up @@ -507,6 +530,7 @@ def build_add_sensor_page_2(self):
async def async_step_add_binary_sensor(
self, user_input=None, errors=None, yaml_variable=False
):
errors = {} if errors is None else errors
if user_input is not None:
try:
user_input.update({CONF_ENTITY_PLATFORM: Platform.BINARY_SENSOR})
Expand Down Expand Up @@ -537,6 +561,7 @@ async def async_step_add_binary_sensor(
async def async_step_add_device_tracker(
self, user_input=None, errors=None, yaml_variable=False
):
errors = {} if errors is None else errors
if user_input is not None:
try:
user_input.update({CONF_ENTITY_PLATFORM: Platform.DEVICE_TRACKER})
Expand Down Expand Up @@ -564,6 +589,42 @@ async def async_step_add_device_tracker(
},
)

async def async_step_add_device(
self, user_input=None, errors=None, yaml_variable=False
):
errors = {} if errors is None else errors
if user_input is not None:
try:
user_input.update({CONF_ENTITY_PLATFORM: CONF_DEVICE})
user_input.update({CONF_YAML_VARIABLE: yaml_variable})

# Cannot use cv.url validation in the schema itself so apply
# extra validation here
if user_input.get(ATTR_CONFIGURATION_URL, None):
cv.url(user_input.get(ATTR_CONFIGURATION_URL))
info = await validate_sensor_input(self.hass, user_input)
_LOGGER.debug(f"[New Device] updated user_input: {user_input}")
return self.async_create_entry(
title=info.get("title", ""), data=user_input
)
except vol.Invalid:
errors["base"] = "invalid_url"
except Exception as e:
_LOGGER.exception(
f"Unexpected exception. {e.__class__.__qualname__}: {e}"
)
errors["base"] = "unknown"

# If there is no user input or there were errors, show the form again, including any errors that were found with the input.
return self.async_show_form(
step_id="add_device",
data_schema=ADD_DEVICE_SCHEMA,
errors=errors,
description_placeholders={
"component_config_url": COMPONENT_CONFIG_URL,
},
)

# this is run to import the configuration.yaml parameters\
async def async_step_import(self, import_config=None) -> FlowResult:
"""Import a config entry from configuration.yaml."""
Expand Down Expand Up @@ -609,12 +670,14 @@ async def async_step_init(
step_id="init",
menu_options=[change_value, change_options],
)
elif self.config_entry.data.get(CONF_ENTITY_PLATFORM) == CONF_DEVICE:
return await self.async_step_device_options()
return False

async def async_step_change_sensor_value(
self, user_input=None, errors=None
) -> FlowResult:
errors = {}
errors = {} if errors is None else errors
ent = entity_registry.async_entries_for_config_entry(
entity_registry.async_get(self.hass), self.config_entry.entry_id
)
Expand Down Expand Up @@ -799,7 +862,7 @@ def build_change_sensor_value(self, state):
async def async_step_change_binary_sensor_value(
self, user_input=None, errors=None
) -> FlowResult:
errors = {}
errors = {} if errors is None else errors
ent = entity_registry.async_entries_for_config_entry(
entity_registry.async_get(self.hass), self.config_entry.entry_id
)
Expand Down Expand Up @@ -897,7 +960,7 @@ def build_change_binary_sensor_value(self, state):
async def async_step_change_device_tracker_value(
self, user_input=None, errors=None
) -> FlowResult:
errors = {}
errors = {} if errors is None else errors
ent = entity_registry.async_entries_for_config_entry(
entity_registry.async_get(self.hass), self.config_entry.entry_id
)
Expand Down Expand Up @@ -1113,6 +1176,7 @@ def build_change_device_tracker_value(self, state):
async def async_step_sensor_options(
self, user_input=None, errors=None
) -> FlowResult:
errors = {} if errors is None else errors
if user_input is not None:
_LOGGER.debug(f"[Sensor Options Page 1] page_1_input: {user_input}")
self.sensor_options_page_1 = user_input
Expand Down Expand Up @@ -1198,8 +1262,8 @@ def build_sensor_options_page_1(self):

return SENSOR_OPTIONS_PAGE_1_SCHEMA

async def async_step_sensor_options_page_2(self, user_input=None):
errors = {}
async def async_step_sensor_options_page_2(self, user_input=None, errors=None):
errors = {} if errors is None else errors
if user_input is not None:
_LOGGER.debug(f"[Sensor Options Page 2] user_input: {user_input}")
if (
Expand Down Expand Up @@ -1527,6 +1591,7 @@ def build_sensor_options_page_2(self):
async def async_step_binary_sensor_options(
self, user_input=None, errors=None
) -> FlowResult:
errors = {} if errors is None else errors
if user_input is not None:
_LOGGER.debug(f"[Binary Sensor Options] user_input: {user_input}")
for m in dict(self.config_entry.data).keys():
Expand Down Expand Up @@ -1642,6 +1707,7 @@ async def async_step_binary_sensor_options(
async def async_step_device_tracker_options(
self, user_input=None, errors=None
) -> FlowResult:
errors = {} if errors is None else errors
if user_input is not None:
_LOGGER.debug(f"[Device Tracker Options] user_input: {user_input}")
for m in dict(self.config_entry.data).keys():
Expand Down Expand Up @@ -1832,3 +1898,71 @@ async def async_step_device_tracker_options(
"disp_name": disp_name,
},
)

async def async_step_device_options(
self, user_input=None, errors=None
) -> FlowResult:

errors = {} if errors is None else errors
if user_input is not None:
try:
# Cannot use cv.url validation in the schema itself so apply
# extra validation here
if user_input.get(ATTR_CONFIGURATION_URL, None):
cv.url(user_input.get(ATTR_CONFIGURATION_URL))
for m in dict(self.config_entry.data).keys():
user_input.setdefault(m, self.config_entry.data[m])
_LOGGER.debug(f"[Device Options] updated user_input: {user_input}")
except vol.Invalid:
errors["base"] = "invalid_url"
except Exception as e:
_LOGGER.exception(
f"Unexpected exception. {e.__class__.__qualname__}: {e}"
)
errors["base"] = "unknown"
else:
self.hass.config_entries.async_update_entry(
self.config_entry,
data=user_input,
options={},
)
# await self.hass.config_entries.async_reload(self.config_entry.entry_id)
await update_device(self.hass, self.config_entry, user_input)
return self.async_create_entry(title="", data=user_input)

DEVICE_OPTIONS_SCHEMA = vol.Schema({})

options = [
ATTR_CONFIGURATION_URL,
ATTR_MANUFACTURER,
ATTR_HW_VERSION,
ATTR_MODEL,
ATTR_MODEL_ID,
ATTR_SERIAL_NUMBER,
ATTR_SW_VERSION,
]
for option in options:
if self.config_entry.data.get(option, None):
DEVICE_OPTIONS_SCHEMA = DEVICE_OPTIONS_SCHEMA.extend(
{
vol.Optional(
option, default=self.config_entry.data.get(option)
): cv.string
}
)
else:
DEVICE_OPTIONS_SCHEMA = DEVICE_OPTIONS_SCHEMA.extend(
{vol.Optional(option): cv.string}
)
_LOGGER.debug(
f"[Device Options] self.config_entry.data: {self.config_entry.data}"
)
return self.async_show_form(
step_id="device_options",
data_schema=DEVICE_OPTIONS_SCHEMA,
errors=errors,
description_placeholders={
"component_config_url": COMPONENT_CONFIG_URL,
"disp_name": self.config_entry.data.get(CONF_NAME),
},
)
Loading

0 comments on commit d15c235

Please sign in to comment.