Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add romy vacuum integration #93750

Merged
merged 97 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
6d3fcd3
Add romy vacuum core integration
xeniter May 29, 2023
17986ea
code review changes
xeniter May 31, 2023
ed53e38
Update homeassistant/components/romy/__init__.py
xeniter May 31, 2023
aba84f7
Update homeassistant/components/romy/const.py
xeniter May 31, 2023
3dd8804
Update homeassistant/components/romy/coordinator.py
xeniter May 31, 2023
a7f1d6b
code review cleanup
xeniter May 31, 2023
a291bca
Update homeassistant/components/romy/vacuum.py
xeniter Jun 1, 2023
3565537
Update homeassistant/components/romy/vacuum.py
xeniter Jun 1, 2023
04e0aaf
code review change: remove not reachable if
xeniter Jun 2, 2023
6e9853b
Update homeassistant/components/romy/vacuum.py
xeniter Jun 2, 2023
6025c88
code review change: _attrs
xeniter Jun 2, 2023
ad8939c
code review changes: language support
xeniter Jun 3, 2023
cbf09a3
code review change: typing DataUpdateCoordinator
xeniter Jun 5, 2023
d5afa6d
changes to pass language test
xeniter Jun 5, 2023
edecec9
Adjust services and properties from deprecated VacuumEntity to StateV…
xeniter Jul 12, 2023
20b670d
code review change: removed VacuumEntityFeature SEND_COMMAND
xeniter Aug 24, 2023
f2caa01
code review changes: using attr
xeniter Aug 28, 2023
0feb799
cleanup
xeniter Aug 28, 2023
c41f291
Update homeassistant/components/romy/config_flow.py
xeniter Sep 3, 2023
467c7fe
Update homeassistant/components/romy/config_flow.py
xeniter Sep 3, 2023
2bf0cb0
Update homeassistant/components/romy/config_flow.py
xeniter Sep 3, 2023
8bf5008
removed tabs
xeniter Sep 3, 2023
19560fb
code review changes: translation of names and attributes
xeniter Sep 6, 2023
ea91ee1
Update homeassistant/components/romy/config_flow.py
xeniter Sep 28, 2023
0512b46
Update homeassistant/components/romy/config_flow.py
xeniter Sep 28, 2023
d6fe685
Update tests/components/romy/test_config_flow.py
xeniter Sep 28, 2023
eeb18a2
import ip adress for config flow, tests passing local now again
xeniter Sep 28, 2023
ab98367
Update homeassistant/components/romy/config_flow.py
xeniter Sep 28, 2023
c3683c5
config flow fixes
xeniter Sep 29, 2023
dfa9988
Update homeassistant/components/romy/vacuum.py
xeniter Sep 29, 2023
7e697e5
Update homeassistant/components/romy/vacuum.py
xeniter Sep 29, 2023
5151d98
Update homeassistant/components/romy/vacuum.py
xeniter Sep 29, 2023
88526a7
Update homeassistant/components/romy/vacuum.py
xeniter Sep 29, 2023
19db5ca
code review cleanup, remove is_on function
xeniter Sep 29, 2023
ecb9d21
code review changes for name handling
xeniter Sep 29, 2023
df42259
Update homeassistant/components/romy/vacuum.py
xeniter Oct 2, 2023
305af42
Update homeassistant/components/romy/vacuum.py
xeniter Oct 2, 2023
196b88b
Update homeassistant/components/romy/vacuum.py
xeniter Oct 2, 2023
2f7012d
Update homeassistant/components/romy/strings.json
xeniter Oct 2, 2023
a54b180
Update homeassistant/components/romy/manifest.json
xeniter Oct 2, 2023
017f447
code review change: move icon definition
xeniter Oct 2, 2023
e212133
code review changes
xeniter Oct 2, 2023
e8b99fa
Proper Error Message if romys http interface is locked
xeniter Oct 2, 2023
5b5546f
code review changes for device info
xeniter Oct 2, 2023
e6accaf
Update homeassistant/components/romy/config_flow.py
xeniter Oct 13, 2023
15a9f8d
Update homeassistant/components/romy/config_flow.py
xeniter Oct 13, 2023
196ec49
Update homeassistant/components/romy/config_flow.py
xeniter Oct 13, 2023
a428883
Update homeassistant/components/romy/config_flow.py
xeniter Oct 13, 2023
b1d4b95
Update homeassistant/components/romy/config_flow.py
xeniter Oct 13, 2023
cfcc820
code review changes -> using constants
xeniter Oct 13, 2023
34b2b47
Update homeassistant/components/romy/vacuum.py
xeniter Oct 13, 2023
25e938b
fix a mypy check issue
xeniter Oct 17, 2023
83ae444
Update homeassistant/components/romy/config_flow.py
xeniter Nov 8, 2023
b590f27
Update homeassistant/components/romy/config_flow.py
xeniter Nov 29, 2023
b354f4c
add testcase where robot name is not provided with user input
xeniter Nov 30, 2023
160d53c
Update homeassistant/components/romy/config_flow.py
xeniter Nov 30, 2023
444087a
code review changes
xeniter Nov 30, 2023
cb8f3e7
Update homeassistant/components/romy/__init__.py
xeniter Dec 12, 2023
9e68f4a
Update homeassistant/components/romy/vacuum.py
xeniter Dec 12, 2023
24eb792
corrected stop behavior
xeniter Dec 12, 2023
1faeefb
code review change: unified fetching uniqueID
xeniter Dec 12, 2023
e1a7331
code review changes
xeniter Dec 12, 2023
12fa597
Update homeassistant/components/romy/vacuum.py
xeniter Dec 13, 2023
a2ba7ae
removed pause function, cause it did only the same as the stop function
xeniter Dec 13, 2023
b91afa0
changed config flow, do not handle robot name anymore, zeroconf confi…
xeniter Dec 13, 2023
8b88333
Update homeassistant/components/romy/__init__.py
xeniter Dec 14, 2023
ed4ebee
Update homeassistant/components/romy/config_flow.py
xeniter Dec 14, 2023
244fd57
reworked config flow, added steps step_unlock_http_interface, finish_…
xeniter Dec 14, 2023
4a7b512
adjust test for new config flow
xeniter Dec 14, 2023
e752e6a
ruff-format changes
xeniter Dec 14, 2023
4dd4d6b
code review changes
xeniter Dec 18, 2023
4983a2c
Update homeassistant/components/romy/config_flow.py
xeniter Dec 18, 2023
e97ce49
update listener added
xeniter Dec 19, 2023
4fbd0ab
Update homeassistant/components/romy/config_flow.py
xeniter Dec 19, 2023
9d246d1
Update homeassistant/components/romy/config_flow.py
xeniter Dec 19, 2023
6ff2d0e
cleanup schemas, adjust password config flow step
xeniter Dec 19, 2023
a41e7f8
code review changes
xeniter Jan 6, 2024
95d265e
code reveview changes (revert osoenergy)
xeniter Jan 8, 2024
d5aeea4
code review changes
xeniter Jan 10, 2024
36c36f4
Update homeassistant/components/osoenergy/config_flow.py
xeniter Jan 17, 2024
84d46a1
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
63cf1b4
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
e095968
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
c3b5662
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
3db2584
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
4bc84d3
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
8af1aa2
Update homeassistant/components/romy/strings.json
xeniter Jan 17, 2024
086466c
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
c982372
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
1c242a8
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
c34b890
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
9367f9d
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
e73d89a
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
bfe3242
Update tests/components/romy/test_config_flow.py
xeniter Jan 17, 2024
27786f0
code review changes, rewrote config flow tests, all tests ends now wi…
xeniter Jan 17, 2024
5858eb7
code review changes -> pytest mock adjusts
xeniter Jan 21, 2024
daaad6f
code review change, update pypi package to 0.0.7(review changes)
xeniter Jan 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,9 @@ omit =
homeassistant/components/ripple/sensor.py
homeassistant/components/roborock/coordinator.py
homeassistant/components/rocketchat/notify.py
homeassistant/components/romy/__init__.py
homeassistant/components/romy/coordinator.py
homeassistant/components/romy/vacuum.py
homeassistant/components/roomba/__init__.py
homeassistant/components/roomba/binary_sensor.py
homeassistant/components/roomba/braava.py
Expand Down
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ homeassistant.components.rhasspy.*
homeassistant.components.ridwell.*
homeassistant.components.rituals_perfume_genie.*
homeassistant.components.roku.*
homeassistant.components.romy.*
homeassistant.components.rpi_power.*
homeassistant.components.rss_feed_template.*
homeassistant.components.rtsp_to_webrtc.*
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,8 @@ build.json @home-assistant/supervisor
/tests/components/roborock/ @humbertogontijo @Lash-L
/homeassistant/components/roku/ @ctalkington
/tests/components/roku/ @ctalkington
/homeassistant/components/romy/ @xeniter
/tests/components/romy/ @xeniter
/homeassistant/components/roomba/ @pschmitt @cyr-ius @shenxn @Xitee1
/tests/components/roomba/ @pschmitt @cyr-ius @shenxn @Xitee1
/homeassistant/components/roon/ @pavoni
Expand Down
42 changes: 42 additions & 0 deletions homeassistant/components/romy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""ROMY Integration."""

import romy

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD
from homeassistant.core import HomeAssistant

from .const import DOMAIN, LOGGER, PLATFORMS
from .coordinator import RomyVacuumCoordinator


async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Initialize the ROMY platform via config entry."""

new_romy = await romy.create_romy(
config_entry.data[CONF_HOST], config_entry.data.get(CONF_PASSWORD, "")
)

coordinator = RomyVacuumCoordinator(hass, new_romy)
await coordinator.async_config_entry_first_refresh()

hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = coordinator

await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)

config_entry.async_on_unload(config_entry.add_update_listener(update_listener))

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Handle removal of an entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok


async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
"""Handle options update."""
LOGGER.debug("update_listener")
await hass.config_entries.async_reload(config_entry.entry_id)
148 changes: 148 additions & 0 deletions homeassistant/components/romy/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
"""Config flow for ROMY integration."""
from __future__ import annotations

import romy
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.components import zeroconf
from homeassistant.const import CONF_HOST, CONF_PASSWORD
from homeassistant.data_entry_flow import FlowResult
import homeassistant.helpers.config_validation as cv

from .const import DOMAIN, LOGGER


class RomyConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle config flow for ROMY."""

VERSION = 1

def __init__(self) -> None:
"""Handle a config flow for ROMY."""
self.host: str = ""
self.password: str = ""
self.robot_name_given_by_user: str = ""

async def async_step_user(
xeniter marked this conversation as resolved.
Show resolved Hide resolved
self, user_input: dict[str, str] | None = None
) -> FlowResult:
"""Handle the user step."""
errors: dict[str, str] = {}

if user_input:
self.host = user_input[CONF_HOST]

new_romy = await romy.create_romy(self.host, "")

if not new_romy.is_initialized:
errors[CONF_HOST] = "cannot_connect"
else:
await self.async_set_unique_id(new_romy.unique_id)
self._abort_if_unique_id_configured()

self.robot_name_given_by_user = new_romy.user_name

if not new_romy.is_unlocked:
return await self.async_step_password()
return await self._async_step_finish_config()

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_HOST): cv.string,
},
),
errors=errors,
)

async def async_step_password(
self, user_input: dict[str, str] | None = None
) -> FlowResult:
"""Unlock the robots local http interface with password."""
errors: dict[str, str] = {}

if user_input:
self.password = user_input[CONF_PASSWORD]
new_romy = await romy.create_romy(self.host, self.password)

if not new_romy.is_initialized:
errors[CONF_PASSWORD] = "cannot_connect"
elif not new_romy.is_unlocked:
errors[CONF_PASSWORD] = "invalid_auth"

if not errors:
return await self._async_step_finish_config()

return self.async_show_form(
step_id="password",
data_schema=vol.Schema(
{vol.Required(CONF_PASSWORD): vol.All(cv.string, vol.Length(8))},
),
errors=errors,
)

async def async_step_zeroconf(
self, discovery_info: zeroconf.ZeroconfServiceInfo
) -> FlowResult:
"""Handle zeroconf discovery."""

LOGGER.debug("Zeroconf discovery_info: %s", discovery_info)

# connect and gather information from your ROMY
self.host = discovery_info.host
LOGGER.debug("ZeroConf Host: %s", self.host)

new_discovered_romy = await romy.create_romy(self.host, "")

self.robot_name_given_by_user = new_discovered_romy.user_name
LOGGER.debug("ZeroConf Name: %s", self.robot_name_given_by_user)

# get unique id and stop discovery if robot is already added
unique_id = new_discovered_romy.unique_id
LOGGER.debug("ZeroConf Unique_id: %s", unique_id)
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured(updates={CONF_HOST: discovery_info.host})

self.context.update(
{
"title_placeholders": {
"name": f"{self.robot_name_given_by_user} ({self.host} / {unique_id})"
},
"configuration_url": f"http://{self.host}:{new_discovered_romy.port}",
}
)

# if robot got already unlocked with password add it directly
if not new_discovered_romy.is_initialized:
return self.async_abort(reason="cannot_connect")

if new_discovered_romy.is_unlocked:
return await self.async_step_zeroconf_confirm()

return await self.async_step_password()

async def async_step_zeroconf_confirm(
self, user_input: dict[str, str] | None = None
) -> FlowResult:
"""Handle a confirmation flow initiated by zeroconf."""
if user_input is None:
return self.async_show_form(
step_id="zeroconf_confirm",
description_placeholders={
"name": self.robot_name_given_by_user,
"host": self.host,
},
)
return await self._async_step_finish_config()

async def _async_step_finish_config(self) -> FlowResult:
"""Finish the configuration setup."""
return self.async_create_entry(
title=self.robot_name_given_by_user,
data={
CONF_HOST: self.host,
CONF_PASSWORD: self.password,
},
)
11 changes: 11 additions & 0 deletions homeassistant/components/romy/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Constants for the ROMY integration."""

from datetime import timedelta
import logging

from homeassistant.const import Platform

DOMAIN = "romy"
PLATFORMS = [Platform.VACUUM]
UPDATE_INTERVAL = timedelta(seconds=5)
LOGGER = logging.getLogger(__package__)
22 changes: 22 additions & 0 deletions homeassistant/components/romy/coordinator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""ROMY coordinator."""

from romy import RomyRobot

from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import DOMAIN, LOGGER, UPDATE_INTERVAL


class RomyVacuumCoordinator(DataUpdateCoordinator[None]):
"""ROMY Vacuum Coordinator."""

def __init__(self, hass: HomeAssistant, romy: RomyRobot) -> None:
"""Initialize."""
super().__init__(hass, LOGGER, name=DOMAIN, update_interval=UPDATE_INTERVAL)
self.hass = hass
self.romy = romy

async def _async_update_data(self) -> None:
"""Update ROMY Vacuum Cleaner data."""
await self.romy.async_update()
10 changes: 10 additions & 0 deletions homeassistant/components/romy/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"domain": "romy",
"name": "ROMY Vacuum Cleaner",
"codeowners": ["@xeniter"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/romy",
"iot_class": "local_polling",
"requirements": ["romy==0.0.7"],
"zeroconf": ["_aicu-http._tcp.local."]
}
51 changes: 51 additions & 0 deletions homeassistant/components/romy/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"config": {
"flow_title": "{name}",
xeniter marked this conversation as resolved.
Show resolved Hide resolved
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
},
"step": {
"user": {
"data": {
"host": "[%key:common::config_flow::data::host%]"
}
},
"password": {
"title": "Password required",
"data": {
"password": "[%key:common::config_flow::data::password%]"
},
"data_description": {
"password": "(8 characters, see QR Code under the dustbin)."
}
},
"zeroconf_confirm": {
"description": "Do you want to add ROMY Vacuum Cleaner {name} to Home Assistant?"
}
}
},
"entity": {
"vacuum": {
"romy": {
"state_attributes": {
"fan_speed": {
"state": {
"default": "Default",
"normal": "Normal",
"silent": "Silent",
"intensive": "Intensive",
"super_silent": "Super silent",
"high": "High",
"auto": "Auto"
}
}
}
}
}
}
}
Loading
Loading