diff --git a/custom_components/ev_smart_charging/const.py b/custom_components/ev_smart_charging/const.py index 3bb1f1d..849e8cd 100644 --- a/custom_components/ev_smart_charging/const.py +++ b/custom_components/ev_smart_charging/const.py @@ -34,6 +34,7 @@ # Entity names ENTITY_NAME_CHARGING_SENSOR = "Charging" +ENTITY_NAME_STATUS_SENSOR = "Status" ENTITY_NAME_ACTIVE_SWITCH = "Smart charging activated" ENTITY_NAME_APPLY_LIMIT_SWITCH = "Apply price limit" ENTITY_NAME_CONTINUOUS_SWITCH = "Continuous charging preferred" diff --git a/custom_components/ev_smart_charging/coordinator.py b/custom_components/ev_smart_charging/coordinator.py index 2037815..9f5428c 100644 --- a/custom_components/ev_smart_charging/coordinator.py +++ b/custom_components/ev_smart_charging/coordinator.py @@ -55,7 +55,11 @@ get_start_hour_utc, ) from .helpers.general import Validator, get_parameter, get_platform -from .sensor import EVSmartChargingSensor +from .sensor import ( + EVSmartChargingSensor, + EVSmartChargingSensorCharging, + EVSmartChargingSensorStatus, +) _LOGGER = logging.getLogger(__name__) @@ -71,6 +75,7 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: self.listeners = [] self.sensor = None + self.sensor_status = None self.switch_active = None self.switch_apply_limit = None self.switch_apply_limit_entity_id = None @@ -266,26 +271,35 @@ async def update_state( self.sensor.charging_number_of_hours = ( self.scheduler.get_charging_number_of_hours() ) - if self.auto_charging_state == STATE_ON: - self.sensor.charging_status = CHARGING_STATUS_CHARGING - else: - self.sensor.charging_status = CHARGING_STATUS_WAITING_CHARGING + if self.sensor_status: + if self.auto_charging_state == STATE_ON: + self.sensor_status.native_value = CHARGING_STATUS_CHARGING + else: + self.sensor_status.native_value = ( + CHARGING_STATUS_WAITING_CHARGING + ) else: _LOGGER.debug("Charging summary removed") self.sensor.charging_is_planned = False self.sensor.charging_start_time = None self.sensor.charging_stop_time = None self.sensor.charging_number_of_hours = 0 - if not self.switch_active: - self.sensor.charging_status = CHARGING_STATUS_NOT_ACTIVE - elif not self.switch_ev_connected: - self.sensor.charging_status = CHARGING_STATUS_DISCONNECTED - elif self.switch_keep_on and self.auto_charging_state == STATE_ON: - self.sensor.charging_status = CHARGING_STATUS_KEEP_ON - elif time_now.hour >= self.ready_hour_local and not self.tomorrow_valid: - self.sensor.charging_status = CHARGING_STATUS_WAITING_NEW_PRICE - else: - self.sensor.charging_status = CHARGING_STATUS_NO_PLAN + if self.sensor_status: + if not self.switch_active: + self.sensor_status.native_value = CHARGING_STATUS_NOT_ACTIVE + elif not self.switch_ev_connected: + self.sensor_status.native_value = CHARGING_STATUS_DISCONNECTED + elif self.switch_keep_on and self.auto_charging_state == STATE_ON: + self.sensor_status.native_value = CHARGING_STATUS_KEEP_ON + elif ( + time_now.hour >= self.ready_hour_local + and not self.tomorrow_valid + ): + self.sensor_status.native_value = ( + CHARGING_STATUS_WAITING_NEW_PRICE + ) + else: + self.sensor_status.native_value = CHARGING_STATUS_NO_PLAN self._charging_schedule = Scheduler.get_empty_schedule() self.sensor.charging_schedule = self._charging_schedule @@ -321,9 +335,13 @@ async def turn_off_charging(self): """Turn off charging""" await self.turn_on_charging(False) - async def add_sensor(self, sensor: EVSmartChargingSensor): + async def add_sensor(self, sensors: list[EVSmartChargingSensor]): """Set up sensor""" - self.sensor = sensor + for sensor in sensors: + if isinstance(sensor, EVSmartChargingSensorCharging): + self.sensor = sensor + if isinstance(sensor, EVSmartChargingSensorStatus): + self.sensor_status = sensor self.price_entity_id = get_parameter(self.config_entry, CONF_PRICE_SENSOR) self.price_adaptor.set_price_platform( diff --git a/custom_components/ev_smart_charging/sensor.py b/custom_components/ev_smart_charging/sensor.py index dc5dbff..6f70825 100644 --- a/custom_components/ev_smart_charging/sensor.py +++ b/custom_components/ev_smart_charging/sensor.py @@ -6,7 +6,13 @@ from homeassistant.const import STATE_OFF -from .const import DOMAIN, ENTITY_NAME_CHARGING_SENSOR, SENSOR +from .const import ( + CHARGING_STATUS_NOT_ACTIVE, + DOMAIN, + ENTITY_NAME_CHARGING_SENSOR, + ENTITY_NAME_STATUS_SENSOR, + SENSOR, +) from .entity import EVSmartChargingEntity _LOGGER = logging.getLogger(__name__) @@ -16,20 +22,40 @@ async def async_setup_entry(hass: HomeAssistant, entry, async_add_devices): """Setup sensor platform.""" _LOGGER.debug("EVSmartCharging.sensor.py") coordinator = hass.data[DOMAIN][entry.entry_id] - sensor = EVSmartChargingSensor(entry) - async_add_devices([sensor]) - await coordinator.add_sensor(sensor) + sensors = [] + sensors.append(EVSmartChargingSensorCharging(entry)) + sensors.append(EVSmartChargingSensorStatus(entry)) + async_add_devices(sensors) + await coordinator.add_sensor(sensors) class EVSmartChargingSensor(EVSmartChargingEntity, SensorEntity): """EV Smart Charging sensor class.""" + def __init__(self, entry): + _LOGGER.debug("EVSmartChargingSensor.__init__()") + super().__init__(entry) + id_name = self._attr_name.replace(" ", "").lower() + self._attr_unique_id = ".".join([entry.entry_id, SENSOR, id_name]) + + @SensorEntity.native_value.setter + def native_value(self, new_value): + """Set the value reported by the sensor.""" + self._attr_native_value = new_value + self.update_ha_state() + + +class EVSmartChargingSensorCharging(EVSmartChargingSensor): + """EV Smart Charging sensor class.""" + _attr_name = ENTITY_NAME_CHARGING_SENSOR def __init__(self, entry): _LOGGER.debug("EVSmartChargingSensor.__init__()") super().__init__(entry) - self._attr_unique_id = ".".join([entry.entry_id, SENSOR]) + self._attr_unique_id = ".".join( + [entry.entry_id, SENSOR] + ) # Keep to make it backward compatible. self._attr_native_value = STATE_OFF self._current_price = None @@ -42,13 +68,6 @@ def __init__(self, entry): self._charging_start_time = None self._charging_stop_time = None self._charging_number_of_hours = None - self._charging_status = None - - @SensorEntity.native_value.setter - def native_value(self, new_value): - """Return the value reported by the sensor.""" - self._attr_native_value = new_value - self.update_ha_state() @property def extra_state_attributes(self) -> dict: @@ -56,7 +75,6 @@ def extra_state_attributes(self) -> dict: "current_price": self._current_price, "EV SOC": self._ev_soc, "EV target SOC": self._ev_target_soc, - "Charging status": self._charging_status, "Charging is planned": self._charging_is_planned, "Charging start time": self._charging_start_time, "Charging stop time": self._charging_stop_time, @@ -115,16 +133,6 @@ def charging_schedule(self, new_value): self._charging_schedule = new_value self.update_ha_state() - @property - def charging_status(self): - """Getter for charging_status.""" - return self._charging_status - - @charging_status.setter - def charging_status(self, new_value): - self._charging_status = new_value - self.update_ha_state() - @property def charging_is_planned(self): """Getter for charging_is_planned.""" @@ -164,3 +172,15 @@ def charging_number_of_hours(self): def charging_number_of_hours(self, new_value): self._charging_number_of_hours = new_value self.update_ha_state() + + +class EVSmartChargingSensorStatus(EVSmartChargingSensor): + """EV Smart Charging sensor class.""" + + _attr_name = ENTITY_NAME_STATUS_SENSOR + + def __init__(self, entry): + _LOGGER.debug("EVSmartChargingSensorStatus.__init__()") + super().__init__(entry) + + self._attr_native_value = CHARGING_STATUS_NOT_ACTIVE diff --git a/tests/coordinator/test_coordinator.py b/tests/coordinator/test_coordinator.py index 1868426..a68ed92 100644 --- a/tests/coordinator/test_coordinator.py +++ b/tests/coordinator/test_coordinator.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -24,6 +24,7 @@ from tests.price import PRICE_20220930, PRICE_20221001 from tests.const import MOCK_CONFIG_ALL, MOCK_CONFIG_MIN_SOC, MOCK_CONFIG_NO_TARGET_SOC + # pylint: disable=unused-argument async def test_coordinator( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -45,9 +46,9 @@ async def test_coordinator( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) assert coordinator.ev_target_soc == 100 @@ -56,9 +57,9 @@ async def test_coordinator( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) assert coordinator.ev_target_soc == 80 await coordinator.turn_on_charging() @@ -168,9 +169,9 @@ async def test_coordinator_min_soc1( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -229,9 +230,9 @@ async def test_coordinator_min_soc2( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -317,9 +318,9 @@ async def test_coordinator_fix_soc( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) assert coordinator.ev_target_soc == 80 # Provide price diff --git a/tests/coordinator/test_coordinator_keep_on.py b/tests/coordinator/test_coordinator_keep_on.py index 9274309..9071313 100644 --- a/tests/coordinator/test_coordinator_keep_on.py +++ b/tests/coordinator/test_coordinator_keep_on.py @@ -11,7 +11,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -25,6 +25,7 @@ MOCK_CONFIG_KEEP_ON2, ) + # pylint: disable=unused-argument async def test_coordinator_keep_on1( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -49,9 +50,9 @@ async def test_coordinator_keep_on1( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -92,6 +93,13 @@ async def test_coordinator_keep_on1( assert coordinator.auto_charging_state == STATE_OFF assert coordinator.sensor.state == STATE_OFF + # Move time to after completion time + freezer.move_to("2022-10-01T10:30:00+02:00") + await coordinator.update_sensors() + await hass.async_block_till_done() + assert coordinator.auto_charging_state == STATE_OFF + assert coordinator.sensor.state == STATE_OFF + # Move back time to recreate the schedule freezer.move_to("2022-09-30T20:00:00+02:00") MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -126,6 +134,18 @@ async def test_coordinator_keep_on1( assert coordinator.auto_charging_state == STATE_ON assert coordinator.sensor.state == STATE_ON + # Loose some charge + MockSOCEntity.set_state(hass, "79") + await coordinator.update_sensors() + await hass.async_block_till_done() + + # Move time to after completion time + freezer.move_to("2022-10-01T10:30:00+02:00") + await coordinator.update_sensors() + await hass.async_block_till_done() + assert coordinator.auto_charging_state == STATE_ON + assert coordinator.sensor.state == STATE_ON + async def test_coordinator_keep_on2( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -150,9 +170,9 @@ async def test_coordinator_keep_on2( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -202,9 +222,9 @@ async def test_coordinator_keep_on2( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -269,9 +289,9 @@ async def test_coordinator_keep_on3( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -367,9 +387,9 @@ async def test_coordinator_keep_on4( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -538,9 +558,9 @@ async def test_coordinator_keep_on5( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -656,9 +676,9 @@ async def test_coordinator_keep_on6( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) diff --git a/tests/coordinator/test_coordinator_keep_on2.py b/tests/coordinator/test_coordinator_keep_on2.py index 5d52779..7f74ec6 100644 --- a/tests/coordinator/test_coordinator_keep_on2.py +++ b/tests/coordinator/test_coordinator_keep_on2.py @@ -12,7 +12,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -26,6 +26,7 @@ MOCK_CONFIG_KEEP_ON2, ) + # pylint: disable=unused-argument async def test_coordinator_keep_on_get_entities( hass: HomeAssistant, set_cet_timezone, freezer @@ -116,9 +117,9 @@ async def test_coordinator_keep_on_schedule( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -214,9 +215,9 @@ async def test_coordinator_keep_on_connect( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -368,9 +369,9 @@ async def test_coordinator_keep_on_connect2( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) @@ -486,9 +487,9 @@ async def test_coordinator_keep_on_connect3( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await coordinator.update_sensors() await hass.async_block_till_done() assert coordinator.tomorrow_valid diff --git a/tests/coordinator/test_coordinator_late_ready.py b/tests/coordinator/test_coordinator_late_ready.py index cb58895..774b2b4 100644 --- a/tests/coordinator/test_coordinator_late_ready.py +++ b/tests/coordinator/test_coordinator_late_ready.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -24,6 +24,7 @@ from tests.price import PRICE_20220930, PRICE_20221001, PRICE_20221002 from tests.const import MOCK_CONFIG_LATE, MOCK_CONFIG_LATE24 + # pylint: disable=unused-argument async def test_coordinator_late_ready( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -46,9 +47,9 @@ async def test_coordinator_late_ready( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price. This should give a 12:00-17:00 schedule await coordinator.update_sensors() @@ -224,9 +225,9 @@ async def test_coordinator_late_ready2( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price. This should give a 5h schedule, 19:00-24:00 schedule await coordinator.update_sensors() @@ -290,9 +291,9 @@ async def test_coordinator_late_ready3( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price. await coordinator.update_sensors() diff --git a/tests/coordinator/test_coordinator_no_ready.py b/tests/coordinator/test_coordinator_no_ready.py index aef8e8b..e3a819b 100644 --- a/tests/coordinator/test_coordinator_no_ready.py +++ b/tests/coordinator/test_coordinator_no_ready.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -24,6 +24,7 @@ from tests.price import PRICE_20220930, PRICE_20221001 from tests.const import MOCK_CONFIG_NO_READY + # pylint: disable=unused-argument async def test_coordinator_no_ready( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -46,9 +47,9 @@ async def test_coordinator_no_ready( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price. This should give a 5h schedule, 19:00-24:00 await coordinator.update_sensors() @@ -127,9 +128,9 @@ async def test_coordinator_no_ready2( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) # Provide price. This should give a 5h schedule, 19:00-24:00 await coordinator.update_sensors() diff --git a/tests/coordinator/test_coordinator_reschedule.py b/tests/coordinator/test_coordinator_reschedule.py index 181eda1..14e6c1e 100644 --- a/tests/coordinator/test_coordinator_reschedule.py +++ b/tests/coordinator/test_coordinator_reschedule.py @@ -16,7 +16,7 @@ from custom_components.ev_smart_charging.const import ( DOMAIN, ) -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.const import MOCK_CONFIG_ALL from tests.helpers.helpers import ( @@ -27,6 +27,7 @@ ) from tests.price import PRICE_20220930, PRICE_20221001 + # pylint: disable=unused-argument @freeze_time("2022-09-30T05:59:50+02:00", tick=True) async def test_coordinator_reschedule( @@ -47,9 +48,9 @@ async def test_coordinator_reschedule( config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG_ALL, entry_id="test") coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) coordinator.ready_hour_local = 8 await hass.async_block_till_done() await coordinator.switch_active_update(True) diff --git a/tests/coordinator/test_coordinator_start_hour_both_same.py b/tests/coordinator/test_coordinator_start_hour_both_same.py index ce94855..dfdd309 100644 --- a/tests/coordinator/test_coordinator_start_hour_both_same.py +++ b/tests/coordinator/test_coordinator_start_hour_both_same.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -27,6 +27,7 @@ MOCK_CONFIG_START_HOUR_3B, ) + # pylint: disable=unused-argument async def test_coordinator_start_hour_both_same_3a( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -54,9 +55,9 @@ async def test_coordinator_start_hour_both_same_3a( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) @@ -140,9 +141,9 @@ async def test_coordinator_start_hour_both_same_3b( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) diff --git a/tests/coordinator/test_coordinator_start_hour_end_before_start.py b/tests/coordinator/test_coordinator_start_hour_end_before_start.py index a658253..759f302 100644 --- a/tests/coordinator/test_coordinator_start_hour_end_before_start.py +++ b/tests/coordinator/test_coordinator_start_hour_end_before_start.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -28,6 +28,7 @@ MOCK_CONFIG_START_HOUR_2C, ) + # pylint: disable=unused-argument async def test_coordinator_start_hour_end_before_start_2a( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -57,9 +58,9 @@ async def test_coordinator_start_hour_end_before_start_2a( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) @@ -164,9 +165,9 @@ async def test_coordinator_start_hour_end_before_start_2b( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) @@ -271,9 +272,9 @@ async def test_coordinator_start_hour_end_before_start_2c( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) diff --git a/tests/coordinator/test_coordinator_start_hour_only_start.py b/tests/coordinator/test_coordinator_start_hour_only_start.py index 6974e41..412335d 100644 --- a/tests/coordinator/test_coordinator_start_hour_only_start.py +++ b/tests/coordinator/test_coordinator_start_hour_only_start.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -27,6 +27,7 @@ MOCK_CONFIG_START_HOUR_4B, ) + # pylint: disable=unused-argument async def test_coordinator_start_hour_only_start_4a( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -54,9 +55,9 @@ async def test_coordinator_start_hour_only_start_4a( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) @@ -144,9 +145,9 @@ async def test_coordinator_start_hour_only_start_4b( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) diff --git a/tests/coordinator/test_coordinator_start_hour_start_before_end.py b/tests/coordinator/test_coordinator_start_hour_start_before_end.py index c441163..f90e82d 100644 --- a/tests/coordinator/test_coordinator_start_hour_start_before_end.py +++ b/tests/coordinator/test_coordinator_start_hour_start_before_end.py @@ -13,7 +13,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -28,6 +28,7 @@ MOCK_CONFIG_START_HOUR_1C, ) + # pylint: disable=unused-argument async def test_coordinator_start_hour_start_before_end_1a( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -57,9 +58,9 @@ async def test_coordinator_start_hour_start_before_end_1a( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) @@ -164,9 +165,9 @@ async def test_coordinator_start_hour_start_before_end_1b( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) @@ -275,9 +276,9 @@ async def test_coordinator_start_hour_start_before_end_1c( ) coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await hass.async_block_till_done() await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(False) diff --git a/tests/coordinator/test_coordinator_status.py b/tests/coordinator/test_coordinator_status.py index 75e4552..c62f003 100644 --- a/tests/coordinator/test_coordinator_status.py +++ b/tests/coordinator/test_coordinator_status.py @@ -20,7 +20,10 @@ CHARGING_STATUS_WAITING_NEW_PRICE, DOMAIN, ) -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import ( + EVSmartChargingSensorCharging, + EVSmartChargingSensorStatus, +) from tests.const import MOCK_CONFIG_ALL from tests.helpers.helpers import ( @@ -31,6 +34,7 @@ ) from tests.price import PRICE_20220930, PRICE_20221001 + # pylint: disable=unused-argument async def test_coordinator_status( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -58,9 +62,12 @@ async def test_coordinator_status( config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG_ALL, entry_id="test") coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) - assert sensor is not None - await coordinator.add_sensor(sensor) + sensors = [] + sensors.append(EVSmartChargingSensorCharging(config_entry)) + sensors.append(EVSmartChargingSensorStatus(config_entry)) + assert sensors[0] is not None + assert sensors[1] is not None + await coordinator.add_sensor(sensors) await hass.async_block_till_done() await coordinator.switch_active_update(False) await coordinator.switch_apply_limit_update(False) @@ -69,37 +76,37 @@ async def test_coordinator_status( await coordinator.switch_keep_on_update(False) await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_NOT_ACTIVE + assert coordinator.sensor_status.native_value == CHARGING_STATUS_NOT_ACTIVE await coordinator.switch_active_update(True) await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_DISCONNECTED + assert coordinator.sensor_status.native_value == CHARGING_STATUS_DISCONNECTED await coordinator.switch_ev_connected_update(True) await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_NO_PLAN + assert coordinator.sensor_status.native_value == CHARGING_STATUS_NO_PLAN freezer.move_to("2022-09-30T11:00:00+02:00") await coordinator.update_sensors() await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_WAITING_NEW_PRICE + assert coordinator.sensor_status.native_value == CHARGING_STATUS_WAITING_NEW_PRICE freezer.move_to("2022-09-30T14:00:00+02:00") MockPriceEntity.set_state(hass, PRICE_20220930, PRICE_20221001) await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_NO_PLAN + assert coordinator.sensor_status.native_value == CHARGING_STATUS_NO_PLAN # Ready hour 08:00. Charge 04:00-07:00 MockSOCEntity.set_state(hass, "67") await coordinator.switch_keep_on_update(True) await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_WAITING_CHARGING + assert coordinator.sensor_status.native_value == CHARGING_STATUS_WAITING_CHARGING freezer.move_to("2022-10-01T04:00:00+02:00") MockPriceEntity.set_state(hass, PRICE_20221001, None) await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_CHARGING + assert coordinator.sensor_status.native_value == CHARGING_STATUS_CHARGING MockSOCEntity.set_state(hass, "80") await hass.async_block_till_done() - assert coordinator.sensor.charging_status == CHARGING_STATUS_KEEP_ON + assert coordinator.sensor_status.native_value == CHARGING_STATUS_KEEP_ON diff --git a/tests/test_daylight_saving.py b/tests/test_daylight_saving.py index b345e8d..8ca6aea 100644 --- a/tests/test_daylight_saving.py +++ b/tests/test_daylight_saving.py @@ -13,7 +13,7 @@ ) from custom_components.ev_smart_charging.const import DOMAIN from custom_components.ev_smart_charging.helpers.coordinator import Raw -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -31,6 +31,7 @@ ) from .const import MOCK_CONFIG_ALL + # pylint: disable=unused-argument async def test_to_daylight_saving_time( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -49,9 +50,9 @@ async def test_to_daylight_saving_time( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(True) await coordinator.switch_continuous_update(True) @@ -170,9 +171,9 @@ async def test_from_daylight_saving_time( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await coordinator.switch_active_update(True) await coordinator.switch_apply_limit_update(True) await coordinator.switch_continuous_update(True) diff --git a/tests/test_external_issues.py b/tests/test_external_issues.py index 55046aa..194fbed 100644 --- a/tests/test_external_issues.py +++ b/tests/test_external_issues.py @@ -11,7 +11,7 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import DOMAIN -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import EVSmartChargingSensorCharging from tests.helpers.helpers import ( MockChargerEntity, @@ -22,6 +22,7 @@ from tests.price import PRICE_20221001 from tests.const import MOCK_CONFIG_ALL + # pylint: disable=unused-argument async def test_external_issue_nordpool_235( hass: HomeAssistant, skip_service_calls, set_cet_timezone, freezer @@ -46,9 +47,9 @@ async def test_external_issue_nordpool_235( coordinator = EVSmartChargingCoordinator(hass, config_entry) assert coordinator is not None - sensor: EVSmartChargingSensor = EVSmartChargingSensor(config_entry) + sensor: EVSmartChargingSensorCharging = EVSmartChargingSensorCharging(config_entry) assert sensor is not None - await coordinator.add_sensor(sensor) + await coordinator.add_sensor([sensor]) await coordinator.update_sensors() await hass.async_block_till_done() diff --git a/tests/test_sensor.py b/tests/test_sensor.py index b09b7c9..f02deab 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -13,10 +13,14 @@ EVSmartChargingCoordinator, ) from custom_components.ev_smart_charging.const import ( + CHARGING_STATUS_CHARGING, CHARGING_STATUS_WAITING_CHARGING, DOMAIN, ) -from custom_components.ev_smart_charging.sensor import EVSmartChargingSensor +from custom_components.ev_smart_charging.sensor import ( + EVSmartChargingSensorCharging, + EVSmartChargingSensorStatus, +) from .const import MOCK_CONFIG_ALL @@ -27,6 +31,7 @@ # Assertions allow you to verify that the return value of whatever is on the left # side of the assertion matches with the right side. + # pylint: disable=unused-argument async def test_sensor(hass, bypass_validate_input_sensors): """Test sensor properties.""" @@ -45,9 +50,13 @@ async def test_sensor(hass, bypass_validate_input_sensors): ) coordinator = hass.data[DOMAIN][config_entry.entry_id] assert coordinator.sensor is not None - assert isinstance(coordinator.sensor, EVSmartChargingSensor) + assert isinstance(coordinator.sensor, EVSmartChargingSensorCharging) sensor = coordinator.sensor + assert coordinator.sensor_status is not None + assert isinstance(coordinator.sensor_status, EVSmartChargingSensorStatus) + sensor_status = coordinator.sensor_status + # Test the sensor sensor.native_value = STATE_OFF assert sensor.native_value == STATE_OFF @@ -71,9 +80,6 @@ async def test_sensor(hass, bypass_validate_input_sensors): sensor.charging_schedule = one_list assert sensor.charging_schedule == one_list - sensor.charging_status = CHARGING_STATUS_WAITING_CHARGING - assert sensor.charging_status == CHARGING_STATUS_WAITING_CHARGING - sensor.charging_is_planned = True assert sensor.charging_is_planned is True @@ -98,7 +104,6 @@ async def test_sensor(hass, bypass_validate_input_sensors): assert extra["current_price"] == 12.1 assert extra["EV SOC"] == 56 assert extra["EV target SOC"] == 80 - assert extra["Charging status"] == CHARGING_STATUS_WAITING_CHARGING assert extra["Charging is planned"] is True assert extra["Charging start time"] == datetime( 2022, 9, 30, 1, 0, tzinfo=ZoneInfo(key="Europe/Stockholm") @@ -108,6 +113,12 @@ async def test_sensor(hass, bypass_validate_input_sensors): ) assert extra["Charging number of hours"] == 4 + # Test sensor_status + sensor_status.native_value = CHARGING_STATUS_WAITING_CHARGING + assert sensor_status.native_value == CHARGING_STATUS_WAITING_CHARGING + sensor_status.native_value = CHARGING_STATUS_CHARGING + assert sensor_status.native_value == CHARGING_STATUS_CHARGING + # Unload the entry and verify that the data has been removed assert await async_unload_entry(hass, config_entry) assert config_entry.entry_id not in hass.data[DOMAIN]