siku2 / hass-dingz

Home Assistant support for dingz wall switches
MIT License
14 stars 5 forks source link

APIv2: Blinds position/lamella setting fails #20

Closed OdyX closed 1 year ago

OdyX commented 1 year ago

I haven't managed to understand, hence fix the source of this issue I'm getting:

[547411987152] [Errno None] Can not write request body for http://10.40.2.53/api/v1/shade/1 :

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 205, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1910, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1950, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 226, in handle_service
    await service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 811, in entity_service_call
    future.result()  # pop exception if have
    ^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1034, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 851, in _handle_entity_call
    await result
  File "/config/custom_components/dingz/cover.py", line 93, in async_stop_cover
    await self._dingz_session.blind_stop(self._index)
  File "/config/custom_components/dingz/api.py", line 747, in blind_stop
    await self._post_plain(f"/shade/{index}/stop", **kwargs)
  File "/config/custom_components/dingz/api.py", line 657, in _post_plain
    async with self.__post_request(path, data) as resp:
  File "/usr/local/lib/python3.11/site-packages/aiohttp/client.py", line 1141, in __aenter__
    self._resp = await self._coro
                 ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/client.py", line 560, in _request
    await resp.start(conn)
  File "/usr/local/lib/python3.11/site-packages/aiohttp/client_reqrep.py", line 899, in start
    message, payload = await protocol.read()  # type: ignore[union-attr]
                       ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/streams.py", line 616, in read
    await self._waiter
aiohttp.client_exceptions.ClientOSError: [Errno 104] Connection reset by peer

This happens when I'm clicking to set a blind or lamella position; the POST request doesn't go through.

siku2 commented 1 year ago

This might be fixed in the new version. Can you give it a shot, @OdyX?

OdyX commented 1 year ago

Yay. I had to resetup the whole thing (and can't seem to manage to access blinds' position in UI), but this all works again, thanks a lot!

siku2 commented 1 year ago

Sorry about having to re-do the entire setup, but after 2 years of not being able to work on this it was easier to just start from scratch.

[...] can't seem to manage to access blinds' position in UI

Can you elaborate on this? Would love to get this fixed as well.

letienne commented 1 year ago

Thanks for updating this ! I can confirm that blinds control is working, however I'm unable to read the state/position. What kind of debug/output can I provide to help?

I have firmware version 2.0.21

Here is that the state looks like in MQTT: dingz/<mac>/dz1f-4b/state/motor/N : {"motion":"0","position":0,"lamella":0}

And via the API: http://<ip>/api/v1/shade : {"0":{"target":{"blind":1,"lamella":54},"current":{"blind":1,"lamella":54},"disabled":false,"index":{"relative":0,"absolute":0}},"1":{"target":{"blind":100,"lamella":100},"current":{"blind":0,"lamella":43},"disabled":false,"index":{"relative":1,"absolute":1}}}

or with each shade: http://<ip>/api/v1/shade/N : {"target":{"blind":0,"lamella":0},"current":{"blind":0,"lamella":0,"disabled":false,"index":{"relative":0,"absolute":0}}}

Thanks again !

siku2 commented 1 year ago

@letienne awesome, thanks for including the API responses for me. Can you provide me with the API response of http://<ip>/api/v1/state when the cover is fully open and separately for when it's fully closed (this should be the same as /api/v1/shade, but since the integration is using /state, I want to make sure?

Additionally, since you appear to have multiple covers connected, can you confirm if the MQTT topics are numbered correctly, i.e. when you move the cover with index 1, does it actually send a message on state/motor/1. This causes issues for outputs, which is why I'm not listening to the MQTT messages for them, but maybe it works properly for the motors.

letienne commented 1 year ago

Here is what state looks like with the first motor (index 0) fully opened, and the second one (index 1) fully closed:

{"dimmers":[],"blinds":[{"moving":"stop","position":100,"lamella":100,"readonly":false,"index":{"relative":0,"absolute":0}},{"moving":"stop","position":0,"lamella":0,"readonly":false,"index":{"relative":1,"absolute":1}}],"led":{"on":false,"hsv":"0;0;100","rgb":"FFFFFF","mode":"hsv","ramp":1023},"sensors":{"brightness":10,"light_state":"night","light_state_lpf":"night","room_temperature":25,"uncompensated_temperature":37.125,"temp_offset":6,"cpu_temperature":63.33,"puck_temperature":37,"fet_temperature":36.1,"input_state":null,"pirs":[null,{"enabled":false,"motion":false,"mode":"idle","light_off_timer":0,"suspend_timer":0}],"power_outputs":[{"value":0},{"value":0},{"value":0},{"value":0}]},"dyn_light":{"mode":"night"},"thermostat":{"active":false,"state":"off","mode":"off","enabled":false,"target_temp":21,"min_target_temp":17,"max_target_temp":31,"temp":25},"wifi":{"version":"2.0.21","mac":"mac","ssid":"ssid","ip":"<ip>.235","mask":"255.255.255.0","gateway":"<ip>.1","dns":"<ip>.2","static":false,"connected":true},"cloud":{"aws":"connected"},"time":"2023-08-21 19:23:54","config":{"timestamp":0}}

Here is what it looks like with one motor and two outputs:

closed {"dimmers":[{"on":false,"output":0,"ramp":0,"readonly":false,"index":{"relative":0,"absolute":2}},{"on":false,"output":0,"ramp":0,"readonly":true,"index":{"relative":1,"absolute":3}}],"blinds":[{"moving":"stop","position":0,"lamella":0,"readonly":false,"index":{"relative":0,"absolute":0}}],"led":{"on":false,"hsv":"0;0;100","rgb":"FFFFFF","mode":"rgb","ramp":501},"sensors":{"brightness":0,"light_state":"night","light_state_lpf":"night","room_temperature":28.5,"uncompensated_temperature":40.25,"temp_offset":6,"cpu_temperature":65,"puck_temperature":39,"fet_temperature":38.8,"input_state":null,"pirs":[null,{"enabled":false,"motion":false,"mode":"idle","light_off_timer":0,"suspend_timer":0}],"power_outputs":[{"value":0},{"value":0},{"value":0},{"value":0}]},"dyn_light":{"mode":"night"},"thermostat":{"active":false,"state":"off","mode":"off","enabled":false,"target_temp":21,"min_target_temp":17,"max_target_temp":31,"temp":28.5},"wifi":{"version":"2.0.21","mac":"mac","ssid":"ssid","ip":"<ip>.231","mask":"255.255.255.0","gateway":"<ip>.1","dns":"<ip>.2","static":false,"connected":true},"cloud":{"aws":"disconnected"},"time":"2023-08-21 20:15:34","config":{"timestamp":1690205913}} opening {"dimmers":[{"on":false,"output":0,"ramp":0,"readonly":false,"index":{"relative":0,"absolute":2}},{"on":false,"output":0,"ramp":0,"readonly":true,"index":{"relative":1,"absolute":3}}],"blinds":[{"moving":"up","position":33,"lamella":100,"readonly":false,"index":{"relative":0,"absolute":0}}],"led":{"on":false,"hsv":"0;0;100","rgb":"FFFFFF","mode":"rgb","ramp":501},"sensors":{"brightness":7,"light_state":"night","light_state_lpf":"night","room_temperature":28.5,"uncompensated_temperature":40.3125,"temp_offset":6,"cpu_temperature":65.56,"puck_temperature":39,"fet_temperature":38.8,"input_state":null,"pirs":[null,{"enabled":false,"motion":false,"mode":"idle","light_off_timer":0,"suspend_timer":0}],"power_outputs":[{"value":82.9},{"value":0},{"value":0},{"value":0}]},"dyn_light":{"mode":"night"},"thermostat":{"active":false,"state":"off","mode":"off","enabled":false,"target_temp":21,"min_target_temp":17,"max_target_temp":31,"temp":28.5},"wifi":{"version":"2.0.21","mac":"mac","ssid":"ssid","ip":"<ip>.231","mask":"255.255.255.0","gateway":"<ip>.1","dns":"<ip>.2","static":false,"connected":true},"cloud":{"aws":"disconnected"},"time":"2023-08-21 20:16:37","config":{"timestamp":1690205913}} open {"dimmers":[{"on":false,"output":0,"ramp":0,"readonly":false,"index":{"relative":0,"absolute":2}},{"on":false,"output":0,"ramp":0,"readonly":true,"index":{"relative":1,"absolute":3}}],"blinds":[{"moving":"stop","position":100,"lamella":100,"readonly":false,"index":{"relative":0,"absolute":0}}],"led":{"on":false,"hsv":"0;0;100","rgb":"FFFFFF","mode":"rgb","ramp":501},"sensors":{"brightness":14,"light_state":"night","light_state_lpf":"night","room_temperature":28.5,"uncompensated_temperature":40.375,"temp_offset":6,"cpu_temperature":65.56,"puck_temperature":39,"fet_temperature":38.7,"input_state":null,"pirs":[null,{"enabled":false,"motion":false,"mode":"idle","light_off_timer":0,"suspend_timer":0}],"power_outputs":[{"value":0},{"value":0},{"value":0},{"value":0}]},"dyn_light":{"mode":"night"},"thermostat":{"active":false,"state":"off","mode":"off","enabled":false,"target_temp":21,"min_target_temp":17,"max_target_temp":31,"temp":28.5},"wifi":{"version":"2.0.21","mac":"mac","ssid":"ssid","ip":"<ip>.231","mask":"255.255.255.0","gateway":"<ip>.1","dns":"<ip>.2","static":false,"connected":true},"cloud":{"aws":"disconnected"},"time":"2023-08-21 20:17:25","config":{"timestamp":1690205913}}

So far I've never seen a mqtt index issue with the shades. I've seen it with the lights, but it's usually after I play for too long with the UI, and fixed with a reboot of the dingz; so I'm assuming this is a bug.

Thanks !

siku2 commented 1 year ago

@letienne, thanks, this is exactly what I needed.

I just released a beta release v0.3.2 if you want to try it out. I will implement MQTT support for the covers before creating a full release.

One more question though, if you have the time. Can you give me the output of http://<host>/api/v1/output_config. I'm trying to find out if the motors show up there as well. The integration tries to use the name that the user assigned in the dingz config for the home assistant entities, but I'm not sure how that works for blinds / motors. Right now the integration is using the name of the output with the corresponding index. Does that work on your end?

letienne commented 1 year ago

sure output_config appears to be giving the outputs config (such as lights, switches). The blinds output is: http:///api/v1/blind_config which returns:

{"blinds":[{"active":true,"name":"","type":"blind","min_value":0,"max_value":100,"def_blind":0,"def_lamella":80,"groups":"z","auto_calibration":true,"shade_up_time":62.45,"shade_down_time":61.66,"invert_direction":true,"lamella_time":1.8,"step_duration":300,"step_interval":1200,"state":"Initialised"},{"active":true,"name":"","type":"blind","min_value":0,"max_value":100,"def_blind":0,"def_lamella":80,"groups":"z","auto_calibration":true,"shade_up_time":180,"shade_down_time":180,"invert_direction":false,"lamella_time":1.8,"step_duration":300,"step_interval":1200,"state":"Not initialised"}]}

The "active":true is wrong, there is only one motor active in the above config.

(same for the lights, my dingz with 2 motors (and 0 lights) states that the 4 outputs are active -_-)

Thanks !

siku2 commented 1 year ago

@letienne, the full release is out now. Thanks for your help!

letienne commented 1 year ago

Thank you, looking good :) I'll let you know if something goes wrong.

letienne commented 1 year ago

I noticed some stderr on my container :

ValueError: '0' is not a valid MotorMotion 2023-08-23 00:06:53.311 ERROR (MainThread) [homeassistant.util.logging] Exception in _handle_mqtt_motor when handling msg on 'dingz//dz1f-4b/state/motor/0': '{"motion":"0","position":0,"lamella":52}'

letienne commented 1 year ago

it looks like the motion value is sent as string and not as int...

siku2 commented 1 year ago

Wow, I guess that's just yet another issue with the documentation. Why even use an enum if they end up sending it as a string...

Anyway, the fix for this is straight forward. Can you check that it's always a string and not just when the value is 0?

siku2 commented 1 year ago

@letienne, new release is out. Let me know if that did the trick.

letienne commented 1 year ago

Sorry...

Logger: homeassistant.setup Source: loader.py:821 First occurred: 9:20:35 PM (1 occurrences) Last logged: 9:20:35 PM

Setup failed for custom integration dingz: Unable to import component: Exception importing custom_components.dingz Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/loader.py", line 813, in get_component ComponentProtocol, importlib.import_module(self.pkg_path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/importlib/init.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "", line 1204, in _gcd_import File "", line 1176, in _find_and_load File "", line 1147, in _find_and_load_unlocked File "", line 690, in _load_unlocked File "", line 940, in exec_module File "", line 241, in _call_with_frames_removed File "/config/custom_components/dingz/init.py", line 7, in from .shared import Shared File "/config/custom_components/dingz/shared.py", line 256, in class MotorMotion(IntEnum): File "/config/custom_components/dingz/shared.py", line 264, in MotorMotion def parse(cls, value: str | int | "MotorMotion") -> "MotorMotion":


TypeError: unsupported operand type(s) for |: 'types.UnionType' and 'str'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/setup.py", line 215, in _async_setup_component
    component = integration.get_component()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/loader.py", line 821, in get_component
    raise ImportError(f"Exception importing {self.pkg_path}") from err
ImportError: Exception importing custom_components.dingz
siku2 commented 1 year ago

@letienne, that's on me... I made a seemingly minor change just before releasing the previous version and didn't bother to test it. You know the rest :)

letienne commented 1 year ago

0.4.2 seems to be the one :) thanks !

OdyX commented 1 year ago

Awesome, thanks. (And sorry for not being active on that front.)