Displaying a sensor value that is a datetime/timestamp

I’ve done something that I’m not sure is the best way to go about it, even though it works. I’d be keen to hear if there is a better way to approach this.

I have a camera (Raspberry PI NOIR, but it’s not important) with a live feed in Lovelace. I have an automation that takes snapshots when motion is detected. To display the latest snapshot, I’ve set up a local file camera. This all works just fine.

I also want to display the datetime of the last snapshot. When I take the snapshot, I also write a UNIX timestamp (long int) to a text file. I read this value using a file sensor. I convert this value to a datetime using the template "{{ value | int | timestamp_local }}".

It doesn’t seem a camera using the local file platform has a last_changed or last_updated attribute, otherwise, I would’ve used it. I also couldn’t find a neat way to get the image file’s metadata (thinking about it now, I could probably use a shell script, but I’d still roughly end up in the same position).

The reason I think this is perhaps too hacky is that I don’t think sensors were intended to use with datetime’s, but rather ints and floats (even though my value is a long int timestamp).

Is there a better way to achieve this?

PS: During this, I also experimented with the relative_time function in the template, but it doesn’t seem to accept the datetime returned by strptime. I didn’t dig into the Python code to figure out why but did see some older and similar issues reported. I’m not sure whether this is a known issue. Happy to provide more info if someone wants to know more.

Wow, you must like doing things the hard way. :stuck_out_tongue_winking_eye: Why not just save the timestamp to an Input Datetime? (See the examples that save the current time using the now() function.) Or, if you don’t want the user to be able to change the time, or just want to control how the datetime is displayed, then you could save {{ now().timestamp() }} to an Input Number, then use a Template Sensor to display its value using the timestamp device class or whatever value_template you like.

Every state in the state machine has last_changed and last_updated fields (not to be confused with attributes.) See State Objects. In this case last_changed won’t help much because the state never changes from idle. However, depending on how you’re using the local_file camera, last_updated might be useful. Can you post your current automation?

2 Likes

Thanks, this helped a lot. My config isn’t much simpler, but the semantics are much better.

I opted for input_datetime over input_number as the latter requires me to set a min and max value so I will have to set max to max(longint) which seems unnecessary. (Side note: The value must not be set by a human/user.)

I made a mistake with how a queried last_changed and last_updated. Unfortunately, neither gives me a value that agrees with my need: Both get reset after a restart.

Here’s my latest config:

configuration.yaml:

shell_command:
  copy_last_snapshot_image: "cp `ls -t /tmp/camera.security_camera_*.jpg | head -n1` /home/homeassistant/.homeassistant/www/camera.security_camera_last.jpg"

ui-lovelace.yaml:

  - title: Security
    path: security
    icon: mdi:security
    badges: []
    cards:
      - type: picture-glance
        title: Security Camera
        camera_image: camera.security_camera
        entities:
          - switch.motion_led
          - automation.take_motion_snapshots
          - entity: script.security_camera_record_clip
            tap_action: 
              action: call-service
              service: script.turn_on
              service_data:
                entity_id: script.security_camera_record_clip
      - type: vertical-stack
        cards:                
          - type: picture-glance
            title: Last Motion Captured
            camera_image: camera.security_camera_last_snapshot
            entities: []
          - type: entities
            entities:
              - entity: sensor.security_camera_last_snapshot_relative
                name: Last Event

sensors.yaml:

  - platform: template
    sensors:
      security_camera_last_snapshot:
        entity_id: input_datetime.security_camera_last_snapshot
        device_class: timestamp
        value_template: "{{ states('camera.security_camera_last_snapshot') }}"
      security_camera_last_snapshot_relative:
        entity_id: input_datetime.security_camera_last_snapshot
        value_template: >
          {%- set t = state_attr('input_datetime.security_camera_last_snapshot', 'timestamp') %}
          {%- if t != None %}
            {%- set n = now().timestamp() %}
            {%- set d = n-t %}
            {%- set midnight_today = as_timestamp(strptime(now().date() | string, "%Y-%m-%d")) %}
            {%- set midnight_yesterday = midnight_today - 86400 %}
            {%- set midnight_week_ago = midnight_today - 604800 %}
            {%- if d < 60 %}
              {{ d | int }} seconds ago
            {%- elif d >= 60 and d < 120 %}
              1 minute ago
            {%- elif d < 3600 %}
              {{ (d // 60) | int }} minutes ago
            {%- elif d < n-midnight_today %}
              Today at {{ t | timestamp_custom('%H:%M') }}
            {%- elif d < n-midnight_yesterday %}
              Yesterday at {{ t | timestamp_custom('%H:%M') }}
            {%- elif d < n-midnight_week_ago %}
              {{ t | timestamp_custom('%A at %H:%M') }}
            {%- else %}
              {{ t | timestamp_local }}
            {%- endif %}
          {% else %}
            unknown
          {% endif %}

automations.yaml:

- alias: "Take Motion Snapshots"
  initial_state: false
  trigger:
    platform: state
    entity_id: binary_sensor.motion_sensor
    to: "on"
  action:
    - service: script.turn_on
      entity_id: script.security_camera_create_snapshot

scripts.yaml:

security_camera_create_snapshot:
  sequence:
    - service: input_datetime.set_datetime
      entity_id: input_datetime.security_camera_last_snapshot
      data_template:
        datetime: "{{ now() }}"
    - service: camera.snapshot
      data:
        entity_id: camera.security_camera
        filename: '/tmp/{{ entity_id.entity_id }}_{{ now().strftime("%Y%m%d-%H%M%S") }}.jpg'
    - service: shell_command.copy_last_snapshot_image
    - service: notify.family
      data:
        title: Security Camera
        message: "Motion detected!"
        data:
          attachment:
            url: http://securitypi.local/local/camera.security_camera_last.jpg