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

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

Open Mookunicorn opened this issue 4 months ago • 9 comments

Problem description

Missing controls the target temperature of the heater with possible values: comfort, eco, frost_protection, off, comfort_-1, comfort_-2. Currently just an "on, off" switch

Solution description

Add controls of the heater (comfort, eco, frost_protection, off, comfort_-1, comfort_-2.)

Screenshots/Video

Screenshots/Video

image

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=4747, 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": "NodOn",
  "model": "SIN-4-FP-21",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2024.3.0",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.12.2",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Paris",
    "os_name": "Linux",
    "os_version": "6.6.20-haos",
    "supervisor": "2024.03.0",
    "host_os": "Home Assistant OS 12.1",
    "docker_version": "24.0.7",
    "chassis": "vm",
    "run_as_root": true
  },
  "custom_components": {
    "zha_toolkit": {
      "version": "v1.1.8",
      "requirements": [
        "pytz"
      ]
    },
    "smartlife": {
      "version": "0.1.0",
      "requirements": [
        "tuya-device-sharing-sdk==0.2.0"
      ]
    },
    "dyson_local": {
      "version": "0.16.4-4",
      "requirements": [
        "libdyson==0.8.11"
      ]
    },
    "espsomfy_rts": {
      "version": "2.4.1",
      "requirements": [
        "websocket-client==1.7.0"
      ]
    },
    "scheduler": {
      "version": "v0.0.0",
      "requirements": []
    },
    "hacs": {
      "version": "1.34.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly",
      "@TheJulianJES"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "import_executor": true,
    "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.38.1",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.112",
      "zigpy-deconz==0.23.1",
      "zigpy==0.63.4",
      "zigpy-xbee==0.20.1",
      "zigpy-zigate==0.12.0",
      "zigpy-znp==0.12.1",
      "universal-silabs-flasher==0.0.18",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*slzb-07*",
        "known_devices": [
          "smlight slzb-07"
        ]
      },
      {
        "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": "0403",
        "pid": "6015",
        "description": "*conbee*",
        "known_devices": [
          "Conbee III"
        ]
      },
      {
        "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": 15611,
    "manufacturer": "NodOn",
    "model": "SIN-4-FP-21",
    "name": "NodOn SIN-4-FP-21",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4747,
    "power_source": "Mains",
    "lqi": 124,
    "rssi": -69,
    "last_seen": "2024-03-13T19:30:27",
    "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=4747, 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": "NodOn",
      "model": "SIN-4-FP-21"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "button.chauffage_bureau_identifier",
        "name": "NodOn SIN-4-FP-21"
      },
      {
        "entity_id": "select.chauffage_bureau_comportement_au_demarrage",
        "name": "NodOn SIN-4-FP-21"
      },
      {
        "entity_id": "sensor.nodon_sin_4_fp_21_rssi_3",
        "name": "NodOn SIN-4-FP-21"
      },
      {
        "entity_id": "sensor.nodon_sin_4_fp_21_lqi_3",
        "name": "NodOn SIN-4-FP-21"
      },
      {
        "entity_id": "sensor.chauffage_bureau_demande_instantanee",
        "name": "NodOn SIN-4-FP-21"
      },
      {
        "entity_id": "sensor.chauffage_bureau_summation_delivered",
        "name": "NodOn SIN-4-FP-21"
      },
      {
        "entity_id": "switch.chauffage_bureau_commutateur",
        "name": "NodOn SIN-4-FP-21"
      }
    ],
    "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": "48"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x0934",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "32"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x181E",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "101"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x2D05",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "136"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Parent",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x5DE3",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "163"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xA6CD",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "95"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xC414",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "70"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xD9B0",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "90"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xEA8F",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "240"
      }
    ],
    "routes": [
      {
        "dest_nwk": "0x0000",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x5DE3"
      }
    ],
    "endpoint_names": [
      {
        "name": "SMART_PLUG"
      },
      {
        "name": "COMBO_BASIC"
      }
    ],
    "user_given_name": "Chauffage Bureau",
    "device_reg_id": "91995077342180562333b3e9aa0ef82e",
    "area_id": "bureau",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "SMART_PLUG",
          "id": 81
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 3
              },
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 3
              },
              "0x0006": {
                "attribute_name": "date_code",
                "value": "2021"
              },
              "0x0014": {
                "attribute_name": "disable_local_config",
                "value": 0
              },
              "0x0003": {
                "attribute_name": "hw_version",
                "value": 52
              },
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "NodOn"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "SIN-4-FP-21"
              },
              "0x0007": {
                "attribute_name": "power_source",
                "value": 1
              },
              "0x0002": {
                "attribute_name": "stack_version",
                "value": 103
              },
              "0x4000": {
                "attribute_name": "sw_build_id",
                "value": "3.0.0-1.4.4"
              },
              "0x0000": {
                "attribute_name": "zcl_version",
                "value": 8
              }
            },
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 2
              },
              "0x0000": {
                "attribute_name": "identify_time",
                "value": 0
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 3
              },
              "0x0000": {
                "attribute_name": "name_support",
                "value": 0
              }
            },
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 3
              },
              "0x0000": {
                "attribute_name": "count",
                "value": 0
              },
              "0x0002": {
                "attribute_name": "current_group",
                "value": 0
              },
              "0x0001": {
                "attribute_name": "current_scene",
                "value": 0
              },
              "0x0004": {
                "attribute_name": "name_support",
                "value": 0
              },
              "0x0003": {
                "attribute_name": "scene_valid",
                "value": 0
              }
            },
            "unsupported_attributes": {}
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 2
              },
              "0x4000": {
                "attribute_name": "global_scene_control",
                "value": 1
              },
              "0x4002": {
                "attribute_name": "off_wait_time",
                "value": 0
              },
              "0x0000": {
                "attribute_name": "on_off",
                "value": 1
              },
              "0x4001": {
                "attribute_name": "on_time",
                "value": 0
              },
              "0x4003": {
                "attribute_name": "start_up_on_off",
                "value": 255
              }
            },
            "unsupported_attributes": {
              "0x0011": {},
              "0x0001": {}
            }
          },
          "0x0702": {
            "endpoint_attribute": "smartenergy_metering",
            "attributes": {
              "0x0000": {
                "attribute_name": "current_summ_delivered",
                "value": 4738
              },
              "0x000a": {
                "attribute_name": "default_update_period",
                "value": 1
              },
              "0x0304": {
                "attribute_name": "demand_formatting",
                "value": 19
              },
              "0x0302": {
                "attribute_name": "divisor",
                "value": 1000
              },
              "0x0400": {
                "attribute_name": "instantaneous_demand",
                "value": 0
              },
              "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"
              },
              "0x0001": {
                "attribute_name": "current_summ_received"
              },
              "0x0104": {
                "attribute_name": "current_tier3_summ_delivered"
              },
              "0x0106": {
                "attribute_name": "current_tier4_summ_delivered"
              },
              "0x010a": {
                "attribute_name": "current_tier6_summ_delivered"
              },
              "0x0108": {
                "attribute_name": "current_tier5_summ_delivered"
              }
            }
          },
          "0x1000": {
            "endpoint_attribute": "lightlink",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xfc00": {
            "endpoint_attribute": "manufacturer_specific",
            "attributes": {},
            "unsupported_attributes": {
              "0x0000": {},
              "0x0001": {},
              "0x0020": {}
            }
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 4
              },
              "0x0002": {
                "attribute_name": "current_file_version",
                "value": 66564
              }
            },
            "unsupported_attributes": {
              "0x0002": {
                "attribute_name": "current_file_version"
              }
            }
          }
        }
      },
      "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
Sorry I didn't manage to make it, obviously I'm not focused enough to understand how to make it. But I'm trying and if I find how to do it, I promise I'll post it here.

Additional information

No response

Mookunicorn avatar Mar 13 '24 18:03 Mookunicorn

Related: https://github.com/zigpy/zha-device-handlers/issues/2777

Skunnyk avatar Mar 18 '24 16:03 Skunnyk

Waiting also for ZHA support...

Kriss1670 avatar Mar 21 '24 16:03 Kriss1670

I've just made some progress on it using quirks v2. It is my first quirk and I'm new to HA so I believe there is room for improvement.

Here is the quirk

"""NodOn on/off switch two channels."""
from typing import Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import add_to_registry_v2, EntityType, EntityPlatform
from zigpy.zcl.foundation import (
    BaseAttributeDefs,
    BaseCommandDefs,
    ZCLAttributeDef,
    ZCLCommandDef
)

from zigpy.zcl import ClusterType

import zigpy.types as t

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"
    
    
    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,
        )


(
    add_to_registry_v2("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,"pilot_wire_mode")
)

And the result in entity view Nodon

oxillo avatar May 13 '24 20:05 oxillo

And with an addition also_applies_to() that should solve #2777

(
    add_to_registry_v2("NodOn", "SIN-4-FP-21")
    .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,"pilot_wire_mode")
)
```

oxillo avatar May 13 '24 20:05 oxillo

Thanks for your work, the Quirks applies correctly but when I try to change modes there is an error message that says Échec de l'appel du service select/select_option. Failed to write attribute pilot_wire_mode=<NodonPilotWireMode.ECO: 2> :<Status.INVALID_DATA_TYPE: 141>

Maybe I did something wrong

Custom quirk
"""NodOn pilot wire switch two channels."""
from typing import Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import add_to_registry_v2, EntityType, EntityPlatform
from zigpy.zcl.foundation import (
    BaseAttributeDefs,
    BaseCommandDefs,
    ZCLAttributeDef,
    ZCLCommandDef
)

from zigpy.zcl import ClusterType

import zigpy.types as t

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"
    
    
    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,
        )

(
    add_to_registry_v2("NodOn", "SIN-4-FP-21")
    .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,"pilot_wire_mode")
)

The problem occurs on all 5 modules.

Error logs
Enregistreur: homeassistant.components.websocket_api.http.connection
Source: components/websocket_api/commands.py:239
intégration: Home Assistant WebSocket API ([documentation](https://www.home-assistant.io/integrations/websocket_api), [problèmes](https://github.com/home-assistant/core/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+websocket_api%22))
S'est produit pour la première fois: 14:23:47 (1 occurrences)
Dernier enregistrement: 14:23:47

[139849444259520] Unexpected exception
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 239, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2738, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2779, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 975, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 1047, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/select/__init__.py", line 191, in async_handle_select_option
    await self.async_select_option(option)
  File "/usr/src/homeassistant/homeassistant/components/zha/select.py", line 227, in async_select_option
    await self._cluster_handler.write_attributes_safe(
  File "/usr/src/homeassistant/homeassistant/components/zha/core/cluster_handlers/__init__.py", line 552, in write_attributes_safe
    raise HomeAssistantError(
homeassistant.exceptions.HomeAssistantError: Failed to write attribute pilot_wire_mode=<NodonPilotWireMode.COMFORT_MINUS_1: 4>: <Status.INVALID_DATA_TYPE: 141>

Mookunicorn avatar May 14 '24 12:05 Mookunicorn

Hello, I'm using the quirk on the latest version of HA (2024.5.3). What version do you use ? Quirks v2 are new and support is evolving at every version.

oxillo avatar May 14 '24 19:05 oxillo

I'm on 2024.5.3 too 🤔 Screenshot_20240514-210825.png

Mookunicorn avatar May 14 '24 19:05 Mookunicorn

I wonder if the problem could be with the ZigBee key.

I use SkyConnect without multiprotocol

Mookunicorn avatar May 14 '24 19:05 Mookunicorn

This is not your installation; it is my solution. The enum entity tries to write the pilot_wire_mode attribute which is not supported. You must use the command to change the mode.

oxillo avatar May 18 '24 18:05 oxillo

Some update to catch attribute write and replace by commands

"""NodOn SIN-4-FP-21 pilot wire module."""
from typing import Any, Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import add_to_registry_v2, 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"

    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"))
            return [[WriteAttributesStatusRecord(Status.SUCCESS)]]
        return await super().write_attributes(attributes, manufacturer=manufacturer)


(
    add_to_registry_v2("NodOn", "SIN-4-FP-21")
    .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)
)

oxillo avatar May 19 '24 17:05 oxillo

Oh my boooy it work well. I just took the liberty of translating the different modes. Do you want me to add the Quirk in my initial request (of course mentioning you are the boss)

Mookunicorn avatar May 21 '24 12:05 Mookunicorn

Happy to see it works for you ! You can add the quirk to your initial request. I would like to work on the HMI but I have other projects in parallel that requires my attention. I'll look into it in some weeks.

oxillo avatar May 28 '24 17:05 oxillo