mirror of
https://github.com/Lash-L/RoborockCustomMap.git
synced 2026-07-26 16:18:32 +02:00
init commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.idea
|
||||
@@ -0,0 +1,50 @@
|
||||
# Roborock Custom Map
|
||||
|
||||
This allows you to use the core Roborock integration with the [Xiaomi Map Card](https://github.com/PiotrMachowski/lovelace-xiaomi-vacuum-map-card)
|
||||
|
||||
If you would like to support me, you can do so here:
|
||||
|
||||
[![BuyMeCoffee][buymecoffeebadge]][buymecoffee]
|
||||
|
||||
[![PaypalMe][paypalmebadge]][paypalme]
|
||||
|
||||
### Setup
|
||||
|
||||
1. Install the [Roborock Core Integration](https://my.home-assistant.io/redirect/config_flow_start?domain=roborock) and set it up
|
||||
2. It is recommended that you first disable the Image entities within the core integration. Open each image entity, hit the gear icon, then trigger the toggle by enabled.
|
||||
3. Install this integration
|
||||
4. This integration works by piggybacking off of the Core integration, so the Core integration will do all the data updating to help prevent rate-limits. But that means that the core integration must be setup and loaded first. If you run into any issues, make sure the Roborock integration is loaded first, and then reload this one.
|
||||
5. Setup the map card like normal! An example configuration would look like
|
||||
```yaml
|
||||
type: custom:xiaomi-vacuum-map-card
|
||||
vacuum_platform: roborock
|
||||
entity: vacuum.s7
|
||||
map_source:
|
||||
camera: image.s7_downstairs_full_custom
|
||||
calibration_source:
|
||||
camera: true
|
||||
```
|
||||
6. You can hit Generate Room Configs to allow for cleaning of rooms. It might generate extra keys, so check the yaml and make sure there are no extra 'predefined_sections'
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
### Installing via HACS
|
||||
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=Lash-L&repository=RoborockCustomMap&category=integration)
|
||||
|
||||
or
|
||||
|
||||
1. Go to HACS->Integrations
|
||||
1. Add this repo(https://github.com/Lash-L/RoborockCustomMap) into your HACS custom repositories
|
||||
1. Search for Roborock Custom Map and Download it
|
||||
1. Restart your HomeAssistant
|
||||
1. Go to Settings->Devices & Services
|
||||
1. Add the Roborock Custom Map integration
|
||||
|
||||
|
||||
|
||||
[buymecoffee]: https://www.buymeacoffee.com/LashL
|
||||
[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge
|
||||
[paypalme]: https://paypal.me/LLashley304
|
||||
[paypalmebadge]: https://cdn.rawgit.com/twolfson/paypal-github-button/1.0.0/dist/button.svg
|
||||
[hacsbutton]: https://my.home-assistant.io/redirect/hacs_repository/?owner=Lash-L&repository=tempofit&category=integration
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Roborock Custom Map integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
|
||||
PLATFORMS = [Platform.IMAGE]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Roborock Custom map from a config entry."""
|
||||
roborock_entries = hass.config_entries.async_entries("roborock")
|
||||
coordinators = []
|
||||
|
||||
async def unload_this_entry():
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
|
||||
for r_entry in roborock_entries:
|
||||
if r_entry.state == ConfigEntryState.LOADED:
|
||||
coordinators.extend(r_entry.runtime_data.v1)
|
||||
# If any unload, then we should reload as well in case there are major changes.
|
||||
r_entry.async_on_unload(unload_this_entry)
|
||||
if len(coordinators) == 0:
|
||||
raise ConfigEntryNotReady("No Roborock entries loaded. Cannot start.")
|
||||
entry.runtime_data = coordinators
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
@@ -0,0 +1,24 @@
|
||||
"""Config flow for Roborock Custom Map integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Roborock Custom Map."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle the initial step."""
|
||||
self.async_set_unique_id(DOMAIN)
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(title="Roborock Custom Map", data={})
|
||||
@@ -0,0 +1,3 @@
|
||||
"""Constants for Roborock Custom Map integration."""
|
||||
|
||||
DOMAIN = "roborock_custom_map"
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Support for Roborock image."""
|
||||
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
from homeassistant.components.image import ImageEntity
|
||||
from homeassistant.components.roborock.coordinator import RoborockDataUpdateCoordinator
|
||||
from homeassistant.components.roborock.entity import RoborockCoordinatedEntityV1
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock image platform."""
|
||||
|
||||
async_add_entities(
|
||||
(
|
||||
RoborockMap(
|
||||
config_entry,
|
||||
f"{coord.duid_slug}_custom_map_{map_info.name}",
|
||||
coord,
|
||||
map_info.flag,
|
||||
map_info.name,
|
||||
)
|
||||
for coord in config_entry.runtime_data
|
||||
for map_info in coord.maps.values()
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class RoborockMap(RoborockCoordinatedEntityV1, ImageEntity):
|
||||
"""A class to let you visualize the map."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
image_last_updated: datetime
|
||||
_attr_name: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config_entry: ConfigEntry,
|
||||
unique_id: str,
|
||||
coordinator: RoborockDataUpdateCoordinator,
|
||||
map_flag: int,
|
||||
map_name: str,
|
||||
) -> None:
|
||||
"""Initialize a Roborock map."""
|
||||
RoborockCoordinatedEntityV1.__init__(self, unique_id, coordinator)
|
||||
ImageEntity.__init__(self, coordinator.hass)
|
||||
self.config_entry = config_entry
|
||||
self._attr_name = map_name + "_custom"
|
||||
self.map_flag = map_flag
|
||||
self.cached_map = b""
|
||||
self._attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
@property
|
||||
def is_selected(self) -> bool:
|
||||
"""Return if this map is the currently selected map."""
|
||||
return self.map_flag == self.coordinator.current_map
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""When entity is added to hass load any previously cached maps from disk."""
|
||||
await super().async_added_to_hass()
|
||||
self._attr_image_last_updated = self.coordinator.maps[
|
||||
self.map_flag
|
||||
].last_updated
|
||||
self.async_write_ha_state()
|
||||
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
# If the coordinator has updated the map, we can update the image.
|
||||
self._attr_image_last_updated = self.coordinator.maps[
|
||||
self.map_flag
|
||||
].last_updated
|
||||
|
||||
super()._handle_coordinator_update()
|
||||
|
||||
async def async_image(self) -> bytes | None:
|
||||
"""Get the cached image."""
|
||||
return self.coordinator.maps[self.map_flag].image
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
map_data = self.coordinator.maps[self.map_flag].map_data
|
||||
if map_data is None:
|
||||
return {}
|
||||
for room in map_data.rooms.values():
|
||||
room.name = self.coordinator.maps[self.map_flag].rooms.get(room.number)
|
||||
|
||||
return {
|
||||
"calibration_points": self.coordinator.maps[
|
||||
self.map_flag
|
||||
].map_data.calibration(),
|
||||
"rooms": map_data.rooms,
|
||||
"zones": map_data.zones,
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"domain": "roborock_custom_map",
|
||||
"name": "Roborock Custom Map",
|
||||
"codeowners": ["@Lash-L"],
|
||||
"config_flow": true,
|
||||
"dependencies": ["roborock"],
|
||||
"documentation": "https://github.com/Lash-L/RoborockCustomMap",
|
||||
"iot_class": "local_polling",
|
||||
"issue_tracker": "https://github.com/Lash-L/RoborockCustomMap/issues",
|
||||
"requirements": [],
|
||||
|
||||
"version": "0.1.0"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user