mdeweerd / zha-toolkit

🧰 Zigbee Home Assistant Toolkit - service for "rare" Zigbee operations using ZHA on Home Assistant
GNU General Public License v3.0
193 stars 29 forks source link

Contactor Legrand 412171 #85

Closed mycanaletto closed 2 years ago

mycanaletto commented 2 years ago

The contactor Legrand 412171 (or 70) is recognized in ZHA, by default it is in HC/HP mode but the option to switch it to on/off mode is not present (unlike z2m).

To add this you can theoretically do it with ZHA services or ZHA Toolkit but it doesn't work or I missed something (change attribute 0 of cluster 0xfc01 (6512) from 4 to 3).

Anyway, I'm stumped, if someone has already played with these functions...

  "config" : [
    {"endpoint" : 1,"cluster":64513,"attribute":0,"manufacturer":64513,"name":"Mode","type":"select","values":[{"value":3,"name":"on/off"},{"value":4,"name":"hp/hc"}]},
    {"endpoint" : 1,"cluster":64513,"attribute":1,"manufacturer":64513,"name":"Led dark","type":"select","values":[{"value":0,"name":"Off"},{"value":1,"name":"On"}]},
    {"endpoint" : 1,"cluster":64513,"attribute":2,"manufacturer":64513,"name":"Led if on","type":"select","values":[{"value":0,"name":"Off"},{"value":1,"name":"On"}]}
  ],
My test:
`service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 0
  attr_val: "3"
  attr_type: 0x21
  manf: 4129
  allow_create: true`

Merci ;-)

mdeweerd commented 2 years ago

Bonjour (but I'll reply in English for the benefit of the "masses").

  1. I recommend generating an event when your command finished, at least during test (event_done: some_event_name) and monitor that by listening on the event in a separate browser window. This provides information about the results.
  2. I can't tell if your attribute_type is correct for sure. When the device supports it, 'scan_device' will provide this information, or even read_attribute will provide it.
    Basically, you are not required to specify what zha-toolkit can discover, and this limits human errors:
    • The endpoint is discovered if there is only one matching the cluster (but if you mention the endpoint, there is less computation);
    • The attribute_type is discovered if you set "read_before_write" as the type is provided in the read response, or when it already determined by an attribute definition somewhere in ZHA/zigpy. In your case, the attribute is not set, so it is either correctly set (0x21) or it can be discovered using a read before write.
    • allow_create is only useful when reading the attribute to a state and having at least state_id set as well.

So I suggest listening at "legrand_done" before executing the following:

service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 0
  attr_val: 3
  # attr_type: 0x21  # not setting this, and let read_before_write do it
  manf: 4129
  event_done: legrand_done
  # Read attribute before writing it (defaults to True)
  read_before_write: true
  # Read attribute after writing it (defaults to True)
  read_after_write: true
  # Write attribute when the read value matches (defaults to False)
  write_if_equal: false

The above will do a read before the write, but also after the write. When the value is already ok, no write will be done so that should not surprise you.

mycanaletto commented 2 years ago

Bonjour et merci,

If I don't put attr_type: Status.MAC_NO_ACK: 233

And the scan returns this to me:

Failed 'discover_attributes_extended' starting 0x0000/0x0000. Error: Request failed after 5 attempts: <Status.MAC_NO_ACK: 233>
Couldn't read 0x0000/0xf000:

device signature

`{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=1, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4129, maximum_buffer_size=89, maximum_incoming_transfer_size=63, server_mask=10752, maximum_outgoing_transfer_size=63, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x010a",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x000f",
        "0x0b04",
        "0xfc01",
        "0xfc41"
      ],
      "out_clusters": [
        "0x0000",
        "0x0019",
        "0xfc01"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": " Legrand",
  "model": " Contactor",
  "class": "zigpy.device.Device"
}`
mdeweerd commented 2 years ago

attr_write (even with read enable) does not perform an attributres discovery, that's something that scan_device does. So apparently attribute discovery is not supported.

What is the result of the write I proposed?

mycanaletto commented 2 years ago
websocket_api script: Error executing script. Unexpected error for call_service at pos 1: Request failed after 5 attempts: <Status.MAC_NO_ACK: 233>
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 447, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 680, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1738, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1775, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/config/custom_components/zha_toolkit/__init__.py", line 717, in toolkit_service
    raise handler_exception
  File "/config/custom_components/zha_toolkit/__init__.py", line 681, in toolkit_service
    await handler(
  File "/config/custom_components/zha_toolkit/__init__.py", line 766, in command_handler_default
    await default.default(
  File "/config/custom_components/zha_toolkit/default.py", line 33, in default
    await handler(app, listener, ieee, cmd, data, service, params, event_data)
  File "/config/custom_components/zha_toolkit/zcl_attr.py", line 315, in attr_write
    result_read = await u.cluster_read_attributes(
  File "/config/custom_components/zha_toolkit/utils.py", line 756, in cluster_read_attributes
    return await cluster.read_attributes(attrs, manufacturer=manufacturer)
  File "/usr/local/lib/python3.10/site-packages/zigpy/zcl/__init__.py", line 482, in read_attributes
    result = await self.read_attributes_raw(to_read, manufacturer=manufacturer)
  File "/usr/local/lib/python3.10/site-packages/zigpy/device.py", line 291, in request
    radio_result, msg = await self._application.request(
  File "/usr/local/lib/python3.10/site-packages/zigpy_znp/zigbee/application.py", line 302, in request
    return await self._send_request(
  File "/usr/local/lib/python3.10/site-packages/zigpy_znp/zigbee/application.py", line 1288, in _send_request
    raise DeliveryError(
zigpy.exceptions.DeliveryError: Request failed after 5 attempts: <Status.MAC_NO_ACK: 233>
mycanaletto commented 2 years ago

T``` raceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 447, in _async_step await getattr(self, handler)() File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 680, in _async_call_service_step await service_task File "/usr/src/homeassistant/homeassistant/core.py", line 1738, in async_call task.result() File "/usr/src/homeassistant/homeassistant/core.py", line 1775, in _execute_service await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)( File "/config/custom_components/zha_toolkit/init.py", line 717, in toolkit_service raise handler_exception File "/config/custom_components/zha_toolkit/init.py", line 681, in toolkit_service await handler( File "/config/custom_components/zha_toolkit/init.py", line 766, in command_handler_default await default.default( File "/config/custom_components/zha_toolkit/default.py", line 33, in default await handler(app, listener, ieee, cmd, data, service, params, event_data) File "/config/custom_components/zha_toolkit/zcl_attr.py", line 315, in attr_write result_read = await u.cluster_read_attributes( File "/config/custom_components/zha_toolkit/utils.py", line 756, in cluster_read_attributes return await cluster.read_attributes(attrs, manufacturer=manufacturer) File "/usr/local/lib/python3.10/site-packages/zigpy/zcl/init.py", line 482, in read_attributes result = await self.read_attributes_raw(to_read, manufacturer=manufacturer) File "/usr/local/lib/python3.10/site-packages/zigpy/device.py", line 291, in request radio_result, msg = await self._application.request( File "/usr/local/lib/python3.10/site-packages/zigpy_znp/zigbee/application.py", line 302, in request return await self._send_request( File "/usr/local/lib/python3.10/site-packages/zigpy_znp/zigbee/application.py", line 1288, in _send_request raise DeliveryError( zigpy.exceptions.DeliveryError: Request failed after 5 attempts: <Status.MAC_NO_ACK: 233>

mdeweerd commented 2 years ago

Ok, so "MAC_NO_ACK" means that there was no response whatsoever from the device (NO ACK on the MAC level = protocol level below Zigbee).

Either the device is not reachable (bad connection/not powered), or it's working on batteries (but according to the documentation I find, it's powered from mains) or it's not responding to manufacturer writes (but then the error should not be a MAC_NO_ACK error IMHO) or there is a gateway issue.

You could check connectivity using another simple read of a mandatory attribute:

service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 0
  attribute: 1
  event_done: legrand_done

(which is the "application version").

When I try the following call, similar to yours but on cluster 0 to test an existing cluster on one of my devices:

service: zha_toolkit.attr_write
data:
  ieee: light.tz3000_dbou1ap4_ts0505a_9afc91fe_level_light_color_on_off
  endpoint: 1
  cluster: 0
  attribute: 0
  attr_val: 3
  manf: 4129
  event_done: legrand_done
  read_before_write: true
  read_after_write: true
  write_if_equal: false

I get in "Status.UNSUPPORTED_ATTRIBUTE: 134" my log (because I have the debug active):

2022-09-12 14:34:05.227 DEBUG (MainThread) [custom_components.zha_toolkit] Fire legrand_done -> {'zha_toolkit_version': 'dev', 'zigpy_version': '0.50.2', 'zigpy_rf_version': '0.8.2', 'ieee_org': 'light.tz3000_dbou1ap4_ts0505a_9afc91fe_level_light_color_on_off', 'ieee': '60:a4:23:ff:fe:91:fc:9a', 'command': 'attr_write', 'command_data': None, 'start_time': '2022-09-12T12:34:04.931412+00:00', 'errors': [], 'params': {'endpoint_id': 1, 'cluster_id': 0, 'attr_id': 0, 'attr_val': 3, 'dir': 0, 'manf': 4129, 'tries': 1, 'expect_reply': True, 'args': [], 'event_done': 'legrand_done', 'read_before_write': True, 'read_after_write': True}, 'compare_val': 3, 'write_is_equal': False, 'read_before': ({}, {0: <Status.UNSUPPORTED_ATTRIBUTE: 134>}), 'result_write': Write_Attributes_rsp(status_records=[WriteAttributesStatusRecord(status=<Status.UNSUPPORTED_ATTRIBUTE: 134>, attrid=0x0000)]), 'result_read': ({}, {0: <Status.UNSUPPORTED_ATTRIBUTE: 134>}), 'warnings': ['Result: {0: <Status.UNSUPPORTED_ATTRIBUTE: 134>} - Attribute 0 not in read ({}, {0: <Status.UNSUPPORTED_ATTRIBUTE: 134>})'], 'success': False}

And the same information as event data in the UI:

event_type: legrand_done
data:
  zha_toolkit_version: dev
  zigpy_version: 0.50.2
  zigpy_rf_version: 0.8.2
  ieee_org: light.tz3000_dbou1ap4_ts0505a_9afc91fe_level_light_color_on_off
  ieee: 60:a4:23:ff:fe:91:fc:9a
  command: attr_write
  command_data: null
  start_time: "2022-09-12T12:34:04.931412+00:00"
  errors: []
  params:
    endpoint_id: 1
    cluster_id: 0
    attr_id: 0
    attr_val: 3
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  compare_val: 3
  write_is_equal: false
  read_before:
    - {}
    - "0": 134
  result_write:
    - - status: 134
        attrid: 0
  result_read:
    - {}
    - "0": 134
  warnings:
    - >-
      Result: {0: <Status.UNSUPPORTED_ATTRIBUTE: 134>} - Attribute 0 not in read
      ({}, {0: <Status.UNSUPPORTED_ATTRIBUTE: 134>})
  success: false
origin: LOCAL
time_fired: "2022-09-12T12:34:05.235194+00:00"
context:
  id: 01GCRV2HSKQMHH1PJHZESNABQ0
  parent_id: null
  user_id: null

Which implies that the device responded (as expected) that it does not know this attribute. We got no response from the Legrand device.

mycanaletto commented 2 years ago

If I pass the first order I have: [281471560779088] Error handling message: required key not provided @ data['attr_val']. Got None (invalid_format)

If I add attr_val I have:

Failed 'discover_attributes_extended' starting 0x0000/0x0000. Error: Request failed after 5 attempts: <Status.MAC_NO_ACK: 233>
Couldn't read 0x0000/0xf000:

Here are the links to the information I used as a source and how they add these attributes in phoscon:

https://community.jeedom.com/t/probleme-commande-legrand-412171-contacteur-drivia/66924/6 https://community.jeedom.com/t/tuto-app-deconz-legrand-netatmo-cablage-et-parametrage/29982 https://community.jeedom.com/t/legrand-412171-contacteur-drivia/80928/3

mdeweerd commented 2 years ago

Sorry, I forgot to change write to read:

service: zha_toolkit.attr_read
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 0
  attribute: 1
  event_done: legrand_done
mycanaletto commented 2 years ago

2022-09-12T13:09:51.796895+00:00,Basic,app_version,0,0x0001,0x0000,1,00:04:74:00:00:83:f4:f6,

mdeweerd commented 2 years ago

There already is a dimmer device with similar attributes, so you could copy it and make a local quirk for your device. https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/legrand/dimmer.py

It shows that the dimmer value (attribute 0) is a uint16, so type 0x21 is appropriate. However, I am not sure that your device has a dimmer function, so possibly attribute 0 is something else, which is why reading it would be useful.

Now, regardless of the quirk, ZHA-toolkit should be able to get the right command sent out, if the device is not responding, then there is not much reason that the quirk would do better.

mdeweerd commented 2 years ago

2022-09-12T13:09:51.796895+00:00,Basic,app_version,0,0x0001,0x0000,1,00:04:74:00:00:83:f4:f6,

Good, that means it is connected, and apparently not responding to the attribute read. Try reading the manufacturer attributes 0, 1 and 2.

mycanaletto commented 2 years ago

Well it's a DIN contactor, by default it's in HC/HP and the purpose is to activate the on/off mode as it is done in z2m

2022-09-12T13:48:27.046374+00:00,Basic,zcl_version,2,0x0000,0x0000,1,00:04:74:00:00:83:f4:f6,
2022-09-12T13:48:44.987085+00:00,Basic,hw_version,2,0x0003,0x0000,1,00:04:74:00:00:83:f4:f6,
2022-09-12T13:49:06.504714+00:00,Basic,stack_version,66,0x0002,0x0000,1,00:04:74:00:00:83:f4:f6,
2022-09-12T13:49:52.519559+00:00,Manufacturer Specific,2,Bool.false,0x0002,0xFC01,1,00:04:74:00:00:83:f4:f6,
2022-09-12T13:50:16.979721+00:00,Manufacturer Specific,0,"[4, 0]",0x0000,0xFC01,1,00:04:74:00:00:83:f4:f6,
2022-09-12T13:50:21.323264+00:00,Manufacturer Specific,1,Bool.false,0x0001,0xFC01,1,00:04:74:00:00:83:f4:f6,
2022-09-12T13:50:25.704042+00:00,Manufacturer Specific,2,Bool.false,0x0002,0xFC01,1,00:04:74:00:00:83:f4:f6,
mdeweerd commented 2 years ago

Ok, now read attribute 0 and get the event-done information.

I can see that attribute 0 is not a uin16 because then it would have been listed as an integer and it is listed as two bytes which suggests it is an array. Unfortunately, it is not logged to the outputs (CSV/event), so you have to enable the debug log for this and look for something like:

2022-09-12 16:03:37.297 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Type determined from read: 0x20

when doing the read.

And to write, you need to specify: [3, 0] - which may work if you do a read before write. I am still puzzled why the write does not do anything successful while the read does.

You should be able to get the debug information by calling:

service: logger.set_level
data:
  custom_components.zha_toolkit: debug

which enables debug until HA is restarted.

mycanaletto commented 2 years ago
2022-09-12 16:25:09.417 DEBUG (MainThread) [custom_components.zha_toolkit] module is <module 'custom_components.zha_toolkit' from '/config/custom_components/zha_toolkit/__init__.py'>
2022-09-12 16:25:09.420 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Parameters '{'ieee': 00:04:74:00:00:83:f4:f6, 'endpoint': 1, 'cluster': 64513, 'attribute': 1, 'event_done': 'legrand_done', 'csvout': 'legrand1.csv'}'
2022-09-12 16:25:09.420 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Final manf 'None'
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] 'ieee' parameter: '00:04:74:00:00:83:f4:f6' -> IEEE Addr: '00:04:74:00:00:83:f4:f6'
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] Default handler for attr_read
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] Handler: <function command_handler_default at 0xffff3b263a30>
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] running default command: <ServiceCall zha_toolkit.attr_read (c:01GCS1DXRPNTAPDWBGACYRSQM4): ieee=00:04:74:00:00:83:f4:f6, endpoint=1, cluster=64513, attribute=1, event_done=legrand_done, csvout=legrand1.csv>
2022-09-12 16:25:09.423 DEBUG (MainThread) [custom_components.zha_toolkit.default] Trying to import custom_components.zha_toolkit.zcl_attr to call attr_read
2022-09-12 16:25:09.425 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Request attr read [1]
2022-09-12 16:25:09.426 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True, *is_reply=False), tsn=133, command_id=<GeneralCommand.Read_Attributes: 0>, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-09-12 16:25:09.427 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Sending request: Read_Attributes(attribute_ids=[1])
2022-09-12 16:25:09.490 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Received ZCL frame: b'\x18\x85\x01\x01\x00\x00\x10\x00'
2022-09-12 16:25:09.490 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=133, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-09-12 16:25:09.491 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Decoded ZCL frame: ManufacturerSpecificCluster:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0001, status=<Status.SUCCESS: 0>, value=TypeValue(type=Bool, value=<Bool.false: 0>))])
2022-09-12 16:25:09.492 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Reading attr result (attrs, status): ({1: <Bool.false: 0>}, {})
2022-09-12 16:25:09.492 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Type determined from read: 0x10
2022-09-12 16:25:09.494 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Appended 1=<Bool.false: 0> to '/config/csv/legrand1-csv'
2022-09-12 16:25:09.497 DEBUG (MainThread) [custom_components.zha_toolkit] event_data {'zha_toolkit_version': 'v0.8.14', 'zigpy_version': '0.50.3', 'zigpy_rf_version': '0.8.2', 'ieee_org': 00:04:74:00:00:83:f4:f6, 'ieee': '00:04:74:00:00:83:f4:f6', 'command': 'attr_read', 'command_data': None, 'start_time': '2022-09-12T14:25:09.421940+00:00', 'errors': [], 'params': {'endpoint_id': 1, 'cluster_id': 64513, 'attr_id': 1, 'dir': 0, 'tries': 1, 'expect_reply': True, 'args': [], 'event_done': 'legrand_done', 'read_before_write': True, 'read_after_write': True, 'csvfile': 'legrand1.csv'}, 'write_is_equal': False, 'result_read': ({1: <Bool.false: 0>}, {}), 'success': True}
2022-09-12 16:25:09.498 DEBUG (MainThread) [custom_components.zha_toolkit] Fire legrand_done -> {'zha_toolkit_version': 'v0.8.14', 'zigpy_version': '0.50.3', 'zigpy_rf_version': '0.8.2', 'ieee_org': 00:04:74:00:00:83:f4:f6, 'ieee': '00:04:74:00:00:83:f4:f6', 'command': 'attr_read', 'command_data': None, 'start_time': '2022-09-12T14:25:09.421940+00:00', 'errors': [], 'params': {'endpoint_id': 1, 'cluster_id': 64513, 'attr_id': 1, 'dir': 0, 'tries': 1, 'expect_reply': True, 'args': [], 'event_done': 'legrand_done', 'read_before_write': True, 'read_after_write': True, 'csvfile': 'legrand1.csv'}, 'write_is_equal': False, 'result_read': ({1: <Bool.false: 0>}, {}), 'success': True}
2022-09-12 16:25:10.205 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x04DD](TS011F): Device seen - marking the device available and resetting counter
mycanaletto commented 2 years ago

att 3

service: zha_toolkit.attr_read
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 3
  event_done: legrand_done
  csvout: legrand1.csv

event_done=legrand_done, csvout=legrand1.csv>
2022-09-12 16:25:09.417 DEBUG (MainThread) [custom_components.zha_toolkit] module is <module 'custom_components.zha_toolkit' from '/config/custom_components/zha_toolkit/__init__.py'>
2022-09-12 16:25:09.420 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Parameters '{'ieee': 00:04:74:00:00:83:f4:f6, 'endpoint': 1, 'cluster': 64513, 'attribute': 1, 'event_done': 'legrand_done', 'csvout': 'legrand1.csv'}'
2022-09-12 16:25:09.420 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Final manf 'None'
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] 'ieee' parameter: '00:04:74:00:00:83:f4:f6' -> IEEE Addr: '00:04:74:00:00:83:f4:f6'
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] Default handler for attr_read
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] Handler: <function command_handler_default at 0xffff3b263a30>
2022-09-12 16:25:09.422 DEBUG (MainThread) [custom_components.zha_toolkit] running default command: <ServiceCall zha_toolkit.attr_read (c:01GCS1DXRPNTAPDWBGACYRSQM4): ieee=00:04:74:00:00:83:f4:f6, endpoint=1, cluster=64513, attribute=1, event_done=legrand_done, csvout=legrand1.csv>
2022-09-12 16:25:09.423 DEBUG (MainThread) [custom_components.zha_toolkit.default] Trying to import custom_components.zha_toolkit.zcl_attr to call attr_read
2022-09-12 16:25:09.425 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Request attr read [1]
2022-09-12 16:25:09.426 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=False, direction=<Direction.Server_to_Client: 0>, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True, *is_reply=False), tsn=133, command_id=<GeneralCommand.Read_Attributes: 0>, *direction=<Direction.Server_to_Client: 0>, *is_reply=False)
2022-09-12 16:25:09.427 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Sending request: Read_Attributes(attribute_ids=[1])
2022-09-12 16:25:09.490 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Received ZCL frame: b'\x18\x85\x01\x01\x00\x00\x10\x00'
2022-09-12 16:25:09.490 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True, *is_reply=True), tsn=133, command_id=1, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)
2022-09-12 16:25:09.491 DEBUG (MainThread) [zigpy.zcl] [0x5AE8:1:0xfc01] Decoded ZCL frame: ManufacturerSpecificCluster:Read_Attributes_rsp(status_records=[ReadAttributeRecord(attrid=0x0001, status=<Status.SUCCESS: 0>, value=TypeValue(type=Bool, value=<Bool.false: 0>))])
2022-09-12 16:25:09.492 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Reading attr result (attrs, status): ({1: <Bool.false: 0>}, {})
2022-09-12 16:25:09.492 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Type determined from read: 0x10
2022-09-12 16:25:09.494 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Appended 1=<Bool.false: 0> to '/config/csv/legrand1-csv'
2022-09-12 16:25:09.497 DEBUG (MainThread) [custom_components.zha_toolkit] event_data {'zha_toolkit_version': 'v0.8.14', 'zigpy_version': '0.50.3', 'zigpy_rf_version': '0.8.2', 'ieee_org': 00:04:74:00:00:83:f4:f6, 'ieee': '00:04:74:00:00:83:f4:f6', 'command': 'attr_read', 'command_data': None, 'start_time': '2022-09-12T14:25:09.421940+00:00', 'errors': [], 'params': {'endpoint_id': 1, 'cluster_id': 64513, 'attr_id': 1, 'dir': 0, 'tries': 1, 'expect_reply': True, 'args': [], 'event_done': 'legrand_done', 'read_before_write': True, 'read_after_write': True, 'csvfile': 'legrand1.csv'}, 'write_is_equal': False, 'result_read': ({1: <Bool.false: 0>}, {}), 'success': True}
2022-09-12 16:25:09.498 DEBUG (MainThread) [custom_components.zha_toolkit] Fire legrand_done -> {'zha_toolkit_version': 'v0.8.14', 'zigpy_version': '0.50.3', 'zigpy_rf_version': '0.8.2', 'ieee_org': 00:04:74:00:00:83:f4:f6, 'ieee': '00:04:74:00:00:83:f4:f6', 'command': 'attr_read', 'command_data': None, 'start_time': '2022-09-12T14:25:09.421940+00:00', 'errors': [], 'params': {'endpoint_id': 1, 'cluster_id': 64513, 'attr_id': 1, 'dir': 0, 'tries': 1, 'expect_reply': True, 'args': [], 'event_done': 'legrand_done', 'read_before_write': True, 'read_after_write': True, 'csvfile': 'legrand1.csv'}, 'write_is_equal': False, 'result_read': ({1: <Bool.false: 0>}, {}), 'success': True}
2022-09-12 16:25:10.205 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x04DD](TS011F): Device seen - marking the device available and resetting counter
2022-09-12 16:25:10.205 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x04DD](TS011F): Update device availability -  device available: True - new availability: True - changed: False
2022-09-12 16:25:10.207 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x406E](TS0121): Device seen - marking the device available and resetting counter
2022-09-12 16:25:10.207 DEBUG (MainThread) [homeassistant.components.zha.core.device] [0x406E](TS0121): Update device availability -  device available: True - new availability: True - changed: False
mdeweerd commented 2 years ago

2022-09-12 16:25:09.492 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Type determined from read: 0x10

Et

2022-09-12 16:25:09.492 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Type determined from read: 0x10

These are booleans, which we knew already.

Attribute 0 doesn't have its type identified yet.

mdeweerd commented 2 years ago

Version 0.8.15 adds the attribute type information to the CSV output and event data (no need to restart HA if you upgrade from 0.8.14).

mdeweerd commented 2 years ago

You could check if there is a FW update for your device (at least download and trigger it), if you setup the oatu_directory and then call ota_notify:

service: zha_toolkit.ota_notify
data:
  ieee: 00:04:74:00:00:83:f4:f6
  download: true

But out of interest I would do that AFTER identifying the attr_type in the current firmware to see if it was updated to uint16 in a later version.

You could also add the script https://github.com/mdeweerd/zha-toolkit/blob/v0.8.15/examples/script_read_basic_cluster.yaml and call it as in https://github.com/mdeweerd/zha-toolkit/blob/v0.8.15/examples/service_call_read_basic_cluster.yaml .

The script reads the first 7 attributes of the basic cluster which contains model data, version, etc.

You can update it to read the 3 (or more) attributes from your manufacturer cluster, do then you read all of them in sequence to a file.

mycanaletto commented 2 years ago
service: script.zhatk
data:
  entity_name: button.legrand_contactor_identifybutton
  csv: ../csv/legrand_scr.csv

2022-09-12T15:44:32.438209+00:00,Basic,zcl_version,2,0x0000,0x0000,1,00:04:74:00:00:83:f4:f6,,0x20
2022-09-12T15:44:32.569949+00:00,Basic,app_version,0,0x0001,0x0000,1,00:04:74:00:00:83:f4:f6,,0x20
2022-09-12T15:44:32.688646+00:00,Basic,stack_version,66,0x0002,0x0000,1,00:04:74:00:00:83:f4:f6,,0x20
2022-09-12T15:44:32.814024+00:00,Basic,hw_version,2,0x0003,0x0000,1,00:04:74:00:00:83:f4:f6,,0x20
2022-09-12T15:44:32.933531+00:00,Basic,manufacturer, Legrand,0x0004,0x0000,1,00:04:74:00:00:83:f4:f6,,0x42
2022-09-12T15:44:33.082004+00:00,Basic,model, Contactor,0x0005,0x0000,1,00:04:74:00:00:83:f4:f6,,0x42
2022-09-12T15:44:33.219944+00:00,Basic,date_code, ,0x0006,0x0000,1,00:04:74:00:00:83:f4:f6,,0x42
mdeweerd commented 2 years ago

Ok, that sets the base line for the version which is a bit disappointing for a "Legrand" product because there is no DateCode. And confirms that you are using the new version with the attribute type at the end of the line: 0x20 or 0x42 for the attributes in the basic cluster.

However, you need to read attribute 0 from the manufacturer cluster.

In the script, you can update the following:

        - service: zha_toolkit.attr_read
          data:
            ieee: '{{ entity_name }}'
            cluster: 0
            attribute: '{{ current }}'
            tries: 3
            state_id: sensor.basic_cluster
            state_attr: '{{ "%s%04X" % (entity_name, current|int) }}'
            allow_create: true
            csvout: '{{ csv }}'

to

        - service: zha_toolkit.attr_read
          data:
            ieee: '{{ entity_name }}'
            cluster: 64513
            manf: 4129  # Note: this may need to be avoided (commented)
            attribute: '{{ current }}'
            tries: 3
            state_id: sensor.basic_cluster
            state_attr: '{{ "%s%04X" % (entity_name, current|int) }}'
            allow_create: true
            csvout: '{{ csv }}'

I indicated manf: 4129 # Note: this may need to be avoided (commented) because you seem to have successfully read the manufacturer attributes without specifying the manufacturer. For attribute 3 you indicated:

service: zha_toolkit.attr_read
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 3
  event_done: legrand_done
  csvout: legrand1.csv

So no manufacturer there, and yet: success when reading. So possibly you need to read these attributes without setting the manufacturer (zigpy might be adding them automatically, but I think I avoided that in the toolkit).

So you can test both if you like.

mycanaletto commented 2 years ago

In the script, if you go from cluster 0 to 64513 (with or without manf) it doesn't work. Error

mdeweerd commented 2 years ago

The Error was not provided.

Apparently

service: zha_toolkit.attr_read
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 3
  event_done: legrand_done
  csvout: legrand1.csv

worked, so maybe "endpoint: 1" needs to be added as well. The script is using the "zha_toolkit.attr_read" service, so if the individual command works, the script should as well.

mycanaletto commented 2 years ago
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/decorators.py", line 27, in _handle_async_response
    await func(hass, connection, msg)
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 647, in handle_execute_script
    await script_obj.async_run(msg.get("variables"), context=context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1513, in async_run
    await asyncio.shield(run.async_run())
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 405, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 449, in _async_step
    self._handle_exception(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 472, in _handle_exception
    raise exception
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 447, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 680, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1738, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1775, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/config/custom_components/zha_toolkit/__init__.py", line 717, in toolkit_service
    raise handler_exception
  File "/config/custom_components/zha_toolkit/__init__.py", line 681, in toolkit_service
    await handler(
  File "/config/custom_components/zha_toolkit/__init__.py", line 766, in command_handler_default
    await default.default(
  File "/config/custom_components/zha_toolkit/default.py", line 33, in default
    await handler(app, listener, ieee, cmd, data, service, params, event_data)
  File "/config/custom_components/zha_toolkit/zcl_attr.py", line 273, in attr_read
    await attr_write(*args, **kwargs)
  File "/config/custom_components/zha_toolkit/zcl_attr.py", line 340, in attr_write
    event_data["attr_type"] = f"0x{attr_type:02X}"
TypeError: unsupported format string passed to NoneType.__format__

and

websocket_api script: Error executing script. Unexpected error for call_service at pos 1: unsupported format string passed to NoneType.__format__
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 447, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 680, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1738, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1775, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/config/custom_components/zha_toolkit/__init__.py", line 717, in toolkit_service
    raise handler_exception
  File "/config/custom_components/zha_toolkit/__init__.py", line 681, in toolkit_service
    await handler(
  File "/config/custom_components/zha_toolkit/__init__.py", line 766, in command_handler_default
    await default.default(
  File "/config/custom_components/zha_toolkit/default.py", line 33, in default
    await handler(app, listener, ieee, cmd, data, service, params, event_data)
  File "/config/custom_components/zha_toolkit/zcl_attr.py", line 273, in attr_read
    await attr_write(*args, **kwargs)
  File "/config/custom_components/zha_toolkit/zcl_attr.py", line 340, in attr_write
    event_data["attr_type"] = f"0x{attr_type:02X}"
TypeError: unsupported format string passed to NoneType.__format__
mycanaletto commented 2 years ago

attribute 1 and 2 ok, 3 this error

mdeweerd commented 2 years ago

Ok, apparently I introduced a bug in 0.8.15 when the attr_type ends being nothing, So attribute 3 does not exist apparently. What about attribute 0?

Fixed in 0.8.16 - just update zha-toolkit, no need to restart HA. If you used the script, then you may have some output in the CSV that is useable as the file is extended after each attr_read.

mycanaletto commented 2 years ago

ok

2022-09-12T19:28:39.764178+00:00,Manufacturer Specific,0,"[4, 0]",0x0000,0xFC01,1,00:04:74:00:00:83:f4:f6,,0x09
2022-09-12T19:28:39.894338+00:00,Manufacturer Specific,1,Bool.false,0x0001,0xFC01,1,00:04:74:00:00:83:f4:f6,,0x10
2022-09-12T19:28:40.024960+00:00,Manufacturer Specific,2,Bool.false,0x0002,0xFC01,1,00:04:74:00:00:83:f4:f6,,0x10
mdeweerd commented 2 years ago

Very well, now we have the actual data type and the method to access it:

So now hopefully the following works:

service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:83:f4:f6
  endpoint: 1
  cluster: 64513
  attribute: 0
  attr_val: [3, 0]
  attr_type: 0x09  # Should be optional if reading before write.
  # manf: 4129  # Not setting the manufacturer as that does not seem to be needed
  event_done: legrand_done
  # Read attribute before writing it: setting to false, not sure how "true" works out for 0x09 types, but you can test it once you have success
  read_before_write: false
  # Read attribute after writing it (defaults to True) - always good to read back.
  read_after_write: true
  # Write attribute when the read value matches (defaults to False), not used when skipping read.
  write_if_equal: false
mycanaletto commented 2 years ago

Yessss !!!

mycanaletto commented 2 years ago

Thank you for your help and patience!

I will now write a post on my blog for everyone to enjoy. I would take the opportunity to check that the other values are OK, the kw/h is missing but I'm not sure if the module supports it, at worst we can fix it with Reiman under HA.

Thanks again for your work!

https://canaletto.fr/category/Domotique

mdeweerd commented 2 years ago

In fact, it does match https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/legrand/dimmer.py#L32-L42 but not the earlier version https://github.com/zigpy/zha-device-handlers/blame/ea31a3b4e3425c1559275fc8f35caedae18d211d/zhaquirks/legrand/dimmer.py#L38-L42 which I read and which suggests those are "manufacturer_attributes" requiring the manufacturer id to be sent.

So now it's just a small excercise to create a basic quirk for this device....

mdeweerd commented 2 years ago

The module does have the 0x0b04 cluster which is for electrical measurement, so the attributes are in there.

You can check https://github.com/zigpy/zigpy/blob/29f5268125714003cd7ce67e4886ac4ab7fd44d7/zigpy/zcl/clusters/homeautomation.py#L87-L232 to see the attributes that are in there. You could update the script to loop over attributes (loop from 0 to 0x0A, multiply by 256 and add to loop index from 0 to 0x17 which would cover every potential attribute).

mycanaletto commented 2 years ago

I didn't understand everything....

To have directly the kw/h?

image

mdeweerd commented 2 years ago

Ok, I thought you were missing these values.

The code extract I provided lists the attribute_id and then its short label and type.

I checked the specification and apparently 0x0b04 only provides instantaneous values, not cumulative totals, which is something that is done in cluster 0x0702 - and that is missing.

Worst case you can use https://github.com/bramstroker/homeassistant-powercalc to create a virtual meter based on the instantaneous values.

Regarding the other properties you can check (in French): https://github.com/KiwiHC16/Abeille/issues/850

mdeweerd commented 2 years ago

BTW: you can never have the kW/h ! You can have the kW or the kWh !!!

mycanaletto commented 2 years ago

Yes of course, the goal would be to have this directly, even if you can do it via a sensor in HA

image

mycanaletto commented 2 years ago

And that's it! I'll see later for the kWh (I also have a job...)

Merci !

https://www.canaletto.fr/post/home-assistant-zha-and-legrand

mdeweerd commented 2 years ago

Like me... .

mycanaletto commented 1 year ago

Hello,

In the same way for a Legrand cable outlet... I can't send the mode commands, you probably have an idea...

Pilot Wire mode : cluster FC01, attribut 0000, dataType 09, value: on 0002 / off 0001

Command to set mode : cluster FC40, attribut 0000, dataType 30, value: confort 00 / confort -1 01 / confort -2 02 / eco 03 / hors-gel 04 / off 05

The ZHA integration is not complete, I guess the only way to switch between modes is to send these commands...

More information here : https://github.com/Koenkk/zigbee-herdsman-converters/blob/12566e7ad635a6e941846abeafeab62039a8f939/converters/toZigbee.js#L4869

Merci pour l'aide ;-)

mdeweerd commented 1 year ago
  1. You can see if a "scan_device" provides more information - the attributes might appear in that report, and we may see if they are writable.
  2. As far as I understand the Z2M implementation, you need to send the data as a manufacturer attribute. And it is the attribute that is written.
  3. The attr_type is '9' - 16bit data (not int) - normally ZHA-Toolkit detects this (by performing a read). It is somewhat safer to not specify the type (to avoid a mistake), but faster if you do not want the "read_before_write".

So try to read first:

service: zha_toolkit.attr_read
data:
  ieee: whatever.entity_name
  cluster: 0xFC01
  attribute: 0
  manf:  0x1021
  event_done: legrand_done
service: zha_toolkit.attr_read
data:
  ieee: whatever.entity_name
  cluster: 0xFC40
  attribute: 0
  manf:  0x1021
  event_done: legrand_done

I do not know if the attribute value of type '9' is converted correctly - I'ld need to check (if it doesn't). If you enable debug for zha_toolkit, you can see something corresonding to "Converted %s to %s - will compare to %s - Type: 0x%02X" in the log.

And maybe we should meet one day - see my invite.

mycanaletto commented 1 year ago

And here is the return:

PS: what invitation?

event_type: legrand_done
data:
  zha_toolkit_version: v0.8.29
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: attr_read
  command_data: null
  start_time: "2023-02-16T00:32:31.101817+00:00"
  errors: []
  params:
    cluster_id: 64513
    attr_id: 0
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  attr_type: "0x09"
  write_is_equal: false
  result_read:
    - "0":
        - 2
        - 0
    - {}
  success: true
origin: LOCAL
time_fired: "2023-02-16T00:32:31.178564+00:00"
context:
  id: 01GSBT65EA377KRXVPCA71XYTP
  parent_id: null
  user_id: null
event_type: legrand_done
data:
  zha_toolkit_version: v0.8.29
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: attr_read
  command_data: null
  start_time: "2023-02-16T00:36:01.974975+00:00"
  errors: []
  params:
    cluster_id: 64576
    attr_id: 0
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  attr_type: "0x30"
  write_is_equal: false
  result_read:
    - "0": 0
    - {}
  success: true
origin: LOCAL
time_fired: "2023-02-16T00:36:02.069480+00:00"
context:
  id: 01GSBTCKCNEWJGVDF8PDBFPEMS
  parent_id: null
  user_id: null
mdeweerd commented 1 year ago

2 x Success !

P.S.: Invitation @ image First:

  attr_type: "0x09"
  result_read:
    - "0":
        - 2
        - 0
    - {}

Second:

  attr_type: "0x30"
  result_read:
    - "0": 0
    - {}

So you should be able to write like this:

service: zha_toolkit.attr_write
data:
  ieee: whatever.entity_name
  cluster: 0xFC01
  attribute: 0
  manf:  0x1021
  attr_type: 9   # Optional, can help avoid read before write.
  attr_val: [ 2, 0 ]  # Change this to the value you write. 
  event_done: legrand_done

(There is an example of an "octet_string" in the documentation and apparently the data* types needs to be specified the same way.)

The other one is simpler:

service: zha_toolkit.attr_write
data:
  ieee: whatever.entity_name
  cluster: 0xFC01
  attribute: 0
  manf:  0x1021
  attr_type: 0x30   # Optional, can help avoid read before write.
  attr_val: 0  # Change this to the value you write. 
  event_done: legrand_done

I personally add "csv_out" to a lot of my scripts so that I have the possibility to check when I changed a configuration - and with read_before_write I get the old value just before the change as well.

mycanaletto commented 1 year ago

And here is the return, an invitation accepted ;-)

event_type: legrand_done
data:
  zha_toolkit_version: v0.8.29
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: attr_write
  command_data: null
  start_time: "2023-02-16T12:52:19.374772+00:00"
  errors: []
  params:
    cluster_id: 64513
    attr_id: 0
    attr_type: 9
    attr_val:
      - 2
      - 0
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  compare_val:
    - 2
    - 0
  attr_type: "0x09"
  write_is_equal: true
  info: Data read is equal to data to write
  result_read:
    - "0":
        - 2
        - 0
    - {}
  success: true
origin: LOCAL
time_fired: "2023-02-16T12:52:19.478356+00:00"
context:
  id: 01GSD4GSCPSTH5CFQN3G1NDH3A
  parent_id: null
  user_id: null

et

event_type: legrand_done
data:
  zha_toolkit_version: v0.8.29
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: attr_write
  command_data: null
  start_time: "2023-02-16T12:53:15.223425+00:00"
  errors: []
  params:
    cluster_id: 64513
    attr_id: 0
    attr_type: 48
    attr_val: 0
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  compare_val: 0
  attr_type: "0x30"
  write_is_equal: false
  read_before:
    - "0":
        - 2
        - 0
    - {}
  result_write:
    - - status: 141
        attrid: 0
  result_read:
    - "0":
        - 2
        - 0
    - {}
  success: false
origin: LOCAL
time_fired: "2023-02-16T12:53:15.538447+00:00"
context:
  id: 01GSD4JG4JSFFCAXVZKM4TY6A0
  parent_id: null
  user_id: null
mdeweerd commented 1 year ago

You forgot to change the cluster id in the second call - and you should try o change the value in the first call or set "read_before_write" to false to really make the write (zha-toolkit does not write if it reads the data first and it is equal to what should be written).

mycanaletto commented 1 year ago
service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:23:3d:b5
  cluster: 0xFC40
  attribute: 0
  manf:  0x1021
  attr_type: 0x30   # Optional, can help avoid read before write.
  attr_val: 0  # Change this to the value you write. 
  event_done: legrand_done
event_type: legrand_done
data:
  zha_toolkit_version: v0.8.29
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: attr_write
  command_data: null
  start_time: "2023-02-16T13:46:57.578772+00:00"
  errors: []
  params:
    cluster_id: 64576
    attr_id: 0
    attr_type: 48
    attr_val: 0
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args: []
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  compare_val: 0
  attr_type: "0x30"
  write_is_equal: true
  info: Data read is equal to data to write
  result_read:
    - "0": 0
    - {}
  success: true
origin: LOCAL
time_fired: "2023-02-16T13:46:57.696396+00:00"
context:
  id: 01GSD7MTS0KX1E4W7CMZFX6MTW
  parent_id: null
  user_id: null
mycanaletto commented 1 year ago

I had understood that it was necessary to send an order?

mdeweerd commented 1 year ago

When you omit the attr_type, the read is needed if the type can not be determined from the zigpy internals. The response to a read request contains the attr_type as well, so that is reused by zha-toolkit during the write. That helps us being lazy when using it as a toolkit: there is no need to lookup the the type.

In this case, you are (still) writing the values that are already in the device. So what is happening is that zha-toolkit first reads the values, compares to what you want to write and as the values are equal, does not write at all (saving 2 transactions - so energy, and also saving a potential needless flash write in the device). So if you want to make sure that you really write even when the value is already set, you have to set attr_type in this case and read_before_write to false. Or you can write something else - which is your main goal.

mycanaletto commented 1 year ago

I found this other information

https://forum.hacf.fr/t/utilisation-legrand-fil-pilote-avec-deconz-api-rest/18978

But I confess that I am a bit lost...

If I summarize what I understood, there must be

mdeweerd commented 1 year ago

In this case, the device_mode can be changed by writing the attribute (seen here) and the "cable outlet mode" is controlled using a manufacturer command (seen here ).

So the command can be written with zha_toolkit:

service: zha_toolkit.zcl_cmd
data:
  ieee: 00:04:74:00:00:23:3d:b5
  cmd: 0
  args:  [ 3 ]  # Set the code for the desired mode.
  cluster: 0xFC40
  endpoint: XXXX # Set the correct endpoint.
  manf:  0x1021

(zha-toolkit does not detect the endpoint for this command, so you need to set it).

After that you should be able to read back the attribute to verify it's changed.

mdeweerd commented 1 year ago

Actually, zha_toolkit.zcl_cmd likely does detect the endpoint if you omit it - you can validate that and if it works then the documentation has to be updated.

mycanaletto commented 1 year ago

The good news is that the mode change works:

service: zha_toolkit.attr_write
data:
  ieee: 00:04:74:00:00:23:3d:b5
  cluster: 64513
  attribute: 0
  manf: 4129
  attr_type: 9
  attr_val:
    - 1      #  Mode
    - 0
  event_done: legrand_done

but the command (with or without endpoint) returns : KeyError(0)

event_type: legrand_done
data:
  zha_toolkit_version: v0.8.29
  zigpy_version: 0.53.0
  zigpy_rf_version: 0.9.2
  ieee_org:
    - 181
    - 61
    - 35
    - 0
    - 0
    - 116
    - 4
    - 0
  ieee: 00:04:74:00:00:23:3d:b5
  command: zcl_cmd
  command_data: null
  start_time: "2023-02-16T15:27:05.757371+00:00"
  errors:
    - KeyError(0)
  params:
    cmd_id: 0
    endpoint_id: 1
    cluster_id: 64576
    dir: 0
    manf: 4129
    tries: 1
    expect_reply: true
    args:
      - 3
    event_done: legrand_done
    read_before_write: true
    read_after_write: true
  success: false
origin: LOCAL
time_fired: "2023-02-16T15:27:05.760899+00:00"
context:
  id: 01GSDDC610E3YY1TSBVV6VWBN2
  parent_id: null
  user_id: null