Jump to content

BTicino/Legrand/Netatmo Zigbee devices refuse to connect to third-party gateways

From Consumer Rights Wiki
Revision as of 07:51, 28 August 2025 by DreamingCodes (talk | contribs)

Legrand and its child companies (such as BTicino with their Living Now series) manufacture Zigbee-based smart devices. While these devices use the Zigbee protocol, they are intentionally restricted to work only with Legrand’s own gateways.

[Incident]

During the pairing process, Legrand devices send a non-standard Zigbee command and expect a specific reply from the coordinator. If the expected response is not received, the device will refuse to complete the pairing process.This effectively blocks the use of Legrand devices with third-party Zigbee gateways such as Zigbee2MQTT, Home Assistant’s ZHA, or other open-source coordinators.


When a Legrand device is powered on and attempts to join a network, it sends a read frame to every device on the network. The payload includes the number of seconds since the device was powered.

  • If the coordinator responds with a valid value (e.g., 23 seconds), the device continues pairing.
  • If the response is missing or the value is too high (e.g., 200), the device leaves the network and refuses to pair.

This mechanism acts as a vendor lock-in, ensuring that only Legrand’s own gateways can provide the expected response.

Zigbee2MQTT Workaround

The Zigbee2MQTT project implevemented a workaround to support Legrand dices by simulating the expected response during pairing. Below is their current implementation:

// support Legrand security protocol
// when pairing, a powered device will send a read frame to every device on the network
// it expects at least one answer. The payload contains the number of seconds
// since when the device is powered. If the value is too high, it will leave & not pair
// 23 works, 200 doesn't
if (device.manufacturerID === Zcl.ManufacturerCode.LEGRAND_GROUP && !device.customReadResponse) {
    device.customReadResponse = (frame, endpoint) => {
        if (frame.isCluster("genBasic") && frame.payload.find((i: {attrId: number}) => i.attrId === 61440)) {
            const options = {manufacturerCode: Zcl.ManufacturerCode.LEGRAND_GROUP, disableDefaultResponse: true};
            const payload = {61440: {value: 23, type: 35}};

            endpoint.readResponse("genBasic", frame.header.transactionSequenceNumber, payload, options).catch((e) => {
                logger.warning(`Legrand security read response failed: ${e}`, NS);
            });

            return true;
        }

        return false;
    };
}

https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/src/index.ts#L638-L658

References