From 02745be44d3558573b2a337764f3de7d8c63e5b3 Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Sat, 23 Feb 2019 09:02:39 -0500 Subject: [PATCH] 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. --- .../components/utility_meter/__init__.py | 7 +- .../components/utility_meter/const.py | 1 + .../components/utility_meter/sensor.py | 15 +++-- tests/components/utility_meter/test_sensor.py | 66 +++++++++++++++++++ 4 files changed, 80 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py index 3cf1b2fea61..2f062851ee6 100644 --- a/homeassistant/components/utility_meter/__init__.py +++ b/homeassistant/components/utility_meter/__init__.py @@ -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]), }) diff --git a/homeassistant/components/utility_meter/const.py b/homeassistant/components/utility_meter/const.py index 4d2df0372b5..c5cb6b8aa33 100644 --- a/homeassistant/components/utility_meter/const.py +++ b/homeassistant/components/utility_meter/const.py @@ -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' diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index a01c53b20e3..21dc1099442 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -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 diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py index 23fc8872570..03c95fdf897 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -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 = {