How do I convert a string into a "number"?

Only have a “half-assed” solution that doesn’t really even passes the “configuration” check :sweat_smile:

AspirarIntent:
  action:
    service: script.turn_on
    target:
      entity_id: script.aspirar
    data:
      variables:
        divisao: "{{ divisao }}"
  speech:
    type: plain
    text: !include alexa_confirmation.yaml
aspirar:
  fields:
    divisao:
      description: "Divisão a aspirar"
  sequence:
    - variables:
        div: >
          {%- if {{ divisao }} == "corredor" -%}
          "1,11"
          {%- elif {{ divisao }} == "pais" -%}
          "3"
          {%- elif {{ divisao }} == "sala" -%}
          "6"
          {%- elif {{ divisao }} == "meninos" -%}
          "7"
          {%- elif {{ divisao }} == "gonçalo" -%}
          "8"
          {%- elif {{ divisao }} == "cozinha" -%}
          "9"
          {%- elif {{ divisao }} == "escritório" -%}
          "12"
          {% endif %}
    - service: xiaomi_miot.call_action
      target:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
      data:
        siid: 4
        aiid: 13
        params: [0, 1, "{{ div }}"]

change that to


    - variables:
        div: >
          {%- if divisao  == "corredor" -%}
            1,11
          {%- elif divisao == "pais" -%}
            3,
          {%- elif divisao == "sala" -%}
            6,
          {%- elif divisao == "meninos" -%}
            7,
          {%- elif divisao == "gonçalo" -%}
            8,
          {%- elif divisao == "cozinha" -%}
            9,
          {%- elif divisao == "escritório" -%}
            12, 
          {% endif %}

and

to

    - service: xiaomi_miot.call_action
      target:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
      data:
        siid: 4
        aiid: 13
        params: {{ [0, 1] + div }}

that last part doesn’t look right.

The last index of the array must contain a string with all the division ids that should be vacuumed. For example:

1 division (“sala”):
params: [0, 1, "6"]
2 divisions (“sala” + “cozinha”):
params: [0, 1, "6, 9"]

I see how it’s possible to pass the name of one room via the variable divisao but how are you passing the names of two rooms?

Are you separating the names with a comma so that divisao gets a value like this:

sala, cozinha

The reason why I’m asking is because the if-elif chain you created can only process the name of a single room.

Put the div in brackets, as in

      data:
        siid: 4
        aiid: 13
        params: {{ [0, 1] + [div] }}

You can’t concatenate a string with an array but an array with another array works.

Pro-tip. play around in Developer tools > Template with your code first to see what works :slight_smile:

By the way, I’ve done something similar for Google Assistant and Xiaomi vacuums (through IFTTT) and in the end I went with writing a python script for some more flexibility.

Not saying you should but check here if you want some inspiration:

What I wrote does that. Div is already a list, So you simply have to add them.

His API on the other hand requires a string that is comma separated as a last argument. So your suggestion will not work.

@r3pek on mobile currently, will post a modification when I get to a desktop

ok, my bad. Yeah, only one. expect for the first case (“corredor”) where I actually already map 2 values on it (because it’s actually 2 rooms).

@oscarb
The Jinja gods don’t like me :wink:

“Check configuration” says:

Error loading /config/configuration.yaml: while parsing a flow mapping
in "/config/scripts.yaml", line 46, column 18
expected ',' or '}', but got '<scalar>'
in "/config/scripts.yaml", line 46, column 27

(line 46 is the params line)

EDIT: Same error with or without the brackets around div

aspirar:
  fields:
    divisao:
      description: "Divisão a aspirar"
  sequence:
    - variables:
        rooms:
          corredor: '1, 11'
          pais: '3'
          sala: '6'
          meninos: '7'
          gonçalo: '8'
          cozinha: '9'
          escritório: '12'
    - service: xiaomi_miot.call_action
      target:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
      data:
        siid: 4
        aiid: 13
        params: [0, 1, "{{ rooms.get(divisao, '') }}"]

EDIT

This is the functional equivalent in the Template Editor:


Correction. Removed errant > symbol.

Ok, if you want to feed it multiple rooms like @123 is eluding, you’ll have to make the template differently.

    - variables:
        div: >
          {% set which = divisao if divisao is iterable and divisao is not string else [ divisao ] %}
          {% set items = {
            "pais": 3,
            "sala": 6,
            "meninos": 7,
            "gonçalo": 8,
            "cozinha": 9,
            "escritório": 12
          } %}
          {% set ret = items.items() | list | selectattr('0', 'in', which) | map(attribute='1') | list %}
          {% set ret = ret + [1,11] if 'corredor' in divisao else ret %}
          {{ ret | sort }}

Then later on in your service call…

    - service: xiaomi_miot.call_action
      target:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
      data:
        siid: 4
        aiid: 13
        params: [0, 1, "{{ div | join(', ') }}" ]

secondly, if you’re using the template editor, you it won’t create the variables for you. You have to create them.

In order to test the the first template…

          {% set divisao = 'sala', 'corredor' %}
          {% set which = divisao if divisao is iterable and divisao is not string else [ divisao ] %}
          {% set items = {
            "pais": 3,
            "sala": 6,
            "meninos": 7,
            "gonçalo": 8,
            "cozinha": 9,
            "escritório": 12
          } %}
          {% set ret = items.items() | list | selectattr('0', 'in', which) | map(attribute='1') | list %}
          {% set ret = ret + [1,11] if 'corredor' in divisao else ret %}
          {{ ret | sort }}

in order to test the second template…

          {% set divisao = 'sala', 'corredor' %}
          {% set which = divisao if divisao is iterable and divisao is not string else [ divisao ] %}
          {% set items = {
            "pais": 3,
            "sala": 6,
            "meninos": 7,
            "gonçalo": 8,
            "cozinha": 9,
            "escritório": 12
          } %}
          {% set ret = items.items() | list | selectattr('0', 'in', which) | map(attribute='1') | list %}
          {% set ret = ret + [1,11] if 'corredor' in divisao else ret %}
          {% set div = ret | sort %}
        params: [0, 1, "{{ div | join(', ') }}" ]

I’m not entirely sure that will work. I don’t believe the template resolver can handle a dictionary that doesn’t look like a dictionary.

EDIT, as I suspected, it cannot

EDIT2: And i’m not sure it can use portuguese letters as yaml, which is why he may have to resort to using an old fashion jinja dictionary.

I think the only mistake there is the > left over from copy-paste. Without it, that seems like a valid dictionary.

I’ll test it in a script to confirm (you may be right about the ç).

The biggest concern with that way is the special characters. If that does work the next hurdle would be the automatic typing which might turn corredor into a list of numbers.

@r3pek I want to know what room is a battle room

I tested this script by passing gonçalo to it and it reported 8. Seems to have had no problem with the accented characters.

aspirar:
  fields:
    divisao:
      description: "Divisão a aspirar"
  sequence:
    - variables:
        rooms:
          corredor: '1, 11'
          pais: '3'
          sala: '6'
          meninos: '7'
          gonçalo: '8'
          cozinha: '9'
          escritório: '12'
    - service: notify.persistent_notification
      data:
        message: "{{ rooms.get(divisao, '') }}"

Screenshot from 2022-03-07 16-12-36

Screenshot from 2022-03-07 16-12-26

The master bedroom? :sweat_smile:

1 Like

if that’s the case mixing the 2…

aspirar:
  fields:
    divisao:
      description: "Divisão a aspirar"
  sequence:
    - variables:
        rooms:
          corredor: 1, 11
          pais: 3
          sala: 6
          meninos: 7
          gonçalo: 8
          cozinha: 9
          escritório: 12
        div:
          {% set which = divisao if divisao is iterable and divisao is not string else [ divisao ] %}
          {% set ns = namespace(ret=[]) %}
          {% for x in rooms.items() | list | selectattr('0', 'in', which) | map(attribute='1') | list %}
            {% set v = [ x ] if x is is_number else x %}
            {% set ns.ret = ns.ret + v %}
          {% endfor %}
          {{ ns.ret }}
    - service: xiaomi_miot.call_action
      target:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
      data:
        siid: 4
        aiid: 13
        params: [0, 1, "{{ div | join(', ') }}"]

Funnily enough, when I had asked my question about passing multiple room names, I had already whipped up something to handle it. :slight_smile: However, your version is more bulletproof because it validates the received data whereas mine assumes it arrives in the correct format (ergo “whipped up”).

aspirar:
  fields:
    divisao:
      description: "Divisão a aspirar"
  sequence:
    - variables:
        rooms:
          corredor: '1, 11'
          pais: '3'
          sala: '6'
          meninos: '7'
          gonçalo: '8'
          cozinha: '9'
          escritório: '12'
        div: >
          {% set ns = namespace(d=[]) %}
          {% for d in divisao.split(', ') %}
            {% set ns.d = ns.d + [rooms.get(d, '0')] %}
          {% endfor %}
          {{ ns.d | join(', ') }}
    - service: xiaomi_miot.call_action
      target:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
      data:
        siid: 4
        aiid: 13
        params: [0, 1, "{{ div }}"]

Yah, I’ve learned to never assume when it comes to the resolver. I.e. I always assume wrong :rofl:

Love you guys :wink: Used this solution:

aspirar:
  fields:
    divisao:
      description: "Divisão a aspirar"
  sequence:
    - variables:
        rooms:
          corredor: "1,11"
          pais: "3"
          sala: "6"
          meninos: "7"
          gonçalo: "8"
          cozinha: "9"
          escritório: "12"
    - service: xiaomi_miot.call_action
      data:
        entity_id: vacuum.viomi_v18_e271_robot_cleaner
        siid: 4
        aiid: 13
        params: [0, 1, "{{ rooms.get(divisao, '') }}"]

@petro the “battle room” is wherever the wife wants it to be :innocent:

Now, the only problem I have is with “corredor” since it passes 2 room ids.

While testing the service call, this works:

service: xiaomi_miot.call_action
data:
  entity_id: vacuum.viomi_v18_e271_robot_cleaner
  siid: 4
  aiid: 13
  params: [0,1,"1,11"]

But for some reason, when using the script above, it doesn’t.
This shows up on the logs:

Viomi S9(viomi.vacuum.v18): Call miot action {'did': '329449566', 'siid': 4, 'aiid': 13, 'in': [{'piid': 36, 'value': 0}, {'piid': 37, 'value': 1}, {'piid': 38, 'value': (1, 11)}]} failed: {'code': -9999, 'message': 'user ack timeout'}