core: Dict key must be str when sending parameters

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

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Reactions: 3
  • Comments: 28 (9 by maintainers)

Commits related to this issue

Most upvoted comments

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

2023.12.3 and the problem is still there with an automation

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

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

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

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

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

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.