zha-device-handlers icon indicating copy to clipboard operation
zha-device-handlers copied to clipboard

[Device Support Request] - SIN-4-FP-21_EQU

Open APCM-1 opened this issue 2 years ago • 18 comments

Problem description

I have a Pilot wire heating module (Leroy Merlin version) and I want to control it via ZHA.

Brand : ADEO Model : SIN-4-FP-21_EQU

3624961

At the moment we don't have mode handling, only On and Off (Hors Gel) with power measurement.

Some people seems to have handle this module with Z2M but not ZHA.

https://www.zigbee2mqtt.io/devices/SIN-4-FP-21_EQU.html

https://github.com/Koenkk/zigbee2mqtt/issues/19169

Solution description

We need to have mode handling. There are 6 modes : confort, confort -1, confort -2, eco, Hors Gel, Off.

Screenshots/Video

Screenshots/Video

Capture d'écran 2023-11-27 161003

Device signature

Device signature
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4727, maximum_buffer_size=82, maximum_incoming_transfer_size=500, server_mask=11264, maximum_outgoing_transfer_size=500, 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": "0x0104",
      "device_type": "0x0051",
      "input_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0702",
        "0x1000",
        "0xfc00"
      ],
      "output_clusters": [
        "0x0019"
      ]
    },
    "242": {
      "profile_id": "0xa1e0",
      "device_type": "0x0066",
      "input_clusters": [
        "0x0021"
      ],
      "output_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "Adeo",
  "model": "SIN-4-FP-21_EQU",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant Supervised",
    "version": "2023.11.3",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.6",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Europe/Paris",
    "os_name": "Linux",
    "os_version": "6.1.24-v8+",
    "supervisor": "2023.11.3",
    "host_os": "Debian GNU/Linux 11 (bullseye)",
    "docker_version": "24.0.7",
    "chassis": "",
    "run_as_root": true
  },
  "custom_components": {
    "hacs": {
      "version": "1.33.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "bellows==0.36.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.106",
      "zigpy-deconz==0.21.1",
      "zigpy==0.59.0",
      "zigpy-xbee==0.19.0",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.6",
      "universal-silabs-flasher==0.0.14",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 41678,
    "manufacturer": "Adeo",
    "model": "SIN-4-FP-21_EQU",
    "name": "Adeo SIN-4-FP-21_EQU",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4727,
    "power_source": "Mains",
    "lqi": 176,
    "rssi": -56,
    "last_seen": "2023-11-27T16:20:28",
    "available": true,
    "device_type": "Router",
    "signature": {
      "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4727, maximum_buffer_size=82, maximum_incoming_transfer_size=500, server_mask=11264, maximum_outgoing_transfer_size=500, 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": "0x0104",
          "device_type": "0x0051",
          "input_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0702",
            "0x1000",
            "0xfc00"
          ],
          "output_clusters": [
            "0x0019"
          ]
        },
        "242": {
          "profile_id": "0xa1e0",
          "device_type": "0x0066",
          "input_clusters": [
            "0x0021"
          ],
          "output_clusters": [
            "0x0021"
          ]
        }
      },
      "manufacturer": "Adeo",
      "model": "SIN-4-FP-21_EQU"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "button.chauffage_chambres_identifier",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "sensor.chauffage_chambres_demande_instantanee",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "sensor.chauffage_chambres_summation_delivered",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "switch.chauffage_chambres_commutateur",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "select.chauffage_chambres_comportement_au_demarrage",
        "name": "Adeo SIN-4-FP-21_EQU"
      }
    ],
    "neighbors": [
      {
        "device_type": "Coordinator",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x0000",
        "permit_joining": "Unknown",
        "depth": "0",
        "lqi": "154"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x1E44",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "114"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x2D56",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "122"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x56B7",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "108"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x88C4",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "88"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x9E18",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "109"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xCF76",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "125"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xD40F",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "123"
      }
    ],
    "routes": [
      {
        "dest_nwk": "0x0000",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x0000"
      },
      {
        "dest_nwk": "0xAB2E",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0xAB2E"
      },
      {
        "dest_nwk": "0xCF76",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x1E44"
      },
      {
        "dest_nwk": "0x56B7",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x56B7"
      },
      {
        "dest_nwk": "0xD40F",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0xD40F"
      }
    ],
    "endpoint_names": [
      {
        "name": "SMART_PLUG"
      },
      {
        "name": "COMBO_BASIC"
      }
    ],
    "user_given_name": "Chauffage Chambres",
    "device_reg_id": "50237090f1dac5121b7c9eb9b8bdf801",
    "area_id": "chambre",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "SMART_PLUG",
          "id": 81
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "Adeo"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "SIN-4-FP-21_EQU"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {
              "0x0000": {
                "attribute_name": "on_off",
                "value": 1
              },
              "0x4003": {
                "attribute_name": "start_up_on_off",
                "value": 255
              }
            },
            "unsupported_attributes": {}
          },
          "0x0702": {
            "endpoint_attribute": "smartenergy_metering",
            "attributes": {
              "0x0000": {
                "attribute_name": "current_summ_delivered",
                "value": 39737
              },
              "0x0304": {
                "attribute_name": "demand_formatting",
                "value": 19
              },
              "0x0302": {
                "attribute_name": "divisor",
                "value": 1000
              },
              "0x0400": {
                "attribute_name": "instantaneous_demand",
                "value": 1028
              },
              "0x0306": {
                "attribute_name": "metering_device_type",
                "value": 0
              },
              "0x0301": {
                "attribute_name": "multiplier",
                "value": 1
              },
              "0x0200": {
                "attribute_name": "status",
                "value": 0
              },
              "0x0303": {
                "attribute_name": "summation_formatting",
                "value": 59
              },
              "0x0300": {
                "attribute_name": "unit_of_measure",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0100": {
                "attribute_name": "current_tier1_summ_delivered"
              },
              "0x0102": {
                "attribute_name": "current_tier2_summ_delivered"
              },
              "0x0104": {
                "attribute_name": "current_tier3_summ_delivered"
              },
              "0x0106": {
                "attribute_name": "current_tier4_summ_delivered"
              },
              "0x0108": {
                "attribute_name": "current_tier5_summ_delivered"
              },
              "0x010a": {
                "attribute_name": "current_tier6_summ_delivered"
              }
            }
          },
          "0x1000": {
            "endpoint_attribute": "lightlink",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xfc00": {
            "endpoint_attribute": "manufacturer_specific",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      },
      "242": {
        "device_type": {
          "name": "COMBO_BASIC",
          "id": 102
        },
        "profile_id": 41440,
        "in_clusters": {
          "0x0021": {
            "endpoint_attribute": "green_power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0021": {
            "endpoint_attribute": "green_power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

Logs
[Paste the logs here]

Custom quirk

Custom quirk
[Paste your custom quirk here]

Additional information

No response

APCM-1 avatar Nov 27 '23 15:11 APCM-1

Hello, i have those devices since a couple of days. I'm using Deconz (Phoscon) to add device to my zigbee network: devices are recognized as Lamp in Phoscon and i can only On and Off but without power measurement. So there is also no Power Measurement in Home Assistant (ZHA). What have you done to see power measurement please?

Capture d'écran 2023-11-29 105128

ConteZer0 avatar Nov 29 '23 09:11 ConteZer0

Hello,

I just paired modules to Home Assistant and they were recognized as a socket and the consumption information came automatically

APCM-1 avatar Nov 29 '23 11:11 APCM-1

Ok thanks. I finally removed DeconZ and i replaced it with ZHA. I have now "Commutateur", "Demande instantanée" and "Summation delivered" but not "Consommation chauffage". Is it usefull?

ConteZer0 avatar Nov 30 '23 09:11 ConteZer0

Oh yes sorry this one is a manual entry to know how much consumption I have each day

APCM-1 avatar Nov 30 '23 10:11 APCM-1

Great! Can you explain me how to do that please?

ConteZer0 avatar Nov 30 '23 12:11 ConteZer0

I'm also interested. It will be interesting to check if the device is the same with SIN-4-fp-21 because they are both made by nodon

Ce post m'intéresse aussi. Il serait intéressant de voir si un développement peut permettre de faire fonctionner la référence du fabricant Nodon: la sin-4-fp-21

romain563 avatar Dec 19 '23 20:12 romain563

Great! Can you explain me how to do that please?

Into parameters, in entries tab, create a new one, you need to choose a utiliy meter (water, electricity) in french its "Compteur de services publics (eau, gaz, électricité…)" and set the same parameters as the screenshot

Capture

APCM-1 avatar Dec 20 '23 08:12 APCM-1

I'm also interested. It will be interesting to check if the device is the same with SIN-4-fp-21 because they are both made by nodon

Ce post m'intéresse aussi. Il serait intéressant de voir si un développement peut permettre de faire fonctionner la référence du fabricant Nodon: la sin-4-fp-21

I think it's the same, I see somewhere else on github that people reference the SIN-4-FP-21 as the same device as the SIN-4-FP-21_EQU.

APCM-1 avatar Dec 20 '23 08:12 APCM-1

Great! Can you explain me how to do that please?

Into parameters, in entries tab, create a new one, you need to choose a utiliy meter (water, electricity) in french its "Compteur de services publics (eau, gaz, électricité…)" and set the same parameters as the screenshot

Capture

Thnaks!!

ConteZer0 avatar Jan 02 '24 21:01 ConteZer0

Any news on this ? Is everything working with ZHA ?

stadros83 avatar Jan 03 '24 09:01 stadros83

Any news on this ? Is everything working with ZHA ?

Hi,

I asked directly the manufecturer for information. For Z2M the integration will be available in late January but for ZHA it will be available later.

APCM-1 avatar Jan 04 '24 05:01 APCM-1

I flag here to follow. I have several of these modules on my heaters and I would like more that consumption and on/off. :)

anoril1979 avatar Feb 14 '24 21:02 anoril1979

hi, I am also interested in this integration under ZHA: the SIN-4-FP-21 boxes seem very good, I am waiting to be able to control my radiators with them.

popof1664 avatar Feb 20 '24 14:02 popof1664

Same issue here. added yesterday to HA through ZHA, it shows a switch toggle, and consumption, but no control to the heater. I aslo have to mention that the "switch" part of the module has no effect on y heater, which is kind of weird to me.

laur3nt95 avatar Mar 01 '24 09:03 laur3nt95

Hi i've asked to Nodon's support and they told me the ZHA intégration is on the pipe and it will be released in the coming weeks. Seb

Le ven. 1 mars 2024, 10:10, laur3nt95 @.***> a écrit :

Same issue here. added yesterday to HA through ZHA, it shows a switch toggle, and consumption, but no control to the heater. I aslo have to mention that the "switch" part of the module has no effect on y heater, which is kind of weird to me.

— Reply to this email directly, view it on GitHub https://github.com/zigpy/zha-device-handlers/issues/2777#issuecomment-1972799249, or unsubscribe https://github.com/notifications/unsubscribe-auth/A6BFTUPNNVFWJL37I4AENT3YWBAXHAVCNFSM6AAAAAA74GUVVWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNZSG44TSMRUHE . You are receiving this because you are subscribed to this thread.Message ID: @.***>

seb-tinet avatar Mar 01 '24 11:03 seb-tinet

Hi,

I have a SIN-4-FP-21 (the one from Nodon), and I am able to use it with ZHA, via zha_toolkit, with the help of https://github.com/Koenkk/zigbee2mqtt/issues/19169#issuecomment-1801181411 .

You can use zha_toolkit.scan_device to scan your zigbee device for all its informations, and look at the "Manufacture specific" cluster_id:

        "0xfc00": {
          "cluster_id": "0xfc00",
          "title": "Manufacturer Specific",
          "name": "manufacturer_specific",
          "attributes": {
            "0x0000": {
              "attribute_id": "0x0000",
              "attribute_name": "0",
              "value_type": [
                "0x20",
                "uint8_t",
                "Analog"
              ],
              "access": "READ|WRITE|REPORT",
              "access_acl": 7,
              "manf_id": 4747,
              "attribute_value": 1
            }
          },
          "commands_received": {},
          "commands_generated": {}
        }

Now you can send command to the module:

service: zha_toolkit.attr_write
data:
  ieee: xx:xx:xx:xx:xx:xx # your sin-4-fp-21 module id
  manf: 4747 # 0x128b, nodon
  endpoint: 1
  cluster: 64512 # 0xfc00
  attribute: 0 # which attribute we want to write, only 0 / 0x0000 is available in this cluster
  attr_val: "1" # 1: Confort, 2: Eco, 3: Hors Gel, see https://github.com/Koenkk/zigbee2mqtt/issues/19169#issuecomment-1801181411

Et voila©®, you can now integrate it in custom configuration in HA.

I hope this can help you, until Nodon/ZHA-device-handlers integrate this natively :)

Skunnyk avatar Mar 07 '24 16:03 Skunnyk

They just changed their support page with devices compatibility... Bad news for SIN-4-FP-21, it seems that HA is through Z2M only...

image

Mysticronos avatar Mar 15 '24 08:03 Mysticronos

Does anybody know if the information above can be used to write a Quirk for ZHA? This would avoid the need for installing zha_toolkit.

Btw. Thanks a lot @Skunnyk for finding this information!

steenlarsen avatar Mar 20 '24 20:03 steenlarsen

I've posted a quirk in #3040 that may also support ADEO variant. Feel free to test.

oxillo avatar May 28 '24 17:05 oxillo

Hello I made some adaptations of Nodon quirk in #3040 to make it working with Adeo device. Here is the code of custom quirk working for me:

"""Adeo SIN-4-FP-21_EQU pilot wire module."""
from typing import Any, Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder, EntityType, EntityPlatform
from zigpy.zcl.foundation import (
    BaseAttributeDefs,
    BaseCommandDefs,
    ZCLAttributeDef,
    ZCLCommandDef,
    WriteAttributesStatusRecord,
    Status
)

from zigpy.zcl import ClusterType

import zigpy.types as t

import logging
_LOGGER = logging.getLogger(__name__)

class NodonPilotWireMode(t.enum16):
    OFF = 0x00
    COMFORT = 0x01
    ECO = 0x02
    FROST_PROTECTION = 0x03
    COMFORT_MINUS_1 = 0x04
    COMFORT_MINUS_2 = 0x05

NODON_PILOT_WIRE_CLUSTER_ID = 0xfc00  #64512

class NodonPilotWireCluster(CustomCluster):
    """NodOn pilot wire manufacturer-specific cluster."""

    cluster_id: Final = NODON_PILOT_WIRE_CLUSTER_ID
    name: Final = "Pilot Wire"
    ep_attribute: Final = "pilot_wire_cluster"
    manufacturer_id_override: Final = 4747
    
    class AttributeDefs(BaseAttributeDefs):
        pilot_wire_mode: Final = ZCLAttributeDef(
            id=0x0000, 
            type=NodonPilotWireMode, 
            access="r"
        )

    class ClientCommandDefs(BaseCommandDefs):
        setMode: Final = ZCLCommandDef(
            id=0x0000,
            schema={"mode": NodonPilotWireMode},
            direction=True,
            is_manufacturer_specific=True
        )
    
    async def write_attributes(
        self, attributes: dict[str | int, Any], manufacturer: int | None = None
    ) -> list:
        """Override writes to the pilot_wire_mode attribute."""
        if "pilot_wire_mode" in attributes:
            await self.client_command(0, attributes.get("pilot_wire_mode"), manufacturer=4747)
            await self.read_attributes(attributes)
            return [[WriteAttributesStatusRecord(Status.SUCCESS)]]
        return await super().write_attributes(attributes, manufacturer=4747)

    async def read_attributes(
        self,
        attributes: list[int | str],
        allow_cache: bool = False,
        only_cache: bool = False,
        manufacturer: int | t.uint16_t | None = None,
    ) -> Any:
        return await super().read_attributes(attributes, allow_cache=False, only_cache=False, manufacturer=4747)

(

    QuirkBuilder("ADEO", "SIN-4-FP-21_EQU")
    .also_applies_to("Adeo","SIN-4-FP-21_EQU")
    .replaces(NodonPilotWireCluster)
    .enum("pilot_wire_mode",NodonPilotWireMode,NODON_PILOT_WIRE_CLUSTER_ID,
        ClusterType.Server,1,EntityType.STANDARD,EntityPlatform.SELECT,False,True)
    .add_to_registry()
)

garc33 avatar Sep 18 '24 16:09 garc33

Will test it ASAP! THANKS!

anoril1979 avatar Sep 18 '24 19:09 anoril1979

Hello I made some adaptations of Nodon quirk in #3040 to make it working with Adeo device. Here is the code of custom quirk working for me:

"""Adeo SIN-4-FP-21_EQU pilot wire module."""
from typing import Any, Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder, EntityType, EntityPlatform
from zigpy.zcl.foundation import (
    BaseAttributeDefs,
    BaseCommandDefs,
    ZCLAttributeDef,
    ZCLCommandDef,
    WriteAttributesStatusRecord,
    Status
)

from zigpy.zcl import ClusterType

import zigpy.types as t

import logging
_LOGGER = logging.getLogger(__name__)

class NodonPilotWireMode(t.enum16):
    OFF = 0x00
    COMFORT = 0x01
    ECO = 0x02
    FROST_PROTECTION = 0x03
    COMFORT_MINUS_1 = 0x04
    COMFORT_MINUS_2 = 0x05

NODON_PILOT_WIRE_CLUSTER_ID = 0xfc00  #64512

class NodonPilotWireCluster(CustomCluster):
    """NodOn pilot wire manufacturer-specific cluster."""

    cluster_id: Final = NODON_PILOT_WIRE_CLUSTER_ID
    name: Final = "Pilot Wire"
    ep_attribute: Final = "pilot_wire_cluster"
    manufacturer_id_override: Final = 4747
    
    class AttributeDefs(BaseAttributeDefs):
        pilot_wire_mode: Final = ZCLAttributeDef(
            id=0x0000, 
            type=NodonPilotWireMode, 
            access="r"
        )

    class ClientCommandDefs(BaseCommandDefs):
        setMode: Final = ZCLCommandDef(
            id=0x0000,
            schema={"mode": NodonPilotWireMode},
            direction=True,
            is_manufacturer_specific=True
        )
    
    async def write_attributes(
        self, attributes: dict[str | int, Any], manufacturer: int | None = None
    ) -> list:
        """Override writes to the pilot_wire_mode attribute."""
        if "pilot_wire_mode" in attributes:
            await self.client_command(0, attributes.get("pilot_wire_mode"), manufacturer=4747)
            await self.read_attributes(attributes)
            return [[WriteAttributesStatusRecord(Status.SUCCESS)]]
        return await super().write_attributes(attributes, manufacturer=4747)

    async def read_attributes(
        self,
        attributes: list[int | str],
        allow_cache: bool = False,
        only_cache: bool = False,
        manufacturer: int | t.uint16_t | None = None,
    ) -> Any:
        return await super().read_attributes(attributes, allow_cache=False, only_cache=False, manufacturer=4747)

(

    QuirkBuilder("ADEO", "SIN-4-FP-21_EQU")
    .also_applies_to("Adeo","SIN-4-FP-21_EQU")
    .replaces(NodonPilotWireCluster)
    .enum("pilot_wire_mode",NodonPilotWireMode,NODON_PILOT_WIRE_CLUSTER_ID,
        ClusterType.Server,1,EntityType.STANDARD,EntityPlatform.SELECT,False,True)
    .add_to_registry()
)

Shouldn't the last part with "QuirkBuilder" be like this?

(

    QuirkBuilder("ADEO", "SIN-4-FP-21_EQU")
    .also_applies_to("NodOn","SIN-4-FP-21")
    .replaces(NodonPilotWireCluster)
    .enum("pilot_wire_mode",NodonPilotWireMode,NODON_PILOT_WIRE_CLUSTER_ID,
        ClusterType.Server,1,EntityType.STANDARD,EntityPlatform.SELECT,False,True)
    .add_to_registry()
)

Mookunicorn avatar Sep 19 '24 11:09 Mookunicorn

I’m not sure the manufacturer override works for nodon device. Furthermore the name of manufacturer in signature is Adeo not ADEO on my setup. I don’t it is always the case or not.

garc33 avatar Sep 19 '24 12:09 garc33

Hi! It took me a while but I tested the quirk right now. Quirk execute with no issue. My warmers are well discovered and use the quirk. I guess that as a lot of attribute names changed. Alas, I still have only switch, power on demand and total summed power. Nothing about changing the pilot-wire setup from eco to something else.

I'm not sure the quirk was doing this, either. But I hoped :)

anoril1979 avatar Sep 29 '24 14:09 anoril1979

FYI: https://github.com/zigpy/zha-device-handlers/pull/3364 got merged. It supports both NodOn and Adeo. The code should become part of the 2024.12 release. Unfortunately, the change comes with only ZHA attributes (one which changes via "Manage Zigbee Device") and not with enum in the HA interface due to concerns from maintainers.

ikruglov avatar Nov 27 '24 15:11 ikruglov

To anyone interested in a temporary workaround based on the recent https://github.com/zigpy/zha-device-handlers/pull/3364

Here is a template Select allowing you to change mode directly within HA. Unfortunately, I do not found a way to read the attribute value yet. If anyone as a clue about how i can sync it with se template select state, i'll take it !

template:
  - select:
        name: "Mode seche serviette"
        icon: mdi:radiator
        unique_id: "select_mode_seche_serviette"
        options: >-
            {{
            [
                "Off",
                "Confort",
                "Eco",
                "Hors Gel",
                "Confort -1",
                "Confort -2"
            ]
            }}
        state: ""
        select_option:
            - service: zha.set_zigbee_cluster_attribute
              data:
                cluster_type: "in"
                endpoint_id: 1
                cluster_id: 64512
                ieee: "<device-address>"
                attribute: 0
                value: >-
                    {% set modes = {
                    'Off': 'NodOnPilotWireMode.Off',
                    'Confort': 'NodOnPilotWireMode.Comfort',
                    'Eco': 'NodOnPilotWireMode.Eco',
                    'Hors Gel': 'NodOnPilotWireMode.FrostProtection',
                    'Confort -1': 'NodOnPilotWireMode.ComfortMinus1',
                    'Confort -2': 'NodOnPilotWireMode.ComfortMinus2'
                    } %}
                    {{ modes[option] }}

dprslt avatar Dec 12 '24 20:12 dprslt

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Aug 07 '25 03:08 github-actions[bot]

Works fine for me since few updates. 👍

romain563 avatar Aug 07 '25 05:08 romain563