Open nobges opened 9 months ago
I am strugling with the same issue and didn't also tried the pr's without succes.
By default, the keyboard only sends action messages after the correct pin+action_button is pressed. Default user pin = 1234, so pressing 1234(lock) should result as an action. Refer here for keypad internal commands to change its behavior: https://manuals.plus/immax/07505l-neo-smart-keypad-manual#axzz8R2Z5dWOe
Updated Post! Modification: added User id for datapoint 112 Manual: https://manuals.plus/immax/07505l-neo-smart-keypad-manual#axzz8R2Z5dWOe
I had the same issue(1.35), but diving deeper into the debug log, i found out that not only the manufacturer code was not right, but the tuya datapoint were wrong too. There for i satrted thinking that the device got an updated FW in a newer production. Zigbee Manufacturer _TZE200_moycceze So i made my custom converter for this device.
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 e = exposes.presets;
const ea = exposes.access;
const toZigbeeConverters = {
arm_delay_time: {
key: ['arm_delay_time'],
convertSet: async (entity, key, value, meta) => {
const dp = 103;
await tuya.sendDataPointValue(entity, dp, value);
},
convertGet: async (entity, key, meta) => {
const dp = 103;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
beep_sound_enabled: {
key: ['beep_sound_enabled'],
convertSet: async (entity, key, value, meta) => {
const dp = 104;
await tuya.sendDataPointBool(entity, dp, value === 'ON');
},
convertGet: async (entity, key, meta) => {
const dp = 104;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
quick_home_enabled: {
key: ['quick_home_enabled'],
convertSet: async (entity, key, value, meta) => {
const dp = 105;
await tuya.sendDataPointBool(entity, dp, value === 'ON');
},
convertGet: async (entity, key, meta) => {
const dp = 105;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
quick_disarm_enabled: {
key: ['quick_disarm_enabled'],
convertSet: async (entity, key, value, meta) => {
const dp = 106;
await tuya.sendDataPointBool(entity, dp, value === 'ON');
},
convertGet: async (entity, key, meta) => {
const dp = 106;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
quick_arm_enabled: {
key: ['quick_arm_enabled'],
convertSet: async (entity, key, value, meta) => {
const dp = 107;
await tuya.sendDataPointBool(entity, dp, value === 'ON');
},
convertGet: async (entity, key, meta) => {
const dp = 107;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
arm_delay_beep_sound: {
key: ['arm_delay_beep_sound'],
convertSet: async (entity, key, value, meta) => {
const dp = 111;
await tuya.sendDataPointBool(entity, dp, value === 'ON');
},
convertGet: async (entity, key, meta) => {
const dp = 111;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
admin_code: {
key: ['admin_code'],
convertSet: async (entity, key, value, meta) => {
const dp = 108;
await tuya.sendDataPointValue(entity, dp, value);
},
convertGet: async (entity, key, meta) => {
const dp = 108;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
last_added_user_code: {
key: ['last_added_user_code'],
convertSet: async (entity, key, value, meta) => {
const dp = 109;
await tuya.sendDataPointValue(entity, dp, value);
},
convertGet: async (entity, key, meta) => {
const dp = 109;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
user_id: {
key: ['user_id'],
convertSet: async (entity, key, value, meta) => {
const dp = 112;
await tuya.sendDataPointValue(entity, dp, value);
},
convertGet: async (entity, key, meta) => {
const dp = 112;
await tuya.sendDataPointValue(entity, dp, 0);
},
},
};
const fromZigbeeConverters = {
tamper: {
cluster: 'manuSpecificTuya',
type: 'commandDataReport',
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 24);
if (dpValue) {
const value = dpValue.data[0];
const tamper = value === 1;
return { tamper: tamper };
}
},
},
arm_delay_time: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 103);
if (dpValue && dpValue.data && Array.isArray(dpValue.data) && dpValue.data.length > 0) {
const value = dpValue.data[0];
const clampedValue = Math.min(Math.max(value, 0), 180);
return { arm_delay_time: clampedValue };
}
},
},
beep_sound_enabled: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 104);
if (dpValue) {
return { beep_sound_enabled: dpValue.data[0] === 1 ? 'ON' : 'OFF' };
}
},
},
quick_home_enabled: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 105);
if (dpValue) {
return { quick_home_enabled: dpValue.data[0] === 1 ? 'ON' : 'OFF' };
}
},
},
quick_disarm_enabled: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 106);
if (dpValue) {
return { quick_disarm_enabled: dpValue.data[0] === 1 ? 'ON' : 'OFF' };
}
},
},
quick_arm_enabled: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 107);
if (dpValue) {
return { quick_arm_enabled: dpValue.data[0] === 1 ? 'ON' : 'OFF' };
}
},
},
arm_delay_beep_sound: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 111);
if (dpValue) {
return { arm_delay_beep_sound: dpValue.data[0] === 1 ? 'ON' : 'OFF' };
}
},
},
admin_code: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 108);
if (dpValue) {
return { admin_code: dpValue.data.toString() };
}
},
},
last_added_user_code: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 109);
if (dpValue) {
return { last_added_user_code: dpValue.data.toString() };
}
},
},
user_id: {
cluster: 'manuSpecificTuya',
type: ['commandDataReport', 'commandDataResponse', 'commandSetDataResponse'],
convert: (model, msg, publish, options, meta) => {
const dpValue = msg.data.dpValues.find(dpValue => dpValue.dp === 112);
if (dpValue) {
const value = dpValue.data[0];
const clampedValue = Math.min(Math.max(value, 0), 9);
return { user_id: clampedValue.toString() };
}
},
},
};
const definition = {
fingerprint: tuya.fingerprint('TS0601', ['_TZE200_moycceze']),
model: '07505L',
vendor: 'Immax',
description: 'Neo smart keypad',
fromZigbee: [
tuya.fz.datapoints,
fromZigbeeConverters.tamper,
fromZigbeeConverters.arm_delay_time,
fromZigbeeConverters.beep_sound_enabled,
fromZigbeeConverters.quick_home_enabled,
fromZigbeeConverters.quick_disarm_enabled,
fromZigbeeConverters.quick_arm_enabled,
fromZigbeeConverters.arm_delay_beep_sound,
fromZigbeeConverters.admin_code,
fromZigbeeConverters.last_added_user_code,
fromZigbeeConverters.user_id,
],
toZigbee: [
toZigbeeConverters.arm_delay_time,
toZigbeeConverters.beep_sound_enabled,
toZigbeeConverters.quick_home_enabled,
toZigbeeConverters.quick_disarm_enabled,
toZigbeeConverters.quick_arm_enabled,
toZigbeeConverters.arm_delay_beep_sound,
toZigbeeConverters.admin_code,
toZigbeeConverters.last_added_user_code,
toZigbeeConverters.user_id,
],
exposes: [
e.action(['disarm', 'arm_home', 'arm_away', 'sos']),
e.battery(),
e.tamper(),
exposes.text('admin_code', ea.STATE_SET)
.withDescription('Admin code')
.withAccess(ea.STATE),
exposes.text('last_added_user_code', ea.STATE_SET)
.withDescription('Last Added User code')
.withAccess(ea.STATE),
exposes.numeric('arm_delay_time', ea.STATE_SET)
.withValueMin(0).withValueMax(180)
.withDescription('Arm Delay Time'),
exposes.binary('beep_sound_enabled', ea.STATE_SET, 'ON', 'OFF')
.withDescription('Beep Sound Enabled'),
exposes.binary('quick_home_enabled', ea.STATE_SET, 'ON', 'OFF')
.withDescription('Quick Home Enabled'),
exposes.binary('quick_disarm_enabled', ea.STATE_SET, 'ON', 'OFF')
.withDescription('Quick Disarm Enabled'),
exposes.binary('quick_arm_enabled', ea.STATE_SET, 'ON', 'OFF')
.withDescription('Quick Arm Enabled'),
exposes.binary('arm_delay_beep_sound', ea.STATE_SET, 'ON', 'OFF')
.withDescription('Arm Delay Beep Sound'),
exposes.text('user_id', ea.STATE)
.withDescription('User ID'),
],
meta: {
tuyaDatapoints: [
[3, 'battery', tuya.valueConverter.raw],
[24, 'tamper', tuya.valueConverter.raw],
[26, 'action', tuya.valueConverter.static('disarm')],
[27, 'action', tuya.valueConverter.static('arm_away')],
[28, 'action', tuya.valueConverter.static('arm_home')],
[29, 'action', tuya.valueConverter.static('sos')],
[108, 'admin_code', tuya.valueConverter.raw],
[109, 'last_added_user_code', tuya.valueConverter.raw],
[103, 'arm_delay_time', tuya.valueConverter.raw],
[104, 'beep_sound_enabled', tuya.valueConverter.trueFalse],
[105, 'quick_home_enabled', tuya.valueConverter.trueFalse],
[106, 'quick_disarm_enabled', tuya.valueConverter.trueFalse],
[107, 'quick_arm_enabled', tuya.valueConverter.trueFalse],
[111, 'arm_delay_beep_sound', tuya.valueConverter.trueFalse],
[112, 'user_id', tuya.valueConverter.raw],
],
},
};
module.exports = definition;
Have fun whit it!
@martin1997nm Thank you for the code. I have managed to get it working finally. Just one thing, with the latest Z2M version I had to remove the line: const extend = require( 'zigbee-herdsman-converters/lib/extend'); Converter wouldn't load with it.
Could you make a PR to add out of the box support for this device?
Hello @martin1997nm
Thank you for the code. Please could you make a PR as this keypad is still not supported directly by Z2M ?
Hi @martin1997nm,
Do you maybe know if there is a possibility for this keyboard to be given a mqtt command to beep for countdown. For example I can enable countdown when arming, but it would be good to have it beep when it is triggered and waiting for disarm code. I don't use it with their proprietary hub so I don't know if it has this option at all, and the user manual is very short.
Regards,
Nikola
Hi! It does not have that funcionality in the firmware!
Hi @martin1997nm in the action for the keypad when arming/disarming/any action there is no info "action": "", I`ve got "user_id": "0". Any idea what I can do?
logs:
[2024-09-06 15:36:34] info: z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/Alarm keypad', payload '{"action":"arm_away", . . . .}'
[2024-09-06 15:36:34] info: z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/Alarm keypad', payload '{"action":"", . . . .}'
[2024-09-06 15:36:34] info: z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/Alarm keypad/action', payload 'arm_away'
on arming there are 3 messages, 1 of them is empty. In HA I can see cahnging it for arm_way in the logs, but instantly it is back to "" (empty)
What happened?
Hello,
I bought a Immax 07505L alarm keypad and I am trying to get it working. No issue adding the device to the network and getting it identified, however no actions are recognized when I press its buttons. I looked it up and found those posts: https://github.com/Koenkk/zigbee2mqtt/issues/17800 https://github.com/zigpy/zha-device-handlers/issues/1852 https://github.com/Koenkk/zigbee2mqtt/issues/11728
Which all use an external converter with varying levels of success. I tried this one (including the modifications suggested in the thread). But while the converter is properly linked to the device, it's still not working.
This is what logs indicate:
Exception while calling fromZigbee converter: Cannot read properties of undefined (reading '0')} debug 2023-12-17 21:53:12 TypeError: Cannot read properties of undefined (reading '0') at Object.convert (/app/data/extension/externally-loaded.js:36:32) at Receive.onDeviceMessage (/app/lib/extension/receive.ts:150:51) at EventEmitter.emit (node:events:525:35) at EventBus.emitDeviceMessage (/app/lib/eventBus.ts:102:22) at Controller.<anonymous> (/app/lib/zigbee.ts:108:27) at Controller.emit (node:events:513:28) at Controller.selfAndDeviceEmit (/app/node_modules/zigbee-herdsman/src/controller/controller.ts:527:14) at Controller.onZclOrRawData (/app/node_modules/zigbee-herdsman/src/controller/controller.ts:738:18) at ZStackAdapter.<anonymous> (/app/node_modules/zigbee-herdsman/src/controller/controller.ts:144:70) at ZStackAdapter.emit (node:events:513:28)
"
Object.convert (/app/data/extension/externally-loaded.js:36:32
" refers to this line in the converter : "const dp = msg.data.dpValues[0].dp;
"But from there I don't know how to troubleshoot it. Any idea?
Thanks a lot!
What did you expect to happen?
No response
How to reproduce it (minimal and precise)
No response
Zigbee2MQTT version
1.34.0
Adapter firmware version
20221226
Adapter
SONOFF ZigBee 3.0 USB Dongle Plus TI CC2652P
Debug log
No response