rytilahti / homeassistant-xiaomi-ng

3 stars 2 forks source link

Xiaomi Air Purifier 4: cannot change entities starting with `select.` #13

Closed amozeo closed 6 months ago

amozeo commented 7 months ago

Xiaomi Air Purifier 4 (zhimi.airp.mb5a) was connected using this ng integration with "Use generic miot implementation" enabled (without it, it fails configuration with WARNING (SyncWorker_24) [miio.device] 'AirPurifierMiot' does not specify any descriptors, please considering creating a PR. in logs, and I do expect that)

When trying to change any entity with id starting with select. (in the log below I tried to change fan level of mode manual) it fails with following error in logs:

2024-04-09 18:00:46.393 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140575151305664] Object of type Fan Level is not JSON serializable
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 239, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2319, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2356, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 905, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 975, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/select/__init__.py", line 195, in async_handle_select_option
    await self.async_select_option(option)
  File "/config/custom_components/xiaomi_miio/select.py", line 75, in async_select_option
    if await self._try_command(
       ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/xiaomi_miio/entity.py", line 85, in _try_command
    result = await self.hass.async_add_executor_job(full_func)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/miio/click_common.py", line 186, in _wrap
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/miio/miot_device.py", line 172, in set_property_by
    return self.send(
           ^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/miio/device.py", line 98, in send
    return self._protocol.send(
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/miio/miioprotocol.py", line 181, in send
    m = Message.build(msg, token=self.token)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 336, in build
    self.build_stream(obj, stream, **contextkw)
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 348, in build_stream
    self._build(obj, stream, context, "(building)")
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 2144, in _build
    buildret = sc._build(subobj, stream, context, path)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 2657, in _build
    return self.subcon._build(obj, stream, context, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 4304, in _build
    buildret = self.subcon._build(obj, stream, context, path)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 4616, in _build
    buildret = self.subcon._build(value, stream, context, path)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/construct/core.py", line 707, in _build
    obj2 = self._encode(obj, context, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/miio/protocol.py", line 160, in _encode
    json.dumps(obj).encode("utf-8") + b"\x00", context["_"]["token"]
    ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/json/encoder.py", line 200, in encode
    chunks = self.iterencode(o, _one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/json/encoder.py", line 258, in iterencode
    return _iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/json/encoder.py", line 180, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Fan Level is not JSON serializable

Home assistant version: Container 2024.4.2

rytilahti commented 6 months ago

it fails configuration with WARNING (SyncWorker_24) [miio.device] 'AirPurifierMiot' does not specify any descriptors, please considering creating a PR. in logs, and I do expect that

Yes, this is expected as the implementation does not define descriptors (https://python-miio.readthedocs.io/en/latest/contributing.html#status-containers). The genericmiot will hopefully replace the *Miot implementations in the future when it matures.