Python script interfering with state machine: how to improve-proceed

Continuing the discussion from Spook - Not your homie:

I have a few more of those python script ‘setting’ a state (and in fact creating that entity in the states machine.). Those scripts have been in my system from the start, and Ive grown so accustomed to them, optimized, and edited them, I fear losing some of their functionality.

My dilemma: Id love to keep them, because Python is so very flexible, and the above, but dont want to ‘mess’ with the state machine, and follow Frenck’s directive not to do so…

so please let me ask what to do, or how to move forward, on this given python script:

##############################################################################################################
# python script to show the loaded components on a  Ha instance, and order them alphabetically, grouping
# components that have sub components (attributes)
# this script gets its data from the rest_sensor:
#   - platform: rest
#     name: Ha Rpi4 config
#     resource: !secret resource_ha_rpi4_config
#     authentication: basic
#     value_template: >
#       {{ value_json.version }}
#     json_attributes:
#       - components
#       - unit_system
#       - config_dir
#     headers:
#       Content-Type: application/json
#       Authorization: !secret api_bearer_token
#       User-Agent: Home Assistant REST sensor

# https://community.home-assistant.io/t/template-to-display-loaded-components-on-ha-instance/114402/59
# @123 and @apop pointed to the rest sensor, and made that availabe in Lovelace
# @petro had a great hand in creating the script
# thanks for joining in on a great HA community!
# @mariusthvdb 20190504
# See https://community.home-assistant.io/t/new-script-integration/203554/22?u=mariusthvdb for change in line 38
##############################################################################################################
attributes = {}
components = hass.states.get('sensor.ha_main_config').attributes['components']
cnt = len(components)
components.sort()

# Make a dictionary of all main domains, add each sub domain to the main domain list.
compdict = {}
subdict = {}
for component in components:
    if component.count('.') == 0 and component not in compdict:
        compdict[component] = []
    if component.count('.') == 1:
        domain, subdomain = component.split('.')
#        compdict[domain].append(subdomain)
        compdict.setdefault(domain, []).append(subdomain)
        if len(domain) > 1:
            subdict.setdefault(subdomain, []).append(domain)
# Make the dictionary into a flat list of strings.

complist = []

for key, value in compdict.items():
    if value:
        value.sort()
        # Adding a domain & series of sub domains
        complist.append('- {}: \n for: {}'.format(key, ', '.join(value)))
    else:
        complist.append('- {}'.format(key))

sublist = []
cntsub = 0
for key, value in subdict.items():
    if value:
        value.sort()
        # Adding a subdomain & series of domains
        if len(value) > 1:
            sublist.append('- {}: \n for: {}'.format(key, ', '.join(value)))
        cntsub = cntsub + 1
#     else:
#         sublist.append('- {}'.format(key))

# join each component with a carriage return
complist = '\n'.join(complist)
sublist = '\n'.join(sublist)

# text = '{} Loaded Components:\n' \
#        '{}'.format(cnt, complist)
#
# subtext = '{} Multiple subdomains:\n' \
#        '{}'.format(cntsub, sublist)

attributes['per subdomain'] = sublist
hass.states.set('sensor.overview_components', cnt, {
  'friendly_name' : 'Components and domains',
  'icon' : 'mdi:format-list-bulleted-type',
   'components' : cnt,
   '---------------' : '--------',
  'per domain' : complist,
  'subdomains' : cntsub,
  '***************' : '--------',
  'per subdomain' : sublist
  })

##############################################################################################################
# first attempt, simply creating an unordered list of components
# components = hass.states.get('sensor.ha_rpi4_config').attributes['components']
# count = len(components)
# components.sort()
# list = ', '.join(components)
#
# text = '*========== {} Loaded Components ========\n' \
#         '+{}' \
#           .format(count,
#                   list)
#
#
# hass.states.set('sensor.ha_rpi4_components', count, {
#         'text': text
#     })

Ive purposely left all comments in, so you can see how this came about. As said, some more of these python script in my system use hass.states.set, and tbh, Ive never noticed anything going awol because of it. Most known might well be the date count down script , which even has its HACS spot. Ive added that before it was released on HACS, and that too works just fine.

cut it short: what to do?

to give you some idea of the scripts I use for monitoring my system:

##########################################################################################
# https://home-assistant.io/components/python_script/
# https://home-assistant.io/docs/configuration/state_object/
##########################################################################################

debug = False

if debug:
    event = data.get('event')
    logger.error('\n\nLIGHTS: ' + str(event))

##########################################################################################
# count
# filter = # Filter to list
# badge = # Badge 'belt' (unit_of_measurement)
# pic = # none, one, or a list of pictures (picture position = match the count)
##########################################################################################

dt_prevstate = None

utc_offset = hass.states.get('sensor.utc_offset').state
try:
    timeDifference = float(utc_offset)
except ValueError as err:
    timeDifference = 0.0

group = 'light.all_lights_only'
fname = 'Lights'
on_format = 'Lampen aan: {} -- {}'
off_format = 'Geen lampen aan sinds '
filter = 'on'
pic = 'lamp_off|lamp'
icon = 'mdi:lightbulb'

count = 0
desc = ''

def flatten(entity_id, result=[], searched=[]):
    state = hass.states.get(entity_id)

    if state is not None:
        entity_ids = state.attributes.get('entity_id')
        if entity_ids is not None:
            searched.append(entity_id)
            for entity_id in entity_ids:
                if entity_id not in result and entity_id not in searched:
                    flatten(entity_id, result, searched)
        else:
            result.append(entity_id)
#
# light_ids = []
# light_groups = ['group.main_inside_lights','group.guest_inside_lights',
#                 'group.living_ceiling_spots','group.outside_flood_lights',
#                 'group.terrace_outdoors_spots']
#
# for group in light_groups:
#     for entity_id in hass.states.get(group).attributes['entity_id']:
#         light_ids.append(entity_id)

light_ids = []
flatten(group, light_ids)
for entity_id in light_ids:

# for entity_id in light_ids: #hass.states.get(group).attributes['entity_id']:
    state = hass.states.get(entity_id)

    if (state.state == filter or debug):
        dt = state.last_changed + datetime.timedelta(hours= timeDifference)
        time = '%02d:%02d' % (dt.hour,dt.minute)

      # If state changed in the past days show the date too
        if dt.date() < datetime.datetime.now().date():
            time = '{} {}'.format('%02d/%02d' % (dt.day,dt.month),time)

#       check if hue lights are 'reachable' is needed because of allow_unreachable: true
#         binary_sensor_id = 'binary_sensor.{}_reachable'.format(state.object_id)
#         binary_sensor = hass.states.get(binary_sensor_id)
#         if binary_sensor is None or binary_sensor.state == 'on':
#             count = count + 1
#             desc = '{} {} ({}), '.format(desc,state.name,time)
        count = count + 1
        desc = '{} {} ({}), '.format(desc,state.name,time)

    else:
        if (dt_prevstate is None):
            dt_prevstate = state.last_changed
        else:
            if (not state.last_changed is None):
                if (state.last_changed > dt_prevstate):
                    dt_prevstate = state.last_changed

# Final format for the group

picturelist = pic.split('|')

if (count == 0):
    desc = off_format
    picture = picturelist[0]
   # If there is none 'On/Home' state in group, show 'since'
    if (desc.find(' since ') > 0):
        dt = dt_prevstate + datetime.timedelta(hours= timeDifference)
        desc = '{} {}'.format(desc,'%02d:%02d' % (dt.hour,dt.minute))
else:
    desc = on_format.format(count, desc[:-2])
    picture = picturelist[1]

##########################################################################################
# Create sensor and badge
##########################################################################################

badge_id = 'sensor.{}_badge'.format(fname.replace(' ', '').lower());
sensor_id = 'sensor.{}_summary'.format(fname.replace(' ', '').lower());

picture = '/local/badges/{}.png'.format(picture)

# badge
hass.states.set(badge_id, count, {
  'friendly_name': ' ',
  fname: desc,
  'unit_of_measurement': fname + ': ' + str(count),
  'entity_picture': picture,
#  'icon': icon,
})

# sensor
hass.states.set(sensor_id, count, {
  'friendly_name': fname,
  fname: desc,
#  'unit_of_measurement': badge + ': ' + str(count),
  'entity_picture': picture,
#  'icon': icon,
})

# Turn Off Input_boolean that triggered the automation (package_summary.yaml)
hass.services.call(
    'input_boolean',
    'turn_off',
    {'entity_id': 'input_boolean.run_lights_summary'}
    )

which provides for this info:

ofc, the other domains have their separate script/automation combo.

I could probably create those lists, with time of change per entity in template: ? So I can use them on a button:

Scherm­afbeelding 2023-05-26 om 17.28.42

with more-info:

and ofc use them in that markdown listing (still like the monitor feedback my admin pages…)