Skip to content

Commit

Permalink
Rework services again
Browse files Browse the repository at this point in the history
  • Loading branch information
bergdahl committed Jul 2, 2024
1 parent 926ad6a commit 1431277
Showing 7 changed files with 264 additions and 62 deletions.
10 changes: 7 additions & 3 deletions custom_components/growcube/const.py
Original file line number Diff line number Diff line change
@@ -4,8 +4,12 @@
CHANNEL_NAME = ['A', 'B', 'C', 'D']
CHANNEL_ID = ['a', 'b', 'c', 'd']
SERVICE_WATER_PLANT = "water_plant"
SERVICE_SET_WATERING_MODE = "set_watering_mode"
SERVICE_SET_SMART_WATERING = "set_smart_watering"
SERVICE_SET_SCHEDULED_WATERING = "set_scheduled_watering"
SERVICE_DELETE_WATERING = "delete_watering"
ARGS_CHANNEL = "channel"
ARGS_DURATION = "duration"
ARGS_MIN_VALUE = "min_value"
ARGS_MAX_VALUE = "max_value"
ARGS_MIN_MOISTURE = "min_moisture"
ARGS_MAX_MOISTURE = "max_moisture"
ARGS_ALL_DAY = "all_day"
ARGS_INTERVAL = "interval"
42 changes: 36 additions & 6 deletions custom_components/growcube/coordinator.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
LockStateGrowcubeReport,
CheckOutletLockedGrowcubeReport,
)
from growcube_client import WateringModeCommand, SyncTimeCommand
from growcube_client import WateringModeCommand, SyncTimeCommand, PlantEndCommand, ClosePumpCommand
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import HomeAssistantError
from homeassistant.const import (
@@ -312,15 +312,45 @@ async def handle_water_plant(self, channel: Channel, duration: int) -> None:
)
await self.client.water_plant(channel, duration)

async def handle_set_watering_mode(self, channel: Channel, min_value: int, max_value: int) -> None:
async def handle_set_smart_watering(self, channel: Channel,
all_day: bool,
min_moisture: int,
max_moisture: int) -> None:

_LOGGER.debug(
"%s: Service set_smart_watering called, %s, %s, %s, %s",
self.data.device_id,
channel,
all_day,
min_moisture,
max_moisture,
)

watering_mode = WateringMode.Smart if all_day else WateringMode.SmartOutside
command = WateringModeCommand(channel, watering_mode, min_moisture, max_moisture)
self.client.send_command(command)

async def handle_set_manual_watering(self, channel: Channel, duration: int, interval: int) -> None:

command = WateringModeCommand(channel, WateringMode.Smart, min_value, max_value)
_LOGGER.debug(
"%s: Service set_watering_mode called, %s, %s, %s",
"%s: Service set_manual_watering called, %s, %s, %s",
self.data.device_id,
channel,
min_value,
max_value,
duration,
interval,
)

command = WateringModeCommand(channel, WateringMode.Manual, interval, duration)
self.client.send_command(command)

async def handle_delete_watering(self, channel: Channel) -> None:

_LOGGER.debug(
"%s: Service delete_watering called, %s,",
self.data.device_id,
channel
)
command = PlantEndCommand(channel)
self.client.send_command(command)
command = ClosePumpCommand(channel)
self.client.send_command(command)
4 changes: 2 additions & 2 deletions custom_components/growcube/manifest.json
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
"issue_tracker": "https://github.com/jonnybergdahl/homeassistant_growcube/issues",
"iot_class": "local_push",
"requirements": [
"growcube-client==1.2.0"
"growcube-client==1.2.2"
],
"version": "0.11.0"
"version": "0.12.0"
}
179 changes: 137 additions & 42 deletions custom_components/growcube/services.py
Original file line number Diff line number Diff line change
@@ -10,8 +10,9 @@
from homeassistant.helpers import device_registry as dr

from . import GrowcubeDataCoordinator
from .const import DOMAIN, CHANNEL_NAME, SERVICE_WATER_PLANT, SERVICE_SET_WATERING_MODE, ARGS_CHANNEL, ARGS_DURATION, \
ARGS_MIN_VALUE, ARGS_MAX_VALUE
from .const import DOMAIN, CHANNEL_NAME, SERVICE_WATER_PLANT, SERVICE_SET_SMART_WATERING, \
SERVICE_SET_SCHEDULED_WATERING, SERVICE_DELETE_WATERING, \
ARGS_CHANNEL, ARGS_DURATION, ARGS_MIN_MOISTURE, ARGS_MAX_MOISTURE, ARGS_ALL_DAY, ARGS_INTERVAL
import logging

_LOGGER = logging.getLogger(__name__)
@@ -22,8 +23,14 @@ async def async_setup_services(hass):
async def async_call_water_plant_service(service_call: ServiceCall) -> None:
await _async_handle_water_plant(hass, service_call.data)

async def async_call_set_watering_mode_service(service_call: ServiceCall) -> None:
await _async_handle_set_watering_mode(hass, service_call.data)
async def async_call_set_smart_watering_service(service_call: ServiceCall) -> None:
await _async_handle_set_smart_watering(hass, service_call.data)

async def async_call_set_scheduled_watering_service(service_call: ServiceCall) -> None:
await _async_handle_set_scheduled_watering(hass, service_call.data)

async def async_call_delete_watering_service(service_call: ServiceCall) -> None:
await _async_handle_delete_watering(hass, service_call.data)

hass.services.async_register(DOMAIN,
SERVICE_WATER_PLANT,
@@ -33,27 +40,45 @@ async def async_call_set_watering_mode_service(service_call: ServiceCall) -> Non
vol.Required(ATTR_DEVICE_ID): cv.string,
vol.Required(ARGS_CHANNEL, default='A'): cv.string,
vol.Required(ARGS_DURATION, default=5): cv.positive_int,
},
}
))
hass.services.async_register(DOMAIN,
SERVICE_SET_SMART_WATERING,
async_call_set_smart_watering_service,
schema=vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): cv.string,
vol.Required(ARGS_CHANNEL, default='A'): cv.string,
vol.Required(ARGS_ALL_DAY, default=True): cv.boolean,
vol.Required(ARGS_MIN_MOISTURE, default=15): cv.positive_int,
vol.Required(ARGS_MAX_MOISTURE, default=40): cv.positive_int,
}
))
hass.services.async_register(DOMAIN,
SERVICE_SET_WATERING_MODE,
async_call_set_watering_mode_service,
SERVICE_SET_SCHEDULED_WATERING,
async_call_set_scheduled_watering_service,
schema=vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): cv.string,
vol.Required(ARGS_CHANNEL, default='A'): cv.string,
vol.Required(ARGS_DURATION, default=6): cv.positive_int,
vol.Required(ARGS_INTERVAL, default=3): cv.positive_int,
}
))
hass.services.async_register(DOMAIN,
SERVICE_DELETE_WATERING,
async_call_delete_watering_service,
schema=vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): cv.string,
vol.Required(ARGS_CHANNEL, default='A'): cv.string,
vol.Required(ARGS_MIN_VALUE, default=15): cv.positive_int,
vol.Required(ARGS_MAX_VALUE, default=40): cv.positive_int,
}
))


async def _async_handle_water_plant(hass: HomeAssistant, data: Mapping[str, Any]) -> None:

device_registry = dr.async_get(hass)
device_entry = device_registry.async_get(data[ATTR_DEVICE_ID])
device = list(device_entry.identifiers)[0][1]
coordinator = _get_coordinator(hass, device)
coordinator = _get_coordinator(hass, data)

if coordinator is None:
_LOGGER.warning(f"Unable to find coordinator for {data[ATTR_DEVICE_ID]}")
@@ -97,69 +122,139 @@ async def _async_handle_water_plant(hass: HomeAssistant, data: Mapping[str, Any]
await coordinator.handle_water_plant(channel, duration)


async def _async_handle_set_watering_mode(hass: HomeAssistant, data: Mapping[str, Any]) -> None:
async def _async_handle_set_smart_watering(hass: HomeAssistant, data: Mapping[str, Any]) -> None:

device_registry = dr.async_get(hass)
device_entry = device_registry.async_get(data[ATTR_DEVICE_ID])
device = list(device_entry.identifiers)[0][1]
coordinator = _get_coordinator(hass, device)
coordinator, device = _get_coordinator(hass, data)

if coordinator is None:
_LOGGER.error(f"Unable to find coordinator for {device}")
return

channel_str = data["channel"]
min_value = data["min_value"]
max_value = data["max_value"]
channel_str = data[ARGS_CHANNEL]
min_moisture = data[ARGS_MIN_MOISTURE]
max_moisture = data[ARGS_MAX_MOISTURE]
all_day = data[ARGS_ALL_DAY]

# Validate data
if channel_str not in CHANNEL_NAME:
_LOGGER.error(
"%s: %s - Invalid channel specified: %s",
device,
SERVICE_SET_WATERING_MODE,
SERVICE_SET_SMART_WATERING,
channel_str
)
raise HomeAssistantError(f"Invalid channel '{channel_str}' specified")

if min_value <= 0 or min_value > 100:
if min_moisture <= 0 or min_moisture > 100:
_LOGGER.error(
"%s: %s - Invalid min_value specified: %s",
"%s: %s - Invalid min_moisture specified: %s",
device,
SERVICE_SET_WATERING_MODE,
min_value
SERVICE_SET_SMART_WATERING,
min_moisture
)
raise HomeAssistantError(f"Invalid min_value '{min_value}' specified")
raise HomeAssistantError(f"Invalid min_moisture '{min_moisture}' specified")

if max_value <= 0 or max_value > 100:
if max_moisture <= 0 or max_moisture > 100:
_LOGGER.error(
"%s: %s - Invalid max_value specified: %s",
"%s: %s - Invalid max_moisture specified: %s",
device,
SERVICE_SET_WATERING_MODE,
max_value
SERVICE_SET_SMART_WATERING,
max_moisture
)
raise HomeAssistantError(f"Invalid max_value '{max_value}' specified")
raise HomeAssistantError(f"Invalid max_moisture '{max_moisture}' specified")

if max_value <= min_value:
if max_moisture <= min_moisture:
_LOGGER.error(
"%s: %s - Invalid values specified, max_value %s must be bigger than min_value %s",
"%s: %s - Invalid values specified, max_moisture %s must be bigger than min_moisture %s",
device,
SERVICE_SET_WATERING_MODE,
min_value,
max_value
SERVICE_SET_SMART_WATERING,
min_moisture,
max_moisture
)
raise HomeAssistantError(
f"Invalid values specified, max_value {max_value}must be bigger than min_value {min_value}")
f"Invalid values specified, max_moisture {max_moisture} must be bigger than min_moisture {min_moisture}")

channel = Channel(CHANNEL_NAME.index(channel_str))
await coordinator.handle_set_watering_mode(channel, min_value, max_value)
await coordinator.handle_set_smart_watering(channel, all_day, min_moisture, max_moisture)


async def _async_handle_set_scheduled_watering(hass: HomeAssistant, data: Mapping[str, Any]) -> None:

coordinator, device = _get_coordinator(hass, data)

if coordinator is None:
_LOGGER.error(f"Unable to find coordinator for {device}")
return

channel_str = data[ARGS_CHANNEL]
duration = data[ARGS_DURATION]
interval = data[ARGS_INTERVAL]

# Validate data
if channel_str not in CHANNEL_NAME:
_LOGGER.error(
"%s: %s - Invalid channel specified: %s",
device,
SERVICE_SET_SMART_WATERING,
channel_str
)
raise HomeAssistantError(f"Invalid channel '{channel_str}' specified")

if duration <= 0 or duration > 100:
_LOGGER.error(
"%s: %s - Invalid duration specified: %s",
device,
SERVICE_SET_SMART_WATERING,
duration
)
raise HomeAssistantError(f"Invalid duration '{duration}' specified")

if interval <= 0 or interval > 240:
_LOGGER.error(
"%s: %s - Invalid interval specified: %s",
device,
SERVICE_SET_SMART_WATERING,
interval
)
raise HomeAssistantError(f"Invalid interval '{interval}' specified")

channel = Channel(CHANNEL_NAME.index(channel_str))
await coordinator.handle_set_manual_watering(channel, duration, interval)


async def _async_handle_delete_watering(hass: HomeAssistant, data: Mapping[str, Any]) -> None:

coordinator, device = _get_coordinator(hass, data)

if coordinator is None:
raise HomeAssistantError(f"Unable to find coordinator for {device}")

channel_str = data["channel"]

# Validate data
if channel_str not in CHANNEL_NAME:
_LOGGER.error(
"%s: %s - Invalid channel specified: %s",
id,
SERVICE_DELETE_WATERING,
channel_str
)
raise HomeAssistantError(f"Invalid channel '{channel_str}' specified")

channel = Channel(CHANNEL_NAME.index(channel_str))
await coordinator.handle_delete_watering(channel)


def _get_coordinator(hass: HomeAssistant, data: Mapping[str, Any]) -> { GrowcubeDataCoordinator, str }:
device_registry = dr.async_get(hass)
device_id = data[ATTR_DEVICE_ID]
device_entry = device_registry.async_get(device_id)
device = list(device_entry.identifiers)[0][1]

def _get_coordinator(hass: HomeAssistant, device: str) -> GrowcubeDataCoordinator:
for key in hass.data[DOMAIN]:
coordinator = hass.data[DOMAIN][key]
if coordinator.data.device_id == device:
return coordinator
return coordinator, device_id

_LOGGER.error("No coordinator found for %s", device)
return None
return None, device_id
Loading

0 comments on commit 1431277

Please sign in to comment.