core icon indicating copy to clipboard operation
core copied to clipboard

Dict key must be str when sending parameters

Open geekofweek opened this issue 1 year ago • 20 comments

The problem

When attempting to send param data via an automation it consistently throws an error that Dict key must be str. Oddly enough if I send the same command via the services menu in the UI it works. I don't actually believe this is an issue with the iRobot integration but something else upstream with how it is the parsing data but is the only integration I've ran into this issue on thus far.

Services UI (Works):

service: vacuum.send_command
target:
  entity_id: vacuum.basement_roomba
data:
  command: start
  params:
    pmap_id: snnFyIYBTzmsjnbyPbW64R
    regions:
      - region_id: "2"
        type: rid

Automation (Does Not Work):

    - service: vacuum.send_command
      data:
        command: start
        params:
          ordered: '1'
          pmap_id: snnFyIYBTzmsjnbyPbW64R
          regions:
            - region_id: '7'
              type: rid
      target:
        entity_id: vacuum.basement_roomba

Automation - Reformatting the param payload (Does Not Work):

    - service: vacuum.send_command
      data:
        command: start
        params: {"pmap_id": "snnFyIYBTzmsjnbyPbW64R", "regions": [{"region_id": "7", "type": "rid"}]}
      target:
        entity_id: vacuum.basement_roomba

I've attempted various methods of putting quotes or apostrophe around the pmap_id with no luck.

When I put {"pmap_id": "snnFyIYBTzmsjnbyPbW64R", "regions": [{"region_id": "7", "type": "rid"}]} into the template tool in the UI it reports it back as a string.

I've read through the various release notes and changes and couldn't find a documented reason this would no longer function as it did previously.

What version of Home Assistant Core has the issue?

core-2023.12.0

What was the last working version of Home Assistant Core?

core-2023.11.3

What type of installation are you running?

Home Assistant Container

Integration causing the issue

Robot Roomba and Braava

Link to integration documentation on our website

https://www.home-assistant.io/integrations/roomba/

Diagnostics information

No response

Example YAML snippet

- service: vacuum.send_command
      data:
        command: start
        params:
          ordered: '1'
          pmap_id: snnFyIYBTzmsjnbyPbW64R
          regions:
            - region_id: '7'
              type: rid
      target:
        entity_id: vacuum.basement_roomba


    - service: vacuum.send_command
      data:
        command: start
        params: {"pmap_id": "snnFyIYBTzmsjnbyPbW64R", "regions": [{"region_id": "7", "type": "rid"}]}
      target:
        entity_id: vacuum.basement_roomba

Anything in the logs that might be useful for us?

2023-12-08 11:59:55.529 ERROR (MainThread) [homeassistant.components.automation.roomba_run_upstairs_roomba_in__office] While executing automation automation.roomba_run_upstairs_roomba_in_office
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/automation/__init__.py", line 655, in async_trigger
    await self.action_script.async_run(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1578, in async_run
    return await asyncio.shield(run.async_run())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 420, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 470, in _async_step
    self._handle_exception(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 493, in _handle_exception
    raise exception
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 468, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 704, in _async_call_service_step
    response_data = await self._async_run_long_action(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 666, in _async_run_long_action
    return long_task.result()
           ^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2067, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2104, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 272, in handle_service
    return await service.entity_service_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 878, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 948, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/roomba/irobot_base.py", line 266, in async_send_command
    await self.hass.async_add_executor_job(
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/roombapy/roomba.py", line 224, in send_command
    str_command = orjson.dumps(roomba_command).decode("utf-8")
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Dict key must be str

Additional information

I have a feeling that the following issues might be related, I tried the changes in https://github.com/home-assistant/core/pull/105314 but that did not fix it.

https://github.com/home-assistant/core/issues/105309 https://github.com/home-assistant/core/issues/105315 https://github.com/home-assistant/core/pull/105314 https://github.com/home-assistant/core/issues/105318

geekofweek avatar Dec 08 '23 18:12 geekofweek

Hey there @pschmitt, @cyr-ius, @shenxn, @xitee1, mind taking a look at this issue as it has been labeled with an integration (roomba) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of roomba can trigger bot actions by commenting:

  • @home-assistant close Closes the issue.
  • @home-assistant rename Awesome new title Renames the issue.
  • @home-assistant reopen Reopen the issue.
  • @home-assistant unassign roomba Removes the current integration label and assignees on the issue, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the issue.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the issue.

(message by CodeOwnersMention)


roomba documentation roomba source (message by IssueLinks)

home-assistant[bot] avatar Dec 08 '23 18:12 home-assistant[bot]

Facing the same issue with my automation. CleanShot 2023-12-11 at 18 57 52@2x

nk3750 avatar Dec 12 '23 02:12 nk3750

I worked around it in a much more complicated way. I used some python scripts that ties into input booleans per room, when toggled on and the script is executed it cleans those rooms in that order. The automations just toggle on those input booleans and execute the script. It gave me a way to setup room cleaning in the UI and worked around this problem for now.

Just make sure the input booleans are created and update the python scripts to utilize your RID or ZIDs, input boolean entity names, Roomba entity name, and the pmap_id.

I think this is a larger change with how strings are being interpreted in automations, I just worked around it for now until I can find more time to look into it further. I'm not even sure I know where the change happened at this point.

geekofweek avatar Dec 12 '23 05:12 geekofweek

I am having the exact same issue - kindly let me know how I can help troubleshoot

ghanjiboy avatar Dec 16 '23 13:12 ghanjiboy

Have the same problem here, roomba cleaner is no more able to work

khorchanov avatar Dec 16 '23 15:12 khorchanov

Same problem!

ugomark avatar Dec 16 '23 22:12 ugomark

I think this may have been resolved with the 2023.12.3 patch. I just updated and I’m able to send commands now.

(Mentioning @geekofweek @ugomark @khorchanov @nk3750 @jeeftor for posterity, since this was pretty frustrating to try to troubleshoot for me, and this latest update fixed it)

kylehakala avatar Dec 17 '23 23:12 kylehakala

Agreed, seems to be working on 2023.12.3, thanks folks!

edsaavedra84 avatar Dec 19 '23 15:12 edsaavedra84

Fun fact, nothing really changed in 2023.12.3

joostlek avatar Dec 19 '23 15:12 joostlek

Appears that 2023.12.3 resolves it. Will open a new case if the problem persists in the future.

geekofweek avatar Dec 19 '23 15:12 geekofweek

@geekofweek fyi I have 2023.12.3 and the problem is still there :(

khorchanov avatar Dec 19 '23 16:12 khorchanov

Ah no, my bad, I ran the vaccum: send command service on the "run" option and that actually works fine when you test it:

image

But if it's called from an automation, I keep getting the same error:

image

  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 878, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 948, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/roomba/irobot_base.py", line 266, in async_send_command
    await self.hass.async_add_executor_job(
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/roombapy/roomba.py", line 224, in send_command
    str_command = orjson.dumps(roomba_command).decode("utf-8")
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Dict key must be str

edsaavedra84 avatar Dec 19 '23 16:12 edsaavedra84

2023.12.3 and the problem is still there with an automation

Rep-Hueman avatar Dec 19 '23 17:12 Rep-Hueman

I'll reopen since I don't see any code change that would've fixed this and people are reporting it's not working

joostlek avatar Dec 19 '23 17:12 joostlek

For me this error appears when i run the command to start roomba with params in a script. When executing the same command directly in a Dashboard-Button it works just fine. Strange Also same as above when running the sequence alone from the ui.

Script (Not Working):

alias: asdf
sequence:
  - service: vacuum.send_command
    target:
      entity_id: vacuum.roomba
    data:
      command: start
      params:
        pmap_id: asdf
        regions:
          - region_id: "asdf"
            type: rid
        user_pmapv_id: asdf
mode: single
icon: mdi:robot-vacuum-variant

Dashboard-Button (Working):

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: vacuum.send_command
  target:
    entity_id: vacuum.roomba
  data:
    command: start
    params:
      pmap_id: asdf
      regions:
        - region_id: "asdf"
          type: rid
      user_pmapv_id: asdf

oliverhildner avatar Dec 19 '23 19:12 oliverhildner

I have the same as oliverhildner. Everything works when executing command via a button, but when calling a script to run the same commands, it throws an error.

Running on 2023.12.3 (edit: correct script tag used)

Script:

vacuum_clean_area:
   description: "Set the correct area and start cleaning"
   sequence:
   - service: input_select.select_option
     data: 
       option: "{{ area }}"
     target:
       entity_id: input_select.vacuum_areas
   - service: vacuum.send_command
     data:
       entity_id: vacuum.assepoets
       command: start
       params:
         pmap_id: "{{ pmap_id }}"
         regions: "{{ regions  }}"        
         user_pmapv_id: "{{ user_pmapv_id }}"
   mode: single
   icon: mdi:vacuum-outline

Lovelace:

    service: script.vacuum_clean_area
        data:
          area: "Boven"
          pmap_id: "----"
          regions:
          - region_id: '1' # Gang
            type: rid 
          - region_id: '10' # Slaapkamer
            type: rid 
          - region_id: '8' # Babykamer
            type: rid 
          - region_id: '9' # Logeerkamer
            type: rid     
          user_pmapv_id: "----"

dhoeben avatar Dec 20 '23 10:12 dhoeben

Maybe it's also notable to say that this error appears only when any parameter is added to the command. So executing the script without any params works. But unfortunately they are neccessary for the script to make sense in this case.

oliverhildner avatar Dec 22 '23 14:12 oliverhildner

Just adding another voice to this conversation. I, too, have this issue and I've only now noticed it because I've been away from home for several weeks.

ecodweeb avatar Dec 22 '23 19:12 ecodweeb

Same here..

sequence:
  - service: vacuum.send_command
    target:
      device_id: xyz
    data:
      command: start
      params:
        pmap_id: xyz
        regions:
          - region_id: "10"
            type: rid
mode: single
icon: mdi:robot-vacuum

2023-12-23 14:31:58.739 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [544259798720] Dict key must be str
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 238, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2067, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2104, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 605, in _service_handler
    response = await self._async_start_run(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 563, in _async_start_run
    script_result = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 594, in _async_run
    return await self.script.async_run(script_vars, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1578, in async_run
    return await asyncio.shield(run.async_run())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 420, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 470, in _async_step
    self._handle_exception(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 493, in _handle_exception
    raise exception
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 468, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 704, in _async_call_service_step
    response_data = await self._async_run_long_action(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 666, in _async_run_long_action
    return long_task.result()
           ^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2067, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2104, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 272, in handle_service
    return await service.entity_service_call(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 878, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 948, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/roomba/irobot_base.py", line 266, in async_send_command
    await self.hass.async_add_executor_job(
  File "/usr/local/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/roombapy/roomba.py", line 224, in send_command
    str_command = orjson.dumps(roomba_command).decode("utf-8")
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Dict key must be str

nullbit-dev avatar Dec 23 '23 14:12 nullbit-dev

I am very much confused by this issue. The issue itself sounds like something is wrong with HA. When we look at the logs, it looks like we are sending something invalid to the library.

There is debug logging that logs the command being sent to the roomba. I tried both ways with logging and to my surprise:

2023-12-26 16:57:52.300 DEBUG (MainThread) [homeassistant.components.roomba.irobot_base] async_send_command start ({'pmap_id': 'snnFyIYBTzmsjnbyPbW64R', 'regions': [{'region_id': '2', 'type': 'rid'}]}), {}
2023-12-26 16:57:52.301 DEBUG (SyncWorker_12) [roombapy.roomba] Send command: start
2023-12-26 16:58:33.034 DEBUG (MainThread) [homeassistant.components.roomba.irobot_base] async_send_command start ({'pmap_id': 'snnFyIYBTzmsjnbyPbW64R', 'regions': [{'region_id': '2', 'type': 'rid'}]}), {}
2023-12-26 16:58:33.037 DEBUG (SyncWorker_1) [roombapy.roomba] Send command: start

They both send exactly the same data. So I am a bit weirded out on why this happens. I can't dig deeper as I am not on my main dev pc. But I will try to look into this somewhere soon

joostlek avatar Dec 26 '23 16:12 joostlek

The reason behind this error is that orjson doesn't support subclasses of str. See https://github.com/ijl/orjson/issues/446 for more info. The key of the dict is of type NodeStrClass instead of str, I'll ask around

joostlek avatar Dec 28 '23 19:12 joostlek

I’ll take a look in the morning as it’s too late now for me

bdraco avatar Dec 29 '23 09:12 bdraco

https://github.com/pschmitt/roombapy/pull/214 should fix the issue once its merged, released, and bumped in HA

bdraco avatar Dec 29 '23 19:12 bdraco

You guys are the best, thank you! Can't wait for it to be in the next update :P

oliverhildner avatar Dec 30 '23 14:12 oliverhildner

Heads up! This fix has been merged in the 2024.1 update that is rolling out now.

kylehakala avatar Jan 04 '24 03:01 kylehakala

Ha... it's release day I didn't even realize! :)

jeeftor avatar Jan 04 '24 04:01 jeeftor

Seems to be working now! Thanks for the quick (and not easy) fix!

dhoeben avatar Jan 04 '24 12:01 dhoeben

thank you guys, working like a charm again!

edsaavedra84 avatar Jan 04 '24 14:01 edsaavedra84