Koenkk / zigbee2mqtt

Zigbee 🐝 to MQTT bridge 🌉, get rid of your proprietary Zigbee bridges 🔨
https://www.zigbee2mqtt.io
GNU General Public License v3.0
11.77k stars 1.64k forks source link

Tuya external converters crashing 1.31.0-1 #17863

Closed JudahBella closed 1 year ago

JudahBella commented 1 year ago

What happened?

Zigbee working normally, and suddenly stopped working. Realised HAOS auto updated z2m with following error:

[01:12:28] INFO: Preparing to start...
[01:12:28] INFO: Socat not enabled
[01:12:30] INFO: Starting Zigbee2MQTT...
/app/node_modules/zigbee-herdsman-converters/index.js:79
        if (converter.options) {
                      ^
TypeError: Cannot read properties of undefined (reading 'options')
    at Object.addDefinition [as addDeviceDefinition] (/app/node_modules/zigbee-herdsman-converters/index.js:79:23)
    at new ExternalConverters (/app/lib/extension/externalConverters.ts:15:17)
    at new Controller (/app/lib/controller.ts:84:58)
    at start (/app/index.js:106:18)

I have 2 Tuya external converters, created according to this issue https://github.com/Koenkk/zigbee2mqtt/issues/12300

const fz = require( 'zigbee-herdsman-converters/converters/fromZigbee' );
const tz = require( 'zigbee-herdsman-converters/converters/toZigbee' );
const exposes = require( 'zigbee-herdsman-converters/lib/exposes' );
const reporting = require( 'zigbee-herdsman-converters/lib/reporting' );
const extend = require( 'zigbee-herdsman-converters/lib/extend' );
const tuya = require( 'zigbee-herdsman-converters/lib/tuya' );
const e = exposes.presets;
const ea = exposes.access;

const definition = {
        zigbeeModel: [
            'owvfni3\u0000', 'owvfni3', 'u1rkty3', 'aabybja',
            'mcdj3aq', 'mcdj3aq\u0000',
            ],
        fingerprint: [
            { modelID: 'TS0601', manufacturerName: '_TZE200_hsgrhjpf' },
            ],           
        model: 'TS0601_cover',
        vendor: 'Tuya',
        description: 'Curtain motor/roller blind motor/window pusher/tubular motor',
        whiteLabel: [
            {vendor: 'Tuya', model: 'TM616EGZT'},
            ],
        fromZigbee: [
            fz.ZMAM02_cover
            ],
        toZigbee: [
            tz.ZMAM02_cover,
            ],
        onEvent: tuya.onEventSetTime,
        exposes: [
            e.cover_position().setAccess('position', ea.STATE_SET),
            exposes.enum('motor_direction', ea.STATE_SET, Object.values(tuya.ZMLookups.AM02Direction)), // forward/backward
            exposes.enum('border', ea.STATE_SET, Object.values(tuya.ZMLookups.AM02Border)),
            ],
    };

module.exports = definition;
const fz = require( 'zigbee-herdsman-converters/converters/fromZigbee' );
const tz = require( 'zigbee-herdsman-converters/converters/toZigbee' );
const exposes = require( 'zigbee-herdsman-converters/lib/exposes' );
const reporting = require( 'zigbee-herdsman-converters/lib/reporting' );
const extend = require( 'zigbee-herdsman-converters/lib/extend' );
const tuya = require( 'zigbee-herdsman-converters/lib/tuya' );
const e = exposes.presets;
const ea = exposes.access;

const definition = {
        zigbeeModel: [
            'owvfni3\u0000', 'owvfni3', 'u1rkty3', 'aabybja',
            'mcdj3aq', 'mcdj3aq\u0000',
            ],
        fingerprint: [
            { modelID: 'TS0601', manufacturerName: '_TZE200_nueqqe6k' },
            ],           
        model: 'TS0601_cover',
        vendor: 'Tuya',
        description: 'Curtain motor/roller blind motor/window pusher/tubular motor',
        whiteLabel: [
            {vendor: 'Tuya', model: 'M515EGZT'},
            ],
        fromZigbee: [
            fz.ZMAM02_cover
            ],
        toZigbee: [
            tz.ZMAM02_cover,
            ],
        onEvent: tuya.onEventSetTime,
        exposes: [
            e.cover_position().setAccess('position', ea.STATE_SET),
            ],
    };

module.exports = definition;

What did you expect to happen?

All zigbee devices working properly as per normal

How to reproduce it (minimal and precise)

Update z2m to 1.31.0-1

Zigbee2MQTT version

1.31.0-1

Adapter firmware version

20211217

Adapter

tube_zb_gw_cc2652p2

Debug log

No response

bdariusb commented 1 year ago

same here, error:

/app/node_modules/zigbee-herdsman-converters/index.js:79
        if (converter.options) {
                      ^
TypeError: Cannot read properties of undefined (reading 'options')
    at Object.addDefinition [as addDeviceDefinition] (/app/node_modules/zigbee-herdsman-converters/index.js:79:23)
    at new ExternalConverters (/app/lib/extension/externalConverters.ts:15:17)
    at new Controller (/app/lib/controller.ts:84:58)
    at start (/app/index.js:106:18)

converter:

const tuya = require('zigbee-herdsman-converters/lib/tuya');
const hy_set_time_request = {
    cluster: 'manuSpecificTuya',
    type: ['commandMcuSyncTime'],
    convert: async (model, msg, publish, options, meta) => {
        const OneJanuary2000 = new Date('January 01, 2000 00:00:00 UTC+00:00').getTime();
        const currentTime = new Date().getTime();
        const utcTime = Math.round((currentTime - OneJanuary2000) / 1000);
        const localTime = Math.round(currentTime / 1000) - (new Date()).getTimezoneOffset() * 60;
        const endpoint = msg.endpoint;
        const payload = {
            payloadSize: 8,
            payload: [
                ...tuya.convertDecimalValueTo4ByteHexArray(utcTime),
                ...tuya.convertDecimalValueTo4ByteHexArray(localTime),
            ],
        };
        await endpoint.command('manuSpecificTuya', 'mcuSyncTime', payload, {});
    },
}

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 ea = exposes.access;
const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_znzs7yaw'}],
    model: 'HY08WE',
    vendor: 'TuYa',
    description: 'Wall-mount thermostat (CUSTOM)',
    fromZigbee: [fz.hy_thermostat, fz.ignore_basic_report, hy_set_time_request],
    toZigbee: [tz.hy_thermostat],
    exposes: [exposes.climate().withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET)
        .withLocalTemperature(ea.STATE)
        .withSystemMode(['off', 'auto', 'heat'], ea.STATE_SET).withRunningState(['idle', 'heat'], ea.STATE)],
};
JudahBella commented 1 year ago

Ok I managed to fix it. Referencing https://github.com/Koenkk/zigbee-herdsman-converters/blob/master/src/devices/zemismart.js, I changed

const fz = require( 'zigbee-herdsman-converters/converters/fromZigbee' );
const tz = require( 'zigbee-herdsman-converters/converters/toZigbee' );

to

const legacy = require('zigbee-herdsman-converters/lib/legacy');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = {...require('zigbee-herdsman-converters/converters/toZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').toZigbee};

and fz.ZMAM02_cover to fz.legacy.ZMAM02_cover, tz.ZMAM02_cover to tz.legacy.ZMAM02_cover.

Z2M back to normal.

JudahBella commented 1 year ago

same here, error:

/app/node_modules/zigbee-herdsman-converters/index.js:79
        if (converter.options) {
                      ^
TypeError: Cannot read properties of undefined (reading 'options')
    at Object.addDefinition [as addDeviceDefinition] (/app/node_modules/zigbee-herdsman-converters/index.js:79:23)
    at new ExternalConverters (/app/lib/extension/externalConverters.ts:15:17)
    at new Controller (/app/lib/controller.ts:84:58)
    at start (/app/index.js:106:18)

converter:

const tuya = require('zigbee-herdsman-converters/lib/tuya');
const hy_set_time_request = {
    cluster: 'manuSpecificTuya',
    type: ['commandMcuSyncTime'],
    convert: async (model, msg, publish, options, meta) => {
        const OneJanuary2000 = new Date('January 01, 2000 00:00:00 UTC+00:00').getTime();
        const currentTime = new Date().getTime();
        const utcTime = Math.round((currentTime - OneJanuary2000) / 1000);
        const localTime = Math.round(currentTime / 1000) - (new Date()).getTimezoneOffset() * 60;
        const endpoint = msg.endpoint;
        const payload = {
            payloadSize: 8,
            payload: [
                ...tuya.convertDecimalValueTo4ByteHexArray(utcTime),
                ...tuya.convertDecimalValueTo4ByteHexArray(localTime),
            ],
        };
        await endpoint.command('manuSpecificTuya', 'mcuSyncTime', payload, {});
    },
}

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 ea = exposes.access;
const definition = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_znzs7yaw'}],
    model: 'HY08WE',
    vendor: 'TuYa',
    description: 'Wall-mount thermostat (CUSTOM)',
    fromZigbee: [fz.hy_thermostat, fz.ignore_basic_report, hy_set_time_request],
    toZigbee: [tz.hy_thermostat],
    exposes: [exposes.climate().withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET)
        .withLocalTemperature(ea.STATE)
        .withSystemMode(['off', 'auto', 'heat'], ea.STATE_SET).withRunningState(['idle', 'heat'], ea.STATE)],
};

Try changing:

const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = require('zigbee-herdsman-converters/converters/toZigbee');

to

const legacy = require('zigbee-herdsman-converters/lib/legacy');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = {...require('zigbee-herdsman-converters/converters/toZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').toZigbee};

and

fz.hy_thermostat to fz.legacy.hy_thermostat

and

tz.hy_thermostat to tz.legacy.hy_thermostat

All the best.

JudahBella commented 1 year ago

Realised I no longer need _TZE200_nueqqe6k. I must have added it because it was not supported before (it has been awhile).

I still need _TZE200_hsgrhjpf as border and motor_direction are still missing. It is the odd TM616EGZT model that does not allow limits and motor direction to be set physically on the device (as detailed in https://github.com/Koenkk/zigbee2mqtt/issues/12300).

zamog commented 1 year ago

Same here;

/app/node_modules/zigbee-herdsman-converters/index.js:79 if (converter.options) { ^ TypeError: Cannot read properties of undefined (reading 'options') at Object.addDefinition [as addDeviceDefinition] (/app/node_modules/zigbee-herdsman-converters/index.js:79:23) at new ExternalConverters (/app/lib/extension/externalConverters.ts:15:17) at new Controller (/app/lib/controller.ts:84:58) at start (/app/index.js:106:18)

Koenkk commented 1 year ago

It looks like your external converter is not compatible with the latest z2m. The fix from @mrJudahBella (https://github.com/Koenkk/zigbee2mqtt/issues/17863#issuecomment-1572588042) might work in some cases.

Note that external converters are only meant for temporary testing, once the device works with the external converter a PR should be created for out-of-the-box support.

JudahBella commented 1 year ago

It looks like your external converter is not compatible with the latest z2m. The fix from @mrJudahBella (#17863 (comment)) might work in some cases.

Note that external converters are only meant for temporary testing, once the device works with the external converter a PR should be created for out-of-the-box support.

I don’t mind, how do I do this?

Koenkk commented 1 year ago

You can find docs about creating a pull request here: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request

gmendezg commented 1 year ago

Same problem. I don't have external converters

sticilface commented 1 year ago

What confused me is that is was still finding my old configuration and using that, which did have an external converter in it. Once i removed that line from the config, it worked. For what ever reason the config it was using was not being populated in the GUI of home assistant.

deanpribetic commented 1 year ago

This is still happening with v1.31.2-1

I have commented out my external converter:

#external_converters:
#  - ts0601.js

and now none of the Tuya devices will work with Zigbee2MQTT

Tuttle13 commented 1 year ago

Hi, incredibly fruastrating that something I've been using for over 2 years suddenly breaks overnight, despite me doing no updates nor gave auto-updating turned on.

Anyway, can someone help me work out how to fix this same issue given the same code? Cheers:

const fz = require('zigbee-herdsman-converters/converters/fromZigbee'); const tz = require('zigbee-herdsman-converters/converters/toZigbee'); const exposes = require('zigbee-herdsman-converters/lib/exposes'); const reporting = require('zigbee-herdsman-converters/lib/reporting'); const extend = require('zigbee-herdsman-converters/lib/extend'); const ota = require('zigbee-herdsman-converters/lib/ota'); const tuya = require('zigbee-herdsman-converters/lib/tuya'); const utils = require('zigbee-herdsman-converters/lib/utils'); const e = exposes.presets; const ea = exposes.access;

const definition = { fingerprint: tuya.fingerprint('TS0601', ['_TZE200_jwsjbxjs']), model: 'TS0601_switch_5', vendor: 'TuYa', description: 'Zigbee 5 gang smart switch', fromZigbee: [tuya.fzDataPoints], toZigbee: [tuya.tzDataPoints], configure: tuya.configureMagicPacket, exposes: [ e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'), e.switch().withEndpoint('l4'), e.switch().withEndpoint('l5') ], endpoint: (device) => { return {'l1': 1, 'l2': 1, 'l3': 1, 'l4': 1, 'l5': 1}; }, meta: { multiEndpoint: true, tuyaDatapoints: [ [1, 'state_l1', tuya.valueConverter.onOff], [2, 'state_l2', tuya.valueConverter.onOff], [3, 'state_l3', tuya.valueConverter.onOff], [4, 'state_l4', tuya.valueConverter.onOff], [5, 'state_l5', tuya.valueConverter.onOff], ], }, };

module.exports = definition;

Koenkk commented 1 year ago

_TZE200_jwsjbxjs is supported out-of-the-box, you can remove your ext converter.