Skip to content

Commit

Permalink
v0.0.22: fixing #18, added some logging to help troubleshoot #25. sho…
Browse files Browse the repository at this point in the history
…uld also help #13. Also moved helper functions to helpers.py.

Lastly: sensors now carry the name of the instance as well (#22).
  • Loading branch information
jeroenterheerdt committed May 29, 2020
1 parent fc04602 commit da18cf8
Show file tree
Hide file tree
Showing 8 changed files with 396 additions and 194 deletions.
23 changes: 18 additions & 5 deletions custom_components/smart_irrigation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from datetime import timedelta
import logging
import datetime
import weakref

import voluptuous as vol

Expand Down Expand Up @@ -157,7 +158,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
coordinator.platforms.append(p)
hass.async_add_job(hass.config_entries.async_forward_entry_setup(entry, p))

entry.add_update_listener(async_reload_entry)
# add update listener if not already added.
if weakref.ref(async_reload_entry) not in entry.update_listeners:
entry.add_update_listener(async_reload_entry)

# register the services
hass.services.async_register(
Expand All @@ -179,7 +182,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):

async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Reload config entry."""
_LOGGER.warning("async_reload_entry")
coordinator = hass.data[DOMAIN][entry.entry_id]
if coordinator.entry_setup_completed:
await async_unload_entry(hass, entry)
Expand All @@ -188,7 +190,6 @@ async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry):

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Handle removal of an entry."""
_LOGGER.warning("async unload entry")
coordinator = hass.data[DOMAIN][entry.entry_id]
unloaded = all(
await asyncio.gather(
Expand Down Expand Up @@ -264,8 +265,12 @@ def __init__(
if self.auto_refresh:
hour = int(self.auto_refresh_time.split(":")[0])
minute = int(self.auto_refresh_time.split(":")[1])
if minute < 10:
minute_str = f"0{minute}"
else:
minute_str = minute
_LOGGER.info(
"Auto refresh is enabled. Scheduling for {}:{}".format(hour, minute)
"Auto refresh is enabled. Scheduling for {}:{}".format(hour, minute_str)
)
async_track_time_change(
hass,
Expand All @@ -277,7 +282,7 @@ def __init__(
self.entry_setup_completed = True

def register_entity(self, thetype, entity):
_LOGGER.info("registering: type: {}, entity: {}".format(thetype, entity))
_LOGGER.warning("registering: type: {}, entity: {}".format(thetype, entity))
self.entities[thetype] = entity

def handle_reset_bucket(self, call):
Expand Down Expand Up @@ -313,6 +318,14 @@ def _update_last_of_day(self):
bucket_delta = float(cart.attributes[CONF_NETTO_PRECIPITATION].split(" ")[0])
if self.system_of_measurement != SETTING_METRIC:
bucket_delta = bucket_delta / MM_TO_INCH_FACTOR
# if bucket has a unit, parse it out.
if isinstance(self.bucket, str) and " " in self.bucket:
self.bucket = float(self.bucket.split(" "[0]))
_LOGGER.info(
"Updating bucket: {} with netto_precipitation: {}".format(
self.bucket, bucket_delta
)
)
self.bucket = self.bucket + bucket_delta

# fire an event so the sensor can update itself.
Expand Down
107 changes: 77 additions & 30 deletions custom_components/smart_irrigation/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
CONF_AUTO_REFRESH,
CONF_AUTO_REFRESH_TIME,
CONF_NAME,
DEFAULT_LEAD_TIME,
DEFAULT_MAXIMUM_DURATION,
DEFAULT_FORCE_MODE_DURATION,
DEFAULT_SHOW_UNITS,
DEFAULT_AUTO_REFRESH,
DEFAULT_AUTO_REFRESH_TIME,
CONF_CONFIG,
)


Expand Down Expand Up @@ -69,7 +76,11 @@ async def async_step_step3(self, user_input=None):
user_input[CONF_API_KEY] = self._api_key
user_input[CONF_REFERENCE_ET] = self._reference_et
user_input[CONF_NAME] = self._name
await self.async_set_unique_id(self._name)
self._abort_if_unique_id_configured()

return self.async_create_entry(title=self._name, data=user_input)

return await self._show_config_form(user_input)

async def async_step_step2(self, user_input=None):
Expand Down Expand Up @@ -124,16 +135,24 @@ async def async_step_user(self, user_input=None):
# return self.async_abort(reason="single_instance_allowed")

if user_input is not None:
valid_api = await self._test_api_key(user_input[CONF_API_KEY])
if valid_api:
try:
await self._test_api_key(user_input[CONF_API_KEY])
await self._check_unique(user_input[CONF_NAME])

# store values entered
self._api_key = user_input[CONF_API_KEY].strip()
self._name = user_input[CONF_NAME]
# show next step
return await self._show_step2(user_input)
else:
except InvalidAuth:
self._errors["base"] = "auth"
return await self._show_config_form(user_input)
except CannotConnect:
self._errors["base"] = "auth"
except NotUnique:
_LOGGER.error("Instance name is not unique.")
self._errors["base"] = "name"

return await self._show_config_form(user_input)
# valid_et = self._check_reference_et(reference_et)

# if valid_api and valid_et:
Expand Down Expand Up @@ -223,13 +242,17 @@ async def _test_api_key(self, api_key):
client = OWMClient(
api_key=api_key.strip(), latitude=52.353218, longitude=5.0027695
)

try:
await self.hass.async_add_executor_job(client.get_data)
return True
except Exception as Ex:
_LOGGER.error(Ex.strerror)
return False
except OSError:
raise InvalidAuth
except Exception:
raise CannotConnect

async def _check_unique(self, n):
"""Test if the specified name is not already claimed."""
await self.async_set_unique_id(n)
self._abort_if_unique_id_configured()

def _check_reference_et(self, reference_et):
"""Check reference et values here."""
Expand All @@ -254,7 +277,6 @@ class SmartIrrigationOptionsFlowHandler(config_entries.OptionsFlow):
def __init__(self, config_entry):
"""Initialize HACS options flow."""
self.config_entry = config_entry
_LOGGER.warning("config_entry: {}".format(config_entry))
self.options = dict(config_entry.options)
self._errors = {}

Expand All @@ -279,52 +301,77 @@ def _check_time(self, itime):
_LOGGER.error("No valid time specified.")
return False

async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}
if user_input is not None:
valid_time = self._check_time(user_input[CONF_AUTO_REFRESH_TIME])
if not valid_time:
self._errors["base"] = "auto_refresh_time_error"
else:
self.options.update(user_input)
return await self._update_options()

async def _show_options_form(self, user_input):
"""Show the options form to edit info."""
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(
CONF_LEAD_TIME, default=self.options.get(CONF_LEAD_TIME, 0),
CONF_LEAD_TIME,
default=self.options.get(CONF_LEAD_TIME, DEFAULT_LEAD_TIME),
): int,
vol.Required(
CONF_MAXIMUM_DURATION,
default=self.options.get(CONF_MAXIMUM_DURATION, -1),
default=self.options.get(
CONF_MAXIMUM_DURATION, DEFAULT_MAXIMUM_DURATION
),
): int,
vol.Required(
CONF_FORCE_MODE_DURATION,
default=self.options.get(CONF_FORCE_MODE_DURATION, 0),
default=self.options.get(
CONF_FORCE_MODE_DURATION, DEFAULT_FORCE_MODE_DURATION
),
): int,
vol.Required(
CONF_SHOW_UNITS,
default=self.options.get(CONF_SHOW_UNITS, False),
default=self.options.get(CONF_SHOW_UNITS, DEFAULT_SHOW_UNITS),
): bool,
vol.Required(
CONF_AUTO_REFRESH,
default=self.options.get(CONF_AUTO_REFRESH, True),
default=self.options.get(
CONF_AUTO_REFRESH, DEFAULT_AUTO_REFRESH
),
): bool,
vol.Required(
CONF_AUTO_REFRESH_TIME,
default=self.options.get(CONF_AUTO_REFRESH_TIME, "23:00"),
default=self.options.get(
CONF_AUTO_REFRESH_TIME, DEFAULT_AUTO_REFRESH_TIME
),
): str,
},
),
errors=self._errors,
)

async def _update_options(self):
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}
if user_input is not None:
valid_time = self._check_time(user_input[CONF_AUTO_REFRESH_TIME])
if not valid_time:
self._errors["base"] = "auto_refresh_time_error"
return await self._show_options_form(user_input)
else:
# self.options.update(user_input)
return await self._update_options(user_input)

return await self._show_options_form(user_input)

async def _update_options(self, user_input=None):
"""Update config entry options."""
_LOGGER.warning("update_options")
return self.async_create_entry(
title=self.config_entry.data.get(NAME), data=self.options
title=self.config_entry.data.get(NAME), data=user_input
)


class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""


class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""


class NotUnique(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""
11 changes: 10 additions & 1 deletion custom_components/smart_irrigation/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
DOMAIN = "smart_irrigation"
NAME = "Smart Irrigation"
DOMAIN_DATA = f"{DOMAIN}_data"
VERSION = "0.0.21"
VERSION = "0.0.22"

ISSUE_URL = "https://github.com/jeroenterheerdt/HASmartIrrigation/issues"

Expand Down Expand Up @@ -52,6 +52,7 @@
CONF_AUTO_REFRESH = "auto_refresh"
CONF_AUTO_REFRESH_TIME = "auto_refresh_time"
CONF_NAME = "name"
CONF_CONFIG = "config"

# Events
EVENT_BUCKET_UPDATED = "bucket_updated_event"
Expand Down Expand Up @@ -102,6 +103,14 @@
UNIT_OF_MEASUREMENT_GPM = "gallon/minute"
UNIT_OF_MEASUREMENT_LPM = "liter/minute"

# OPTIONS DEFAULTS
DEFAULT_LEAD_TIME = 0
DEFAULT_MAXIMUM_DURATION = -1
DEFAULT_FORCE_MODE_DURATION = 0
DEFAULT_SHOW_UNITS = False
DEFAULT_AUTO_REFRESH = True
DEFAULT_AUTO_REFRESH_TIME = "23:00"

STARTUP_MESSAGE = f"""
-------------------------------------------------------------------
{NAME}
Expand Down
6 changes: 5 additions & 1 deletion custom_components/smart_irrigation/entity.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
"""SmartIrrigationEntity class"""
from homeassistant.helpers.restore_state import RestoreEntity
import logging

from .const import DOMAIN, NAME, VERSION

_LOGGER = logging.getLogger(__name__)


class SmartIrrigationEntity(RestoreEntity):
def __init__(self, coordinator, config_entry, mytype):
self.coordinator = coordinator
self.config_entry = config_entry
self.type = mytype
self.entity_id = f"sensor.{coordinator.name}_{mytype.replace(' ','_')}".lower()

@property
def should_poll(self):
Expand All @@ -32,5 +36,5 @@ async def async_added_to_hass(self):
)

async def async_update(self):
"""Update Brother entity."""
"""Update Coordinator entity."""
await self.coordinator.async_request_refresh()
Loading

0 comments on commit da18cf8

Please sign in to comment.