Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean removal of entities #74

Merged
merged 21 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e978d7a
Fixed error when config contains sensor names that have been removed
Sep 29, 2020
ee2aebf
Introduced intention bug fixed
Sep 30, 2020
2003838
Sync with upstream
Oct 7, 2020
b5d19e2
binary_sensor added to links.sh
Oct 7, 2020
b92970c
Merge diff
Oct 8, 2020
f60d793
Merge branch 'master' of https://github.com/fondberg/easee_hass
Oct 14, 2020
ca02f73
Merge branch 'master' of https://github.com/fondberg/easee_hass
Oct 14, 2020
1e90f07
Merge branch 'master' of https://github.com/fondberg/easee_hass
Oct 16, 2020
bdc8624
Merge branch 'master' of https://github.com/fondberg/easee_hass
Oct 19, 2020
5052d25
Correct spelling mistake in HACS json file
Oct 19, 2020
087fe44
Remove unused dependency
astrandb Oct 21, 2020
272adf6
Proof of concept - Removal of entities
astrandb Oct 21, 2020
486b18d
Validate options: minimun one monitored site
astrandb Oct 22, 2020
df611e5
Fix nb translation
astrandb Oct 22, 2020
b32278d
Clean up after deleting consumption sensors
astrandb Oct 22, 2020
3fe0d85
Merge branch 'master' of https://github.com/fondberg/easee_hass
Oct 23, 2020
c371ea2
Merge branch 'astrandb-WIP' of https://github.com/fondberg/easee_hass…
Oct 23, 2020
62b0fdd
Remove duplicate sensors, if any
astrandb Oct 23, 2020
4c63a39
Merge branch 'astrandb-WIP' of https://github.com/fondberg/easee_hass…
Oct 23, 2020
cef8b41
Fixed equalizer entity removal
Oct 24, 2020
313ed4b
Merge pull request #76 from olalid/removal_of_entities
olalid Oct 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion custom_components/easee/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from .const import (
DOMAIN,
EASEE_ENTITIES,
LISTENER_FN_CLOSE,
MEASURED_CONSUMPTION_DAYS,
VERSION,
Expand Down
29 changes: 20 additions & 9 deletions custom_components/easee/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@

from .const import (
DOMAIN,
CONSUMPTION_DAYS_PREFIX,
MEASURED_CONSUMPTION_DAYS,
MEASURED_CONSUMPTION_OPTIONS,
CUSTOM_UNITS,
CUSTOM_UNITS_OPTIONS,
EASEE_ENTITIES,
OPTIONAL_EASEE_ENTITIES,
MANDATORY_EASEE_ENTITIES,
EASEE_EQ_ENTITIES,
CONF_MONITORED_SITES,
CONF_MONITORED_EQ_CONDITIONS,
Expand Down Expand Up @@ -101,14 +103,18 @@ def __init__(self, config_entry):

async def async_step_init(self, user_input=None):
"""Manage the options."""
if user_input is not None:
self.options.update(user_input)
return await self._update_options()

constroller = self.hass.data[DOMAIN]["controller"]
sensor_multi_select = {x: x for x in list(EASEE_ENTITIES)}
errors = {}
if user_input is not None:
if len(user_input[CONF_MONITORED_SITES]) == 0:
errors["base"] = "no_sites"
else:
self.options.update(user_input)
return await self._update_options()
controller = self.hass.data[DOMAIN]["controller"]
sensor_multi_select = {x: x for x in list(OPTIONAL_EASEE_ENTITIES)}
sensor_eq_multi_select = {x: x for x in list(EASEE_EQ_ENTITIES)}
sites: List[Site] = constroller.get_sites()
sites: List[Site] = controller.get_sites()
sites_multi_select = []
for site in sites:
sites_multi_select.append(site["name"])
Expand All @@ -126,7 +132,7 @@ async def async_step_init(self, user_input=None):
vol.Optional(
CONF_MONITORED_CONDITIONS,
default=self.config_entry.options.get(
CONF_MONITORED_CONDITIONS, ["status"]
CONF_MONITORED_CONDITIONS, []
),
): cv.multi_select(sensor_multi_select),
vol.Optional(
Expand All @@ -147,16 +153,21 @@ async def async_step_init(self, user_input=None):
): cv.multi_select(CUSTOM_UNITS_OPTIONS),
}
),
errors=errors,
)

async def _update_options(self):
for x in self.options[CONF_MONITORED_CONDITIONS]:
if x in MANDATORY_EASEE_ENTITIES:
del self.options[CONF_MONITORED_CONDITIONS][x]
"""Update config entry options."""
self.hass.data[DOMAIN]["entities_to_remove"] = [cond for cond in self.prev_options.get(CONF_MONITORED_CONDITIONS, {})
if cond not in self.options[CONF_MONITORED_CONDITIONS]]
self.hass.data[DOMAIN]["eq_entities_to_remove"] = [cond for cond in self.prev_options.get(CONF_MONITORED_EQ_CONDITIONS, {})
if cond not in self.options[CONF_MONITORED_EQ_CONDITIONS]]
self.hass.data[DOMAIN]["sites_to_remove"] = [cond for cond in self.prev_options.get(CONF_MONITORED_SITES, {})
if cond not in self.options[CONF_MONITORED_SITES]]
self.hass.data[DOMAIN]["days_to_remove"] = [cond for cond in self.prev_options.get(MEASURED_CONSUMPTION_DAYS, {})
self.hass.data[DOMAIN]["days_to_remove"] = [f"{CONSUMPTION_DAYS_PREFIX}{cond}" for cond in self.prev_options.get(MEASURED_CONSUMPTION_DAYS, {})
if cond not in self.options[MEASURED_CONSUMPTION_DAYS]]
_LOGGER.debug("Days_to_remove: %s", self.hass.data[DOMAIN]["days_to_remove"])
return self.async_create_entry(title="", data=self.options)
51 changes: 27 additions & 24 deletions custom_components/easee/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
CONF_MONITORED_SITES = "monitored_sites"
CONF_MONITORED_EQ_CONDITIONS = "monitored_eq_conditions"
CUSTOM_UNITS = "custom_units"
CONSUMPTION_DAYS_PREFIX = "consumption_days_"
PLATFORMS = ("sensor", "switch", "binary_sensor")
LISTENER_FN_CLOSE = "update_listener_close_fn"
MEASURED_CONSUMPTION_OPTIONS = {
Expand All @@ -44,7 +45,32 @@
POWER_KILO_WATT: POWER_WATT,
ENERGY_KILO_WATT_HOUR: ENERGY_WATT_HOUR,
}
EASEE_ENTITIES = {
MANDATORY_EASEE_ENTITIES = {
"status": {
"key": "state.chargerOpMode",
"attrs": [
"config.phaseMode",
"state.outputPhase",
"state.ledMode",
"state.cableRating",
"config.authorizationRequired",
"config.limitToSinglePhaseCharging",
"config.localNodeType",
"config.localAuthorizationRequired",
"config.ledStripBrightness",
"site.id",
"site.name",
"site.siteKey",
"circuit.id",
"circuit.ratedCurrent",
],
"units": None,
"convert_units_func": None,
"device_class": "easee_status",
"icon": "mdi:ev-station",
},
}
OPTIONAL_EASEE_ENTITIES = {
"smart_charging": {
"type": "switch",
"key": "state.smartCharging",
Expand Down Expand Up @@ -81,29 +107,6 @@
"icon": "mdi:lock",
"switch_func": "lockCablePermanently",
},
"status": {
"key": "state.chargerOpMode",
"attrs": [
"config.phaseMode",
"state.outputPhase",
"state.ledMode",
"state.cableRating",
"config.authorizationRequired",
"config.limitToSinglePhaseCharging",
"config.localNodeType",
"config.localAuthorizationRequired",
"config.ledStripBrightness",
"site.id",
"site.name",
"site.siteKey",
"circuit.id",
"circuit.ratedCurrent",
],
"units": None,
"convert_units_func": None,
"device_class": "easee_status",
"icon": "mdi:ev-station",
},
"total_power": {
"key": "state.totalPower",
"attrs": [],
Expand Down
29 changes: 17 additions & 12 deletions custom_components/easee/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
from .const import (
CONF_MONITORED_SITES,
CONF_MONITORED_EQ_CONDITIONS,
EASEE_ENTITIES,
OPTIONAL_EASEE_ENTITIES,
MANDATORY_EASEE_ENTITIES,
EASEE_EQ_ENTITIES,
CONSUMPTION_DAYS_PREFIX,
MEASURED_CONSUMPTION_DAYS,
CUSTOM_UNITS,
CUSTOM_UNITS_TABLE,
Expand Down Expand Up @@ -83,7 +85,7 @@ def __init__(self, charger: Charger, circuit: Circuit, site: Site):
async def schedules_async_refresh(self):
try:
self.schedule = await self.charger.get_basic_charge_plan()
except (TooManyRequestsException, ServerFailureException) as err:
except (TooManyRequestsException, ServerFailureException):
_LOGGER.debug("Got server error while fetching schedule")
except NotFoundException:
self.schedule = None
Expand All @@ -110,7 +112,7 @@ def __init__(
self.equalizers_data: List[EqualizerData] = []
self.switch_entities = []
self.sensor_entities = []
self.equalizer_entities = []
self.equalizer_sensor_entities = []
self.next_consumption_sensor = 0

async def initialize(self):
Expand Down Expand Up @@ -181,7 +183,7 @@ def update_ha_state(self):

def update_equalizers_state(self):
# Schedule an update for all equalizer entities
for entity in self.equalizer_entities:
for entity in self.equalizer_sensor_entities:
entity.async_schedule_update_ha_state(True)

async def add_schedulers(self):
Expand Down Expand Up @@ -289,16 +291,16 @@ def get_sensor_entities(self):
return (
self.sensor_entities
+ self.consumption_sensor_entities
+ self.equalizer_entities
+ self.equalizer_sensor_entities
)

def get_switch_entities(self):
return self.switch_entities

def _create_entitites(self):
monitored_conditions = self.config.options.get(
CONF_MONITORED_CONDITIONS, ["status"]
)
monitored_conditions = list(dict.fromkeys(self.config.options.get(
CONF_MONITORED_CONDITIONS, []
) + [x for x in MANDATORY_EASEE_ENTITIES]))
monitored_eq_conditions = self.config.options.get(
CONF_MONITORED_EQ_CONDITIONS, ["status"]
)
Expand All @@ -309,12 +311,14 @@ def _create_entitites(self):
self.consumption_sensor_entities = []
self.equalizer_sensor_entities = []

all_easee_entities = {**MANDATORY_EASEE_ENTITIES, **OPTIONAL_EASEE_ENTITIES}

for charger_data in self.chargers_data:
for key in monitored_conditions:
# Fix renamed entities previously configured
if key not in EASEE_ENTITIES:
if key not in all_easee_entities:
continue
data = EASEE_ENTITIES[key]
data = all_easee_entities[key]
entity_type = data.get("type", "sensor")

if entity_type == "sensor":
Expand Down Expand Up @@ -403,8 +407,9 @@ def _create_entitites(self):
_LOGGER.info("Will measure days: %s", interval)
self.consumption_sensor_entities.append(
ChargerConsumptionSensor(
self,
charger_data.charger,
f"consumption_days_{interval}",
f"{CONSUMPTION_DAYS_PREFIX}{interval}",
int(interval),
consumption_unit,
)
Expand All @@ -429,7 +434,7 @@ def _create_entitites(self):
if data["units"] in custom_units:
data["units"] = CUSTOM_UNITS_TABLE[data["units"]]

self.equalizer_entities.append(
self.equalizer_sensor_entities.append(
EqualizerSensor(
controller=self,
charger_data=equalizer_data,
Expand Down
14 changes: 12 additions & 2 deletions custom_components/easee/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,24 @@ async def async_added_to_hass(self) -> None:

async def async_will_remove_from_hass(self) -> None:
"""Disconnect object when removed."""
if self in self.controller.sensor_entities:
self.controller.sensor_entities.remove(self)
if self in self.controller.binary_sensor_entities:
self.controller.binary_sensor_entities.remove(self)
if self in self.controller.switch_entities:
self.controller.switch_entities.remove(self)
if self in self.controller.equalizer_sensor_entities:
self.controller.equalizer_sensor_entities.remove(self)
ent_reg = await entity_registry.async_get_registry(self.hass)
entity_entry = ent_reg.async_get(self.entity_id)

dev_reg = await device_registry.async_get_registry(self.hass)
device_entry = dev_reg.async_get(entity_entry.device_id)

_LOGGER.debug("Removing _entity_name: %s", self._entity_name)
if (self._entity_name in self.hass.data[DOMAIN]["entities_to_remove"] or
self.charger_data.charger.site["name"] in self.hass.data[DOMAIN]["sites_to_remove"]):
self._entity_name in self.hass.data[DOMAIN]["eq_entities_to_remove"] or
self.charger_data.site["name"] in self.hass.data[DOMAIN]["sites_to_remove"]):
if len(async_entries_for_device(ent_reg, entity_entry.device_id)) == 1:
dev_reg.async_remove_device(device_entry.id)
return
Expand Down Expand Up @@ -162,7 +172,7 @@ def icon(self):
def device_class(self):
"""Device class of sensor."""
return self._device_class

@property
def should_poll(self):
"""No polling needed."""
Expand Down
3 changes: 0 additions & 3 deletions custom_components/easee/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
],
"homeassistant": "0.113.0",
"config_flow": true,
"dependencies": [
"configurator"
],
"codeowners": [
"@fondberg",
"@tmjo",
Expand Down
42 changes: 23 additions & 19 deletions custom_components/easee/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_SIGNAL_STRENGTH,
)


Expand Down Expand Up @@ -49,14 +49,34 @@ def state(self):
class ChargerConsumptionSensor(Entity):
"""Implementation of Easee charger sensor."""

def __init__(self, charger, name, days, units):
def __init__(self, controller, charger, name, days, units):
"""Initialize the sensor."""
self.controller = controller
self.charger = charger
self._sensor_name = name
self._days = days
self._state = None
self._units = units

async def async_will_remove_from_hass(self) -> None:
"""Disconnect object when removed."""
if self in self.controller.consumption_sensor_entities:
self.controller.consumption_sensor_entities.remove(self)
ent_reg = await entity_registry.async_get_registry(self.hass)
entity_entry = ent_reg.async_get(self.entity_id)

dev_reg = await device_registry.async_get_registry(self.hass)
device_entry = dev_reg.async_get(entity_entry.device_id)

_LOGGER.debug(">>>>>>>>>>>>>> Removing _sensor_name: %s", self._sensor_name)
if (self._sensor_name in self.hass.data[DOMAIN]["days_to_remove"] or
self.charger.site["name"] in self.hass.data[DOMAIN]["sites_to_remove"]):
if len(async_entries_for_device(ent_reg, entity_entry.device_id)) == 1:
dev_reg.async_remove_device(device_entry.id)
return

ent_reg.async_remove(self.entity_id)

@property
def name(self):
"""Return the name of the sensor."""
Expand Down Expand Up @@ -104,7 +124,7 @@ def state_attributes(self):
def device_class(self):
"""Device class of sensor."""
return DEVICE_CLASS_ENERGY

@property
def should_poll(self):
"""No polling needed."""
Expand Down Expand Up @@ -151,22 +171,6 @@ def device_info(self) -> Dict[str, any]:
"model": "Equalizer",
}

async def async_will_remove_from_hass(self) -> None:
"""Disconnect object when removed."""
ent_reg = await entity_registry.async_get_registry(self.hass)
entity_entry = ent_reg.async_get(self.entity_id)

dev_reg = await device_registry.async_get_registry(self.hass)
device_entry = dev_reg.async_get(entity_entry.device_id)

if (self._entity_name in self.hass.data[DOMAIN]["eq_entities_to_remove"] or
self.charger_data.site["name"] in self.hass.data[DOMAIN]["sites_to_remove"]):
if len(async_entries_for_device(ent_reg, entity_entry.device_id)) == 1:
dev_reg.async_remove_device(device_entry.id)
return

ent_reg.async_remove(self.entity_id)

async def async_update(self):
"""Get the latest data and update the state."""
_LOGGER.debug(
Expand Down
3 changes: 3 additions & 0 deletions custom_components/easee/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"description": "Select options",
"title": "Easee EV Charger"
}
},
"error": {
"no_sites": "No monitored sites selected"
}
},
"title": "Easee EV Charger"
Expand Down
3 changes: 3 additions & 0 deletions custom_components/easee/translations/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"description": "Velg instillinger",
"title": "Easee EV Charger"
}
},
"error": {
"no_sites": "Ingen lokasjon valgt"
}
},
"title": "Easee EV Charger"
Expand Down
Loading