Koenkk / zigbee2mqtt

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

Issues when trying to implement ID LOCK 150 #6976

Closed TheStigh closed 3 years ago

TheStigh commented 3 years ago

Hi,

Running latest build HA and 1.18.2 Edge version with debug: enable in Z2M. I'm using MQTT Explorer to monitor the MQTT traffic.

I'm trying to fully integrate the ID LOCK 150 Zigbee module but are only partially successful. There are several issues I would like to kindly ask for assistance to resolve. I am using the fz.lock and fz.lock_operation_event and can operate the lock. I get the lock and battery sensor as entities in Home Assistant. Shown attributes are:

Here my issues start.

1) I am missing expected attributes from 'closuresDoorLock'

doorState I can see the 'attributeReport' from cluster 'closuresDoorLock' (fz.lock) with the data '{"doorState":1}'. Though, this is not passed on to Home Assistant, but I can see the message in MQTT Explorer zigbee2mqtt/logging . I would assume this should be an attribute for the lock.0x... sensor?

soundVolume I did follow your assistance in issue 6551 where you added support for soundVolume inside the fz.lock. I don't get the attribute, and if I add e.sound_volume I get UnhandledPromiseRejectionWarning: TypeError: e.sound_volume is not a function at Z2M startup. According to the documentation of the ID LOCK 150, the soundVolume are supported under cluster 0x0101 and attribute 0x0024. of course, I haven't tested the tz-converter you made to change the volume. Am I doing something wrong?

lockMode Per now I haven't been able to identify this is the MQTT traffic yet, but it should be supported at cluster 0x0101 and attribute 0x4004

2) fz.lock_operation_event

I expected to receive lock and unlock methods as sensors but only see them passing through the log as device-automation. This causes issues as I can't capture the data I need as the messages overlap each other within fraction of seconds.

I can see traffic being passed at topic zigbee2mqtt/<friendly_name>/action but also as a json to zigbee2mqtt/<friendly_name>. For the /action it does not show HOW the door was locked or unlocked. For the json, it passes this information for a bried second until this is overwritten by a new json message. I tried to capture this by creating a MQTT sensor in HA {{ value_json.action_source_name }} but for some reason I don't get the data populated. Also I see the device-automation being sent to homeassistant/device_automation/<friendly_name> but also in these messages the HOW the lock and unlock was performed are not shown.

Zigbee2MQTT:debug 06-04-2021 17:32:07: Received Zigbee message from '0x680ae2fffe6bb522', type 'attributeReport', cluster 'closuresDoorLock', data '{"doorState":1}' from endpoint 1 with groupID 0
Zigbee2MQTT:debug 06-04-2021 17:32:09: Received Zigbee message from '0x680ae2fffe6bb522', type 'commandOperationEventNotification', cluster 'closuresDoorLock', data '{"data":0,"opereventcode":13,"opereventsrc":2,"pin":0,"userid":0,"zigbeelocaltime":4294967295}' from endpoint 1 with groupID 0
Zigbee2MQTT:info  06-04-2021 17:32:09: MQTT publish: topic 'zigbee2mqtt/0x680ae2fffe6bb522', payload '{"action":"manual_lock","action_source":2,"action_source_name":"manual","action_user":0,"battery":65,"linkquality":73,"lock_state":"unlocked","state":"UNLOCK"}'
Zigbee2MQTT:info  06-04-2021 17:32:09: MQTT publish: topic 'zigbee2mqtt/0x680ae2fffe6bb522', payload '{"action":"","battery":65,"linkquality":73,"lock_state":"unlocked","state":"UNLOCK"}'
Zigbee2MQTT:info  06-04-2021 17:32:09: MQTT publish: topic 'zigbee2mqtt/0x680ae2fffe6bb522/action', payload 'manual_lock'

database.db

{"id":1,"type":"Coordinator","ieeeAddr":"0x00124b0018e3012c","nwkAddr":0,"manufId":0,"epList":[1,2,3,4,5,6,8,10,11,12,13,47,110,242],"endpoints":{"1":{"profId":260,"epId":1,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"2":{"profId":257,"epId":2,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"3":{"profId":261,"epId":3,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"4":{"profId":263,"epId":4,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"5":{"profId":264,"epId":5,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"6":{"profId":265,"epId":6,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"8":{"profId":260,"epId":8,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"10":{"profId":260,"epId":10,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"11":{"profId":260,"epId":11,"devId":1024,"inClusterList":[1281],"outClusterList":[1280,1282],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"12":{"profId":49246,"epId":12,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"13":{"profId":260,"epId":13,"devId":5,"inClusterList":[25],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"47":{"profId":260,"epId":47,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"110":{"profId":260,"epId":110,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"242":{"profId":41440,"epId":242,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}}},"interviewCompleted":true,"meta":{},"lastSeen":null}
{"id":2,"type":"EndDevice","ieeeAddr":"0x680ae2fffe6bb522","nwkAddr":19714,"manufId":4919,"manufName":"Datek","powerSource":"Battery","modelId":"ID Lock 150","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":10,"inClusterList":[0,1,3,257],"outClusterList":[3,25],"clusters":{"genBasic":{"attributes":{"modelId":"ID Lock 150","manufacturerName":"Datek","powerSource":3,"zclVersion":3,"appVersion":7,"stackVersion":65,"swBuildId":"0.7"}},"genPowerCfg":{"attributes":{"batteryPercentageRemaining":90}},"closuresDoorLock":{"attributes":{"lockState":2,"doorState":0,"requirePinForRfOperation":0,"keypadOperationEventMask":65535,"rfOperationEventMask":65535,"manualOperationEventMask":65535,"rfidOperationEventMask":65535,"keypadProgrammingEventMask":65535,"rfProgrammingEventMask":65535,"rfidProgrammingEventMask":65535,"soundVolume":2}}},"binds":[{"cluster":257,"type":"endpoint","deviceIeeeAddress":"0x00124b0018e3012c","endpointID":1},{"cluster":1,"type":"endpoint","deviceIeeeAddress":"0x00124b0018e3012c","endpointID":1}],"configuredReportings":[{"cluster":257,"attrId":0,"minRepIntval":0,"maxRepIntval":3600,"repChange":0},{"cluster":1,"attrId":33,"minRepIntval":3600,"maxRepIntval":62000,"repChange":0}],"meta":{}}},"appVersion":7,"stackVersion":65,"swBuildId":"0.7","zclVersion":3,"interviewCompleted":true,"meta":{"configured":1},"lastSeen":1617725361467}

From the database, I should have both attributes doorState and soundVolume

"closuresDoorLock": {
    "attributes": {
        "lockState":2,
        "doorState":0,
        "requirePinForRfOperation":0,
        "keypadOperationEventMask":65535,
        "rfOperationEventMask":65535,
        "manualOperationEventMask":65535,
        "rfidOperationEventMask":65535,
        "keypadProgrammingEventMask":65535,
        "rfProgrammingEventMask":65535,
        "rfidProgrammingEventMask":65535,
        "soundVolume":2
        }
    }

My device:

const device = {
    zigbeeModel: ['ID Lock 150'],
    model: '0402946',
    vendor: 'Datek',
    description: 'Zigbee module for ID Lock 150',
    fromZigbee: [fz.lock, fz.battery, fz.lock_operation_event],
    toZigbee: [tz.lock],
    meta: {configureKey: 1},

    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
        await reporting.lockState(endpoint);
        await reporting.batteryPercentageRemaining(endpoint);
    },
    exposes: [e.lock(), e.battery()],
};
Koenkk commented 3 years ago
TheStigh commented 3 years ago

@Koenkk

This is the current code in my test:

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 constants = require('zigbee-herdsman-converters/lib/constants');
const ota = require('zigbee-herdsman-converters/lib/ota');
const e = exposes.presets;

const fzLocal = {
    lock: {
        cluster: 'closuresDoorLock',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const result = {};
            if (msg.data.hasOwnProperty('lockState')) {
                result.state = msg.data.lockState == 1 ? 'LOCK' : 'UNLOCK';
                const lookup = ['not_fully_locked', 'locked', 'unlocked'];
                result.lock_state = lookup[msg.data['lockState']];
            }

            if (msg.data.hasOwnProperty('soundVolume')) {
                result.sound_volume = constants.lockSoundVolume[msg.data.soundVolume];
            }

            if (msg.data.hasOwnProperty('doorState')) {
                result.door_state = msg.data.doorState;
            }

            if (msg.data.hasOwnProperty('lockMode')) {
                result.lock_mode = msg.data.lockMode;
            }
            return result;
        },
    },
}

const device = {
    zigbeeModel: ['ID Lock 150'],
    model: '0402946',
    vendor: 'Datek',
    description: 'Zigbee module for ID Lock 150',
    fromZigbee: [fzLocal.lock, fz.battery, fz.lock_operation_event, fz.lock_programming_event, fz.lock_pin_code_response],
    toZigbee: [tz.lock, tz.lock_sound_volume],
    meta: {configureKey: 1},

    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await reporting.bind(endpoint, coordinatorEndpoint, ['closuresDoorLock', 'genPowerCfg']);
        await reporting.lockState(endpoint);
        await reporting.batteryPercentageRemaining(endpoint);
    },
    exposes: [e.lock(), e.battery()],
};

module.exports = device;

So I assumed it should expose doorState and soundVolume ? Regarding the doorState states, they are in the doc I linked to you, but here are the numbers:

0x00: open
0x01: closed
0x02: error jammed
0x03: error forced open
0x04: error unspecified
0xff: undefined

soundVolume - if I add the e.sound_Volume() I get the following error: UnhandledPromiseRejectionWarning: TypeError: e.sound_volume is not a function.

lockMode - did you have a look in the linked documentation? I assume this is the documentation you are referring to.

lock_operation_event - I understand but there should ALSO be an attribute in the lock.0xxxx sensor. This is for reasons where a major amount of users don't know how to build automation's with automation-triggers. I even checked for examples, they are really hard to find.

By the way - how do I know if I am on the latest version of convertes? I daily uninstall and reinstall the Edge version...

Koenkk commented 3 years ago

Instead of e.sound_volume() can you try exposes.enum('sound_volume', access.ALL, constants.lockSoundVolume).withDescription('Sound volume of the lock')?

TheStigh commented 3 years ago

Changed to exposes.access.ALL

    exposes: [e.lock(), e.battery(), exposes.enum('sound_volume', 
        exposes.access.ALL, constants.lockSoundVolume).withDescription('Sound volume of the lock')],

Now I have the sensor, but without content.

Deleted device, stopped Z2M, deleted state.json & database.db, restarted Z2M, did a factory def. of the lock.

Here is the log from the interview process.

EDIT

Now what remain (if we look away from that values didn't show until I actually activated those through keypad & closing door), are the lockMode, adjusting soundVolume (I can do that from the Frontend, how can it be done from code?) and relockEnabled.

There is also a setting called openPeriod (7.3.2.10.7 OpenPeriod Attribute in ZCL), I wonder if I can pick it out from the lock, even if it is not specified in the documentation?

Koenkk commented 3 years ago

You need to set the values one, otherwise these are unknown indeed.

There is also a setting called openPeriod (7.3.2.10.7 OpenPeriod Attribute in ZCL), I wonder if I can pick it out from the lock, even if it is not specified in the documentation?

It depends if the lock supports it. You can write a new toZigbee converter for this.

TheStigh commented 3 years ago

You need to set the values one, otherwise these are unknown indeed.

First, I must say it is strange that the states except LOCK/UNLOCK and BATTERY do not update after pairing. I have to send the volume either by /set or from Z2M Frontend to get the states updated within HA entities.

For doorState I added this if (msg.data.hasOwnProperty('doorState')) { with nothing new to the exposes:

    lock: {
        cluster: 'closuresDoorLock',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const result = {};
            if (msg.data.hasOwnProperty('lockState')) {
                result.state = msg.data.lockState == 1 ? 'LOCK' : 'UNLOCK';
                const lookup = ['not_fully_locked', 'locked', 'unlocked'];
                result.lock_state = lookup[msg.data['lockState']];
            }

            if (msg.data.hasOwnProperty('soundVolume')) {
                result.sound_volume = constants.lockSoundVolume[msg.data.soundVolume];
            }

            if (msg.data.hasOwnProperty('doorState')) {
                const lookup = ['open', 'closed', 'error jammed', 'error forced open', 'error unspecified', 'undefined'];
                result.door_state = lookup[msg.data['doorState']];
            }

            return result;
        },
    },

And it works (but I have to wait some minutes after pairing?).

It depends if the lock supports it. You can write a new toZigbee converter for this. I assume this must be taken fromraw (which I have zero experience with).

In the documentation, it says Manufacturer specific attributes under Door Lock Cluster (0x0101). Under this specification you have several options;

All of these 0x4000, 0x4001, 0x4002, 0x4004 and 0x4005. How can we get these into Z2M and HA ?

Koenkk commented 3 years ago

First, I must say it is strange that the states except LOCK/UNLOCK and BATTERY do not update after pairing. I have to send the volume either by /set or from Z2M Frontend to get the states updated within HA entities.

You can read the values upon pairing by adding the following to the configure():

await endpoint.read('closuresDoorLock', ['lockState','soundVolume','doorState']);

For the manufacturer specific things, I've created an example from for the master pin mode:

TheStigh commented 3 years ago

Hi @Koenkk , the binary_sensors indeed appear but in Frontend they are listed with Unknown acces (assume it should be access). What ever I do to change the binary sensors on the lock, do not update in Z2M. Seems they are created during interview, after this there's no zigbee traffic for these in MQTT Explorer.

Current external converter here

image

Koenkk commented 3 years ago

Made a small mistake, please add the following line: https://github.com/Koenkk/zigbee2mqtt.io/blob/9efba9ce07aaf9dbd44283f242056cf3bfa01810/docs/externalConvertersExample/light.js#L6 (const ea = exposes.access;)

TheStigh commented 3 years ago

Now I get the true/false values but Z2M have not updated (read) the states unless I actually trigger a change from the lock. Can I do that ?

Koenkk commented 3 years ago

Yes, but first make sure this works

TheStigh commented 3 years ago

@Koenkk rfid_enable , relock_enable, and master_pin_mode works fine.

Issue I had with master_pin_mode was that the user manual says you need to have at least one user pin registered. After registering a user pin, this mode also worked.

I will put this information in the description of the device.

How can I read the states upon pairing/with no previously stored states?

Could you please provide an example with what you mean with INT8U use value: value instead ?

Koenkk commented 3 years ago

Hereby an example on how to implement the int8u types:

const tzLocal = {
    lock_audio_volume: {
        key: ['audio_volume'],
        convertSet: async (entity, key, value, meta) => {
            const lookup = {off: 0, level_1: 1, level_2: 2, level_3: 3, level_4: 4, level_5: 5};
            await entity.write('closuresDoorLock',
                {0x4006: // <--- Take from Ident. column
                    {
                        value: lookup[value] ,
                        type: 0x20 // <--- Take from Type column
                    }
                },
                {manufacturerCode: 4919},
            );
            return {state: {audio_volume: lookup[value]}};
        },
    },
}

to exposes add: exposes.enum( 'audio_volume', ea.ALL, ['off', 'level_1', 'level_2', 'level_3', 'level_4', 'level_5']).withDescription('Volume level') and to toZigbee add tzLocal.lock_audio_volume

TheStigh commented 3 years ago

So, that I should have figured out myself, dooh!

a) I can't use the /get (also by pressing the update icon in Frontend) to update the state of the lock_mode, just get an error:

Zigbee2MQTT:debug 12-04-2021 21:59:50: Received MQTT message on 'zigbee2mqtt/0x680ae2fffe6bb522/get' with data '{"lock_mode":""}'
Zigbee2MQTT:error 12-04-2021 21:59:50: No converter available for 'get' 'lock_mode' ()

b) Now I have the numbered state (1 rather than auto_on_away_off), but as an attribute and sensor. How can I convert this to text?

c) Still I can't fetch the state at startup for master_pin_mode, rfid_enable, relock_enable and for the latest lock_mode

Latest code here

Koenkk commented 3 years ago

So for reading (/get), the following example:

const tzLocal = {
    lock_master_pin_mode: {
        key: ['master_pin_mode'],
        convertSet: async (entity, key, value, meta) => {
            await entity.write('closuresDoorLock',
                {0x4000: // <--- Take from Ident. column
                    {
                        value: value === true ? 1 : 0, // <-- For boolean in Type column use this code, for the ones with INT8U use value: value instead
                        type: 0x10 // <--- Take from Type column
                    }
                },
                {manufacturerCode: 4919},
            );
            return {state: {master_pin_mode: value}};
        },
        convertGet: async (entity, key, meta) => {
            await entity.read('closuresDoorLock', [0x4000], {manufacturerCode: 4919});
        },
    },
}

const fzLocal = {
    lock_id_lock: {
        cluster: 'closuresDoorLock',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const result = {};
            if (msg.data[0x4000]) {
                result.master_pin_mode = msg.data[0x4000] == 1 ? true : false;
            }

            return result;
        },
    },
}
TheStigh commented 3 years ago

@Koenkk

Sorry for being absent but been away on work.

So, I was able to get a lot to work, but still have some issues I can't get my head around. Current converter here Current log from Z2M startup incl pairing here

Current database:

{"id":1,"type":"Coordinator","ieeeAddr":"0x00124b0018e3012c","nwkAddr":0,"manufId":0,"epList":[242,47,13,12,110,11,10,8,6,5,4,3,2,1],"endpoints":{"1":{"profId":260,"epId":1,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"2":{"profId":257,"epId":2,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"3":{"profId":261,"epId":3,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"4":{"profId":263,"epId":4,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"5":{"profId":264,"epId":5,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"6":{"profId":265,"epId":6,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"8":{"profId":260,"epId":8,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"10":{"profId":260,"epId":10,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"11":{"profId":260,"epId":11,"devId":1024,"inClusterList":[1281],"outClusterList":[1280,1282],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"12":{"profId":49246,"epId":12,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"13":{"profId":260,"epId":13,"devId":5,"inClusterList":[25],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"47":{"profId":260,"epId":47,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"110":{"profId":260,"epId":110,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}},"242":{"profId":41440,"epId":242,"devId":5,"inClusterList":[],"outClusterList":[],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}}},"interviewCompleted":true,"meta":{},"lastSeen":null}
{"id":2,"type":"EndDevice","ieeeAddr":"0x680ae2fffe6bb522","nwkAddr":36579,"manufId":4919,"manufName":"Datek","powerSource":"Battery","modelId":"ID Lock 150","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":10,"inClusterList":[0,1,3,257],"outClusterList":[3,25],"clusters":{"genBasic":{"attributes":{"modelId":"ID Lock 150","manufacturerName":"Datek","powerSource":3,"zclVersion":3,"appVersion":7,"stackVersion":65,"swBuildId":"0.7"}},"closuresDoorLock":{"attributes":{"16384":1,"16385":1,"16388":0,"16389":0,"lockState":2,"soundVolume":1,"doorState":0}},"genPowerCfg":{"attributes":{"batteryPercentageRemaining":100}}},"binds":[{"cluster":257,"type":"endpoint","deviceIeeeAddress":"0x00124b0018e3012c","endpointID":1},{"cluster":1,"type":"endpoint","deviceIeeeAddress":"0x00124b0018e3012c","endpointID":1}],"configuredReportings":[{"cluster":257,"attrId":0,"minRepIntval":0,"maxRepIntval":3600,"repChange":0},{"cluster":1,"attrId":33,"minRepIntval":3600,"maxRepIntval":62000,"repChange":0}],"meta":{}}},"appVersion":7,"stackVersion":65,"swBuildId":"0.7","zclVersion":3,"interviewCompleted":true,"meta":{"configured":1},"lastSeen":1618949083363}

1: After clean Z2M and pairing, lock_mode and relock_enabled do not get read and thus do not show state. The others update state just fine. In the database they are there with correct state(?) : "16388":0,"16389":0

If I trigger either lock_mode or relock_enabled with a /set, it's attribute update correctly, so tzLocal does what it should do.

If I use the update icon in Frontend, I see the values are returned from the device but not passed to broker. Example relock_enabled :

Zigbee2MQTT:debug 20-04-2021 23:47:15: Received MQTT message on 'zigbee2mqtt/0x680ae2fffe6bb522/get' with data '{"relock_enabled":""}'
Zigbee2MQTT:debug 20-04-2021 23:47:15: Publishing get 'get' 'relock_enabled' to '0x680ae2fffe6bb522'
Zigbee2MQTT:debug 20-04-2021 23:47:17: Received Zigbee message from '0x680ae2fffe6bb522', type 'readResponse', cluster 'closuresDoorLock', data '{"16389":0}' from endpoint 1 with groupID 0

Here is an example from rfid_enable that updates fine once the update icon are pressed:

Zigbee2MQTT:debug 20-04-2021 23:48:34: Received MQTT message on 'zigbee2mqtt/0x680ae2fffe6bb522/get' with data '{"rfid_enable":""}'
Zigbee2MQTT:debug 20-04-2021 23:48:34: Publishing get 'get' 'rfid_enable' to '0x680ae2fffe6bb522'
Zigbee2MQTT:debug 20-04-2021 23:48:36: Received Zigbee message from '0x680ae2fffe6bb522', type 'readResponse', cluster 'closuresDoorLock', data '{"16385":1}' from endpoint 1 with groupID 0
Zigbee2MQTT:info  20-04-2021 23:48:36: MQTT publish: topic 'zigbee2mqtt/0x680ae2fffe6bb522', payload '{"battery":50,"door_state":"open","linkquality":39,"lock_mode":null,"lock_state":"unlocked","master_pin_mode":true,"relock_enabled":null,"rfid_enable":true,"sound_volume":"low_volume","state":"UNLOCK"}'

2: On lock_mode I only get the number value, not text as put in const lookup = {0: 'auto_off_away_off', 1: 'auto_on_away_off', 2: 'auto_off_away_on', 3: 'auto_on_away_on'}; I might have written both fzLocal and tzLocal wrong?

image

image

Koenkk commented 3 years ago

My example of https://github.com/Koenkk/zigbee2mqtt/issues/6976#issuecomment-818927285 was a bit wrong, this should work:

const tzLocal = {
    lock_master_pin_mode: {
        key: ['master_pin_mode'],
        convertSet: async (entity, key, value, meta) => {
            await entity.write('closuresDoorLock',
                {0x4000: // <--- Take from Ident. column
                    {
                        value: value === true ? 1 : 0, // <-- For boolean in Type column use this code, for the ones with INT8U use value: value instead
                        type: 0x10 // <--- Take from Type column
                    }
                },
                {manufacturerCode: 4919},
            );
            return {state: {master_pin_mode: value}};
        },
        convertGet: async (entity, key, meta) => {
            await entity.read('closuresDoorLock', [0x4000], {manufacturerCode: 4919});
        },
    },
}

const fzLocal = {
    lock_id_lock: {
        cluster: 'closuresDoorLock',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const result = {};
            if (msg.data["16384"]) { // <---- the "16384" is the attribute ID (0x4000) converted from hex to decimal.
                result.master_pin_mode = msg.data["16384"] == 1 ? true : false;
            }

            return result;
        },
    },
}
TheStigh commented 3 years ago

@Koenkk

How can that change it? For HEX 4000 and 4001, it already updates fine using

 if (msg.data[0x4004]) { 
    result.master_pin_mode = msg.data[0x4004] == 1 ? true : false;

... just not for 4004 and 4005.

Did you notice the added lines

const options = {manufacturerCode: 4919};
await endpoint.read('closuresDoorLock', [0x4000, 0x4001, 0x4004, 0x4005], options);

Without these lines, 4000 and 4001 did not update the status upon pairing. Why 4004 and 4005 do not update... I have absolutely no clue.

Though, did the change you suggested, nothing changed, still the same issue as in my previous comment.

Koenkk commented 3 years ago

I see what is wrong here now. if (msg.data[0x4004]) will evaluate to false when msg.data.0x4000 === 0. Try with if (0x4004 in msg.data) or if ("16388" in msg.data) instead

TheStigh commented 3 years ago

@Koenkk ... ah, that made totally sense! I tested and if the state was 0 (false) in lock settings, it couldn't make sense of it and resulted in null . Now all is OK :) Thank you so much for your assitance on this sucker, I would not been able to fix this one finished myself.

I'll fresh up everything and make the PR's.

Oh, I love Zigbee2MQTT - what you are doing are amazing, Koen!

christian1986 commented 8 months ago

Any idea on why door state still not works? Did it ever work? @TheStigh

TheStigh commented 8 months ago

Any idea on why door state still not works? Did it ever work? @TheStigh

Hi Christian, sure it did - and should still work. With door state you refer to physical open or closed?

christian1986 commented 8 months ago

Solved, so no problem:)

https://github.com/Koenkk/zigbee-herdsman-converters/issues/6820