-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature request]: Support Aqara FP1 Regions #13711
Comments
FP1 is a game changer either way, but if we could get regions support, it would make the device perfect. |
deconz-rest-plugin community did a deep dive in FP1 regions: |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
I’d still be interested! |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
/unstale |
-stale |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
bump |
(post edited, since I found a solution to my problem) I managed to get basic region support implemented using the following external converter: const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const ota = require('zigbee-herdsman-converters/lib/ota');
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 e = exposes.presets;
const ea = exposes.access;
const manufacturerOptions = {
xiaomi: {manufacturerCode: 0x115f, disableDefaultResponse: true},
};
const octet_as_hex = (octet) => {
var hex = ""
for (const num of octet) {
hex += `:${num.toString(16).padStart(2, 0)}`
}
return hex.substring(1);
};
const array_to_byte = (arr) => {
var byte = 0;
for (const x of arr) {
if (x > 4 || x < 0) {
meta.logger.warn(`zigbee-herdsman-converters:aqara_fp1: Invalid X value ${x}. Ignoring.`);
continue;
}
byte += 2**(x-1)
}
return byte;
}
const fzLocal = {
fp1_regions_events: {
cluster: 'aqaraOpple',
type: ['readResponse', 'attributeReport'],
convert: (model, msg, publish, options, meta) => {
const event_lookup = {
1: 'enter',
2: 'leave',
4: 'occupied',
8: 'unoccupied'
};
payload = {};
Object.entries(msg.data).forEach(([key, value]) => {
switch (parseInt(key)) {
case 0x0151:
const event = event_lookup[value[1]];
const region_id = value[0];
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: event: region ${region_id} ${event}`)
payload.region_event = `region_${region_id}_${event}`
break;
case 0xf7:
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: Unhandled key 0x${key.toString(16).padStart(4, "0")} = ${octet_as_hex(value)}`);
break;
case 0x0142:
case 0x0143:
case 0x0144:
case 0x0146:
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: Unhandled key 0x${key.toString(16).padStart(4, "0")} = ${value}`);
break;
default:
meta.logger.warn(`zigbee-herdsman-converters:aqara_fp1: Unknown key 0x${key.toString(16).padStart(4, "0")} = ${value}`);
}
});
return payload;
},
},
};
/*
Config object:
[{"region_id": 1, "action": "create", "definition": {"1": [1, 2, 3, 4]}}]
definition is like {Y1: <array of X values to include>, Y2: ...}, corresponding to X1-X4 and Y1-Y7
*/
const tzLocal = {
fp1_regions_config: {
key: ['regions_config'],
convertSet: async (entity, key, value, meta) => {
try {
var val = JSON.parse(value);
}
catch(err) {
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: ignoring bad JSON: ${value}`);
}
const action_lookup = {create: 1, delete: 2, modify: 3};
for (var region of val) {
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: trying to ${region['action']} region ${region['region_id']}`);
action = action_lookup[region['action']];
var cfg = new Uint8Array(7)
cfg[6] = (action == 2) ? 0x00 : 0xff; // set least-significant bits based on command
cfg[0] = action; // set command flag
cfg[1] = region['region_id']; // set region id
cfg[2] |= array_to_byte(region['definition']['1'] || [])
cfg[2] |= array_to_byte(region['definition']['2'] || []) << 4
cfg[3] |= array_to_byte(region['definition']['3'] || [])
cfg[3] |= array_to_byte(region['definition']['4'] || []) << 4
cfg[4] |= array_to_byte(region['definition']['5'] || [])
cfg[4] |= array_to_byte(region['definition']['6'] || []) << 4
cfg[5] |= array_to_byte(region['definition']['7'] || [])
meta.logger.info(`zigbee-herdsman-converters:aqara_fp1: ${region['action']} region ${region['region_id']}: ${octet_as_hex(cfg)}`);
await entity.write('aqaraOpple', {0x0150: {value: cfg, type: 0x41}}, manufacturerOptions.xiaomi);
}
},
},
fp1_other_regions_config: {
key: ['exits_entrances', 'interference_sources', 'edges'],
convertSet: async (entity, key, value, meta) => {
try {
var val = JSON.parse(value);
}
catch(err) {
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: ignoring bad JSON: ${value}`);
return;
}
meta.logger.debug(`zigbee-herdsman-converters:aqara_fp1: trying to update ${key}`);
var cfg = 0;
for (y in val) {
cfg |= array_to_byte(val[y] || []) << (4*(Number(y)-1));
}
meta.logger.info(`zigbee-herdsman-converters:aqara_fp1: setting ${key} = 0x${cfg.toString(16).padStart(8, '0')}`);
switch (key) {
case 'exits_entrances':
await entity.write('aqaraOpple', {0x0153: {value: cfg, type: 0x23}}, manufacturerOptions.xiaomi);
break;
case 'interference_sources':
await entity.write('aqaraOpple', {0x0154: {value: cfg, type: 0x23}}, manufacturerOptions.xiaomi);
break;
case 'edges':
await entity.write('aqaraOpple', {0x0156: {value: cfg, type: 0x23}}, manufacturerOptions.xiaomi);
break;
}
}
}
};
const definition = {
zigbeeModel: ['lumi.motion.ac01'],
model: 'RTCZCGQ11LM',
vendor: 'Xiaomi',
description: 'Aqara presence detector FP1 (experimental region support)',
fromZigbee: [fzLocal.fp1_regions_events, fz.aqara_opple],
toZigbee: [tz.RTCZCGQ11LM_presence, tz.RTCZCGQ11LM_monitoring_mode, tz.RTCZCGQ11LM_approach_distance,
tz.aqara_motion_sensitivity, tz.RTCZCGQ11LM_reset_nopresence_status, tzLocal.fp1_regions_config, tzLocal.fp1_other_regions_config],
exposes: [e.presence().withAccess(ea.STATE_GET),
exposes.enum('presence_event', ea.STATE, ['enter', 'leave', 'left_enter', 'right_leave', 'right_enter', 'left_leave',
'approach', 'away']).withDescription('Presence events: "enter", "leave", "left_enter", "right_leave", ' +
'"right_enter", "left_leave", "approach", "away"'),
exposes.enum('monitoring_mode', ea.ALL, ['undirected', 'left_right']).withDescription('Monitoring mode with or ' +
'without considering right and left sides'),
exposes.enum('approach_distance', ea.ALL, ['far', 'medium', 'near']).withDescription('The distance at which the ' +
'sensor detects approaching'),
exposes.enum('motion_sensitivity', ea.ALL, ['low', 'medium', 'high']).withDescription('Different sensitivities ' +
'means different static human body recognition rate and response speed of occupied'),
exposes.enum('reset_nopresence_status', ea.SET, ['']).withDescription('Reset the status of no presence'),
e.device_temperature(), e.power_outage_count(), exposes.text('regions_config', ea.SET),
exposes.enum('region_event', ea.STATE, ['region_*_enter', 'region_*_leave', 'region_*_occupied', 'region_*_unoccupied']).withDescription('Region events'),
exposes.text('exits_entrances', ea.SET), exposes.text('interference_sources', ea.SET), exposes.text('edges', ea.SET),
],
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint = device.getEndpoint(1);
await endpoint.read('aqaraOpple', [0x010c], {manufacturerCode: 0x115f});
await endpoint.read('aqaraOpple', [0x0142], {manufacturerCode: 0x115f});
await endpoint.read('aqaraOpple', [0x0144], {manufacturerCode: 0x115f});
await endpoint.read('aqaraOpple', [0x0146], {manufacturerCode: 0x115f});
},
ota: ota.zigbeeOTA,
};
module.exports = definition; In order to add a region, you need to pass a special JSON configuration object to the [{"region_id": 1, "action": "create", "definition": {"1": [1, 2, 3, 4], "2": [2, 3]}}] Where the EDIT 2: support for entrance/exit, interference source, and edge regions is now included. These are set by setting the corresponding attribute to a JSON object of the same format as the "definition" object above. There's still quite a bit of work that could be done on the UI/UX. Suggestions / improvements are welcome. |
Any chance of seeing this included in the next Z2M version? |
Unfortunately I don't have much time currently to finalize the features and prepare a pull request and won't for a few more weeks. Also, one major thing that still should be changed before inclusion in a release is to make the region configuration part of the device-specific settings rather than the normal "exposes" tab. After looking through many examples, I still can't figure out how to do this. If anyone has any tips on that, let me know. |
@patmalcolm91 are you OK with me taking your code and submitting a PR based on your solution (with some code refactoring), mostly as is? I was not able to figure out how to move the newly added configs to "Device specific settings" as well, but the rest works just fine, so I should be able to prepare a merge for basic support. |
Yes, feel free. That would be great! |
* Implement Aqara FP1 region events handling Koenkk/zigbee2mqtt#13711 * Improve region_event field description * Implement Aqara FP1 regions configuration Koenkk/zigbee2mqtt#13711 * Move xiaomi Aqara FP1 definitions & mappers to "constants.js" file * Flatten input parser for regions config & improve error reporting * Improve regions_config field description * Cleanups * Refactor upserting & deleting regions to use exposes.composite instead of JSON as input * Move constants & mappers to xiaomi-specific file * Change region_event into action to leverage HA-integration features * Update xiaomi.js * Update utils.js * Update constants.js * Update xiaomi.js Co-authored-by: Koen Kanters <[email protected]>
This is exciting! It looks like it is getting close. Thank you to all that helped with this! |
Nice to see some progress on this topic. But, it does not work...Setting a region works after some attempts but when i reload the page, the settings are gone. Somehow not saved.... |
That does not necessarily mean the settings were not saved. Have you tried to actually trigger a region event? To verify whether the setting upload (to the device) was successful, you can try to trigger a region event, and verify if it's present in the logs or in momentary I'm unaware of any option to retrieve these settings from the device, so settings are uploaded to the device, but not persisted anywhere in Z2M. Maybe there's a way to persist this in Z2M's state as a secondary settings storage, but I'm not that proficient with Z2M's architecture to know that. |
@mdziekon thx for your answer. i tried setting regions over MQTT as well in the z2m UI and also tried to manually add them in the state.json file, non of them seems to work. Manually adding it in the state.json file:
Btw: I walked around with my Macbook but never got an action :) Log
|
I have this in the homebridge log: what does it means? |
Setting it in I've just tried out the new update (as I usually wait a couple of days for the rest of the stuff to stabilise), tested it on two FP1s I have currently wired up (one in the kitchen, one in the bathroom). I was able to add a region (y = 1, x = 1,2,3,4, so quite a wide area of detection) at my kitchen's sensor, and after that it properly detects the region events:
I was also able to trigger a simpe mobile notification using this HomeAssistant automation: alias: test
description: ""
trigger:
- platform: state
entity_id:
- sensor.kitchen_presence_sensor_action
to: region_1_enter
condition: []
action:
- service: notify.grouped_bygroup_admin_mobile
data:
message: "Triggered: Kitchen, region 1, event enter"
mode: single However, for some weird reason, my other sensor (in the bathroom) doesn't pick up the update, and after some time there's an error log with a timeout from that device. However, it's not the first time I'm seeing this particular device acting up, it's either broken or I have to pair it again to fix its behavior. |
@mdziekon i have 3 FP1‘s but not 1 is working. Are you using the Sonoff Zigbee Dongle (2652P)? With which firmware? |
@chrigu1981 no, I'm using conbee II, with the latest firmware, and all my FP1s have been updated to the latest firmware version. |
@mdziekon Just to clarify, all are working but not with regions. Not sure if i have the latest FW on the sensors but i will try to update them…. Anyway many thanks for your help! |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days |
I'm closing this issue since it's merged, any future issues with regions should probably just be their own. |
about this... I just spent 2 hours setting up regions for my office (which work), but as soon as my wife sat down on her desk, my own desk region stopped getting detected.... do regions only work with 1 single person? if so, what is the limitation here? |
Is your feature request related to a problem? Please describe
Region support in the Aqara FP1 sensor would be great, there are folks who have issues with ceiling fans, and other areas of a monitored room that require ignoring for the sensor to function properly
Describe the solution you'd like
Aqara FP1 device itself supports regions, but that feature is not in zigbee2mqtt, I'd like to be able to define regions, and have region information in the detection event so that I can filter in / out events that I care about.
Describe alternatives you've considered
Positioning the sensor in a way so that it's not seeing the region, but of course, that means there are other regions that I miss.
Additional context
I'm honestly not sure exactly how regions work or are implemented in the FP1, so I'm kind of guessing at what's possible here.
The text was updated successfully, but these errors were encountered: