mirror of
https://github.com/home-assistant/core.git
synced 2026-10-06 14:29:21 -04:00
Remove Melnor RainCloud integration (#183505)
This commit is contained in:
Generated
-1
@@ -1539,7 +1539,6 @@ CLAUDE.md @home-assistant/core
|
||||
/tests/components/radiotherm/ @vinnyfuria
|
||||
/homeassistant/components/rainbird/ @konikvranik @allenporter
|
||||
/tests/components/rainbird/ @konikvranik @allenporter
|
||||
/homeassistant/components/raincloud/ @vanstinator
|
||||
/homeassistant/components/rainforest_eagle/ @gtdiehl @jcalbert @hastarin
|
||||
/tests/components/rainforest_eagle/ @gtdiehl @jcalbert @hastarin
|
||||
/homeassistant/components/rainforest_raven/ @cottsay
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"domain": "melnor",
|
||||
"name": "Melnor",
|
||||
"integrations": ["melnor", "raincloud"]
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
"""Support for Melnor RainCloud sprinkler water timer."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import probatio
|
||||
from raincloudy.core import RainCloudy
|
||||
from requests.exceptions import ConnectTimeout, HTTPError
|
||||
|
||||
from homeassistant.components import persistent_notification
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import dispatcher_send
|
||||
from homeassistant.helpers.event import track_time_interval
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import DATA_RAINCLOUD, SIGNAL_UPDATE_RAINCLOUD
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
NOTIFICATION_ID = "raincloud_notification"
|
||||
NOTIFICATION_TITLE = "Rain Cloud Setup"
|
||||
|
||||
DOMAIN = "raincloud"
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=20)
|
||||
|
||||
CONFIG_SCHEMA = probatio.Schema(
|
||||
{
|
||||
DOMAIN: probatio.Schema(
|
||||
{
|
||||
probatio.Required(CONF_USERNAME): cv.string,
|
||||
probatio.Required(CONF_PASSWORD): cv.string,
|
||||
probatio.Optional(
|
||||
CONF_SCAN_INTERVAL, default=SCAN_INTERVAL
|
||||
): cv.time_period,
|
||||
}
|
||||
)
|
||||
},
|
||||
extra=probatio.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the Melnor RainCloud component."""
|
||||
conf = config[DOMAIN]
|
||||
username = conf.get(CONF_USERNAME)
|
||||
password = conf.get(CONF_PASSWORD)
|
||||
scan_interval = conf.get(CONF_SCAN_INTERVAL)
|
||||
|
||||
try:
|
||||
raincloud = RainCloudy(username=username, password=password)
|
||||
if not raincloud.is_connected:
|
||||
raise HTTPError # noqa: TRY301
|
||||
hass.data[DATA_RAINCLOUD] = RainCloudHub(raincloud)
|
||||
except (ConnectTimeout, HTTPError) as ex:
|
||||
_LOGGER.error("Unable to connect to Rain Cloud service: %s", str(ex))
|
||||
persistent_notification.create(
|
||||
hass,
|
||||
f"Error: {ex}<br />You will need to restart hass after fixing.",
|
||||
title=NOTIFICATION_TITLE,
|
||||
notification_id=NOTIFICATION_ID,
|
||||
)
|
||||
return False
|
||||
|
||||
def hub_refresh(event_time):
|
||||
"""Call Raincloud hub to refresh information."""
|
||||
_LOGGER.debug("Updating RainCloud Hub component")
|
||||
hass.data[DATA_RAINCLOUD].data.update()
|
||||
dispatcher_send(hass, SIGNAL_UPDATE_RAINCLOUD)
|
||||
|
||||
# Call the Raincloud API to refresh updates
|
||||
track_time_interval(hass, hub_refresh, scan_interval)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class RainCloudHub:
|
||||
"""Representation of a base RainCloud device."""
|
||||
|
||||
def __init__(self, data):
|
||||
"""Initialize the entity."""
|
||||
self.data = data
|
||||
@@ -1,81 +0,0 @@
|
||||
"""Support for Melnor RainCloud sprinkler water timer."""
|
||||
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
import probatio
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
PLATFORM_SCHEMA as BINARY_SENSOR_PLATFORM_SCHEMA,
|
||||
BinarySensorEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_MONITORED_CONDITIONS
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from .const import DATA_RAINCLOUD
|
||||
from .entity import RainCloudEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
BINARY_SENSORS = ["is_watering", "status"]
|
||||
|
||||
PLATFORM_SCHEMA = BINARY_SENSOR_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
probatio.Optional(
|
||||
CONF_MONITORED_CONDITIONS, default=list(BINARY_SENSORS)
|
||||
): probatio.All(cv.ensure_list, [probatio.In(BINARY_SENSORS)])
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up a sensor for a raincloud device."""
|
||||
raincloud = hass.data[DATA_RAINCLOUD].data
|
||||
|
||||
sensors = []
|
||||
for sensor_type in config[CONF_MONITORED_CONDITIONS]:
|
||||
if sensor_type == "status":
|
||||
sensors.append(RainCloudBinarySensor(raincloud.controller, sensor_type))
|
||||
sensors.append(
|
||||
RainCloudBinarySensor(raincloud.controller.faucet, sensor_type)
|
||||
)
|
||||
|
||||
else:
|
||||
# create a sensor for each zone managed by faucet
|
||||
sensors.extend(
|
||||
RainCloudBinarySensor(zone, sensor_type)
|
||||
for zone in raincloud.controller.faucet.zones
|
||||
)
|
||||
|
||||
add_entities(sensors, True)
|
||||
|
||||
|
||||
class RainCloudBinarySensor(RainCloudEntity, BinarySensorEntity):
|
||||
"""A sensor implementation for raincloud device."""
|
||||
|
||||
def update(self) -> None:
|
||||
"""Get the latest data and updates the state."""
|
||||
_LOGGER.debug("Updating RainCloud sensor: %s", self.name)
|
||||
state = getattr(self.data, self._sensor_type)
|
||||
if self._sensor_type == "status":
|
||||
self._attr_is_on = state == "Online"
|
||||
else:
|
||||
self._attr_is_on = state
|
||||
|
||||
@property
|
||||
@override
|
||||
def icon(self) -> str | None:
|
||||
"""Return the icon of this device."""
|
||||
if self._sensor_type == "is_watering":
|
||||
return "mdi:water" if self.is_on else "mdi:water-off"
|
||||
if self._sensor_type == "status":
|
||||
return "mdi:pipe" if self.is_on else "mdi:pipe-disconnected"
|
||||
return super().icon
|
||||
@@ -1,17 +0,0 @@
|
||||
"""Support for Melnor RainCloud sprinkler water timer."""
|
||||
|
||||
DATA_RAINCLOUD = "raincloud"
|
||||
|
||||
ICON_MAP = {
|
||||
"auto_watering": "mdi:autorenew",
|
||||
"battery": "",
|
||||
"is_watering": "",
|
||||
"manual_watering": "mdi:water-pump",
|
||||
"next_cycle": "mdi:calendar-clock",
|
||||
"rain_delay": "mdi:weather-rainy",
|
||||
"status": "",
|
||||
"watering_time": "mdi:water-pump",
|
||||
}
|
||||
|
||||
|
||||
SIGNAL_UPDATE_RAINCLOUD = "raincloud_update"
|
||||
@@ -1,62 +0,0 @@
|
||||
"""Support for Melnor RainCloud sprinkler water timer."""
|
||||
|
||||
from typing import Any, override
|
||||
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import SIGNAL_UPDATE_RAINCLOUD
|
||||
|
||||
KEY_MAP = {
|
||||
"auto_watering": "Automatic Watering",
|
||||
"battery": "Battery",
|
||||
"is_watering": "Watering",
|
||||
"manual_watering": "Manual Watering",
|
||||
"next_cycle": "Next Cycle",
|
||||
"rain_delay": "Rain Delay",
|
||||
"status": "Status",
|
||||
"watering_time": "Remaining Watering Time",
|
||||
}
|
||||
|
||||
ICON_MAP = {
|
||||
"auto_watering": "mdi:autorenew",
|
||||
"battery": "",
|
||||
"is_watering": "",
|
||||
"manual_watering": "mdi:water-pump",
|
||||
"next_cycle": "mdi:calendar-clock",
|
||||
"rain_delay": "mdi:weather-rainy",
|
||||
"status": "",
|
||||
"watering_time": "mdi:water-pump",
|
||||
}
|
||||
|
||||
|
||||
class RainCloudEntity(Entity):
|
||||
"""Entity class for RainCloud devices."""
|
||||
|
||||
_attr_attribution = "Data provided by Melnor Aquatimer.com"
|
||||
|
||||
def __init__(self, data, sensor_type):
|
||||
"""Initialize the RainCloud entity."""
|
||||
self.data = data
|
||||
self._sensor_type = sensor_type
|
||||
self._attr_name = f"{self.data.name} {KEY_MAP.get(self._sensor_type)}"
|
||||
self._attr_icon = ICON_MAP.get(self._sensor_type)
|
||||
|
||||
@override
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass, SIGNAL_UPDATE_RAINCLOUD, self._update_callback
|
||||
)
|
||||
)
|
||||
|
||||
def _update_callback(self):
|
||||
"""Call update method."""
|
||||
self.schedule_update_ha_state(True)
|
||||
|
||||
@property
|
||||
@override
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
return {"identifier": self.data.serial}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"domain": "raincloud",
|
||||
"name": "Melnor RainCloud",
|
||||
"codeowners": ["@vanstinator"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/raincloud",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["raincloudy"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["raincloudy==0.0.7"]
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
"""Support for Melnor RainCloud sprinkler water timer."""
|
||||
|
||||
import logging
|
||||
from typing import cast, override
|
||||
|
||||
import probatio
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
||||
SensorEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_MONITORED_CONDITIONS, PERCENTAGE, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from .const import DATA_RAINCLOUD
|
||||
from .entity import RainCloudEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SENSORS = ["battery", "next_cycle", "rain_delay", "watering_time"]
|
||||
|
||||
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
probatio.Optional(
|
||||
CONF_MONITORED_CONDITIONS, default=list(SENSORS)
|
||||
): probatio.All(cv.ensure_list, [probatio.In(SENSORS)])
|
||||
}
|
||||
)
|
||||
|
||||
UNIT_OF_MEASUREMENT_MAP: dict[str, str] = {
|
||||
"auto_watering": "",
|
||||
"battery": PERCENTAGE,
|
||||
"is_watering": "",
|
||||
"manual_watering": "",
|
||||
"next_cycle": "",
|
||||
"rain_delay": UnitOfTime.DAYS,
|
||||
"status": "",
|
||||
"watering_time": UnitOfTime.MINUTES,
|
||||
}
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up a sensor for a raincloud device."""
|
||||
raincloud = hass.data[DATA_RAINCLOUD].data
|
||||
|
||||
sensors = []
|
||||
for sensor_type in config[CONF_MONITORED_CONDITIONS]:
|
||||
if sensor_type == "battery":
|
||||
sensors.append(RainCloudSensor(raincloud.controller.faucet, sensor_type))
|
||||
else:
|
||||
# create a sensor for each zone managed by a faucet
|
||||
sensors.extend(
|
||||
RainCloudSensor(zone, sensor_type)
|
||||
for zone in raincloud.controller.faucet.zones
|
||||
)
|
||||
|
||||
add_entities(sensors, True)
|
||||
|
||||
|
||||
class RainCloudSensor(RainCloudEntity, SensorEntity):
|
||||
"""A sensor implementation for raincloud device."""
|
||||
|
||||
@property
|
||||
@override
|
||||
def native_unit_of_measurement(self) -> str | None:
|
||||
"""Return the units of measurement."""
|
||||
return UNIT_OF_MEASUREMENT_MAP.get(self._sensor_type)
|
||||
|
||||
def update(self) -> None:
|
||||
"""Get the latest data and updates the states."""
|
||||
_LOGGER.debug("Updating RainCloud sensor: %s", self.name)
|
||||
if self._sensor_type == "battery":
|
||||
self._attr_native_value = self.data.battery
|
||||
else:
|
||||
self._attr_native_value = getattr(self.data, self._sensor_type)
|
||||
|
||||
@property
|
||||
@override
|
||||
def icon(self) -> str | None:
|
||||
"""Icon to use in the frontend, if any."""
|
||||
if self._sensor_type == "battery" and self.native_value is not None:
|
||||
return icon_for_battery_level(
|
||||
battery_level=int(cast(float, self.native_value)),
|
||||
charging=False,
|
||||
)
|
||||
return super().icon
|
||||
@@ -1,102 +0,0 @@
|
||||
"""Support for Melnor RainCloud sprinkler water timer."""
|
||||
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
import probatio
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
|
||||
SwitchEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_MONITORED_CONDITIONS
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from .const import DATA_RAINCLOUD
|
||||
from .entity import RainCloudEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ALLOWED_WATERING_TIME = [5, 10, 15, 30, 45, 60]
|
||||
CONF_WATERING_TIME = "watering_minutes"
|
||||
DEFAULT_WATERING_TIME = 15
|
||||
|
||||
SWITCHES = ["auto_watering", "manual_watering"]
|
||||
|
||||
PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
probatio.Optional(
|
||||
CONF_MONITORED_CONDITIONS, default=list(SWITCHES)
|
||||
): probatio.All(cv.ensure_list, [probatio.In(SWITCHES)]),
|
||||
probatio.Optional(
|
||||
CONF_WATERING_TIME, default=DEFAULT_WATERING_TIME
|
||||
): probatio.All(probatio.In(ALLOWED_WATERING_TIME)),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up a sensor for a raincloud device."""
|
||||
raincloud = hass.data[DATA_RAINCLOUD].data
|
||||
default_watering_timer = config[CONF_WATERING_TIME]
|
||||
|
||||
add_entities(
|
||||
(
|
||||
RainCloudSwitch(default_watering_timer, zone, sensor_type)
|
||||
for zone in raincloud.controller.faucet.zones
|
||||
for sensor_type in config[CONF_MONITORED_CONDITIONS]
|
||||
),
|
||||
True,
|
||||
)
|
||||
|
||||
|
||||
class RainCloudSwitch(RainCloudEntity, SwitchEntity):
|
||||
"""A switch implementation for raincloud device."""
|
||||
|
||||
def __init__(self, default_watering_timer, *args):
|
||||
"""Initialize a switch for raincloud device."""
|
||||
super().__init__(*args)
|
||||
self._default_watering_timer = default_watering_timer
|
||||
|
||||
@override
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
if self._sensor_type == "manual_watering":
|
||||
self.data.watering_time = self._default_watering_timer
|
||||
elif self._sensor_type == "auto_watering":
|
||||
self.data.auto_watering = True
|
||||
self._attr_is_on = True
|
||||
|
||||
@override
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
if self._sensor_type == "manual_watering":
|
||||
self.data.watering_time = "off"
|
||||
elif self._sensor_type == "auto_watering":
|
||||
self.data.auto_watering = False
|
||||
self._attr_is_on = False
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update device state."""
|
||||
_LOGGER.debug("Updating RainCloud switch: %s", self.name)
|
||||
if self._sensor_type == "manual_watering":
|
||||
self._attr_is_on = bool(self.data.watering_time)
|
||||
elif self._sensor_type == "auto_watering":
|
||||
self._attr_is_on = self.data.auto_watering
|
||||
|
||||
@property
|
||||
@override
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
return {
|
||||
"default_manual_timer": self._default_watering_timer,
|
||||
"identifier": self.data.serial,
|
||||
}
|
||||
@@ -4339,21 +4339,10 @@
|
||||
"iot_class": "cloud_polling"
|
||||
},
|
||||
"melnor": {
|
||||
"name": "Melnor",
|
||||
"integrations": {
|
||||
"melnor": {
|
||||
"integration_type": "device",
|
||||
"config_flow": true,
|
||||
"iot_class": "local_polling",
|
||||
"name": "Melnor Bluetooth"
|
||||
},
|
||||
"raincloud": {
|
||||
"integration_type": "hub",
|
||||
"config_flow": false,
|
||||
"iot_class": "cloud_polling",
|
||||
"name": "Melnor RainCloud"
|
||||
}
|
||||
}
|
||||
"name": "Melnor Bluetooth",
|
||||
"integration_type": "device",
|
||||
"config_flow": true,
|
||||
"iot_class": "local_polling"
|
||||
},
|
||||
"meraki": {
|
||||
"name": "Meraki",
|
||||
|
||||
Generated
-3
@@ -2952,9 +2952,6 @@ radios==0.3.2
|
||||
# homeassistant.components.radiotherm
|
||||
radiotherm==2.1.0
|
||||
|
||||
# homeassistant.components.raincloud
|
||||
raincloudy==0.0.7
|
||||
|
||||
# homeassistant.components.rapt_ble
|
||||
rapt-ble==2.0.0
|
||||
|
||||
|
||||
@@ -730,7 +730,6 @@ INTEGRATIONS_WITHOUT_QUALITY_SCALE_FILE = [
|
||||
"radarr",
|
||||
"radio_browser",
|
||||
"radiotherm",
|
||||
"raincloud",
|
||||
"rainforest_eagle",
|
||||
"rainforest_raven",
|
||||
"rainmachine",
|
||||
@@ -1667,7 +1666,6 @@ INTEGRATIONS_WITHOUT_SCALE = [
|
||||
"radarr",
|
||||
"radio_browser",
|
||||
"radiotherm",
|
||||
"raincloud",
|
||||
"rainforest_eagle",
|
||||
"rainforest_raven",
|
||||
"rainmachine",
|
||||
|
||||
Reference in New Issue
Block a user