PiotrMachowski / lovelace-xiaomi-vacuum-map-card

This card provides a user-friendly way to fully control map-based vacuums in Home Assistant. Supported brands include Xiaomi (Roborock/Viomi/Dreame/Roidmi/Valetudo/Valetudo RE), Neato, Wyze, Roomba, Ecovacs (and probably more).
MIT License
1.45k stars 249 forks source link

Valetudo RE: Minor improvements for full support #434

Closed maximweb closed 2 years ago

maximweb commented 2 years ago

Description

I finally found the time to update to the latest version of your awesome card and tested the vacuum_platform: rand256/ValetudoRE.

I am close to a fully configured card utilizing pretty much all features, which Valetudo RE supports. I posted my configuration in the discussions (see #435).

While most things work as intended, I observed some minor things, which could be improved:

A) vacuum_clean_segment When selecting repeats > 1, the mqtt command appears to be slightly redundant:

{
  "command": "segmented_cleanup",
  "segment_ids": [
    "Schlafzimmer",
    "Schlafzimmer"
  ],
  "repeats": 2,
  "afterCleaning": "Base"
}

with the segment id being repeated as well as the global "repeats: 2" set. As far as I understand the API, only the latter should be done.

B) vacuum_goto_predefined On the card it is possible to select multiple predefined locations, which results in the following command:

{
  "command": "go_to",
  "spot_id": "Sofa,Schreibtisch"
}

Yet only one selection should be allowed.

C) (predefined)zoned_cleanup As I found the room detection of the map to be not as reliable, I have configured several predefined zones on the vacuum. My card is currently configured to handle them like this:

map_modes:
  - name: test
    icon: mdi:select-drag
    selection_type: ROOM
    service_call_schema:
      service: mqtt.publish
      service_data:
        topic: valetudo/rockrobo/custom_command
        payload: >-
          { "command": "zoned_cleanup", "zone_ids": [[selection]],
          "afterCleaning": "Base" }

What I would like to do is to add repeats with:

    repeats_type: INTERNAL
    max_repeats: 3

The MQTT API requests a form like:

{
"command": "zoned_cleanup",
"zone_ids": [
   "Foo",    // zone without repeat can be parsed directly, as done above
   {   // however, zones with repeat have to be encapsuated like this
        "id": "Bar",
        "repeats": 2
   }
],
"afterCleaning": "Stop"
}

D) Auto-discovery of predefined zones/spots/rooms Valetduo RE allows MQTT access to all predefined zones/spots/rooms from the vacuum with custom_command/get_destinations resulting in something like:

{
  "spots": [
    {
      "name": "SpotA",
      "coordinates": [
        32396,
        24058
      ]
    },
    {
      "name": "SpotB",
      "coordinates": [
        24744,
        28526
      ]
    }
  ],
  "zones": [
    {
      "name": "ZoneA",
      "coordinates": [
        [
          28889,
          23472,
          30306,
          24685,
          1    // I do not know what this number stands for
        ]
      ]
    },
    {
      "name": "ZoneB", // apparently a zone can also consist of multiple rectangles
      "coordinates": [
        [
          28475,
          24604,
          30665,
          25960,
          1
        ],
        [
          28676,
          25871,
          30219,
          29701,
          1
        ]
      ]
    }
  ],
  "rooms": [
    {
      "name": "RoomA",
      "id": 18   // the IDs appear to be auto generated
    },
    {
      "name": "RoomB",
      "id": 17
    }
  ],
  "updated": 1643509313129
}

Yet, I have to either write a Jinja2 template and run it each time new predefined zones/spots/rooms are created on the vacuum, or add all of them manually to the card.

Solution

A) Instead of using REPEAT in the platform template, it should be set to EXTERNAL in order to get:

{
  "command": "segmented_cleanup",
  "segment_ids": [
    "Schlafzimmer"
  ],
  "repeats": 2,
  "afterCleaning": "Base"
}

B) Limit the selection of predefined spots on the card to one. Is this possible?

C) Maybe it is possible to add a service call placeholder, e.g. [[selection_objects]] returning the required object-like output?:

[
  {
    "id": "Foo",
    "repeats": 2
  },
  {
    "id": "Bar",
    "repeats": 2
  }
]

D) I know there are some Jinja2 templates available to generate the required code for the card. However, it would be awesome if the card itself could extract these predefined zones/spots/rooms automatically. This way they would always be up to date with those defined on the vacuum.

Alternatives

No response

Context

No response

PiotrMachowski commented 2 years ago

Thank you @maximweb!

A) That's an easy fix 👍 B) That's an easy fix as well (max_selections: 1) C) Proposed approach might be problematic (different platforms will probably have different formats), but next release will add support for Jinja templates inside service calls, it might solve this issue D) This might be problematic, but maybe someday

PiotrMachowski commented 2 years ago

C) behold! config:

  - template: vacuum_clean_segment
    repeats_type: EXTERNAL
    service_call_schema:
      service: mqtt.publish
      evaluate_data_as_template: true
      service_data:
        topic: valetudo/rockrobo/custom_command
        payload: >-
          {"command": "zoned_cleanup","zone_ids": [{%for s in
          ('[[selection]]')|from_json %}{ "id": "{{s}}", "repeats":
          [[repeats]]}{%if not loop.last%},{%endif%}{%endfor%}],"afterCleaning":
          "Stop"}
    predefined_selections:
      - id: Foo
        label:
          text: Foo
          x: 22932
          'y': 30339
          offset_y: 35
        icon:
          name: mdi:bed
          x: 22932
          'y': 30339
      - id: Bar
        label:
          text: Bar
          x: 22282
          'y': 26496
        icon:
          name: mdi:shower
          x: 22282
          'y': 26496

output:

{
  "topic": "valetudo/rockrobo/custom_command",
  "payload": "{\"command\": \"zoned_cleanup\",\"zone_ids\": [{ \"id\": \"Bar\", \"repeats\": 1},{ \"id\": \"Foo\", \"repeats\": 1}],\"afterCleaning\": \"Stop\"}"
}
maximweb commented 2 years ago

B) That's an easy fix as well (max_selections: 1)

Ahh, thank you. I must have overlooked this in your documentation.

C) behold!

That's interesting! I was not aware that there is an option evaluate_data_as_template: true. Unfortunately this does not evaluate in my configuration. I get:

{ "command": "zoned_cleanup", "zone_ids": [{%for s in ('["Foo","Bar"]')|from_json %}{ "id": "{{s}}", "repeats": 2}{%if not loop.last%},{%endif%}{%endfor%}], "afterCleaning": "Base" }

in my MQTT explorer.

Does this require a specific version of the card or of Home Assistant?

PiotrMachowski commented 2 years ago

Does this require a specific version of the card or of Home Assistant?

Yup, a future one (card) ;)

https://github.com/PiotrMachowski/lovelace-xiaomi-vacuum-map-card/commits/dev

maximweb commented 2 years ago

Does this require a specific version of the card or of Home Assistant?

Yup, a future one ;)

OK, I see it's in the dev branch. I have installed your card using HACS, but don't recall that it offered me an (unstable) dev version. Am I overlooking something or do I either need to pull/compile manually or wait for the next release?

PiotrMachowski commented 2 years ago

Yeah, it isn't really ready for using yet and I haven't configured any beta releases. You would need to compile it by yourself. I can also provide you a compiled version, you can DM me at HA forum https://community.home-assistant.io/u/3_14/summary

PiotrMachowski commented 2 years ago

Current version: xiaomi-vacuum-map-card.zip

PiotrMachowski commented 2 years ago

You can also download a built version here: https://github.com/PiotrMachowski/lovelace-xiaomi-vacuum-map-card/actions?query=branch%3Adev Just select a commit and download an artifact

maximweb commented 2 years ago

You can also download a built version here: https://github.com/PiotrMachowski/lovelace-xiaomi-vacuum-map-card/actions?query=branch%3Adev Just select a commit and download an artifact

Thanks, I will give it a try.

PiotrMachowski commented 2 years ago

@maximweb have you found some time to check it out?

maximweb commented 2 years ago
        payload: >-
          {"command": "zoned_cleanup","zone_ids": [{%for s in
          ('[[selection]]')|from_json %}{ "id": "{{s}}", "repeats":
          [[repeats]]}{%if not loop.last%},{%endif%}{%endfor%}],"afterCleaning":
          "Stop"}

I have tested it with the latest built and it works!

PiotrMachowski commented 2 years ago

Thank you, that's great! I'll add it to the repo

maximweb commented 2 years ago

Thanks for all the swift replies and help.

So: A) clean_segment (rooms) should use external repeat: See PR #448 B) goto_predefined should only allow a single selection: Fixed in d0a4445 C) Nested repeat in zoned_cleanup: Fixed with Jinja template in service call

D) Automatically import vacuum destinations. Can you confirm that the newly added Jinja template evaluation solely works within service calls ?

As my predefined destinations are unlikely to change as often, I am happy using a template for the initial generation of my card using home assistant > developer settings > template. Here's an early version:

{# ----------------- PROVIDE YOUR OWN ENTITY IDS HERE ----------------- #}
{% set camera_entity = "camera.rockrobo_map_data" %}
{% set vacuum_entity = "sensor.rockrobo_destinations" %}
{# ------------------- DO NOT CHANGE ANYTHING BELOW ------------------- #}
{% set attributes = states[vacuum_entity].attributes %}
type: custom:xiaomi-vacuum-map-card
entity: {{ vacuum_entity }}
map_source:
  camera: {{ camera_entity }}
calibration_source:
  camera: true
map_modes:
  - template: vacuum_goto_predefined
{%- for spot in attributes.spots %}
      - position: {{ spot.coordinates }}
        id: {{ spot.name }}
        label:
          text: {{ spot.name }}
          x:  {{ spot.coordinates[0] }}
          'y':  {{ spot.coordinates[1] }}
          offset_y: 35
        icon:
          name: mdi:sofa
          x:  {{ spot.coordinates[0] }}
          'y':  {{ spot.coordinates[1] }}
{%- endfor %}
PiotrMachowski commented 2 years ago

Thanks for your cooperation :)

A) Merged C) Jinja template added to the template D) Yes, Jinja works only for service calls

By the way, I have now figured out that sections A and C of your original question talk about segments and zones. Does A) internally use rooms and C) internally use coordinates?

I have checked documentation and answered this question to myself 👍

You can check out future documentation of this platform here

PiotrMachowski commented 2 years ago

Update

I have added support for: