PimDoos / onesmartcontrolha

Home Assisttant integration for One Smart Control server
Apache License 2.0
4 stars 1 forks source link

Support for light switch modules #3

Closed TheFes closed 2 years ago

TheFes commented 2 years ago

Every light switch in my house had a One Smart Control module behind it, to toggle (and dim) the lights via the app. Would it be possible to add support for those in the integration?

PimDoos commented 2 years ago

Can you run this script debug_devices.py and post the results?

To run the script, you need the const.py and onesmartsocket.py files from the custom_integrations/onesmartcontrol folder. If you get an error about relative imports, change from .const import * to from const import * in onesmartsocket.py. Also, swap out the IP, username and password for valid ones.

This script runs the same discovery process as the integration does during startup:

The script prints every available attribute to the console. If your modules are part of the device tree, we should find them here along with some WRITE commands to toggle them on or off.

TheFes commented 2 years ago

I'm currently on holiday, will try to run the script when I'm back

TheFes commented 2 years ago

I tried to run the script by placing the 3 files in C:\onesmart\ and running py debug_devices.py (of course after changing ip, login name and password)

C:\onesmart>py debug_devices.py
Traceback (most recent call last):
  File "C:\onesmart\debug_devices.py", line 3, in <module>
    from onesmartsocket import OneSmartSocket
  File "C:\onesmart\onesmartsocket.py", line 7, in <module>
    from .const import *
ImportError: attempted relative import with no known parent package

Tried to resolve this by removing the dot before .const in line 7 of onesmartsocket.py

That gave this result

C:\onesmart>py debug_devices.py
JSON Decode failed:
JSON Decode failed:

It still seems to be running, as I don't have a prompt yet, but nothing changes.

PimDoos commented 2 years ago

You might be missing dependencies, can you install these (use a venv if you don't want to install them globally):

pip install pyOpenSSL

You can also enable more detailed logging by adding these lines to the top of debug_devices.py:

import logging
logging.basicConfig(level=logging.DEBUG)
TheFes commented 2 years ago

Got a bit more info now

=== VOORDEUR MIDDEN  ===
Device properties: {'id': '66e2a068-80d4-4a09-a3e1-fc4bc93c20c0', 'name': 'VOORDEUR MIDDEN ', 'type': 'ONELIDPWIINPUT', 'group': 'LIGHTS', 'room': 'd33e7f25-affb-46e2-98a9-db75fefe8345', 'active': True, 'visible': True}
Attributes: 10
blink {'name': 'blink', 'type': 'BOOL', 'access': 'WRITE'}
dsuid {'name': 'dsuid', 'type': 'STRING', 'access': 'READ'} 302e055f19600000000019c000043ffe00
relateddevice {'name': 'relateddevice', 'type': 'STRING', 'access': 'READ'} de115da5-f12b-42ba-af1e-32b31697354f
serial {'name': 'serial', 'type': 'STRING', 'access': 'READ'} 00043FFE
swversion {'name': 'swversion', 'type': 'STRING', 'access': 'READ'} 3.5.6
transmissionquality {'name': 'transmissionquality', 'type': 'OBJECT', 'access': 'READ'} {'downstream': 100, 'upstream': 100}
inputmode {'name': 'inputmode', 'type': 'NUMBER', 'enum': [0, 2, 3, 1], 'access': 'READWRITE'} 0
buttonfunction {'name': 'buttonfunction', 'type': 'NUMBER', 'enum': [16, 17, 18, 19, 20, 21, 30], 'access': 'READWRITE'} 21
buttonpriority {'name': 'buttonpriority', 'type': 'BOOL', 'access': 'READWRITE'} False
buttoncallhome {'name': 'buttoncallhome', 'type': 'BOOL', 'access': 'READWRITE'} True

=== WOONKAMER RECHTS  ===
Device properties: {'id': 'adb5a1b4-2899-463b-9d09-8d0ecf5b5aeb', 'name': 'WOONKAMER RECHTS ', 'type': 'ONELIDPWIINPUT', 'group': 'LIGHTS', 'room': '804d5ea3-890e-44ca-b4f4-1df88e220b3f', 'active': False, 'visible': True}
Traceback (most recent call last):
  File "/home/thefes/onesmart/debug_devices.py", line 67, in <module>
    asyncio.run(run())
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/thefes/onesmart/debug_devices.py", line 37, in run
    attributes = result[RPC_RESULT][RPC_ATTRIBUTES]
KeyError: 'attributes'

Still stops somewhere. I actually have this VOORDEUR MIDDEN in HA in the integration. Basically it is a module behind the momentary wall switch, which can recognize single, double, triple, quadruple presses, and hold (for dimming).

It would be really nice if those button presses could be received as events, so it is possible to use as trigger for automations

PimDoos commented 2 years ago

Interesting data! Although I don't see anything I can use to control the lights yet... I've expanded the script a bit, can you redownload the files from master and run it again?

It will now list as much objects as it can, and afterwards start listening for events. Once '===EVENTS===' shows up in the console, can you flick some lights on and off? I'm curious to see the output.

TheFes commented 2 years ago

I get the following error when running the new script:

Traceback (most recent call last):
  File "/home/thefes/onesmart/debug_devices.py", line 123, in <module>
    asyncio.run(run())
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/thefes/onesmart/debug_devices.py", line 40, in run
    for action_type in [ACTIONTYPE_SITE_PRESET, ACTIONTYPE_PRESET_GROUP]:
NameError: name 'ACTIONTYPE_SITE_PRESET' is not defined
TheFes commented 2 years ago

Here is the complete result, part of it seems new, and does seem to have information about the light modules

DEBUG:asyncio:Using selector: EpollSelector
=== Listing preset ===
DEBUG:onesmartsocket:Packet is 1024 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 2048 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 3072 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 4096 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 5120 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 6144 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 7168 bytes, waiting for more
{'transaction': 2, 'result': {'presets': [{'id': '8c80cfdc-4af0-48b7-b6d6-7767e8ae9378', 'room': 'e24b41fd-78cb-473b-bce9-9cfe9f2d06a6', 'group': 'LIGHTS', 'name': 'UIT', 'type': 'ROOMOFF', 'active': False}, {'id': '89ee716d-e5a9-413d-97a5-28ef96ada1d7', 'room': 'd33e7f25-affb-46e2-98a9-db75fefe8345', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': True}, {'id': '3cbc90ce-57ef-44cd-a59f-c3cc95646f3b', 'room': '476247d5-57da-49c8-b44f-e6eb7bf1d96e', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': 'b21ce4da-1123-4aff-8928-c72e9192c1e2', 'room': '804d5ea3-890e-44ca-b4f4-1df88e220b3f', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': 'f7ccf549-c79e-4287-a5f9-791a1b8b385b', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': 'd9775134-4972-4bff-ac22-d777013c7e82', 'room': '1bfbf03c-ddd6-4281-a126-0194a64039f9', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': '8377f34c-82c0-47be-9a84-cc846704d223', 'room': '47f1916e-3fc9-4056-8855-27a17cad64ad', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': 'b30a8d0e-dc92-462e-aa0e-9d722f4b58e2', 'room': '87fa66c4-e302-4583-adec-77b737ca748d', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': '39de6151-0f41-4bb8-a90a-4128f707e9bc', 'room': 'bc29431d-99d1-4a8e-aa20-a952e5d66203', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': 'bfb35546-b10e-421f-8aa6-997123044302', 'room': 'e3a88dfa-202b-4098-b146-bc4a892cdb5e', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': '31b4a0a9-b001-43ab-af8c-0ee9d5126cfd', 'room': 'b11067b0-982f-46a1-8374-5e70b71541cc', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': True}, {'id': 'c298f4a3-5fd7-47b1-8f6f-02b95bfe9853', 'room': '0f04009a-2f41-47bf-a534-07163f20713c', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': True}, {'id': '68cfe597-02ae-472e-9576-5aeb3c9ed3e0', 'room': '98fb3c5b-708f-47f0-a162-38356d60fa84', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': '0a29733d-1a4b-4883-8782-bc2ef94a5dd3', 'room': '016ea52c-446b-4a14-adb8-7e4c32731d07', 'group': 'LIGHTS', 'name': 'uit', 'type': 'ROOMOFF', 'active': False}, {'id': '0b1b04bf-2df0-47db-83f1-a7070ceac7a9', 'room': 'e24b41fd-78cb-473b-bce9-9cfe9f2d06a6', 'group': 'LIGHTS', 'name': 'gedimd', 'type': 'ROOM1', 'active': False}, {'id': '8b961deb-bc92-45dd-8b9a-0258cba833a8', 'room': 'd33e7f25-affb-46e2-98a9-db75fefe8345', 'group': 'LIGHTS', 'name': 'gedimd', 'type': 'ROOM1', 'active': False}, {'id': 'bc4fc90e-735c-4056-b78b-f0a12eeef604', 'room': '476247d5-57da-49c8-b44f-e6eb7bf1d96e', 'group': 'LIGHTS', 'name': 'aan', 'type': 'ROOM1', 'active': False}, {'id': 'fbf26f6e-8093-4eae-9966-16ceb2075a80', 'room': '804d5ea3-890e-44ca-b4f4-1df88e220b3f', 'group': 'LIGHTS', 'name': 'aan', 'type': 'ROOM1', 'active': False}, {'id': 'bebe9712-ce81-433a-b6aa-717c84395305', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': 'vol aan', 'type': 'ROOM1', 'active': False}, {'id': 'e72eed20-c221-418b-939d-325a88f9ff07', 'room': '1bfbf03c-ddd6-4281-a126-0194a64039f9', 'group': 'LIGHTS', 'name': 'gedimd', 'type': 'ROOM1', 'active': False}, {'id': '2a0237b1-528d-4d03-a082-65771f0557bf', 'room': '47f1916e-3fc9-4056-8855-27a17cad64ad', 'group': 'LIGHTS', 'name': '100%', 'type': 'ROOM1', 'active': False}, {'id': '150ad719-d323-497a-97b9-b96b6abdf112', 'room': '87fa66c4-e302-4583-adec-77b737ca748d', 'group': 'LIGHTS', 'name': '100%', 'type': 'ROOM1', 'active': False}, {'id': 'b3e97d72-5681-415f-a94b-a7789fd72945', 'room': 'bc29431d-99d1-4a8e-aa20-a952e5d66203', 'group': 'LIGHTS', 'name': '100%', 'type': 'ROOM1', 'active': False}, {'id': '1ad03200-88b4-4cff-9740-ca17ad09f2bb', 'room': 'e3a88dfa-202b-4098-b146-bc4a892cdb5e', 'group': 'LIGHTS', 'name': 'aan', 'type': 'ROOM1', 'active': False}, {'id': '917e0f89-31e6-451d-961b-f7fbcbf68f76', 'room': 'b11067b0-982f-46a1-8374-5e70b71541cc', 'group': 'LIGHTS', 'name': 'aan', 'type': 'ROOM1', 'active': False}, {'id': '3d3db3b3-e00d-4360-b757-e8ea7c126843', 'room': '0f04009a-2f41-47bf-a534-07163f20713c', 'group': 'LIGHTS', 'name': 'gedimd', 'type': 'ROOM1', 'active': False}, {'id': '6faca895-c5bf-41ce-9cdf-e2f002b7d076', 'room': '98fb3c5b-708f-47f0-a162-38356d60fa84', 'group': 'LIGHTS', 'name': 'plafond gedimd', 'type': 'ROOM1', 'active': True}, {'id': '457c4553-f0dd-4ab8-9ed8-5c9131e9b48c', 'room': '016ea52c-446b-4a14-adb8-7e4c32731d07', 'group': 'LIGHTS', 'name': 'aan', 'type': 'ROOM1', 'active': False}, {'id': '8084810f-c3fd-4d2d-82bb-d31d4e2b6245', 'room': '1bfbf03c-ddd6-4281-a126-0194a64039f9', 'group': 'LIGHTS', 'name': '100 %', 'type': 'ROOM2', 'active': False}, {'id': '74857c2c-befe-427b-865f-d4236b1e983b', 'room': 'd33e7f25-affb-46e2-98a9-db75fefe8345', 'group': 'LIGHTS', 'name': '100 %', 'type': 'ROOM2', 'active': False}, {'id': 'f4d8ec5b-ff31-4ccc-b6a5-c021f2b78caa', 'room': 'e24b41fd-78cb-473b-bce9-9cfe9f2d06a6', 'group': 'LIGHTS', 'name': '100 %', 'type': 'ROOM2', 'active': False}, {'id': '5b08f6e4-6684-4b17-acd0-98f7ebafe761', 'room': '0f04009a-2f41-47bf-a534-07163f20713c', 'group': 'LIGHTS', 'name': 'aan', 'type': 'ROOM2', 'active': False}, {'id': '724d5f94-63b5-4a6b-8f6a-99ee2dd0050d', 'room': '47f1916e-3fc9-4056-8855-27a17cad64ad', 'group': 'LIGHTS', 'name': 'gedimd', 'type': 'ROOM2', 'active': False}, {'id': 'a58f0406-9a74-4825-807f-b64bc59a40a2', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': '80% gedimd', 'type': 'ROOM2', 'active': False}, {'id': 'c95dfd52-8d5b-4d63-84bb-cab14f0f6583', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': '60% gedimd', 'type': 'ROOM3', 'active': False}, {'id': '5a579522-1f04-4643-8949-b0ba02aa8d37', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': 'Staande lamp_off', 'type': 'AREA1OFF', 'active': False}, {'id': 'f73c2f05-ae44-484e-b08b-3bc32b7780e6', 'room': '98fb3c5b-708f-47f0-a162-38356d60fa84', 'group': 'LIGHTS', 'name': 'plafond gedimd_off', 'type': 'AREA1OFF', 'active': False}, {'id': '7ef92c0c-315e-4403-9edd-11b5867c4d7e', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': 'Staande lamp', 'type': 'AREA1ON', 'active': False}, {'id': '7159b5e2-0343-46d6-8ccd-f06071b58ff0', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': 'Plafondlamp_off', 'type': 'AREA2OFF', 'active': False}, {'id': 'e4806053-fbf2-4a46-ab97-0687df1d97c5', 'room': '2a223061-7849-404d-ad38-d542c3edad41', 'group': 'LIGHTS', 'name': 'Plafondlamp', 'type': 'AREA2ON', 'active': False}, {'id': 'bbdb580b-e7ae-4666-b2c2-ff77b73af9ad', 'room': 'd33e7f25-affb-46e2-98a9-db75fefe8345', 'group': 'ACCESS', 'name': 'toe', 'type': 'ROOMOFF', 'active': False}, {'id': '0fa90d4b-d8a9-46b7-8bb9-e6648405acb1', 'room': 'd33e7f25-affb-46e2-98a9-db75fefe8345', 'group': 'ACCESS', 'name': 'open', 'type': 'ROOM1', 'active': False}]}}
=== Listing presetgroup ===
{'transaction': 3, 'result': {'presetgroups': []}}
=== Listing modules ===
{'cmd': 'unknown command', 'transaction': 4, 'result': {'error': 100, 'description': 'no such command'}}
=== Listing meter ===
DEBUG:onesmartsocket:Packet is 1024 bytes, waiting for more
{'transaction': 5, 'result': {'meters': [{'id': 'b68f3cff-7364-4161-b712-28f692f43161', 'name': 'CIRCUITMETER', 'type': 'CIRCUIT', 'active': True, 'visible': True}, {'id': '5b7fc88a-4dee-4d05-95f3-0c0a40d0e56d', 'name': 'CIRCUITMETER', 'type': 'CIRCUIT', 'active': True, 'visible': True}, {'id': 'ba64884a-a93b-4601-ace7-634a4fe4eb7d', 'name': 'CIRCUITMETER', 'type': 'CIRCUIT', 'active': True, 'visible': True}, {'id': 'e2532de3-1ac6-40ea-b751-2b43f24b34d7', 'name': 'PHASE 1', 'type': 'PHASE', 'active': True, 'visible': True}, {'id': '108f07ce-c97f-453f-ad21-7d8b46277e87', 'name': 'PHASE 2', 'type': 'PHASE', 'active': True, 'visible': True}, {'id': 'b1fea70d-6620-4bfc-9753-86f669bd4e8a', 'name': 'PHASE 3', 'type': 'PHASE', 'active': True, 'visible': True}, {'id': '50a3a93a-5085-40b8-a35b-6e13163712f4', 'name': 'PULSECOUNTER I', 'type': 'PULSE', 'active': True, 'visible': True}, {'id': '0409c9b8-5acc-49bc-9136-9bfd423275ab', 'name': 'PULSECOUNTER II', 'type': 'PULSE', 'active': True, 'visible': True}, {'id': 'd57e65a3-61ee-42d2-b350-77c8a602414e', 'name': 'PULSECOUNTER III', 'type': 'PULSE', 'active': True, 'visible': True}]}}
Traceback (most recent call last):
  File "/home/thefes/onesmart/debug_devices.py", line 123, in <module>
    asyncio.run(run())
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/thefes/onesmart/debug_devices.py", line 40, in run
    for action_type in [ACTIONTYPE_SITE_PRESET, ACTIONTYPE_PRESET_GROUP]:
NameError: name 'ACTIONTYPE_SITE_PRESET' is not defined
PimDoos commented 2 years ago

Looks like I forgot to push those constants into master, whoops. Can you download const.py again and try again?

Transaction 2 in your output does look promising! I'll see if I can integrate that somehow.

PimDoos commented 2 years ago

Also the debug_devices script refers to an older version of constants, I've updated that one as well.

TheFes commented 2 years ago

I seem to be back at square 1 now:

=== Listing preset ===
DEBUG:onesmartsocket:Packet is 1024 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 2048 bytes, waiting for more
WARNING:onesmartsocket:JSON Decode failed:
DEBUG:onesmartsocket:Reply data: "{ reply }"
DEBUG:onesmartsocket:Packet is 1024 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 2048 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 3072 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 4096 bytes, waiting for more
DEBUG:onesmartsocket:Packet is 5120 bytes, waiting for more
WARNING:onesmartsocket:JSON Decode failed:
DEBUG:onesmartsocket:Reply data: "{ reply }"

I've updated the all files with the versions you linked in your first post

TheFes commented 2 years ago

tried on a different device (just to be sure) and got a different error 🤔

DEBUG:asyncio:Using selector: EpollSelector
Traceback (most recent call last):
  File "debug_devices.py", line 122, in <module>
    asyncio.run(run())
  File "/usr/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "debug_devices.py", line 31, in run
    await setup()
  File "debug_devices.py", line 14, in setup
    await gateway.authenticate("removed", "removed")
  File "/root/onesmart/onesmartsocket.py", line 43, in authenticate
    return await self.send_cmd(command=COMMAND_AUTHENTICATE, username=username, password=password_hash)
  File "/root/onesmart/onesmartsocket.py", line 67, in send_cmd
    rpc_message = { RPC_COMMAND:command, RPC_TRANSACTION:transaction_id } | kwargs
TypeError: unsupported operand type(s) for |: 'dict' and 'dict'
PimDoos commented 2 years ago

The second one looks like a Python version mismatch. I'm developing on Python 3.10, some features (like the | operator for dictionaries) are not supported on Python 3.7. The JSON decode error looks broken, I've updated the file to fix that. Maybe we should setup a debug session over Discord, so I can fix any issues you're running into a bit quicker. I've sent you an invite.

PimDoos commented 2 years ago

A summary of our conversation on Discord:

Each light/switch is available as a device, but they don't seem to be linked to the preset. I'll have to think how to represent this in the device registry.

PimDoos commented 2 years ago

First version of the light platform has been merged in #25. At the moment, the integration will create light entities for:

TheFes commented 2 years ago

First of all, I'm really glad with the part which is already working! Greate work!

Some feedback based on the v0.3.0 beta, and test supported by the debug script.

There seem to be 2 types of light modules, one which supports brightness, and one which doesn't. This can be seen by the outputmode in the debug script. The module which only supports on/off has outputmode: [ 0, 35 ] The module which can support brightness has outputmode: [ 0, 16, 22 ] Modules with 16 only support on/off, modules with 22 can have different brightness settings.

Currently all light entities created by the integration have a brightness slider, I suppose it would be good to only enable that for light modules with outputmode: 22

After toggling a light in HA using either the GUI or the service call from deleloper tools > services, it takes a few (2-3) seconds before the light changes state. It takes about 30 seconds before the state is updated in Home Assistant, so when a light is off, and you toggle it in HA, it will be on in a few seconds, but still show as off in HA for 30 seconds. It would be great if this could be updated faster.

As already indicated, the lights have a brightness slider, and it reports the right brighness of the light, but if adjusted in Home Assistant, the light entity does not change. So sliding it from 100% to 50% doesn't change the light (it will stay at 100%) but the slider will stay at 50%, and will not update anymore (waited for several minutes). The brightness attribute of the light will stick at 255 Updating the light using the service call in developer tools also doesn't have any effect. Any change to the light entities representing the devices with outputvalue are not shown in the event log of the debug script.

As setting brightness from HA doesn't seem to work (for now), it would be nice if we could have access to all scenes created in the app (maybe through button entities) so we have some control over the light brightness.

Some brainfarts:

Please let me know if additional specific data or tests are needed to improve the light part of this integration!

PimDoos commented 2 years ago

Implemented in v0.3.0