Valetudo: Useful blueprints for your vacuum robots

Question about this:

I installed the “Valetudo Map Card” HACS frontend lovelace modifier and I can see my map through it. Do these other map viewers provide any additional benefits/features that I’m missing with the frontend modifier I’m using?

I clicked your link (GitHub - Hypfer/ICantBelieveItsNotValetudo: A Valetudo companion service which renders maps to pngs) and it says it’s been archived in favor of something else called valetudopng. This valetudopng github page has links to SEVERAL alternatives and all of these seem to be doing the same thing…

Which one is the best/optimal one to be using?

Depends on your usecase. Personally, I have switched to valetudopng as it provides a native Docker build. I have not tested the alternative solutions. Technically, anything that provides a camera entity can be used.

I’m using GitHub - sca075/valetudo_vacuum_camera: Integration that export Valetudo Vacuums maps to Home Assistant because its just a simple HACS plugin instead of seperate service.
But I can’t get it to show images at all. I had to remove the “mqtt” filter for it to show up on the automation page, but no image in the cleaning finished notification.

Mhm sorry, I don’t have any direct experience with that. I might remove the filter from the blueprint (though I am a bit hesitant because it will then list all the camera entities), but if you already did that locally, I don’t know why the notification would not work. That integration does provide a camera entity and it does work on its own?

Yes it does work on its own, maybe the image notification of the ha app is not working? haven’t used it before.

I haven’t had such an issue reported before, so I assume it does work for both iOS and Android (I can only test iOS). Have you tried in your home network (to exclude any issues with remote access)?

I did a bit a of digging and it looks like dynamic attachments like linking a camera are only supported on IOS Dynamic attachments | Home Assistant Companion Docs

Most of the workarounds I see it make an image snapshot in the www folder, and it turns out the integration already makes those by itself: https://github.com/sca075/valetudo_vacuum_camera/blob/46c2f894538e54b6c8243bcd96c5e52b17bebcf3/docs/snapshots.md !

So I added a second optional field and made the rendered map optional, bit of a hacky solution as you have to leave one empty, but let me know if you want me make a merge request for this (or if you know how to validate only 1 input being used)

blueprint:
  name: 'Valetudo: Notifications'
  description: Sends a notification after a successful clean-up run and on error.
  source_url: https://github.com/mundschenk-at/ha-valetudo-blueprints/blob/13f3d07f981ed24736491a31fa4c605fcfdcba64/yaml/automation/valetudo-notifications.yaml
  domain: automation
  homeassistant:
    min_version: 2022.10.0
  input:
    vacuum:
      name: Vacuum Robot
      description: The vacuum robot entity.
      selector:
        entity:
            filter:
              - domain: vacuum
              - integration: mqtt
            multiple: false
    rendered_map:
      name: Rendered Map (IOS)
      description: Camera sensor of the map (Leave empty if using Android)
      selector:
        entity:
          filter:
            - domain: camera
          multiple: false
      default:
    map_snapshot:
      name: Map Snapshot (Android)
      description: Location inside the www folder where a PNG snapshot is stored (Leave empty if using Rendered Map above)
      default: '/local/snapshot_yourvacuum.png'
    error_message:
      name: Error Message
      description: The sensor containing the last error message.
      selector:
        entity:
          filter:
            - domain: sensor
            - integration: mqtt
          multiple: false
    dashboard_url:
      name: Dashboard URL
      description: The dashboard that should be opened when tapping on the notification.
      default: /lovelace/
      selector:
        text:
          type: url
          multiline: false
    notify_device:
      name: Notification Device(s)
      description: The notified device(s).
      default: false
      selector:
        device:
          filter:
          - integration: mobile_app
          multiple: true
    notify_group:
      name: Notification Group
      description: The name of the notification group to call. ('notify' for all devices)
      default: ''
    language:
      name: Language
      description: The language used for the notifications.
      default: English
      selector:
        select:
          options:
          - English
          - German
          sort: false
          custom_value: false
          multiple: false
trigger_variables:
  rendered_map_sensor: !input rendered_map
  map_snapshot_sensor: !input map_snapshot
  error_message_sensor: !input error_message
  notify_devices: !input notify_device
  group_target: !input notify_group
  language: !input language
trigger:
- platform: state
  entity_id: !input vacuum
  from: cleaning
  to: returning
  id: cleaning_finished
  variables:
    msg_type: success_msg
- platform: state
  entity_id: !input vacuum
  to: error
  for:
    hours: 0
    minutes: 0
    seconds: 5
  id: error
  variables:
    msg_type: error_msg
condition:
- condition: or
  alias: Finished cleaning task or error message is not empty
  conditions:
  - condition: trigger
    id: cleaning_finished
  - condition: not
    conditions:
    - condition: state
      entity_id: !input error_message
      state: ''
variables:
  strings:
    English:
      title: Vacuum
      success_msg: Cleaning task succeeded at {{ now().strftime('%-H:%M') }}.
      error_msg: 'The robot has encountered an issue: {{ states( error_message_sensor
        ) }}'
      default_msg: Everything is working fine.
    German:
      title: Staubsauger
      success_msg: Die Reinigung wurde um {{ now().strftime('%-H:%M') }} Uhr erfolgreich
        abgeschlossen.
      error_msg: 'Der Staubsauger hat ein Problem: {{ states( error_message_sensor
        ) }}'
      default_msg: Alles gut.
  notify_targets: "{% set ns = namespace(targets=[]) %} {% if notify_devices is iterable
    %}\n  {% for device_id in notify_devices -%}\n      {% set ns.targets = ns.targets
    + [ \"notify.mobile_app_\" ~ device_attr( device_id, 'name' )|slugify ] %}\n  {%-
    endfor %}\n{%- endif %} {% if group_target is defined and group_target is string
    and group_target != '' %}\n    {% set ns.targets = ns.targets + [ \"notify.\"
    ~ group_target|slugify ] %}\n{%- endif %} {{ns.targets}}"
  title: '{{ strings[language][''title''] }}'
  message: '{{ strings[language][msg_type] | default(strings[language][''default_msg''])
    }}'
  data:
    entity_id: '{{ rendered_map_sensor | default(none) }}'
    image: '{{ map_snapshot_sensor | default(none) }}'
    priority: high
    url: !input dashboard_url
    clickAction: !input dashboard_url
action:
- repeat:
    for_each: '{{ notify_targets }}'
    sequence:
    - service: '{{ repeat.item }}'
      data:
        title: '{{ title }}'
        message: '{{ message }}'
        data: '{{ data }}'
mode: queued

Thx, I’ll have to look into that. Maybe you can test a new version in the next few days. It should be possible to use camera_proxy instead of manually managing snapshots.

While I didn’t get around to the camera_proxy solution yet, I’ve released a new version of the blueprint that uses the Status Flag sensor provided by newer Valetudo releases to prevent multiple notifications from being sent when a cleaning run is interrupted, but resumed later.

1 Like

Hey, I just found this and it’s super helpful! Thank you!

Before installing this, I started setting up binary sensors to collect which rooms I wanted to be vacuumed, as per the Valetudo documentation:

  • Each of my individual “Vacuum this room?” binary sensors is customized in /config/customize.yaml to have a room_id: attribute, with the segment name stored as the corresponding value.
  • These sensors are grouped under group.vacuum_rooms.

Additionally, I have a Number helper, input_number.vacuum_iterations, which I intend to use to set the number of vacuum passes.

I’ve created a “Valetudo: Clean Rooms” script using this blueprint. When I call that script, how can I pass the list of rooms to clean and the number of iterations to it from these entities?

The script takes a comma-separated list of room names, not the IDs. I dislike the many helper entities recommended in the official documentation, as they are not needed to convert room names to IDs (the blueprint does it with a bit of template magic). Also the number iterations is a script parameter as well.

Wanted to let you know the appreciation I have for you and the ‘helper’.

I used a Roborock S5 with Valetudo using this script, then replaced it with a Q Revo and missed the ease of executing automations. I returned the Q Revo and bought a refurb Dreame L10S and put Valetudo on it. Equal reasons because of the offline aspect of Valetudo and your helpers.

Thank you!

1 Like

I have now added an image to the notification payload using the camera_proxy API. Can you (or someone else with an Android device) please check if this works correctly?

Hi @mundschenk-at

Just tried it on my side, but for now I can’t get it to display the actual room image, only the valetudo embedded image message.

image

EDIT : Ok now that I’ve read previous messages, I installed valetudopng, and it seem to work, but the image is cropped, i’ll have to figure out a way to have the full image.

I tried to add custom limits to valetudopng but something must be wrong, the container does start but image is not available if I don’t leave this blank.

Also I tried to simulate an error by lifting the robot while it was running, but I dont get notified, is there something I’m missing, or is it just not designed to do this ?

Unfortunately, that’s kind of hard to debug as I don’t have an Android device available. I’ve never had to modify the valetudopng output, but maybe that’s because apartment is more squarish?

You’d have to check with the author of valetudopng, but as I understand it, cropping/limits is only intended for when you don’t want to show the whole map. I don’t think this should be solved at the Dock container level.

OK, a quick search shows that there is something funky about the aspect ratio with notifications in Android. I’ll investigate.

That depends entirely on the robot in question. Sometimes my Dreame takes a bit of time until it detects that it is treading air. When the robot signals an error state, the notifications will trigger. If there is no such signal or Valetudo does not expose it, the notification won’t happen.

1 Like

Yeah it looks like an Android limitation, maybe adding a button to interact with the notification and acces a full image would be a good idea, like in this blueprint for Frigate camera notification GitHub - SgtBatten/HA_blueprints: Somewhere to store automation blueprints

button code
    button_1:
      name: Action Button 1 Text
      description: 'The text used on the first Action button at the bottom of the notification. Set the URL below. (Default is "View Clip")'
      default: "View Clip"
    url_1:
      name: Action Button 1 URL
      description: Customise what happens when you press the first Action Button. Select from one of the preconfigured options or enter your own custom URL.
      default: "{{base_url}}/api/frigate{{client_id}}/notifications/{{id}}/{{camera}}/clip.mp4"
      selector:
        select:
          options:
            - label: View Clip
              value: "{{base_url}}/api/frigate{{client_id}}/notifications/{{id}}/{{camera}}/clip.mp4"
            - label: View Snapshot
              value: "{{base_url}}/api/frigate{{client_id}}/notifications/{{id}}/snapshot.jpg"
            - label: View Stream
              value: "{{base_url}}/api/camera_proxy_stream/camera.{{trigger.payload_json['after']['camera'] | lower | replace('-','_')}}?token={{state_attr( 'camera.' ~ camera, 'access_token')}}"
            - label: Open Home Assistant (web)
              value: "{{base_url}}/lovelace"
            - label: Open Home Assistant (app)
              value: /lovelace
            - label: Open Frigate
              value: /ccab4aaf_frigate/dashboard
            - label: Open Frigate (Full Access)
              value: /ccab4aaf_frigate-fa/dashboard
            - label: Open Frigate (proxy)
              value: /ccab4aaf_frigate-proxy/dashboard
            - label: Open Reolink App (Android)
              value: app://com.mcu.reolink
            - label: Custom Action (Manual Trigger)
              value: custom-{{ camera }}
          custom_value: true
    icon_1:
      name: Action Button 1 icon - iOS Only
      description: Customise the Icon on the first Action Button. Only the iOS SFSymbols library is supported, not mdi:icons. e.g., sfsymbols:bell
      default: ""

The interactions redirects you to a clip, or a snapshot in your browser, here’s the result :
image

It’s an old Roborock S50, the “error” does change to something like “wheels not in contact in the floor” (I don’t remember the exact message) when lifting it.

If I understand the blueprint correctly, it’s the vacuum entity that triggers the notification, and it seems to change to error correctly

I’ll have to do some tests :wink:

Have a look at the Trace of your automation execution. You should be able to step through to see why its not executing.

Made a few more tries, and it works, after reading your blueprint again, I noticed it has to stay in “error” state for 5 second before the automation triggers.

Once this was solved, I encountered an other issue, the notification kept displaying “Unknown error undefined”.

After looking at my HA logs, I noticed the error entity goes to this state for 7 to 9 seconds before displaying the “real” error.

So I modified your blueprint to trigger after 10 seconds instead of 5, and it worked like a charm, and now it displays “dustbin missing”, or “wheels not in contact with the floor” correctly :slight_smile:

image

Thanks for your blueprint, and for your help !

Mhm, thanks for that info, looks like it should be configurable.

1 Like

Yeah, maybe have a “classic” and a “Roborock” option, or just a 5 second default, but that you can edit in your automation to fit any robot’s needs, with a short explanation of why this is there.