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

I’m playing with Alexa Skills to try and make Alexa make a robot vacuum cleaner vacuum a specific division.
The slot I get form Alexa API is the room name (“bedroom”, “kitchen”, …), but for the script action that starts the vacuum, I need the room ID (1,2, etc).

How can I convert between the two either directly on the intent_script that receives the Alexa API call, or a secondary script that I can call from the intent_script?

Thanks in advance for all the help!

Can you post everything you have so far? It’ll be much easier to assist you. Otherwise, I can give you a solution however it may not fit into your current flow.

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 }}"]