Utility Meter offset defined by a time_period (#20926)

* change offset from int to Time period dictionary

* track according to offset

* left overs... tks @fabaff

* typo
This commit is contained in:
Diogo Gomes 2019-03-06 12:55:24 +00:00 committed by Charles Garwood
parent 54895fcb1e
commit 8e9a496002
3 changed files with 61 additions and 24 deletions

View file

@ -1,5 +1,6 @@
"""Support for tracking consumption over given periods of time.""" """Support for tracking consumption over given periods of time."""
import logging import logging
from datetime import timedelta
import voluptuous as vol import voluptuous as vol
@ -23,6 +24,8 @@ TARIFF_ICON = 'mdi:clock-outline'
ATTR_TARIFFS = 'tariffs' ATTR_TARIFFS = 'tariffs'
DEFAULT_OFFSET = timedelta(hours=0)
SERVICE_METER_SCHEMA = vol.Schema({ SERVICE_METER_SCHEMA = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.entity_ids, vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
}) })
@ -35,7 +38,8 @@ METER_CONFIG_SCHEMA = vol.Schema({
vol.Required(CONF_SOURCE_SENSOR): cv.entity_id, vol.Required(CONF_SOURCE_SENSOR): cv.entity_id,
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_METER_TYPE): vol.In(METER_TYPES), vol.Optional(CONF_METER_TYPE): vol.In(METER_TYPES),
vol.Optional(CONF_METER_OFFSET, default=0): cv.positive_int, vol.Optional(CONF_METER_OFFSET, default=DEFAULT_OFFSET):
vol.All(cv.time_period, cv.positive_timedelta),
vol.Optional(CONF_METER_NET_CONSUMPTION, default=False): cv.boolean, vol.Optional(CONF_METER_NET_CONSUMPTION, default=False): cv.boolean,
vol.Optional(CONF_TARIFFS, default=[]): vol.All( vol.Optional(CONF_TARIFFS, default=[]): vol.All(
cv.ensure_list, [cv.string]), cv.ensure_list, [cv.string]),

View file

@ -1,6 +1,6 @@
"""Utility meter from sensors providing raw data.""" """Utility meter from sensors providing raw data."""
import logging import logging
from datetime import date, timedelta
from decimal import Decimal, DecimalException from decimal import Decimal, DecimalException
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -128,15 +128,17 @@ class UtilityMeterSensor(RestoreEntity):
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
async def _async_reset_meter(self, event): async def _async_reset_meter(self, event):
"""Determine cycle - Helper function for larger then daily cycles.""" """Determine cycle - Helper function for larger than daily cycles."""
now = dt_util.now() now = dt_util.now().date()
if self._period == WEEKLY and now.weekday() != self._period_offset: if self._period == WEEKLY and\
now != now - timedelta(days=now.weekday())\
+ self._period_offset:
return return
if self._period == MONTHLY and\ if self._period == MONTHLY and\
now.day != (1 + self._period_offset): now != date(now.year, now.month, 1) + self._period_offset:
return return
if self._period == YEARLY and\ if self._period == YEARLY and\
(now.month != (1 + self._period_offset) or now.day != 1): now != date(now.year, 1, 1) + self._period_offset:
return return
await self.async_reset_meter(self._tariff_entity) await self.async_reset_meter(self._tariff_entity)
@ -155,15 +157,16 @@ class UtilityMeterSensor(RestoreEntity):
await super().async_added_to_hass() await super().async_added_to_hass()
if self._period == HOURLY: if self._period == HOURLY:
async_track_time_change(self.hass, self._async_reset_meter, async_track_time_change(
minute=self._period_offset, second=0) self.hass, self._async_reset_meter,
elif self._period == DAILY: minute=self._period_offset.seconds // 60,
async_track_time_change(self.hass, self._async_reset_meter, second=self._period_offset.seconds % 60)
hour=self._period_offset, minute=0, elif self._period in [DAILY, WEEKLY, MONTHLY, YEARLY]:
second=0) async_track_time_change(
elif self._period in [WEEKLY, MONTHLY, YEARLY]: self.hass, self._async_reset_meter,
async_track_time_change(self.hass, self._async_reset_meter, hour=self._period_offset.seconds // 3600,
hour=0, minute=0, second=0) minute=self._period_offset.seconds % 3600 // 60,
second=self._period_offset.seconds % 3600 % 60)
async_dispatcher_connect( async_dispatcher_connect(
self.hass, SIGNAL_RESET_METER, self.async_reset_meter) self.hass, SIGNAL_RESET_METER, self.async_reset_meter)

View file

@ -123,8 +123,8 @@ async def test_non_net_consumption(hass):
assert state.state == '0' assert state.state == '0'
async def _test_self_reset(hass, cycle, start_time, expect_reset=True): def gen_config(cycle, offset=None):
"""Test energy sensor self reset.""" """Generate configuration."""
config = { config = {
'utility_meter': { 'utility_meter': {
'energy_bill': { 'energy_bill': {
@ -134,6 +134,16 @@ async def _test_self_reset(hass, cycle, start_time, expect_reset=True):
} }
} }
if offset:
config['utility_meter']['energy_bill']['offset'] = {
'days': offset.days,
'seconds': offset.seconds
}
return config
async def _test_self_reset(hass, config, start_time, expect_reset=True):
"""Test energy sensor self reset."""
assert await async_setup_component(hass, DOMAIN, config) assert await async_setup_component(hass, DOMAIN, config)
assert await async_setup_component(hass, SENSOR_DOMAIN, config) assert await async_setup_component(hass, SENSOR_DOMAIN, config)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -173,30 +183,50 @@ async def _test_self_reset(hass, cycle, start_time, expect_reset=True):
async def test_self_reset_hourly(hass): async def test_self_reset_hourly(hass):
"""Test hourly reset of meter.""" """Test hourly reset of meter."""
await _test_self_reset(hass, 'hourly', "2017-12-31T23:59:00.000000+00:00") await _test_self_reset(hass, gen_config('hourly'),
"2017-12-31T23:59:00.000000+00:00")
async def test_self_reset_daily(hass): async def test_self_reset_daily(hass):
"""Test daily reset of meter.""" """Test daily reset of meter."""
await _test_self_reset(hass, 'daily', "2017-12-31T23:59:00.000000+00:00") await _test_self_reset(hass, gen_config('daily'),
"2017-12-31T23:59:00.000000+00:00")
async def test_self_reset_weekly(hass): async def test_self_reset_weekly(hass):
"""Test weekly reset of meter.""" """Test weekly reset of meter."""
await _test_self_reset(hass, 'weekly', "2017-12-31T23:59:00.000000+00:00") await _test_self_reset(hass, gen_config('weekly'),
"2017-12-31T23:59:00.000000+00:00")
async def test_self_reset_monthly(hass): async def test_self_reset_monthly(hass):
"""Test monthly reset of meter.""" """Test monthly reset of meter."""
await _test_self_reset(hass, 'monthly', "2017-12-31T23:59:00.000000+00:00") await _test_self_reset(hass, gen_config('monthly'),
"2017-12-31T23:59:00.000000+00:00")
async def test_self_reset_yearly(hass): async def test_self_reset_yearly(hass):
"""Test yearly reset of meter.""" """Test yearly reset of meter."""
await _test_self_reset(hass, 'yearly', "2017-12-31T23:59:00.000000+00:00") await _test_self_reset(hass, gen_config('yearly'),
"2017-12-31T23:59:00.000000+00:00")
async def test_self_no_reset_yearly(hass): async def test_self_no_reset_yearly(hass):
"""Test yearly reset of meter does not occur after 1st January.""" """Test yearly reset of meter does not occur after 1st January."""
await _test_self_reset(hass, 'yearly', "2018-01-01T23:59:00.000000+00:00", await _test_self_reset(hass, gen_config('yearly'),
"2018-01-01T23:59:00.000000+00:00",
expect_reset=False)
async def test_reset_yearly_offset(hass):
"""Test yearly reset of meter."""
await _test_self_reset(hass,
gen_config('yearly', timedelta(days=1, minutes=10)),
"2018-01-02T00:09:00.000000+00:00")
async def test_no_reset_yearly_offset(hass):
"""Test yearly reset of meter."""
await _test_self_reset(hass, gen_config('yearly', timedelta(31)),
"2018-01-30T23:59:00.000000+00:00",
expect_reset=False) expect_reset=False)