How to: Solaredge lastUpdateTime as relative_time?

Ah I see sorry.

no doesn’t work:

Does it work with the hard coded value?

What version of HA are you running?

yes!

using HA 106.5

try separating the states() into it’s own variable then.

keep getting the identical results
fear I must let it go, frustrating as it is…thanks for you relentless help !

It’s 100% the format of the states() result because hardcoded works. try stripping whitespace with .strip() on the states() variable.

dont know why, but this now seems to work:

though

{{relative_time(strptime(states('sensor.solaredge_last_updatetime'), '%Y-%m-%d %H:%M:%S'))}}

still give me the ‘Unknown error rendering template’

cause you aren’t stripping the whitespace. Seems like a bug in whatever code is creating the solaredge_last_updatetime

{{relative_time(strptime(states('sensor.solaredge_last_updatetime').strip(), '%Y-%m-%d %H:%M:%S'))}}

No, ive tried that, and it doesn’t work (or make a difference):

btw, I now notice this in the home assistant log:

2020-03-10 22:47:17 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start
    resp = await task
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle
    resp = await handler(request)
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_middlewares.py", line 119, in impl
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/real_ip.py", line 39, in real_ip_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/ban.py", line 72, in ban_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/auth.py", line 135, in auth_middleware
    return await handler(request)
  File "/usr/src/homeassistant/homeassistant/components/http/view.py", line 123, in handle
    result = await result
  File "/usr/src/homeassistant/homeassistant/components/api/__init__.py", line 388, in post
    return tpl.async_render(data.get("variables"))
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 221, in async_render
    return compiled.render(kwargs).strip()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/usr/local/lib/python3.7/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.7/site-packages/jinja2/sandbox.py", line 462, in call
    return __context.call(__obj, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/util/dt.py", line 195, in get_age
    delta = now() - date
TypeError: can't subtract offset-naive and offset-aware datetimes

could this be the error we’re facing here (thought an unknown error was unknown… apparently the log show what’s going wrong after all)

ah, you need to add a fake timezone to it.

hmm. I’ve found this as solution, but can’t use it presumably. As I am guessing and not yet understanding the core issue at hand, I need some assistance…

.replace(tzinfo=None)

Look at strftime.org figure out whats expected when you use the timezone format, add that to the string and your format.

must be completely missing the point, but anything I try with relative_time throws the template error. This is what does work but leads to nothing:

adding the timezone %z to the strptime doesnt change the output, so probably wrong too…

yes you are missing the point… if you were to add a timezone to the string and the format… it would look like this:

states('sensor.solaredge_last_updatetime') ~ ' +0000'

and your format would be

'%Y-%m-%d %H:%M:%S %z'

EDIT: And I just tested your as_timestamp | timestamp_custom and it worked. Didn’t work for you because you reversed the date and time…

{% set ts = states('sensor.solaredge_last_updatetime') %}
{% set fmat = "%Y-%m-%d %H:%M:%S" %}
{% set tz = " %z" %}
{% set ts2 = as_timestamp(strptime(ts, fmat)) | timestamp_custom(fmat ~ tz) %}
{{ relative_time(strptime(ts2, fmat ~ tz)) }}

yes! his is indeed working as hoped for, thank you very much!

devil is in the details… sorry bout that. this is one for the templates cookbook. thx again.

update

of course the base states('sensor.solaredge_last_updatetime') we worked with here was my current template sensor, so I changed that into:

      solaredge_last_updatetime:
        friendly_name: 'SolarEdge last update'
        value_template: >
          {% set ts = state_attr('sensor.solaredge_overview','lastUpdateTime') %}
          {% set fmat = "%Y-%m-%d %H:%M:%S" %}
          {% set tz = "%z" %}
          {% set ts2 = as_timestamp(strptime(ts, fmat)) | timestamp_custom(fmat ~ tz) %}
          {{ relative_time(strptime(ts2, fmat ~ tz)) }} ago

with the solar edge.overview being a rest sensor, providing all the details:

  - platform: rest
    name: Solaredge overview
    resource: !secret se_overview_resource
    value_template: >
      {{value_json.overview.currentPower.power|round}}
    unit_of_measurement: 'W'
    json_attributes_path: '$.overview'
    json_attributes:
      - lastUpdateTime
      - lifeTimeData
      - lastYearData
      - lastMonthData
      - lastDayData
      - currentPower
      - measuredBy
    scan_interval: 400

resulting in:

lot of effort in such a small entity-row :wink:

thanks!

Hi @petro,

Think I need to get back on this. Every once in a while the ret sensor doesnt get data, resulting in:

2020-03-19 22:21:28 ERROR (MainThread) [homeassistant.helpers.entity] Update for sensor.solaredge_last_updatetime fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 279, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 474, in async_device_update
    await self.async_update()
  File "/usr/src/homeassistant/homeassistant/components/template/sensor.py", line 224, in async_update
    self._state = self._template.async_render()
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 221, in async_render
    return compiled.render(kwargs).strip()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.7/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/usr/local/lib/python3.7/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.7/site-packages/jinja2/sandbox.py", line 462, in call
    return __context.call(__obj, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 813, in strptime
    return datetime.strptime(string, fmt)
TypeError: strptime() argument 1 must be str, not None

Ive tried to add a test for existence first, so not to error out, but that doesnt seem to help. Could you please check I did it correctly:

      solaredge_last_updatetime:
        friendly_name: 'SolarEdge last update'
        value_template: >
          {% if states('sensor.solaredge_overview') != None %}
          {% set ts = state_attr('sensor.solaredge_overview','lastUpdateTime') %}
          {% set fmat = '%Y-%m-%d %H:%M:%S' %}
          {% set tz = '%z' %}
          {% set ts2 = as_timestamp(strptime(ts, fmat))|timestamp_custom(fmat ~ tz) %}
          {{relative_time(strptime(ts2, fmat ~ tz))}} ago
          {% else %} Unknown
          {% endif %}

thanks if you would

looks like the lastUpdateTime is None. Check for that instead.

like this:

          {% if state_attr('sensor.solaredge_overview','lastUpdateTime') != None %}
          {% set ts = state_attr('sensor.solaredge_overview','lastUpdateTime') %}
          {% set fmat = '%Y-%m-%d %H:%M:%S' %}
          {% set tz = '%z' %}
          {% set ts2 = as_timestamp(strptime(ts, fmat))|timestamp_custom(fmat ~ tz) %}
          {{relative_time(strptime(ts2, fmat ~ tz))}} ago
          {% else %} Unknown
          {% endif %}

I would have thought the full rest sensor to be unavailable and as a consequence so would its attributes (of which lastUpdateTime is one). That’s why I hoped to make it easier and test for that rest sensor.
Will test and report back if necessary. thanks.

I figured out from For_less_than: time that the better way to do this is:

{{ as_timestamp(now()) - as_timestamp(state_attr('sensor.solaredge_overview','lastUpdateTime'))| int }}

not sure what you mean to be better, but what you post hardly is a replacement for what I was looking for?:

btw, why I didnt come up with this:

{{relative_time(states.sensor.solaredge_overview.last_changed)}}

before is beyond me. It doesnt yield the same outcome as the larger template, but is very useable info…difference is the relative_time sensor is based on the states machines state for the sensor, while the template sensor is based on the attribute lastUpdateTime the SolarEdge data returns. Which seems to be 1 cycle behind:

btw 2 if you’re looking for simpler ways to write those less than X time ago templates try this:

          {{(now() - trigger.from_state.last_changed).total_seconds() > X|int}}

using this in my setup all the time:

          {{(now() - trigger.from_state.last_changed).total_seconds() >
             states('input_number.presence_timer')|int}}

so you can control the timing in the frontend.