Countdown Sensor Help

Evening All,

I’ve implemented robmarkle’s python script as a day countdown sensor with an automation:

Now, with exception of the bare minimum VB, I have no coding experience. I see he says to create some “dicts” should you wish to add more dates to the sensor. I googled “python dictionaries” and I get the premise. I tried implementing it and failed miserably.

Robmarkle’s original script:

"""
Script to create a sensor displaying the number of days until some event.
Automate to update every day.
"""

EVENT = 'renew_letsencrypt'
YEAR = 2018
MONTH = 2
DAY = 8

day_of_interest = datetime.datetime(YEAR, MONTH, DAY)
now = datetime.datetime.now()
diff = day_of_interest - now

hass.states.set('sensor.' + EVENT, diff.days,{
    'unit_of_measurement': 'days',
    'friendly_name': 'Days until renew LetsEncrypt',
    'icon': 'mdi:calendar'
})

My attempt at defining some more sensors (I appreciate I’m miles off, again this was a shot in the dark):

"""
Script to create a sensor displaying the number of days until some YEAR.
Automate to update every day.
"""
EVENT ={}

EVENT['john'] = 'jbday'
EVENT['kevin'] = 'kbday'
EVENT['wife'] = 'sbday'
EVENT['mot'] = 'motleft'
EVENT['tax'] = 'taxleft'

YEAR = {}

YEAR['john'] = '2018'
YEAR['kevin'] = '2018'
YEAR['wife'] = '2018'
YEAR['mot'] = '2018'
YEAR['tax'] = '2018'

MONTH = {}

MONTH['john'] = '12'
MONTH['kevin'] = '12'
MONTH['wife'] = '12'
MONTH['mot'] = '3'
MONTH['tax'] = '3'

DAY = {}

DAY['john'] = '1'
DAY['kevin'] = '2'
DAY['wife'] = '3'
DAY['mot'] = '4'
DAY['tax'] = '5'

day_of_interest = datetime.datetime(YEAR, MONTH, DAY)
now = datetime.datetime.now()
diff = day_of_interest - now

hass.states.set('sensor.' + EVENT, diff.days,{
    'unit_of_measurement': 'days',
    'friendly_name': 'Days until EVENT',   <--- Not too sure about this part either.
    'icon': 'mdi:calendar'
})

You’re not miles off, only a few yards. :slight_smile: You just need to add a loop:

now = datetime.datetime.now()
for key in ('john', 'kevin', 'wife', 'mot', 'tax'):
    day_of_interest = datetime.datetime(
        YEAR[key], MONTH[key], DAY[key])
    diff = day_of_interest - now

    hass.states.set('sensor.' + EVENT[key], diff.days,{
        'unit_of_measurement': 'days',
        'friendly_name': 'Days until {}'.format(EVENT[key]),
        'icon': 'mdi:calendar'
    })
1 Like

Thanks for this so the way I set out the dictionary was fine?

"""
Script to create a sensor displaying the number of days until some YEAR.
Automate to update every day.
"""
EVENT ={}

EVENT['john'] = 'jbday'
EVENT['kevin'] = 'kbday'
EVENT['wife'] = 'sbday'
EVENT['mot'] = 'motleft'
EVENT['tax'] = 'taxleft'

YEAR = {}

YEAR['john'] = '2018'
YEAR['kevin'] = '2018'
YEAR['wife'] = '2018'
YEAR['mot'] = '2018'
YEAR['tax'] = '2018'

MONTH = {}

MONTH['john'] = '12'
MONTH['kevin'] = '12'
MONTH['wife'] = '12'
MONTH['mot'] = '3'
MONTH['tax'] = '3'

DAY = {}

DAY['john'] = '1'
DAY['kevin'] = '2'
DAY['wife'] = '3'
DAY['mot'] = '4'
DAY['tax'] = '5'

Yes, that’s fine. I probably would have organized it a bit differently, but that comes with learning the language. E.g.:

events = (
    ('john', 'jbday', datetime.datetime(2018, 12, 1)),
    ('kevin', 'kbday', datetime.datetime(2018, 12, 2)),
    ('wife', 'sbday', datetime.datetime(2018, 12, 3)),
    ('mot', 'motleft', datetime.datetime(2018, 3, 4)),
    ('tax', 'taxleft', datetime.datetime(2018, 3, 5)),
)

now = datetime.datetime.now()
for _, event, event_date in events:
    diff = event_date - now
    hass.states.set('.'.join(['sensor', event]), diff.days, {
        'unit_of_measurement': 'days',
        'friendly_name': 'Days until {}'.format(event),
        'icon': 'mdi:calendar'
    })
1 Like

Hmmm something went wrong as I went for exactly what you put above and the sensor is gone (after running the python script).

Edit: Nvm just me being stupid, thank you for you help.

@pnbruckner Can I ask a follow up question?

So you have your dicitonary set as:

events = (
    ('john', 'jbday', datetime.datetime(2018, 12, 1)),

and this called with:

now = datetime.datetime.now()
for _, event, event_date in events:
    diff = event_date - now
    hass.states.set('.'.join(['sensor', event]), diff.days, {
        'unit_of_measurement': 'days',
        'friendly_name': 'Days until {}'.format(event),
        'icon': 'mdi:calendar'
    })

This creates sensor.jbday and pulls through “Days until jbday” as friendly name.

I take it ‘john’ is the internal reference (within the python script itself). Can you add more to each “definition” (sorry don’t know the right term)?

So could I have:

('john', 'jbday', datetime.datetime(2018, 12, 1),"John's Birthday"),

And then pull through that as the friendly name?

events is actually what’s called a tuple. (It’s just Python’s fancy name for an immutable “list”.) In fact, it’s a two dimensional tuple. It’s definitely not a dictionary.

The for loop takes each outside tuple element (which are tuples themselves) in turn, and assigns/expands it to the variables specified (i.e., _, event and event_data, where the variable name _ is typically used when the value isn’t needed. It’s just a convention. You could easily use a variable like name.)

No, it’s just another value in the inside tuples. I put it there because you had it. Strictly speaking, it isn’t needed given what the rest of the script does.

Basically events is just a two-dimensional “array”. You can put whatever you like in it. Just make sure the number of variables you put between for and in in the for-loop is the same as the number of elements in each inside tuple.

BTW, I don’t mind helping like this, but this is really more about learning Python, which is kind of outside the scope of this forum. You should probably find a Python tutorial (there are a zillion of them on the web), or private message me. :slight_smile:

1 Like

nice an elegant!

would be really cool if one could simply jot in the birthday and year (instead of the current implementation with 2018), and the script could take it from there (and show the age as a nice little extra touch)…

Thank you and yes you make a good point, over to reddit for me. Thank you for taking to time to explain

For anyone reading this thread and wondering how to achieve what I asked middle of the thread here is my outcome:

events = (
    ('manbday', 'Days until this mans birthday', datetime.datetime(2018, 11, 22)),
    ('thingtodo', 'Days until this event', datetime.datetime(2018, 11, 21)),
)

now = datetime.datetime.now()
for s_name, f_name, s_value in events:
    diff = s_value - now
    hass.states.set('.'.join(['sensor', s_name]), diff.days, {
        'unit_of_measurement': 'days',
        'friendly_name': '{}'.format(f_name),
        'icon': 'mdi:calendar'
    })

I’ve renamed all the values as I am not the brightest and the terms s_name, f_name and s_value will make sense to future me if I need to look at this.

@pnbruckner, just wanted to say thanks again.

1 Like