-
-
Notifications
You must be signed in to change notification settings - Fork 29.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial commit * test service calls * lint * float -> Decimal * extra tests * lint * lint * lint * lint * fix self reset * clean * add services * improve service example description * add optional paused initialization * fix * travis fix * fix YEARLY * add tests for previous bug * address comments and suggestions from @OttoWinter * lint * remove debug * add discoverability capabilities * no need for _hass * Update homeassistant/components/sensor/utility_meter.py Co-Authored-By: dgomes <diogogomes@gmail.com> * Update homeassistant/components/sensor/utility_meter.py Co-Authored-By: dgomes <diogogomes@gmail.com> * correct comment * improve error handling * address @MartinHjelmare comments * address @MartinHjelmare comments * one patch is enought * follow @ballob suggestion in home-assistant/architecture#131 * fix tests * review fixes * major refactor * lint * lint * address comments by @MartinHjelmare * rename variable
- Loading branch information
Showing
7 changed files
with
713 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
""" | ||
Component to track utility consumption over given periods of time. | ||
For more details about this component, please refer to the documentation | ||
at https://www.home-assistant.io/components/utility_meter/ | ||
""" | ||
|
||
import logging | ||
|
||
import voluptuous as vol | ||
|
||
from homeassistant.const import (ATTR_ENTITY_ID, CONF_NAME) | ||
import homeassistant.helpers.config_validation as cv | ||
from homeassistant.helpers import discovery | ||
from homeassistant.helpers.dispatcher import async_dispatcher_send | ||
from homeassistant.helpers.entity_component import EntityComponent | ||
from homeassistant.helpers.restore_state import RestoreEntity | ||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN | ||
from .const import ( | ||
DOMAIN, SIGNAL_RESET_METER, METER_TYPES, CONF_SOURCE_SENSOR, | ||
CONF_METER_TYPE, CONF_METER_OFFSET, CONF_TARIFF_ENTITY, CONF_TARIFF, | ||
CONF_TARIFFS, CONF_METER, DATA_UTILITY, SERVICE_RESET, | ||
SERVICE_SELECT_TARIFF, SERVICE_SELECT_NEXT_TARIFF, | ||
ATTR_TARIFF) | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
TARIFF_ICON = "mdi:clock-outline" | ||
|
||
ATTR_TARIFFS = 'tariffs' | ||
|
||
SERVICE_METER_SCHEMA = vol.Schema({ | ||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids, | ||
}) | ||
|
||
SERVICE_SELECT_TARIFF_SCHEMA = SERVICE_METER_SCHEMA.extend({ | ||
vol.Required(ATTR_TARIFF): cv.string | ||
}) | ||
|
||
METER_CONFIG_SCHEMA = vol.Schema({ | ||
vol.Required(CONF_SOURCE_SENSOR): cv.entity_id, | ||
vol.Optional(CONF_NAME): cv.string, | ||
vol.Optional(CONF_METER_TYPE): vol.In(METER_TYPES), | ||
vol.Optional(CONF_METER_OFFSET, default=0): cv.positive_int, | ||
vol.Optional(CONF_TARIFFS, default=[]): vol.All( | ||
cv.ensure_list, [cv.string]), | ||
}) | ||
|
||
CONFIG_SCHEMA = vol.Schema({ | ||
DOMAIN: vol.Schema({ | ||
cv.slug: METER_CONFIG_SCHEMA, | ||
}), | ||
}, extra=vol.ALLOW_EXTRA) | ||
|
||
|
||
async def async_setup(hass, config): | ||
"""Set up an Utility Meter.""" | ||
component = EntityComponent(_LOGGER, DOMAIN, hass) | ||
hass.data[DATA_UTILITY] = {} | ||
|
||
for meter, conf in config.get(DOMAIN).items(): | ||
_LOGGER.debug("Setup %s.%s", DOMAIN, meter) | ||
|
||
hass.data[DATA_UTILITY][meter] = conf | ||
|
||
if not conf[CONF_TARIFFS]: | ||
# only one entity is required | ||
hass.async_create_task(discovery.async_load_platform( | ||
hass, SENSOR_DOMAIN, DOMAIN, | ||
[{CONF_METER: meter, CONF_NAME: meter}], config)) | ||
else: | ||
# create tariff selection | ||
await component.async_add_entities([ | ||
TariffSelect(meter, list(conf[CONF_TARIFFS])) | ||
]) | ||
hass.data[DATA_UTILITY][meter][CONF_TARIFF_ENTITY] =\ | ||
"{}.{}".format(DOMAIN, meter) | ||
|
||
# add one meter for each tariff | ||
tariff_confs = [] | ||
for tariff in conf[CONF_TARIFFS]: | ||
tariff_confs.append({ | ||
CONF_METER: meter, | ||
CONF_NAME: "{} {}".format(meter, tariff), | ||
CONF_TARIFF: tariff, | ||
}) | ||
hass.async_create_task(discovery.async_load_platform( | ||
hass, SENSOR_DOMAIN, DOMAIN, tariff_confs, config)) | ||
|
||
component.async_register_entity_service( | ||
SERVICE_RESET, SERVICE_METER_SCHEMA, | ||
'async_reset_meters' | ||
) | ||
|
||
component.async_register_entity_service( | ||
SERVICE_SELECT_TARIFF, SERVICE_SELECT_TARIFF_SCHEMA, | ||
'async_select_tariff' | ||
) | ||
|
||
component.async_register_entity_service( | ||
SERVICE_SELECT_NEXT_TARIFF, SERVICE_METER_SCHEMA, | ||
'async_next_tariff' | ||
) | ||
|
||
return True | ||
|
||
|
||
class TariffSelect(RestoreEntity): | ||
"""Representation of a Tariff selector.""" | ||
|
||
def __init__(self, name, tariffs): | ||
"""Initialize a tariff selector.""" | ||
self._name = name | ||
self._current_tariff = None | ||
self._tariffs = tariffs | ||
self._icon = TARIFF_ICON | ||
|
||
async def async_added_to_hass(self): | ||
"""Run when entity about to be added.""" | ||
await super().async_added_to_hass() | ||
if self._current_tariff is not None: | ||
return | ||
|
||
state = await self.async_get_last_state() | ||
if not state or state.state not in self._tariffs: | ||
self._current_tariff = self._tariffs[0] | ||
else: | ||
self._current_tariff = state.state | ||
|
||
@property | ||
def should_poll(self): | ||
"""If entity should be polled.""" | ||
return False | ||
|
||
@property | ||
def name(self): | ||
"""Return the name of the select input.""" | ||
return self._name | ||
|
||
@property | ||
def icon(self): | ||
"""Return the icon to be used for this entity.""" | ||
return self._icon | ||
|
||
@property | ||
def state(self): | ||
"""Return the state of the component.""" | ||
return self._current_tariff | ||
|
||
@property | ||
def state_attributes(self): | ||
"""Return the state attributes.""" | ||
return { | ||
ATTR_TARIFFS: self._tariffs, | ||
} | ||
|
||
async def async_reset_meters(self): | ||
"""Reset all sensors of this meter.""" | ||
async_dispatcher_send(self.hass, SIGNAL_RESET_METER, | ||
self.entity_id) | ||
|
||
async def async_select_tariff(self, tariff): | ||
"""Select new option.""" | ||
if tariff not in self._tariffs: | ||
_LOGGER.warning('Invalid tariff: %s (possible tariffs: %s)', | ||
tariff, ', '.join(self._tariffs)) | ||
return | ||
self._current_tariff = tariff | ||
await self.async_update_ha_state() | ||
|
||
async def async_next_tariff(self): | ||
"""Offset current index.""" | ||
current_index = self._tariffs.index(self._current_tariff) | ||
new_index = (current_index + 1) % len(self._tariffs) | ||
self._current_tariff = self._tariffs[new_index] | ||
await self.async_update_ha_state() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"""Constants for the utility meter component.""" | ||
DOMAIN = 'utility_meter' | ||
|
||
HOURLY = 'hourly' | ||
DAILY = 'daily' | ||
WEEKLY = 'weekly' | ||
MONTHLY = 'monthly' | ||
YEARLY = 'yearly' | ||
|
||
METER_TYPES = [HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY] | ||
|
||
DATA_UTILITY = 'utility_meter_data' | ||
|
||
CONF_METER = 'meter' | ||
CONF_SOURCE_SENSOR = 'source' | ||
CONF_METER_TYPE = 'cycle' | ||
CONF_METER_OFFSET = 'offset' | ||
CONF_PAUSED = 'paused' | ||
CONF_TARIFFS = 'tariffs' | ||
CONF_TARIFF = 'tariff' | ||
CONF_TARIFF_ENTITY = 'tariff_entity' | ||
|
||
ATTR_TARIFF = 'tariff' | ||
|
||
SIGNAL_START_PAUSE_METER = 'utility_meter_start_pause' | ||
SIGNAL_RESET_METER = 'utility_meter_reset' | ||
|
||
SERVICE_RESET = 'reset' | ||
SERVICE_SELECT_TARIFF = 'select_tariff' | ||
SERVICE_SELECT_NEXT_TARIFF = 'next_tariff' |
Oops, something went wrong.