Does the datetime module work in python_script?

This PR was merged with the release of Home Assistant 0.54. Despite running that version, I can’t seem to be able to actually use the datetime module in python_script. I’m a novice when it comes to Python so I usually have to write my code through trial and error. But no matter what I try, my script results in a variety of errors in the Home Assistant log file every time I call it.

Has anybody else here been able to get datetime to work in python_script? If so, would you mind sharing an example? All I’m trying to do is include a timestamp in my script.

Looks like it will be available after https://github.com/home-assistant/home-assistant/pull/9736 is merged.

datetime is already available. There is no need to import it. You can just reference it in your scripts.

now = datetime.datetime.now().strftime('%H:%M')
logger.info('It is {}'.format(now))

Starting 0.56 we will have dt_util and time available too.

Thank you for the example. Unfortunately, I still cannot get it to work.

This is my python_script:

# Get time and settings
time                = datetime.datetime.now().strftime('%H:%M:%S')
sending             = hass.states.get('input_boolean.notify_pushover').state
default_priority    = hass.states.get('input_slider.pushover_priority').state

# Get script variables
target      = data.get('target') or 'Helios'
title       = (data.get('title') or 'HA automation') + ' @ ' + time
message     = data.get('message')
priority    = data.get('priority') or default_priority

# Call service
if sending == 'on' :
    data = { "target" : target, "title" : title, "message" : message , "data" : { "priority" : int(float(priority)) } }
    hass.services.call('notify', 'pushover', data)

To test it, I’m using the following service data:

{
  "title": "Test",
  "message": "This is a test!",
  "target": "Aphrodite",
  "priority": "0"
}

And I get this error in the Home Assistant log:

2017-10-08 00:40:54 ERROR (Thread-9) [homeassistant.components.python_script.notify_pushover.py] Error executing script: '__import__'
Traceback (most recent call last):
  File "/srv/hass/hass_venv/lib/python3.4/site-packages/homeassistant/components/python_script.py", line 143, in execute
    exec(compiled.code, restricted_globals, local)
  File "notify_pushover.py", line 2, in <module>
KeyError: '__import__'

@balloob that does not work. Here’s the error:

2017-10-12 15:37:32 ERROR (Thread-4) [homeassistant.components.python_script.time_test.py] Error executing script: '__import__'
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/python_script.py", line 143, in execute
    exec(compiled.code, restricted_globals, local)
  File "time_test.py", line 1, in <module>
KeyError: '__import__'

Thank you for confirming my findings, @arsaboo

Glad to know I’m not plain stupid or going crazy lol :stuck_out_tongue:

Okay, weird. So I did not test the above example but it seems that somehow calling strftime is causing the error :thinking:

This works fine:

logger.info(datetime.datetime.now())

This will work too:

now = datetime.datetime.now()
logger.info("It is {}:{}".format(now.hour, now.minute))
2 Likes

Thanks…that works!!

I rewrote my script above with this new information. It now looks like this:

# Get time and settings
now                 = datetime.datetime.now()
time                = "{}:{}:{}".format(now.hour, now.minute, now.second)
sending             = hass.states.get('input_boolean.notify_pushover').state
default_priority    = hass.states.get('input_number.pushover_priority').state

# Get script variables
target      = data.get('target') or 'Helios'
title       = (data.get('title') or 'HA automation') + ' @ ' + time
message     = data.get('message')
priority    = data.get('priority') or default_priority

# Call service
if sending == 'on' :
    data = { "target" : target, "title" : title, "message" : message , "data" : { "priority" : int(float(priority)) } }
    hass.services.call('notify', 'pushover', data)

There are no more errors in the log now and the timestamp works, but the formatting isn’t great. E.g. I get 23:0:1 instead of 23:00:01. Is there a way to fix that, or will that require the use of strftime? And how come strftime doesn’t work to begin with?


EDIT: okay, maybe I should’ve done my research (better) because I found a way around this by changing

time = "{}:{}:{}".format(now.hour, now.minute, now.second)

to

time = "%02d:%02d:%02d" % (now.hour, now.minute, now.second)
2 Likes

I tried this syntax in my custom component and still get an error with the line “now = datetime.datetime.now()”
Any idea why it works for some of you but not for me? (I’m running HomeAssistant 0.59.2)

The top of my component includes:

from datetime import datetime
from datetime import timedelta 
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 199, in async_update_ha_state
    yield from self.async_device_update()
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 306, in async_device_update
    yield from self.hass.async_add_job(self.update)
  File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/util/__init__.py", line 306, in wrapper
    result = method(*args, **kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/sensor/mysensor.py", line 375, in update
    now = datetime.datetime.now()

I think the last line of your traceback is missing, which would tell you what’s wrong.

I tried something similar to your code originally - for timestamp purposes - and couldn’t get it to work either. However, the following bit of code in my python_script works:

now                 = datetime.datetime.now()
time                = "%02d:%02d:%02d" % (now.hour, now.minute, now.second)

I do not import anything in my script to make it work.

Here is the last line that was missing from the original traceback……

AttributeError: type object ‘datetime.datetime’ has no attribute ‘datetime’

Are you using it in a python_script or custom_component? Looks like you are using it in custom_component. Just use

from datetime import datetime
now = datetime.now()

See here for example.

Thanks. Yes, it is in a custom_component.
But the custom_component is written with Python code…
Your suggestion worked - but why does the syntax need to be different when inside a custom_component?

hope this is related, im getting seriously desperate on a time-issue in regular python script

what would be the preferred way of handling a local timezone (utc+1). I now have to add +1 all the time I need a time in the output and a flooded with errors Nonetype cant be used with this

dt = hass.states.get('automation.sense_lights_change').attributes.get('last_triggered')
#    dt.replace(tzinfo=timezone.utc).astimezone(tz=None)
#    dt.replace(tzinfo=datetime.timezone.utc).astimezone(tz=None)
dt = dt + datetime.timedelta(hours=+1)
time = '%02d:%02d' % (dt.hour, dt.minute)

as you can see ive tried the other techniques, but they don’t take away the issue.

I cant import in the script stating either it cant find the imports, or i am not allowed to.
see this for references in the discussion i had with @petro on the subject.

Please have a look and if possible point me to a final conclusion.
in the end I am hoping there is a global way to let python know i am in utc+1, so all ‘last_triggered’ and ‘last_changed’ s know what time to use. Why is this not default??

cheers and thanks,
Marius

You should just use dt = dt + datetime.timedelta(hours = 1). Check my script here that uses something similar.

1 Like

thank you!
not sure if this was a syntax error or not (never got an error on it in the logs… and script ran just fine) but ive changed it like you said.
Hope ive seen the last of it now…

got this though, might it be related?:

Error doing job: Exception in callback <function async_track_point_in_utc_time.<locals>.point_in_time_listener at 0x6e9b58e8>
Traceback (most recent call last):
  File "uvloop/cbhandles.pyx", line 49, in uvloop.loop.Handle._run
  File "/usr/lib/python3.6/site-packages/homeassistant/helpers/event.py", line 211, in point_in_time_listener
    hass.async_run_job(action, now)
  File "/usr/lib/python3.6/site-packages/homeassistant/core.py", line 252, in async_run_job
    target(*args)
  File "/usr/lib/python3.6/site-packages/homeassistant/helpers/script.py", line 95, in async_script_delay
    self._async_listener.remove(unsub)
ValueError: list.remove(x): x not in list

and

Sat Mar 24 2018 20:41:08 GMT+0100 (CET)

Unable to remove unknown listener <function async_track_point_in_utc_time.<locals>.point_in_time_listener at 0x6e9b58e8>

i really wouldn’t know where/what to look for, since no component or script is mentioned in the error…

after ditching all time errors, which is a huge relieve, im facing another challenge, my first daylight change since using Home-assistant.
All timings are one hour off now, except the time displayed on my last-command sensor:

as top of the page badges:

14

as sensors in a state-card
58
Last_command is:

# Get params
event = data.get('event')
# logger.error("LAST CMD: " + str(event))
# Sample: <Event call_service[L]: service_data=, service_call_id=78356624-86, service=mp_playpause, domain=script>

# Find the script name.
pos_start = event.find('service=')+8
pos_end = event.find(',', pos_start)

# Get the state object (script) from the name
entity_id = 'script.' + event[pos_start:pos_end]
state = hass.states.get(entity_id)
dt = datetime.datetime.now() #state.attributes.get('last_triggered') #
time = "%02d:%02d" % (dt.hour, dt.minute)
msg = []

try:
    msg = state.name
except:
    msg = ''

# Ignore some names
# msg = state.name
if (msg == 'None') or (msg.startswith('Set ')):
    msg = ''

if (msg != '') :
    # Sensor update
    hass.states.set('sensor.last_command', '{}'.format( msg), {
#        'custom_ui_state_card': 'state-card-value_only',
#        'text': sensor_message,
        'unit_of_measurement': 'Cmd',
        'friendly_name': time,
        'entity_picture': '/local/buttons/command.png'
    })

would you understand why they show differently in the frontend?
do i need to set some extra timezone info in the summary.py after all? or is it because i use date time.now in the last_command? if so, could i do that also in the summary.py?

hope you can help again,
thanks,
Marius

Wondering if this is the same as what you are experiencing.