Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Livolo switches do not pair, paired switches work (+fix) #26648

Open
flaterichd opened this issue Mar 7, 2025 · 0 comments
Open

Livolo switches do not pair, paired switches work (+fix) #26648

flaterichd opened this issue Mar 7, 2025 · 0 comments
Labels
problem Something isn't working

Comments

@flaterichd
Copy link

What happened?

Livolo siwtches stopped pairing some time in autumn. After initiating pairing, the switches report status and allow control for 1-2 minutes and then become unresponsive until next pairing. Switches that were already paired work fine.

This is separate from the issue of Livolo switches requiring Permit Join to be always be on, which was removed in v2 (I used external extension permit_join_forever.js).

Initially I though it may be related to adapter firmware or Zigbee2MQTT v2, however rolling back both did not make a difference.

I had the following exception in logs when pairing:

[2025-03-07 03:07:51] debug: 	zh:controller:endpoint: TypeError: ZCL command 0x00124b0023522dde/6 genPowerCfg.readRsp({"8194":{"value":0,"type":14}}, {"timeout":10000,"disableResponse":true,"disableRecovery":false,"disableDefaultResponse":true,"direction":1,"reservedBits":3,"manufacturerCode":6866,"transactionSequenceNumber":233,"writeUndiv":true}) failed (Cannot mix BigInt and other types, use explicit conversions)
    at BuffaloZcl.writeUInt56 (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/buffalo/buffalo.ts:97:45)
    at BuffaloZcl.write (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/zspec/zcl/buffaloZcl.ts:700:29)
    at BuffaloZcl.write (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/zspec/zcl/buffaloZcl.ts:783:29)
    at ZclFrame.writePayloadGlobal (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/zspec/zcl/zclFrame.ts:104:29)
    at ZclFrame.toBuffer (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/zspec/zcl/zclFrame.ts:77:18)
    at EmberAdapter.sendZclFrameToEndpoint (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/adapter/ember/adapter/emberAdapter.ts:1965:31)
    at Request.func (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/controller/model/endpoint.ts:298:36)
    at Request.send (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/controller/helpers/request.ts:82:31)
    at Endpoint.sendRequest (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/controller/model/endpoint.ts:324:34)
    at Endpoint.zclCommand (/app/node_modules/.pnpm/[email protected]/node_modules/zigbee-herdsman/src/controller/model/endpoint.ts:949:39)

From some old discussions, I found out that Livolo switches require packets being sent to them during pairing, otherwise they disconnect from the network, which looked like the issue I had.

After some trial and error, I created an external converter, which fixes the issue, so my Livlo switches work fine now. I traced the issue to this commit in zigbee-herdsman, which made into zigbee-herdsman release v1.0.0.

The fix is pretty trivial, replace this:
const payload = {0x2002: {value: [0, 0, 0, 0, 0, 0, 0], type: 0x0e}};

With this:
const payload = {0x2002: {value: 0n, type: 0x0e}};

The exception is gone, and pairing works.

I don't really know much about typescript, or testing of other Livolo devices (I only have TI0001 switches), so I was hoping someone can fix it for everybody using info above. But if you want @Koenkk , I can try to create a pull request for it by copying payload fix for all Livolo devices in devices/livolo.ts.

Here is my external converter, which makes my Livolo TI0001 devices work on z2m v2.1.3:

const exposes = require('zigbee-herdsman-converters/lib/exposes');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;


const poll = async (device) => {
    try {
        const endpoint = device.getEndpoint(6);
        const options = {transactionSequenceNumber: 0, srcEndpoint: 8, disableResponse: true, disableRecovery: true};
        await endpoint.command('genOnOff', 'toggle', {}, options);
    } catch (error) {
        // device is lost, need to permit join
    }
};


module.exports = [
    {
        zigbeeModel: ['TI0001          '],
        model: 'TI0001',
        description: 'CUSTOM: Zigbee switch (1, 2, 3, 4 gang)',
        vendor: 'Livolo',
        exposes: [
            e.switch().withEndpoint('left'),
            e.switch().withEndpoint('right'),
            e.switch().withEndpoint('bottom_left'),
            e.switch().withEndpoint('bottom_right'),
        ],
        fromZigbee: [fz.livolo_switch_state, fz.livolo_switch_state_raw, fz.livolo_new_switch_state_4gang],
        toZigbee: [tz.livolo_socket_switch_on_off],
        endpoint: (device) => {
            return {'left': 6, 'right': 6, 'bottom_left': 6, 'bottom_right': 6};
        },
        configure: poll,
        onEvent: async (type, data, device) => {
            if (type === 'stop') {
                clearInterval(globalStore.getValue(device, 'interval'));
                globalStore.clearValue(device, 'interval');
            }
            if (['start', 'deviceAnnounce'].includes(type)) {
                await poll(device);
                if (!globalStore.hasValue(device, 'interval')) {
                    const interval = setInterval(async () => await poll(device), 300*1000);
                    globalStore.putValue(device, 'interval', interval);
                }
            }
            if (data.cluster === 'genPowerCfg' && data.type === 'raw') {
                const dp = data.data[10];
                if (data.data[0] === 0x7a && data.data[1] === 0xd1) {
                    const endpoint = device.getEndpoint(6);
                    if (dp === 0x01) {
                        const options = {manufacturerCode: 0x1ad2, disableDefaultResponse: true, disableResponse: true,
                            reservedBits: 3, direction: 1, writeUndiv: true};
                        //const payload = {0x2002: {value: [0, 0, 0, 0, 0, 0, 0], type: 0x0e}};
                        const payload = {0x2002: {value: 0n, type: 0x0e}};
                        await endpoint.readResponse('genPowerCfg', 0xe9, payload, options);
                    }
                }
            }
        },
    },
];

What did you expect to happen?

Livolo switches pair to zigbee network as before.

How to reproduce it (minimal and precise)

Start pairing Livolo switch, the switch reports status and allows control for 1-2 minutes and then becomes unresponsive until next pairing.

Zigbee2MQTT version

2.1.3

Adapter firmware version

7.4.5 [GA]

Adapter

Sonoff Dongle-E (EmberZNet)

Setup

Add-on, RPI4, HAOS

Debug log

No response

@flaterichd flaterichd added the problem Something isn't working label Mar 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
problem Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant