Skip to content

Commit

Permalink
Refactoring Services pull #273 from sca075/refactoring_camera
Browse files Browse the repository at this point in the history
Refactoring Services
  • Loading branch information
sca075 authored Nov 17, 2024
2 parents 0855a5d + a5dc8f5 commit d5d0b80
Show file tree
Hide file tree
Showing 5 changed files with 599 additions and 531 deletions.
302 changes: 24 additions & 278 deletions custom_components/mqtt_vacuum_camera/__init__.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
"""MQTT Vacuum Camera.
Version: 2024.11.0"""
Version: 2024.11.1"""

import logging
import os

from homeassistant import config_entries, core
from homeassistant.components import mqtt
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_UNIQUE_ID,
EVENT_HOMEASSISTANT_FINAL_WRITE,
SERVICE_RELOAD,
Platform,
)
from homeassistant.core import ServiceCall
from homeassistant.exceptions import ConfigEntryNotReady, ServiceValidationError

from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.reload import async_register_admin_service
from homeassistant.helpers.storage import STORAGE_DIR

from .common import (
generate_service_data_clean_segments,
generate_service_data_clean_zone,
generate_service_data_go_to,
get_vacuum_device_info,
get_vacuum_mqtt_topic,
get_entity_id,
get_device_info_from_entity_id,
is_rand256_vacuum,
update_options,
)
from .common import get_vacuum_device_info, get_vacuum_mqtt_topic
from .const import (
CAMERA_STORAGE,
CONF_VACUUM_CONFIG_ENTRY_ID,
Expand All @@ -37,11 +27,17 @@
DOMAIN,
)
from .coordinator import MQTTVacuumCoordinator
from .utils.camera.camera_services import reset_trims, reload_config
from .utils.files_operations import (
async_clean_up_all_auto_crop_files,
async_get_translations_vacuum_id,
async_rename_room_description,
)
from .utils.vacuum.mqtt_vacuum_services import (
async_register_vacuums_services,
async_remove_vacuums_services,
is_rand256_vacuum,
)

PLATFORMS = [Platform.CAMERA, Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
Expand All @@ -55,261 +51,6 @@ async def options_update_listener(hass: core.HomeAssistant, config_entry: Config
async def async_setup_entry(hass: core.HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up platform from a ConfigEntry."""

async def _reload_config(call: ServiceCall) -> None:
"""Reload the camera platform for all entities in the integration."""
_LOGGER.debug(f"Reloading the config entry for all {DOMAIN} entities")
# Retrieve all config entries associated with the DOMAIN
camera_entries = hass.config_entries.async_entries(DOMAIN)

# Iterate over each config entry and check if it's LOADED
for camera_entry in camera_entries:
if camera_entry.state == ConfigEntryState.LOADED:
_LOGGER.debug(f"Unloading entry: {camera_entry.entry_id}")
await async_unload_entry(hass, camera_entry)

_LOGGER.debug(f"Reloading entry: {camera_entry.entry_id}")
await async_setup_entry(hass, camera_entry)
else:
_LOGGER.debug(
f"Skipping entry {camera_entry.entry_id} as it is NOT_LOADED"
)

# Optionally, trigger other reinitialization steps if needed
hass.bus.async_fire(f"event_{DOMAIN}_reloaded", context=call.context)

async def vacuum_clean_segments(call: ServiceCall) -> None:
"""Vacuum Clean Segments (rooms) Action"""
try:
# Retrieve coordinates
segments_lists = call.data.get("segments")
repeats = call.data.get("repeats")

# Attempt to get entity_id or device_id
entity_ids = call.data.get("entity_id")
device_ids = call.data.get("device_id")

service_data = generate_service_data_clean_segments(
coordinator=data_coordinator,
entity_id=entity_ids,
device_id=device_ids,
segments=segments_lists,
repeat=repeats,
hass=hass,
)
_LOGGER.debug(f">>>>>> Service data: {service_data}")
if not service_data:
raise ServiceValidationError("No Service data generated. Aborting!")
# elif not service_data["have_rooms"]:
# raise ServiceValidationError("No rooms found in the vacuum map.")
else:
try:
await data_coordinator.connector.publish_to_broker(
service_data["topic"],
service_data["payload"],
)
except Exception as e:
_LOGGER.warning(f"Error sending command to vacuum: {e}")
return
hass.bus.async_fire(
f"event_{DOMAIN}.vacuum_clean_zone",
{
"topic": service_data["topic"],
"zones": segments_lists,
"repeats": repeats,
},
context=call.context,
)
except KeyError as e:
_LOGGER.error(f"Missing required parameter: {e}")

async def vacuum_clean_zone(call: ServiceCall) -> None:
"""Vacuum Zone Clean Action"""
try:
# Retrieve coordinates
zone_lists = call.data.get("zone")
zone_ids = call.data.get("zone_ids")
repeats = call.data.get("repeats")

if zone_ids:
zone_lists = zone_ids

# Attempt to get entity_id or device_id
entity_ids = call.data.get("entity_id")
device_ids = call.data.get("device_id")

service_data = generate_service_data_clean_zone(
entity_id=entity_ids,
device_id=device_ids,
zones=zone_lists,
repeat=repeats,
hass=hass,
)
if not service_data:
_LOGGER.warning("No Service data generated. Aborting!")
return
try:
await data_coordinator.connector.publish_to_broker(
service_data["topic"],
service_data["payload"],
)
except Exception as e:
_LOGGER.warning(f"Error sending command to vacuum: {e}")
return
hass.bus.async_fire(
f"event_{DOMAIN}.vacuum_clean_zone",
{
"topic": service_data["topic"],
"zones": zone_lists,
"repeats": repeats,
},
context=call.context,
)
except KeyError as e:
_LOGGER.error(f"Missing required parameter: {e}")

async def vacuum_goto(call: ServiceCall) -> None:
"""Vacuum Go To Action"""
try:
# Retrieve coordinates
spot_id = call.data.get("spot_id")
if not spot_id:
x_coord = call.data["x_coord"]
y_coord = call.data["y_coord"]
spot_id = None
else:
x_coord = None
y_coord = None

# Attempt to get entity_id or device_id
entity_ids = call.data.get("entity_id")
device_ids = call.data.get("device_id")

service_data = generate_service_data_go_to(
entity_ids, device_ids, x_coord, y_coord, spot_id, hass
)
if not service_data:
_LOGGER.warning("No Service data generated. Aborting!")
return
try:
await data_coordinator.connector.publish_to_broker(
service_data["topic"],
service_data["payload"],
)
except Exception as e:
_LOGGER.warning(f"Error sending command to vacuum: {e}")
return
hass.bus.async_fire(
f"event_{DOMAIN}.vacuum_go_to",
{"topic": service_data["topic"], "x": x_coord, "y": y_coord},
context=call.context,
)
except KeyError as e:
_LOGGER.error(f"Missing required parameter: {e}")

async def vacuum_map_save(call: ServiceCall) -> None:
"""Vacuum Map Save Action"""
try:
# Attempt to get entity_id or device_id
entity_ids = call.data.get("entity_id")
device_ids = call.data.get("device_id")

vacuum_entity_ids = get_entity_id(entity_ids, device_ids, hass)[0]
base_topic = get_vacuum_mqtt_topic(vacuum_entity_ids, hass)
device_info = get_device_info_from_entity_id(vacuum_entity_ids, hass)
is_a_rand256 = is_rand256_vacuum(device_info)

map_name = call.data.get("map_name")
if not map_name:
raise ServiceValidationError("A map name is required to save the map.")
if is_a_rand256:
service_data = {
"topic": f"{base_topic}/custom_command",
"payload": {
"command": "store_map",
"name": map_name,
},
}
else:
raise ServiceValidationError(
"This feature is only available for rand256 vacuums."
)
try:
await data_coordinator.connector.publish_to_broker(
service_data["topic"],
service_data["payload"],
)
except Exception as e:
_LOGGER.warning(f"Error sending command to vacuum: {e}")
return
hass.bus.async_fire(
f"event_{DOMAIN}.vacuum_map_save",
{"topic": service_data["topic"]},
context=call.context,
)
except KeyError as e:
_LOGGER.error(f"Missing required parameter: {e}")

async def vacuum_map_load(call: ServiceCall) -> None:
"""Vacuum Map Load Action"""
try:
# Attempt to get entity_id or device_id
entity_ids = call.data.get("entity_id")
device_ids = call.data.get("device_id")

vacuum_entity_ids = get_entity_id(entity_ids, device_ids, hass)[0]
base_topic = get_vacuum_mqtt_topic(vacuum_entity_ids, hass)
device_info = get_device_info_from_entity_id(vacuum_entity_ids, hass)
is_a_rand256 = is_rand256_vacuum(device_info)

map_name = call.data.get("map_name")
if not map_name:
raise ServiceValidationError("A map name is required to load the map.")
if is_a_rand256:
service_data = {
"topic": f"{base_topic}/custom_command",
"payload": {
"command": "load_map",
"name": map_name,
},
}
else:
raise ServiceValidationError(
"This feature is only available for rand256 vacuums."
)
try:
await data_coordinator.connector.publish_to_broker(
service_data["topic"],
service_data["payload"],
)
except Exception as e:
_LOGGER.warning(f"Error sending command to vacuum: {e}")
return
hass.bus.async_fire(
f"event_{DOMAIN}.vacuum_map_load",
{"topic": service_data["topic"]},
context=call.context,
)
await hass.services.async_call(DOMAIN, "reset_trims")
except KeyError as e:
_LOGGER.error(f"Missing required parameter: {e}")

async def reset_trims(call: ServiceCall) -> None:
"""Action Reset Map Trims."""
_LOGGER.debug(f"Resetting trims for {DOMAIN}")
await async_clean_up_all_auto_crop_files(hass)
await hass.services.async_call(DOMAIN, "reload")
hass.bus.async_fire(f"event_{DOMAIN}_reset_trims", context=call.context)

# Register Services
hass.services.async_register(DOMAIN, "reset_trims", reset_trims)
if not hass.services.has_service(DOMAIN, SERVICE_RELOAD):
async_register_admin_service(hass, DOMAIN, SERVICE_RELOAD, _reload_config)
hass.services.async_register(DOMAIN, "vacuum_go_to", vacuum_goto)
hass.services.async_register(DOMAIN, "vacuum_clean_zone", vacuum_clean_zone)
hass.services.async_register(DOMAIN, "vacuum_clean_segments", vacuum_clean_segments)
hass.services.async_register(DOMAIN, "vacuum_map_save", vacuum_map_save)
hass.services.async_register(DOMAIN, "vacuum_map_load", vacuum_map_load)

hass.data.setdefault(DOMAIN, {})
hass_data = dict(entry.data)

Expand Down Expand Up @@ -339,7 +80,15 @@ async def reset_trims(call: ServiceCall) -> None:
"is_rand256": is_rand256,
}
)

# Register Services
if not hass.services.has_service(DOMAIN, SERVICE_RELOAD):
async_register_admin_service(
hass, DOMAIN, SERVICE_RELOAD, lambda call: reload_config(hass, DOMAIN)
)
hass.services.async_register(
DOMAIN, "reset_trims", lambda call: reset_trims(hass, call, DOMAIN)
)
await async_register_vacuums_services(hass, data_coordinator)
# Registers update listener to update config entry when options are updated.
unsub_options_update_listener = entry.add_update_listener(options_update_listener)
# Store a reference to the unsubscribe function to clean up if an entry is unloaded.
Expand Down Expand Up @@ -373,13 +122,10 @@ async def async_unload_entry(
entry_data = hass.data[DOMAIN].pop(entry.entry_id)
entry_data["unsub_options_update_listener"]()
# Remove services
hass.services.async_remove(DOMAIN, "reset_trims")
hass.services.async_remove(DOMAIN, SERVICE_RELOAD)
hass.services.async_remove(DOMAIN, "vacuum_go_to")
hass.services.async_remove(DOMAIN, "vacuum_clean_zone")
hass.services.async_remove(DOMAIN, "vacuum_clean_segments")
hass.services.async_remove(DOMAIN, "vacuum_map_save")
hass.services.async_remove(DOMAIN, "vacuum_map_load")
if not hass.data[DOMAIN]:
hass.services.async_remove(DOMAIN, "reset_trims")
hass.services.async_remove(DOMAIN, SERVICE_RELOAD)
await async_remove_vacuums_services(hass)
return unload_ok


Expand Down
Loading

0 comments on commit d5d0b80

Please sign in to comment.