Skip to content

Instantly share code, notes, and snippets.

@rosaldanha
Last active December 6, 2023 19:44
Show Gist options
  • Save rosaldanha/a0f8a5be9161745126c7e21563239118 to your computer and use it in GitHub Desktop.
Save rosaldanha/a0f8a5be9161745126c7e21563239118 to your computer and use it in GitHub Desktop.
home assistant pyscript to update device config on rslighsystem !
import homeassistant
from homeassistant.helpers.template import Template
#from homeassistant.helpers.entity_registry import RegistryEntryHider
from homeassistant.helpers.entity_registry import RegistryEntryDisabler
from homeassistant.const import EVENT_SERVICE_REGISTERED
from homeassistant.core import Context
PANELS = 'panels'
def render_template(template, **kwargs):
tpl = Template(template, hass)
return tpl.async_render(kwargs)
# {{ device_entities( '0556da2031a3335ed396db777a69f0b1' ) }}
class Device:
def __init__(self,device_dict, panel):
self.name = device_dict['device']
self.controled_entities = device_dict['controled_entities']
self.relay = device_dict['relay']
self.button_pos = str(device_dict['button_pos']).strip()
self.light_name = device_dict['light_name']
self.panel = panel
def get_entity_id_rslights_version(self):
return f"sensor.{self.name}_rslights_version"
def get_entity_id_controled_entities(self):
return f"sensor.{self.name}_controled_entities"
def get_entity_id_relay(self):
return f"sensor.{self.name}_relay_enabled"
def get_entiy_id_panel_name(self):
return f"sensor.{self.name}_panel_name"
def get_entity_id_button_pos(self):
return f"sensor.{self.name}_button_pos"
def get_entity_id_status(self):
return f"binary_sensor.{self.name}_status"
def get_config_service_name(self):
return f"{self.name}_setup_smr2"
def is_config_synced(self):
return ( state.get(self.get_entity_id_controled_entities()) == self.controled_entities
and state.get(self.get_entity_id_relay()) == self.relay
and str(state.get(self.get_entity_id_button_pos())).strip() == self.button_pos
)
def device_exists_hass(self):
# entreg = homeassistant.helpers.entity_registry.async_get(hass)
# status_entity = entreg.async_get(self.get_entity_id_status())
# return status_entity != None
template_str = "{{ states('"+ self.get_entity_id_rslights_version()+"') == '1.0' }}"
return render_template(template=template_str)
def is_online(self):
return state.get(self.get_entity_id_status()) != 'unavailable'
def get_hass_device_entities_ids(self):
entreg = homeassistant.helpers.entity_registry.async_get(hass)
status_entity = entreg.async_get(self.get_entity_id_status())
# complete entries here
entries = homeassistant.helpers.entity_registry.async_entries_for_device(entreg,
device_id=status_entity.device_id,
include_disabled_entities=True)
return [entry.entity_id for entry in entries]
def sync_light_name(self):
entreg = homeassistant.helpers.entity_registry.async_get(hass)
status_entity = entreg.async_get(self.get_entity_id_status())
if status_entity != None:
# resolving a template
device_current_entities = self.get_hass_device_entities_ids()
current_light_entity_id = None
for entity_name in device_current_entities:
if entity_name.startswith('light.'):
current_light_entity_id = entity_name
current_light_entity = entreg.async_get(current_light_entity_id)
if self.light_name == 'hide':
#check and hide current light entity found above.
if current_light_entity != None:
if current_light_entity.disabled_by == None:
# Hide the entity, RegistryEntryHider.INTEGRATION DO NOT allow the user to unhide, if needed use RegistryEntryHider.USER
entreg.async_update_entity(entity_id=current_light_entity_id,
disabled_by=RegistryEntryDisabler.INTEGRATION)
else:
new_light_id = f"light.{self.light_name.replace(' ','_').lower()}"
if new_light_id != current_light_entity_id:
log.error(new_light_id)
# Change Entity ID and name
try:
entreg.async_update_entity(entity_id=current_light_entity_id,
new_entity_id=new_light_id,
name=self.light_name,
disabled_by=None)
except:
entreg.async_update_entity(entity_id=current_light_entity_id,
new_entity_id=new_light_id,
name=self.light_name)
def sync_device_area(self):
# change/assign an area to a device (all device entities will follow)
devreg = homeassistant.helpers.device_registry.async_get(hass)
entreg = homeassistant.helpers.entity_registry.async_get(hass)
entity = entreg.async_get(self.get_entity_id_status())
if entity != None:
devreg.async_update_device(device_id=entity.device_id, area_id=self.panel.area)
def sync_device(self):
#using rslights services update device config
task.sleep(5)
service.call(domain='esphome',name=self.get_config_service_name(),
controled_entities_value=self.controled_entities,
panel_name_value=self.panel.panel_name,
relay_enabled_value=self.relay,
button_pos_value=self.button_pos )
def enable_service_run(self):
# Enable devices to call services from home assistant !
devreg = homeassistant.helpers.device_registry.async_get(hass)
entreg = homeassistant.helpers.entity_registry.async_get(hass)
entity = entreg.async_get(self.get_entity_id_status())
device = devreg.async_get(entity.device_id)
device_config_entry_id = list(device.config_entries)[0]
device_config_entry = hass.config_entries.async_get_entry(device_config_entry_id)
hass.config_entries.async_update_entry(device_config_entry,options={'allow_service_calls': True })
class Panel:
def __init__(self, panel_name):
self.panel_name = panel_name
self.area = pyscript.app_config[PANELS][self.panel_name]['area']
self.devices = []
for device in pyscript.app_config[PANELS][self.panel_name]['devices']:
self.devices.append(Device(device_dict=device,panel=self))
@service
def sync_rslights():
is_panel_in_sync = True
for panel in pyscript.app_config[PANELS]:
# panel_list.append(Panel(panel))
tmp_panel = Panel(panel)
for device in tmp_panel.devices:
if device.device_exists_hass():
#if render_template(template='')
device.sync_light_name()
if not device.is_config_synced():
log.info(f"Device: {device.name} is out of sync")
is_panel_in_sync = False
device.sync_device()
device.sync_device_area()
device.enable_service_run()
if not is_panel_in_sync:
log.info(f"Panel: {tmp_panel.panel_name} has been synced")
else:
log.info(f"Panel: {tmp_panel.panel_name} was synced")
'''
2023-12-04 05:34:31.878 INFO (MainThread) [custom_components.pyscript.apps.rslights.monitor_service_registred] got
EVENT_SERVICE_REGISTERED with kwargs={
'trigger_type': 'event',
'event_type': 'service_registered',
'context': <homeassistant.core.Context object at 0x7f3798f25ad0>,
'domain': 'esphome', 'service': 'smr2055_setup_smr2'}
'''
@event_trigger(EVENT_SERVICE_REGISTERED,"domain == 'esphome' and service[-11:] == '_setup_smr2' ")
def monitor_service_registred(domain=None, context=None, service=None):
device_name = service[:7]
template_str = "{{ device_id( '" + device_name + "' ) }}"
device_id = render_template(template=template_str)
log.info(f"got EVENT_SERVICE_REGISTERED with context.id={context.id}, device={service[:7]} device_id={device_id}")
for panel in pyscript.app_config[PANELS]:
# panel_list.append(Panel(panel))
tmp_panel = Panel(panel)
for device in tmp_panel.devices:
if device.name == device_name:
if device.device_exists_hass():
log.info(f"NEW Device: {device.name} is out of sync")
task.sleep(5)
device.sync_light_name()
device.sync_device()
device.sync_device_area()
device.enable_service_run()
# device.sync_device()
# device.sync_light_name()
# device.sync_device_area()
log.info(f"NEW Device: {device.name} in sync !")
#TODO: Create a code to generate panels in lovelace each panel with his devices
#TODO: NOTIFY ?
#TODO: detect buttons pressed to identify devices
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment