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:
parent
54895fcb1e
commit
8e9a496002
3 changed files with 61 additions and 24 deletions
|
@ -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]),
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue