From 5cd08f7db393d7362b1a8d2f55ec31256e41582c Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Mon, 18 Feb 2019 22:03:43 -0500 Subject: [PATCH 1/6] Allow the utility_meter to net meter rather than only allow increases. --- homeassistant/components/utility_meter/__init__.py | 8 ++++---- homeassistant/components/utility_meter/const.py | 1 + homeassistant/components/utility_meter/sensor.py | 11 +++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py index 3cf1b2fea6190..7b197b4cb7b96 100644 --- a/homeassistant/components/utility_meter/__init__.py +++ b/homeassistant/components/utility_meter/__init__.py @@ -12,10 +12,9 @@ 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) + CONF_METER_TYPE, CONF_METER_OFFSET, CONF_METER_ROLLOVER, 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 +35,7 @@ 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_ROLLOVER, default=True): 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 4d2df0372b5c6..79eb89e945ab1 100644 --- a/homeassistant/components/utility_meter/const.py +++ b/homeassistant/components/utility_meter/const.py @@ -15,6 +15,7 @@ CONF_SOURCE_SENSOR = 'source' CONF_METER_TYPE = 'cycle' CONF_METER_OFFSET = 'offset' +CONF_METER_ROLLOVER = 'rollover' 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 a01c53b20e345..b4552d7f3d6d3 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -17,7 +17,7 @@ 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_ROLLOVER, CONF_TARIFF, CONF_TARIFF_ENTITY, CONF_METER) _LOGGER = logging.getLogger(__name__) @@ -48,12 +48,14 @@ 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_rollover = hass.data[DATA_UTILITY][meter] + [CONF_METER_ROLLOVER] 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_offset, conf_meter_rollover, conf.get(CONF_TARIFF), conf_meter_tariff_entity)) async_add_entities(meters) @@ -63,7 +65,7 @@ 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): + rollover=True, tariff=None, tariff_entity=None): """Initialize the Utility Meter sensor.""" self._sensor_source_id = source_entity self._state = 0 @@ -77,6 +79,7 @@ def __init__(self, source_entity, name, meter_type, meter_offset=0, self._unit_of_measurement = None self._period = meter_type self._period_offset = meter_offset + self._sensor_rollsover = rollover self._tariff = tariff self._tariff_entity = tariff_entity @@ -96,7 +99,7 @@ def async_reading(self, entity, old_state, new_state): try: diff = Decimal(new_state.state) - Decimal(old_state.state) - if diff < 0: + if self._sensor_rollsover and diff < 0: # Source sensor just rolled over for unknow reasons, return self._state += diff From 2b6267b76d8cb228356796795b12fef5412bc732 Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Mon, 18 Feb 2019 22:34:20 -0500 Subject: [PATCH 2/6] Fix PR issues around CI. --- homeassistant/components/utility_meter/__init__.py | 7 ++++--- homeassistant/components/utility_meter/sensor.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py index 7b197b4cb7b96..107649229a5cd 100644 --- a/homeassistant/components/utility_meter/__init__.py +++ b/homeassistant/components/utility_meter/__init__.py @@ -12,9 +12,10 @@ 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_METER_ROLLOVER, CONF_TARIFF_ENTITY, - CONF_TARIFF, CONF_TARIFFS, CONF_METER, DATA_UTILITY, SERVICE_RESET, - SERVICE_SELECT_TARIFF, SERVICE_SELECT_NEXT_TARIFF, ATTR_TARIFF) + CONF_METER_TYPE, CONF_METER_OFFSET, CONF_METER_ROLLOVER, + 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__) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index b4552d7f3d6d3..d18a9b39d9ea5 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -48,7 +48,7 @@ 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_rollover = hass.data[DATA_UTILITY][meter] + conf_meter_rollover = hass.data[DATA_UTILITY][meter]\ [CONF_METER_ROLLOVER] conf_meter_tariff_entity = hass.data[DATA_UTILITY][meter].get( CONF_TARIFF_ENTITY) From 67e66ac2a40004b0c1a44fde8489ccfd47818719 Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Mon, 18 Feb 2019 22:39:27 -0500 Subject: [PATCH 3/6] Fix line length fallout. --- homeassistant/components/utility_meter/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index d18a9b39d9ea5..83478336233bc 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -48,8 +48,8 @@ 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_rollover = hass.data[DATA_UTILITY][meter]\ - [CONF_METER_ROLLOVER] + conf_meter_rollover =\ + hass.data[DATA_UTILITY][meter][CONF_METER_ROLLOVER] conf_meter_tariff_entity = hass.data[DATA_UTILITY][meter].get( CONF_TARIFF_ENTITY) From 7ec29cb0208995c1ce0aa9abf03a741434a3e8b2 Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Wed, 20 Feb 2019 15:27:13 -0500 Subject: [PATCH 4/6] Change rollover to net_consumption. Add unit tests. --- .../components/utility_meter/__init__.py | 4 +- .../components/utility_meter/const.py | 2 +- .../components/utility_meter/sensor.py | 18 +++--- tests/components/utility_meter/test_sensor.py | 63 +++++++++++++++++++ 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py index 107649229a5cd..2f062851ee6df 100644 --- a/homeassistant/components/utility_meter/__init__.py +++ b/homeassistant/components/utility_meter/__init__.py @@ -12,7 +12,7 @@ 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_METER_ROLLOVER, + 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) @@ -36,7 +36,7 @@ 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_ROLLOVER, default=True): cv.boolean, + 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 79eb89e945ab1..c5cb6b8aa33ee 100644 --- a/homeassistant/components/utility_meter/const.py +++ b/homeassistant/components/utility_meter/const.py @@ -15,7 +15,7 @@ CONF_SOURCE_SENSOR = 'source' CONF_METER_TYPE = 'cycle' CONF_METER_OFFSET = 'offset' -CONF_METER_ROLLOVER = 'rollover' +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 83478336233bc..21dc1099442af 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -17,7 +17,7 @@ DATA_UTILITY, SIGNAL_RESET_METER, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY, CONF_SOURCE_SENSOR, CONF_METER_TYPE, CONF_METER_OFFSET, - CONF_METER_ROLLOVER, CONF_TARIFF, CONF_TARIFF_ENTITY, CONF_METER) + CONF_METER_NET_CONSUMPTION, CONF_TARIFF, CONF_TARIFF_ENTITY, CONF_METER) _LOGGER = logging.getLogger(__name__) @@ -48,15 +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_rollover =\ - hass.data[DATA_UTILITY][meter][CONF_METER_ROLLOVER] + 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_meter_rollover, 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) @@ -64,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, - rollover=True, 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 @@ -79,7 +79,7 @@ def __init__(self, source_entity, name, meter_type, meter_offset=0, self._unit_of_measurement = None self._period = meter_type self._period_offset = meter_offset - self._sensor_rollsover = rollover + self._sensor_net_consumption = net_consumption self._tariff = tariff self._tariff_entity = tariff_entity @@ -99,7 +99,7 @@ def async_reading(self, entity, old_state, new_state): try: diff = Decimal(new_state.state) - Decimal(old_state.state) - if self._sensor_rollsover and 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 23fc8872570cd..a914270763ed1 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -56,6 +56,69 @@ 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.""" From b38c32b7d7f1797ee7c9daae0836f23b0ae70752 Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Wed, 20 Feb 2019 15:41:13 -0500 Subject: [PATCH 5/6] Fix test style issues. --- tests/components/utility_meter/test_sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py index a914270763ed1..ac96a5b39edf7 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -56,6 +56,7 @@ async def test_state(hass): assert state.state == '1' + async def test_net_consumption(hass): """Test utility sensor state.""" config = { @@ -88,6 +89,7 @@ async def test_net_consumption(hass): assert state.state == '-1' + async def test_non_net_consumption(hass): """Test utility sensor state.""" config = { From dd09d6d6edd52e07e09854d25ca3e796d6afb0fa Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Thu, 21 Feb 2019 10:25:50 -0500 Subject: [PATCH 6/6] Fix style in tests. --- tests/components/utility_meter/test_sensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py index ac96a5b39edf7..03c95fdf8971a 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -122,6 +122,7 @@ async def test_non_net_consumption(hass): assert state.state == '0' + async def _test_self_reset(hass, cycle, start_time, expect_reset=True): """Test energy sensor self reset.""" config = {