Closed TheStigh closed 3 years ago
toZigbee
: tz.lock_sound_volume
. The e.sound_volume() should also work, if not make sure you are on the latest zigbee-herdsman-converters versionhomeassitant: true
) an action
will always be cleared to trigger a state change on the entity (otherwise it cannot be used in automations). If you want to persist this value create an automation to save this value to another sensor.@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...
Instead of e.sound_volume()
can you try exposes.enum('sound_volume', access.ALL, constants.lockSoundVolume).withDescription('Sound volume of the lock')
?
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.
door_state: 0
and not the states by text. Same here, strange that it didn't pick it up during pairing/interviewNow 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?
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.
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 from
raw
(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 ?
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:
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}};
},
},
}
toZigbee
array add tzLocal.lock_master_pin_mode
exposes.binary('master_pin_mode', ea.STATE_SET, true, false).withDescription( 'Allow master pin unlock')
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.
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;
)
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 ?
Yes, but first make sure this works
@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
?
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
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
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;
},
},
}
tzLocal.lock_master_pin_mode
fzLocal.lock_id_lock
ea.ALL
is set instead of ea.STATE_SET
.@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?
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;
},
},
}
@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.
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
@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!
Any idea on why door state still not works? Did it ever work? @TheStigh
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?
Solved, so no problem:)
https://github.com/Koenkk/zigbee-herdsman-converters/issues/6820
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
andfz.lock_operation_event
and can operate the lock. I get thelock
andbattery
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 thelock.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 tozigbee2mqtt/<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 tohomeassistant/device_automation/<friendly_name>
but also in these messages the HOW the lock and unlock was performed are not shown.database.db
From the database, I should have both attributes
doorState
andsoundVolume
My device: