Allows the utility_meter to net meter rather than only allow increases. (#21204)

* Allow the utility_meter to net meter rather than only allow increases.

* Fix PR issues around CI.

* Fix line length fallout.

* Change rollover to net_consumption.  Add unit tests.

* Fix test style issues.

* Fix style in tests.
This commit is contained in:
Justin Bassett 2019-02-23 09:02:39 -05:00 committed by Diogo Gomes
parent 616c7628d7
commit 02745be44d
4 changed files with 80 additions and 9 deletions

View File

@ -12,9 +12,9 @@ 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,
CONF_METER_TYPE, CONF_METER_OFFSET, CONF_METER_NET_CONSUMPTION,
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__)
@ -36,6 +36,7 @@ METER_CONFIG_SCHEMA = vol.Schema({
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_METER_NET_CONSUMPTION, default=False): cv.boolean,
vol.Optional(CONF_TARIFFS, default=[]): vol.All(
cv.ensure_list, [cv.string]),
})

View File

@ -15,6 +15,7 @@ CONF_METER = 'meter'
CONF_SOURCE_SENSOR = 'source'
CONF_METER_TYPE = 'cycle'
CONF_METER_OFFSET = 'offset'
CONF_METER_NET_CONSUMPTION = 'net_consumption'
CONF_PAUSED = 'paused'
CONF_TARIFFS = 'tariffs'
CONF_TARIFF = 'tariff'

View File

@ -17,7 +17,7 @@ from .const import (
DATA_UTILITY, SIGNAL_RESET_METER,
HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY,
CONF_SOURCE_SENSOR, CONF_METER_TYPE, CONF_METER_OFFSET,
CONF_TARIFF, CONF_TARIFF_ENTITY, CONF_METER)
CONF_METER_NET_CONSUMPTION, CONF_TARIFF, CONF_TARIFF_ENTITY, CONF_METER)
_LOGGER = logging.getLogger(__name__)
@ -48,13 +48,15 @@ async def async_setup_platform(
conf_meter_source = hass.data[DATA_UTILITY][meter][CONF_SOURCE_SENSOR]
conf_meter_type = hass.data[DATA_UTILITY][meter].get(CONF_METER_TYPE)
conf_meter_offset = hass.data[DATA_UTILITY][meter][CONF_METER_OFFSET]
conf_meter_net_consumption =\
hass.data[DATA_UTILITY][meter][CONF_METER_NET_CONSUMPTION]
conf_meter_tariff_entity = hass.data[DATA_UTILITY][meter].get(
CONF_TARIFF_ENTITY)
meters.append(UtilityMeterSensor(
conf_meter_source, conf.get(CONF_NAME), conf_meter_type,
conf_meter_offset, conf.get(CONF_TARIFF),
conf_meter_tariff_entity))
conf_meter_offset, conf_meter_net_consumption,
conf.get(CONF_TARIFF), conf_meter_tariff_entity))
async_add_entities(meters)
@ -62,8 +64,8 @@ async def async_setup_platform(
class UtilityMeterSensor(RestoreEntity):
"""Representation of an utility meter sensor."""
def __init__(self, source_entity, name, meter_type, meter_offset=0,
tariff=None, tariff_entity=None):
def __init__(self, source_entity, name, meter_type, meter_offset,
net_consumption, tariff=None, tariff_entity=None):
"""Initialize the Utility Meter sensor."""
self._sensor_source_id = source_entity
self._state = 0
@ -77,6 +79,7 @@ class UtilityMeterSensor(RestoreEntity):
self._unit_of_measurement = None
self._period = meter_type
self._period_offset = meter_offset
self._sensor_net_consumption = net_consumption
self._tariff = tariff
self._tariff_entity = tariff_entity
@ -96,7 +99,7 @@ class UtilityMeterSensor(RestoreEntity):
try:
diff = Decimal(new_state.state) - Decimal(old_state.state)
if diff < 0:
if (not self._sensor_net_consumption) and diff < 0:
# Source sensor just rolled over for unknow reasons,
return
self._state += diff

View File

@ -57,6 +57,72 @@ async def test_state(hass):
assert state.state == '1'
async def test_net_consumption(hass):
"""Test utility sensor state."""
config = {
'utility_meter': {
'energy_bill': {
'source': 'sensor.energy',
'net_consumption': True
}
}
}
assert await async_setup_component(hass, DOMAIN, config)
assert await async_setup_component(hass, SENSOR_DOMAIN, config)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
entity_id = config[DOMAIN]['energy_bill']['source']
hass.states.async_set(entity_id, 2, {"unit_of_measurement": "kWh"})
await hass.async_block_till_done()
now = dt_util.utcnow() + timedelta(seconds=10)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
hass.states.async_set(entity_id, 1, {"unit_of_measurement": "kWh"},
force_update=True)
await hass.async_block_till_done()
state = hass.states.get('sensor.energy_bill')
assert state is not None
assert state.state == '-1'
async def test_non_net_consumption(hass):
"""Test utility sensor state."""
config = {
'utility_meter': {
'energy_bill': {
'source': 'sensor.energy',
'net_consumption': False
}
}
}
assert await async_setup_component(hass, DOMAIN, config)
assert await async_setup_component(hass, SENSOR_DOMAIN, config)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
entity_id = config[DOMAIN]['energy_bill']['source']
hass.states.async_set(entity_id, 2, {"unit_of_measurement": "kWh"})
await hass.async_block_till_done()
now = dt_util.utcnow() + timedelta(seconds=10)
with patch('homeassistant.util.dt.utcnow',
return_value=now):
hass.states.async_set(entity_id, 1, {"unit_of_measurement": "kWh"},
force_update=True)
await hass.async_block_till_done()
state = hass.states.get('sensor.energy_bill')
assert state is not None
assert state.state == '0'
async def _test_self_reset(hass, cycle, start_time, expect_reset=True):
"""Test energy sensor self reset."""
config = {