Aqara P100 Multi-State Sensor with Zigbee2MQTT & Home Assistant

I just got a P100 sensor this afternoon and have a working Zigbee2MQTT converter done for it. It was reverse-engineered from Zigbee packet captures.

I think I’ve got every action and setting included, let me know if there’s anything missing. I’ll include any updates in the linked Github repository version.

How to install

  1. In Zigbee2MQTT go to Settings > Dev Console > External Converters
  2. Select Create new converter
  3. Name it p100.mjs
  4. Paste in the code
  5. Click Save
  6. Make sure you have events enabled in the Z2M HA integration settings
  7. Restart Zigbee2MQTT

Pairing the device

  1. In Zigbee2MQTT click Permit join in the side menu
  2. Hold the button on the P100 for 5 seconds
  3. The LED will flash blue several time them pulse purple
  4. It should be recognised in Z2M and have a cyan coloured label “Supported: external
  5. Calibrate the device according to the user manual

Operating Modes

The P100 has two mutually-exclusive operating modes set via device_mode:

Mode Purpose Active exposures
object Watches an object for movement, vibration, tilt, tap, orientation, fall action, orientation
door window Reports a door/window as open/closed using internal motion inference contact

The event-enable toggles (movement_detection, vibration_detection, etc.) and door_window_type only have effect in their respective modes.

Exposures

Events (object mode)

Exposure Values Notes
action triple tap, movement, vibration, orientation, fall Published momentarily on each detected event
orientation face up, face down, vertical, tilt Last reported orientation; meaningful when action = orientation

Contact (door/window mode)

Exposure Values Notes
contact true (closed) / false (open) Derived internally by the device from its motion sensors — not an IAS contact sensor

Settings

Exposure Type Range / Values Description
device_mode enum door window, object Operating mode (see above)
door_window_type enum casement window, hopper window, composite window, hinged door Door/window profile (only relevant in door/window mode)
motion_sensitivity numeric 1–10 Detection sensitivity (1 = low, 10 = high)
report_interval numeric 5–300 seconds How often the device reports state
orientation_detection binary ON / OFF Enable orientation event reporting (object mode)
movement_detection binary ON / OFF Enable movement event reporting (object mode)
fall_detection binary ON / OFF Enable fall event reporting (object mode)
vibration_detection binary ON / OFF Enable vibration event reporting (object mode)
triple_tap_detection binary ON / OFF Enable triple-tap event reporting (object mode)

Diagnostics

Exposure Values Notes
battery 0–100 % From the Aqara bundled buffer (attribute 0x00f7, TLV field 0x18)
voltage mV From the same buffer (TLV field 0x17)
device_posture normal, abnormal Mounting orientation check — abnormal when installed incorrectly or needs calibration

How it appears in Home Assistant

You can get the converter code from my Github repository (recommend), or copy it from below:


import * as lumi from "zigbee-herdsman-converters/lib/lumi";
import * as m from "zigbee-herdsman-converters/lib/modernExtend";

const {lumiModernExtend, manufacturerCode} = lumi;

export default {
    zigbeeModel: ["lumi.vibration.agl002"],
    model: "DWZTCGQ11LM",
    vendor: "Aqara",
    description: "Multi-state sensor P100",
    
    extend: [
        m.quirkCheckinInterval("1_HOUR"),
        lumiModernExtend.addManuSpecificLumiCluster(),
        lumiModernExtend.lumiPreventReset(),
        lumiModernExtend.lumiBattery({
            voltageAttribute: 0x17,
            percentageAtrribute: 0x18, // typo intentional — matches z-h-c lumiBattery() arg name
        }),
        lumiModernExtend.lumiZigbeeOTA(),

        m.enumLookup({
            name: "device_mode",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x0116, type: 0x20},
            lookup: {"door_window": 3, "object": 5},
            description: "Device operating mode",
            access: "STATE_SET",
            entityCategory: "config",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.enumLookup({
            name: "door_window_type",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01eb, type: 0x20},
            lookup: {"casement_window": 1, "hopper_window": 2, "composite_window": 3, "hinged_door": 4},
            description: "Door/window type (applies when device_mode = door window)",
            access: "STATE_SET",
            entityCategory: "config",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.numeric({
            name: "sensitivity",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x010c, type: 0x20},
            valueMin: 1,
            valueMax: 10,
            description: "Detection sensitivity (1 = low, 10 = high)",
            access: "STATE_SET",
            entityCategory: "config",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.numeric({
            name: 'report_interval',
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01ec, type: 0x23},
            unit: "s",
            valueMin: 5,
            valueMax: 300,
            description: "Reporting interval in seconds",
            access: "STATE_SET",
            entityCategory: "config",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.binary({
            name: "orientation_detection",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01f0, type: 0x10},
            valueOn: ["ON", 1],
            valueOff: ["OFF", 0],
            description: "Enable orientation event detection",
            access: "STATE_SET",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.binary({
            name: "movement_detection",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01ed, type: 0x10},
            valueOn: ["ON", 1],
            valueOff: ["OFF", 0],
            description: "Enable movement event detection",
            access: "STATE_SET",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.binary({
            name: "fall_detection",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01d8, type: 0x10},
            valueOn: ["ON", 1],
            valueOff: ["OFF", 0],
            description: "Enable fall event detection",
            access: "STATE_SET",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.binary({
            name: "vibration_detection",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x0107, type: 0x10},
            valueOn: ["ON", 1],
            valueOff: ["OFF", 0],
            description: "Enable vibration event detection",
            access: "STATE_SET",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.binary({
            name: "triple_tap_detection",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01ef, type: 0x10},
            valueOn: ["ON", 1],
            valueOff: ["OFF", 0],
            description: "Enable triple-tap event detection",
            access: "STATE_SET",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        m.enumLookup({
            name: "orientation",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01f1, type: 0x20},
            lookup: {"face_up": 1, "face_down": 2, "vertical": 3, "tilt": 4},
            description: "Last reported orientation (relevant when action = orientation)",
            access: "STATE",
            zigbeeCommandOptions: {manufacturerCode},
        }),
        // 0x01f3 fires true on every detection but never resets — no signal beyond `action`, not exposed.
        m.actionEnumLookup({
            cluster: "closuresDoorLock",
            attribute: {ID: 0x0055, type: 0x21},
            actionLookup: {
                "triple_tap": 0,
                "movement": 1,
                "vibration": 2,
                "orientation": 3,
                "fall": 4,
            },
        }),
        m.binary({
            name: "contact",
            cluster: "genOnOff",
            attribute: "onOff",
            valueOn: [false, 1],
            valueOff: [true, 0],
            description: "Door/window state (door/window mode only)",
            access: "STATE",
        }),
        m.enumLookup({
            name: "device_posture",
            cluster: "manuSpecificLumi",
            attribute: {ID: 0x01ee, type: 0x20},
            lookup: {"normal": 1, "abnormal": 2},
            description: "Mounting orientation check — 'abnormal' when the sensor is incorrectly installed or needs calibration",
            access: "STATE",
            entityCategory: "diagnostic",
            zigbeeCommandOptions: {manufacturerCode},
        }),
    ],
};


6 Likes

Thanks!! Is it possible to be in door mode and receive vibration / fall statuses? For security purposes

2 Likes

Welocone to the forum.

Unfortunately not, the device only detects open/close in door/window mode. Vibration/fall is only available in object mode as per the device specs.

You could in theory use it in object mode and make an automation to detect movement as a door open close event, or tilt as a window opening (depending on the type of window) and vibration/fall as another event, but I don’t know how reliable the open/close interpretation would be.

3 Likes

Thank you so much for your work @absent!
I’ll definitely try it :slight_smile:

2 Likes

I should shortly have a custom ZHA quirk done for the P100 too.

1 Like

Great sharing! :yehec8wxjw08bxitza4t8e_35015:

1 Like

This converter will now be included in the Zigbee2MQTT v2.10.0 release, due for 1st May. The P100 will work with Z2M out of the box after that.

4 Likes

This is great news! Thanks for your effort!
I’m miles away of creating custom converters :smiley:

3 Likes

I would love to test the ZHA quirk if that helps.

3 Likes

I’m having an issue getting the actions to register as device triggers in ZHA at the moment, I don’t have much experience with ZHA. But I’ll hopefully get to back to it at the weekend and get something working, I need to do a bit more reading on ZHA implementation, it’s rather idiosyncratic compared to Z2M.

3 Likes

I don’t want to be a bother, but I wanted to check in and ask whether you’ve had a chance to take a look at it. I would really appreciate your help.

2 Likes

Haven’t had a chance to get the triggers working yet, sorry. ZHA is a real pain to work with compared to Z2M.

2 Likes

Has anyone got the vibration sensor reporting in Z2M? Orientation seems to work ok, but not vibration.

Have you turned on vibration detection for Object mode? You need to press the button on the device to change the detection settings.

Hello,

Isn’t the sensor supposed to work “out of the box” with the 2.10 update?

I am able to pair it—the interview process completes successfully.

However, I’m not receiving any reports—no battery status, nothing. Everything just shows “null” or “N/A”.

I’ve also updated to version 2.10.1.

Does anyone have any ideas?

Regards,
Raphael