Koenkk / zigbee2mqtt

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

[New device support]: Philips Hue Secure contact sensor (SOC001) #19054

Closed fractalcounty closed 11 months ago

fractalcounty commented 11 months ago

Link

https://www.philips-hue.com/en-us/p/hue-secure-contact-sensor/046677580957

Database entry

{"id":8,"type":"EndDevice","ieeeAddr":"0x001788010d81e154","nwkAddr":47959,"manufId":4107,"manufName":"Signify Netherlands B.V.","powerSource":"Battery","modelId":"SOC001","epList":[2],"endpoints":{"2":{"profId":260,"epId":2,"devId":2128,"inClusterList":[0,1,3,64518],"outClusterList":[25,0,3,6],"clusters":{"genBasic":{"attributes":{"32":"0:NULL@0","33":4595,"modelId":"SOC001","manufacturerName":"Signify Netherlands B.V.","powerSource":3,"zclVersion":8,"appVersion":2,"stackVersion":1,"hwVersion":1,"dateCode":"20221008","swBuildId":"2.67.1"}},"genPowerCfg":{"attributes":{"batteryPercentageRemaining":200}},"genOnOff":{"attributes":{}},"manuSpecificUbisysDeviceSetup":{"attributes":{}},"manuSpecificPhilips2":{"attributes":{}}},"binds":[{"cluster":0,"type":"endpoint","deviceIeeeAddress":"0xbc026efffe226881","endpointID":1},{"cluster":3,"type":"endpoint","deviceIeeeAddress":"0xbc026efffe226881","endpointID":1},{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0xbc026efffe226881","endpointID":1},{"cluster":1,"type":"endpoint","deviceIeeeAddress":"0xbc026efffe226881","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":2,"stackVersion":1,"hwVersion":1,"dateCode":"20221008","swBuildId":"2.67.1","zclVersion":8,"interviewCompleted":true,"meta":{},"lastSeen":1695426849731,"defaultSendRequestWhen":"immediate"}

Comments

For context, I am using the zigbee2mqtt addon (dev branch) through Home Assistant OS installed on a RPi4b with the SkyConnect dongle flashed with the zigbee-only firmware. The device I'm attempting to support was recently released in the last few weeks, so as expected there's absolutely zero documentation or information online on how to use it through z2m that I could find. Here is my (failed) attempt at following the supporting new devices documentation:

Pairing the device with Zigbee2MQTT

I toggled Permit Join in z2m, held the button down on the contact sensor until it blinked, then pressed it a bunch of times. It then paired without an issue, and as expected provided the following response in the logs:

Device '0x001788010d81e154' with Zigbee model 'SOC001' and manufacturer name 'Signify Netherlands B.V.' is NOT supported, please follow https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html

External converter

Here are the contents my external converter file titled 'SOC001', placed in my HomeAssistant /config/zigbee2mqtt/ directory. This is likely very incomplete and very incorrect as I have zero prior experience with zigbee2mqtt whatsoever. I tried many different variations that made zero difference, so this what I eventually settled on:

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 e = exposes.presets;
const ea = exposes.access;

const definition = {
    zigbeeModel: ['SOC001'],
    model: '9290035639',
    vendor: 'Signify Netherlands B.V.',
    description: 'Philips Hue Secure contact sensor',
    fromZigbee: [],
    toZigbee: [],
    exposes: [e.battery(), e.linkquality(), e.contact()],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(2);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);    
    },
};

module.exports = definition;

I then proceeded to enable debug logging add add the external converted into the z2m configuration.yaml file like so:

advanced:
  homeassistant_legacy_entity_attributes: false
  legacy_api: false
  legacy_availability_payload: false
  log_level: debug
  external_converters:
    - SOC001.js

Upon restarting z2m and initiating contact between the magnet and sensor, the following messages appear in the logs:

Debug - 2023-09-22 19:29:55 | Received Zigbee message from '0x001788010d81e154', type 'commandOff', cluster 'genOnOff', data '{}' from endpoint 2 with groupID 0
Warning - 2023-09-22 19:29:55 | Received message from unsupported device with Zigbee model 'SOC001' and manufacturer name 'Signify Netherlands B.V.'
Warning - 2023-09-22 19:29:55 | Please see: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html

This is about as far as I've gotten. The documentation recommends looking at similar devices for inspiration for further config, but so far I have failed to find a combination of configuration that works for this device.

The documentation also states that the Clusters page at Zigbee2MQTT's frontend (found under the device in the dashboard) also exposes the clusters, and they are as follows:

0x001788010d81e154
   Endpoint:
      Output clusters:
         genOta
         genBasic
         genIdentify
         genOnOff
      Input clusters:
         genBasic
         genPowerCfg
         genIdentify
         64518 (unidentified, no idea what this is- manufacturer specific?)

So, as of right now, I'm only able to get z2m to utilize the genOnOff cluster when contact is made with the sensor, but it feels rather inconsistent and I have a strong feeling that there may be more to this that I'm likely missing. I understand that adding support to devices like this is a non-trivial process, so any help whatsoever would be very much appreciated.

Thank you!

fractalcounty commented 11 months ago

I did some more research and after much trial and error, I was able to get it working for the most part. Here's my current SOC001.js file:

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 e = exposes.presets;
const ea = exposes.access;

const fzLocal = {
    philips_contact: {
        cluster: 'genOnOff',
        type: ['attributeReport', 'readResponse', 'commandOff', 'commandOn'],
        convert: (model, msg, publish, options, meta) => {
            let contactState = null;
            if (msg.type === 'commandOff') {
                contactState = true;  
            } else if (msg.type === 'commandOn') {
                contactState = false;  
            } else if (msg.data.hasOwnProperty('onOff')) {
                contactState = msg.data['onOff'] === 0; 
            }
            return {contact: contactState};
        },
    },
};

const definition = {
    zigbeeModel: ['SOC001'],
    model: '9290035639',
    vendor: 'Philips',
    description: 'Philips Hue Secure contact sensor',
    fromZigbee: [fz.battery, fzLocal.philips_contact],
    toZigbee: [],
    exposes: [e.battery(), e.contact()],
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(2);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
        await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
        await reporting.batteryPercentageRemaining(endpoint);
    },
};

module.exports = definition;

Like I said, I have zero prior experience with zigbee2mqtt or even JS itself and there's most likely errors here. Despite this, it seems to be working to some degree.

Koenkk commented 11 months ago

Looks good! Can you check with https://gist.github.com/Koenkk/9454157818a15a854a96f69feddde2bc, if it works I can add it.

fractalcounty commented 11 months ago

Looks good! Can you check with https://gist.github.com/Koenkk/9454157818a15a854a96f69feddde2bc, if it works I can add it.

Yup, seems to be working. Battery and link quality are also reported in the HA frontend as well. I still have no clue what the 64518 cluster is or if there's any other functions of this device I missed, but that's well beyond my skill level. Want me to close this?

Somewhat off topic note for anyone else planning to use this device, don't pair it with anything if you're planning on eventually pairing it with zigbee2mqtt. I had purchased two of these and paired one of them with an existing Hue bridge for testing via the app only to find out there's no obvious way to factory reset these things at the moment. I tried removing the battery, holding the button, unpairing in the app, using a Hue dimmer remote- nothing. Hue support offered no help and said there's "no way to factory reset them at the moment", which obviously can't be true, but just keep that in mind until someone finds out a way.

Edit: Nevermind, there's a tiny reset button under the battery cover that I somehow missed. Whoops.

Koenkk commented 11 months ago

Yup, seems to be working. Battery and link quality are also reported in the HA frontend as well. I still have no clue what the 64518

No clue what this is, but since everything works let's ignore it.

I've added the device!

Changes will be available in the dev branch in a few hours from now. (https://www.zigbee2mqtt.io/advanced/more/switch-to-dev-branch.html)

mguaylam commented 4 weeks ago

64518 could include the temper detection, it is a small recess prong at the back of the device. But I was not able to identify the attribute.