삼성SDS SHP-DP960을 Z2M에 연동하기

이 포스팅은 아직 완료되지 않은 부분이 포함하고 있다.

19/20년에 ST카페에서 zigbee/zwave 도어락이 유행하였다.
우선 먼저 떠오른 것은 통신사 연동패키지에서 나온 zwave 연동 도어락이었다. 게이트맨과 samsung sds 제품이 있었으나 게이트맨은 연동팩을 구하기 어려웠고, samsung sds 연동 모듈은 대리점을 통해서 구할 수 있었다.
다만 zwave는 주파수 문제가 있기 때문에, 한국 st 허브가 출시되기 전에는 사용할 수 있는 방법은 open zwave로 연동해서 사용해야했다. (지금은 한국 st허브가 출시되었으니 직접 연결이 가능하겠다.)
사용했던 HA의 zwave stick의 특성을 타는 것인지 연결이 안정적이지 못해서, 새로 이사한 집에는 zigbee 도어락으로 교체하였다.

사용해보니 zwave버전은 zwave의 lock with code(?) 표준을 구현하여서 열림, 키코드 등록이 가능하고 zigbee버전은 wifi 모듈일 때 키코드 등록이 가능하지만 zigbee 모듈로 연동하면 키코드 등록이 불가능하다. (도어락에서 기본적으로 복수의 키코드를 지원하지 않기 때문일지도, zwave 도어락도 zwave 명령을 통해 등록이 가능했었음)

사용하는 모델명 SHP-DP960, 지문인식과 비상키(열쇠) 개방이 되는 고급라인 제품이다. 이 제품은 wifi연결이 기본이나 zigbee 모듈을 통해 연결이 가능하다.

현재 zigbee2mqtt에는 정식 연동이 안되는 제품이다. 도어락이 보통 국가의 안전/보안에 대한 가이드라인을 맞춰야하고 설치규격에 맞춰 나라별로 출시하기에, 해외에서는 또 이러한 도어락을 잘 안쓰는 듯하기에 아직 지원은 없는 듯하다.
최근 st와는 연동이 되는 듯 해보이지만, 나는 HC와 z2m만 사용 중이기에 연동을 진행하였다.

zigbee-herdsman, zigbee-herdsman-converters 코드에 수정해야할 부분은 아래와 같다. 수정한 부분만 발췌했다.

// in cluster.js
// closuresDoorLock > commands
samsungSdsUnlock: {
    ID: 31,
    response: 1,
    parameters: [
        {name: 'code', type: BuffaloZclDataType.LIST_UINT8},
    ],
},
// in devices.js
{
    fingerprint: [
        {type: 'EndDevice', manufacturerID: 3, endpoints: [
            {ID: 1, inputClusters: [0,1,3,4,5,9,257], outputClusters: [25]},
        ]},
    ],
    zigbeeModel: ['SHP-DP960'],
    model: 'SHP-DP960',
    vendor: 'Samsung SDS',
    description: 'Samsung SDS fingerprint lock',
    supports: 'lock/unlock, battery',
    fromZigbee: [fz.samsung_lock, fz.battery],
    toZigbee: [tz.samsung_lock],
},
// in toZigbee.js
const options = {
    'Samsung SDS': {
        manufacturerCode: 0x0003,
    },
...

samsung_lock: {
    key: ['state'],
    convertSet: async (entity, key, value, meta) => {
        await entity.command('closuresDoorLock', 'samsungSdsUnlock', {'code': [16, 4, 49, 50, 51, 53]}, { manufacturerCode: 0x0003 });

        return {readAfterWriteTime: 200};
    },
    convertGet: async (entity, key, meta) => {
        await entity.read('closuresDoorLock', ['lockState']);
    },
},
// in fromZigbee.js
samsung_lock: {
    cluster: 'closuresDoorLock',
    type: 'raw',
    convert: (model, msg, publish, options, meta) => {
        const controlBy = msg.data[3];
        const stateCode = msg.data[4];
        let state = '';
        let lock_state = '';
        let operated_by = '';
        let id = ''
    
        switch (stateCode) {
            case 1:
                state = 'MODIFY LOCK CODE';
                lock_state = 'lock code modified';
                break;
            case 2:
                state = 'UNLOCK';
                lock_state = 'unlocked';
                if (controlBy == 0) {
                    operated_by = 'By Lock Code'
                } else if (controlBy == 4) {
                    operated_by = 'By Fingerprint'
                    id = 'finger-' + (msg.data[5] - 30);
                } else if (controlBy == 3) {
                    operated_by = 'By RFID Tag'
                    id = 'rfid-' + (msg.data[5] - 2);
                } else if (controlBy == 5) {
                    operated_by = 'By Bluetooth'
                } else if (controlBy == 2) {
                    operated_by = 'By Manual'
                } else if (controlBy == 1) {
                    operated_by = 'By Key'
                }
                break;
            case 3:
            case 4:
            case 5:
                state = 'ADD RFID Tag';
                lock_state = 'rfid tag added';
                operated_by = '';
                id = 'rfid-' + (msg.data[5] - 2);
                break;
            case 6:
                state = 'DELETE RFID Tag';
                lock_state = 'rfid tag deleted';
                operated_by = '';
                id = 'rfid-' + (msg.data[5] - 2);
                break;
            case 7:
                state = 'LOCK';
                lock_state = 'locked';
                method = 'Ansimi';
                break;
            case 8:
                state = 'LOCK';
                lock_state = 'locked';
                operated_by = 'Unknown';
                break;
            case 9:
                state = 'UNLOCK';
                lock_state = 'unlocked';
                operated_by = 'By Key';
                break;
            case 13:
                state = 'LOCK';
                lock_state = 'locked';
                operated_by = 'By Key';
                break;
            case 14:
                state = 'UNLOCK';
                lock_state = 'unlocked';
                operated_by = 'From Inside';
                break;
            case 10:
                state = 'LOCK';
                lock_state = 'locked';
                operated_by = 'Auto';
                break;
            case 16:
                state = 'UNLOCK';
                lock_state = 'unlocked';
                operated_by = 'Zigbee';
                break;
            case 33:
                const type = msg.data[5];
                if (type == 4) {
                    if (msg.data[6] == 16) {
                        state = 'DELETE ALL Fingerprint';
                        lock_state = 'all fingerprint deleted';
                    } else if (msg.data[6] == 15) {
                        state = 'DELETE Fingerprint';
                        lock_state = 'fingerprint deleted';
                        id = 'finger-' + (msg.data[7] - 30);
                    } else if (msg.data[6] == 14) {
                        state = 'ADD Fingerprint';
                        lock_state = 'fingerprint added';
                        id = 'finger-' + (msg.data[7] - 30);
                    }
                } else if (type == 3) {
                    state = 'DELETE ALL RFID Tag';
                    lock_state = 'all rfid tag deleted';
                }
                break;
        }
            
        return {
            state,
            id,
            operated_by,
            lock_state
        };
    },
},

UNLOCK만 가능하고, 디바이스로부터 리포트 되는 상태에서는 unlock/lock 상태는 오류가 없지만 키 등록, 열쇠로 열림 등에 대한 정보는 아직 정확하지 않은 것으로 알고 있다.

내가 수정한 코드는 꽤 예전 버전(12.0.224)에 수정했기에 최신버전에서는 맞지 않을 수 있다.
디바이스를 등록하고 나서 디바이스의 모델명을 불러와야하지만 아직 불러오지 않는 문제가 있다. (unknown) 모델명을 불러오는 방법은 확인되었으나, z2m에서 다른 패킷에서 모델 정보가 리포트되면 어떻게 해야할지 모르겠어서 아직 적용되지 않았다.

Show Comments