Smarter (shorter) template possible? loop in Python

HI,

Using this in my python i was wondering (hoping) this could be done smarter. Would make it shorter and more robust.

'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge"; else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else if (value == 7) \
              return "green_badge"'

transform into something using:

(for value 0 to 7, use red_badge, yellow_badge, blue_badge, orange_badge, brown_badge, black_badge, grey_badge, green_badge)

Please have a look?
Thanks!
Marius

something along the lines of

   colors = ["RED_BADGE", "YELLOW_BADGE", "BLUE_BADGE"]
   return colors[value]

might be more attractive

indeed! how would i need to code that? could i simply replace that? fyi, the badges are defined in my config/frontend_themes/themes_badges.yaml,

In my python script this is the relevant bit for this logic:

up_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge"; else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else if (value == 7) \
              return "green_badge"'

down_theme = 'if (value == 7) return "red_badge"; else if (value == 6) \
              return "yellow_badge"; else if (value == 5) return "blue_badge"; \
              else if (value == 4) return "orange_badge"; else if (value == 3) \
              return "brown_badge"; else if (value == 2) return "black_badge"; \
              else if (value == 1) return "grey_badge"; else if (value == 0) \
              return "green_badge"'

and:

groups_theme = [up_theme, up_theme, down_theme, up_theme]

first attempt is erroring out with value=undefined.

up_theme = ["red_badge","yellow_badge","blue_badge","orange_badge","brown_badge",\
             "black_badge","grey_badge","green_badge"]

down_theme = ["green_badge","grey_badge","black_badge","brown_badge","orange_badge",\
              "blue_badge","yellow_badge","red_badge"]

and

groups_theme = [up_theme[value], up_theme[value], down_theme[value], up_theme[value]]

or

groups_theme = [return ‘up_theme[value]’, return ‘up_theme[value]’, return ‘down_theme[value]’, return ‘up_theme[value]’ ]

—edit—

this seems to almost do the trick, always important where to put the ’ '…:

groups_theme = ['return up_theme[value]', 'return up_theme[value]', 'return down_theme[value]', 'return up_theme[value]' ]

doesn’t yet select the correct theme though, but no error messages anymore. Further tweaking needed!
Marius

I can’t see what you are doing with the data, but it would be simpler to have one array and index it in reverse order for the down_them like this

theme = ["red_badge","yellow_badge","blue_badge","orange_badge","brown_badge",\
             "black_badge","grey_badge","green_badge"]

groups_theme = ['return theme[value]', 'return theme[value]', 'return theme[len(theme)-value]', 'return theme[value]' ]

seems better indeed, even shorter.

the values are the count of entities at Home, in Use, playing etc etc.

I want the colors of the badge to reflect these counts. Which isn’t happening with this new code, as it was with the former.

Check:

1607

badge at home should have changed…

Actually, now I see your code isn’t python at all - maybe javascript? Your python script must be returning something to run in the browser?

I don’t have anything to do with the front end, so I can’t really help.

Edit: Although thinking a bit further (waiting for 0.64.1 to install gives you time :grinning:) you just need to return a string containing 'return ’ and the value you want, so

groups_theme = ['return ' + theme[value], 'return ' + theme[value], 'return ' + theme[len(theme) - value], 'return ' + theme[value] ]

might do it. Something on those lines anyway.

—edit—

posts crossed… ill try immediately. i didn’t get any errors, so at least it was executable to the interpreter :wink:


thought we were close… a restart proves wrong, no themes loaded at all now…

ill give you the full section of the python script:

##########################################################################################
## Group count
## Groups config:
##  Entities summary by group name 
# groups = need to have same member_count
# groups_format = # Message prefix
# groups_filter = # Filter to list
# groups_badge = # Badge 'belt' (unit_of_measurement)
# groups_badge_pic = # none, one, or a list of pictures (picture position = match the count)
# groups_min_show = # Mininum count to show
# groups_theme =  # Theme template
# groups_desc = # Can set the default description, for use in case count = 0
# themes build up or down according to counted value
##########################################################################################
theme = ["red_badge","yellow_badge","blue_badge","orange_badge","brown_badge",\
             "black_badge","grey_badge","green_badge"]

groups = ['group.family', 'group.hubs_binary_pinged', 'group.critical_devices_state', \
            'group.tracked_avg_summary'] 
groups_format = ['+{} at home: {}','{} in use: {}','!{} offline: {}',' #{} playing: {}']
groups_filter = ['home', 'on|playing|home', 'off|idle|not_home', 'home|playing|on']
groups_badge = ['Home', 'In use', 'Status', 'Play']
groups_badge_pic = ['', '', 'ok|bug|critical', '']
groups_min_show = [0, 0, 0,0]
groups_theme = ['return theme(value)', 'return theme(value)', \
                              'return theme(len(theme)-value))', 'return theme(value)' ]
groups_desc = ['!Nobody home', '', '+System ok', '#No playing']
groups_count = [0, 0, 0,0]

for group in groups:
    group_count = 0
    group_desc = ''

    for entity_id in hass.states.get(group).attributes['entity_id']:
        state = hass.states.get(entity_id)
        filter = groups_filter[idx]

        if (state.state in filter.split('|') or debug):
            dt = state.last_changed
            dt = dt + datetime.timedelta(hours=+1)
            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)

            group_count = group_count + 1
            group_desc = '{} {} ({}), '.format(group_desc, state.name, time)

    # Final format for this group
    if (group_count >= groups_min_show[idx]):
        if (group_count == 0):
            group_desc = groups_desc[idx]
        else:
            group_desc = groups_format[idx].format(group_count, group_desc[:-2])

        groups_desc[idx] = group_desc
        groups_count[idx] = group_count

    idx = idx + 1

We cross posted. Please see my edit to my previous post. I think you need to concatenate the value of the theme to the return string, so that will execute in the javascript.

trying your code above, but it is complaining the value is not defined… moving the ’ ’ around the expression 'return + theme[value]' takes out the error, but no result either. Must be close.

I am going to have to guess that the value not defined is value the index to the array. Where is this set up?

Edit: I see, its all in the javascript. What you actually wanted is someone to optimize your javascript, not your python.

not sure i completely follow, but the code I pasted above is my python script… you’re saying that this python script contains the javascript code? Because the only other code I use is of the themes themselves, which are in my yaml file.

This is javascript code. You can tell because its all in one line with ; line endings. Your python script is returning it to be executed somewhere, presumably in the browser, and it is there that value is defined, so trying to access it in the python code is not possible.

i see.

couldnt i replace that javascript with regular python code then? reading the themes from this same yaml file, taking the value from above code?

I really have no idea. As I said before, I don’t use the front end except for debugging, so have no real interest in how it works.

ok thanks anyways!, Hope someone else will chime in, recoding to my first javascript for now.
Kinda liked your lean code though, hope something will be possible.

please do have one other look, i think i forgot to show you an essential bit of code…

this is where the actual bades are made, and the template for the theme is also calculated:

if show_badges:
    for badge in groups_badge:
        if (badge != ''):
            entity_id = 'sensor.{}_badge'.format(badge.replace(' ', '').lower());
            hidden = False if (groups_count[idx] >= groups_min_show[idx] or debug) else True
            fname = groups_desc[idx] if debug else ' '
            picture = groups_badge_pic[idx].replace(' ', '').lower()
            theme = groups_theme[idx].replace('value', \
                    'entities["{}"].state'.format(entity_id)) \
                    if (groups_theme[idx] != '') else 'default'

            # Check for picture X index/count
            if (picture != ''):
                list = picture.split('|')
                if (len(list) in [1, groups_count[idx]]):
                    picture = list[len(list)-1]
                else:
                    picture = list[groups_count[idx]]

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


            hass.states.set(entity_id, groups_count[idx], {
              'friendly_name': fname,
              'unit_of_measurement': badge, 
              'entity_picture': picture,
              'hidden': hidden,
              'templates': { 'theme': theme },
              'order': order
            })