Skip to content

Commit

Permalink
feat(homekit): Add motion sensors (#1914)
Browse files Browse the repository at this point in the history
  • Loading branch information
cicoub13 authored Jun 17, 2024
1 parent e83d529 commit 173a47b
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 1 deletion.
1 change: 1 addition & 0 deletions server/services/homekit/lib/buildService.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function buildService(device, features, categoryMapping) {
switch (`${feature.category}:${feature.type}`) {
case `${DEVICE_FEATURE_CATEGORIES.LIGHT}:${DEVICE_FEATURE_TYPES.LIGHT.BINARY}`:
case `${DEVICE_FEATURE_CATEGORIES.SWITCH}:${DEVICE_FEATURE_TYPES.SWITCH.BINARY}`:
case `${DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR}:${DEVICE_FEATURE_TYPES.SENSOR.BINARY}`:
case `${DEVICE_FEATURE_CATEGORIES.LEAK_SENSOR}:${DEVICE_FEATURE_TYPES.SENSOR.BINARY}`: {
const characteristic = service.getCharacteristic(
Characteristic[categoryMapping.capabilities[feature.type].characteristics[0]],
Expand Down
9 changes: 9 additions & 0 deletions server/services/homekit/lib/deviceMappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ const mappings = {
},
},
},
[DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR]: {
service: 'MotionSensor',
capabilities: {
[DEVICE_FEATURE_TYPES.SENSOR.BINARY]: {
characteristics: ['MotionDetected'],
notifDelay: 1000,
},
},
},
[DEVICE_FEATURE_CATEGORIES.LEAK_SENSOR]: {
service: 'LeakSensor',
capabilities: {
Expand Down
1 change: 1 addition & 0 deletions server/services/homekit/lib/sendState.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function sendState(hkAccessory, feature, event) {
switch (`${feature.category}:${feature.type}`) {
case `${DEVICE_FEATURE_CATEGORIES.LIGHT}:${DEVICE_FEATURE_TYPES.LIGHT.BINARY}`:
case `${DEVICE_FEATURE_CATEGORIES.SWITCH}:${DEVICE_FEATURE_TYPES.SWITCH.BINARY}`:
case `${DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR}:${DEVICE_FEATURE_TYPES.SENSOR.BINARY}`:
case `${DEVICE_FEATURE_CATEGORIES.LEAK_SENSOR}:${DEVICE_FEATURE_TYPES.SENSOR.BINARY}`: {
hkAccessory
.getService(Service[mappings[feature.category].service])
Expand Down
59 changes: 59 additions & 0 deletions server/test/services/homekit/lib/buildService.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,65 @@ describe('Build service', () => {
expect(cb.args[2][1]).to.equal(25);
});

it('should build motion sensor service', async () => {
homekitHandler.gladys.device.getBySelector = stub().resolves({
features: [
{
id: '31c6a4a7-9710-4951-bf34-04eeae5b9ff7',
name: 'Motion Detection',
category: DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR,
type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
last_value: 0,
},
],
});
const on = stub();
const getCharacteristic = stub().returns({
on,
props: {
perms: ['PAIRED_READ'],
},
});
const MotionSensor = stub().returns({
getCharacteristic,
});

homekitHandler.hap = {
Characteristic: {
MotionDetected: 'MOTIONDETECTED',
},
CharacteristicEventTypes: stub(),
Perms: {
PAIRED_READ: 'PAIRED_READ',
PAIRED_WRITE: 'PAIRED_WRITE',
},
Service: {
MotionSensor,
},
};
const device = {
name: 'Détecteur garage',
};
const features = [
{
id: '31c6a4a7-9710-4951-bf34-04eeae5b9ff7',
name: 'Motion Detection',
category: DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR,
type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
},
];

const cb = stub();

await homekitHandler.buildService(device, features, mappings[DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR]);
await on.args[0][1](cb);

expect(MotionSensor.args[0][0]).to.equal('Détecteur garage');
expect(on.callCount).to.equal(1);
expect(getCharacteristic.args[0][0]).to.equal('MOTIONDETECTED');
expect(cb.args[0][1]).to.equal(0);
});

it('should build contact sensor service', async () => {
homekitHandler.gladys.device.getBySelector = stub().resolves({
features: [
Expand Down
29 changes: 28 additions & 1 deletion server/test/services/homekit/lib/sendState.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const {
DEVICE_FEATURE_UNITS,
} = require('../../../../utils/constants');

describe('Notify change to HomeKit', () => {
describe('Send state to HomeKit', () => {
const homekitHandler = {
serviceId: '7056e3d4-31cc-4d2a-bbdd-128cd49755e6',
sendState,
Expand All @@ -23,10 +23,12 @@ describe('Notify change to HomeKit', () => {
Saturation: 'SATURATION',
ColorTemperature: 'COLORTEMPERATURE',
ContactSensorState: 'CONTACTSENSORSTATE',
MotionDetected: 'MOTIONDETECTED',
CurrentTemperature: 'CURRENTTEMPERATURE',
},
Service: {
ContactSensor: 'CONTACTSENSOR',
MotionSensor: 'MOTIONSENSOR',
},
},
notifyTimeouts: {},
Expand Down Expand Up @@ -82,6 +84,31 @@ describe('Notify change to HomeKit', () => {
expect(updateCharacteristic.args[0]).eql(['CONTACTSENSORSTATE', 1]);
});

it('should notify motion sensor', async () => {
const updateCharacteristic = stub().returns();
const accessory = {
UUID: '4756151c-369e-4772-8bf7-943a6ac70583',
getService: stub().returns({ updateCharacteristic }),
};

const event = {
type: EVENTS.DEVICE.NEW_STATE,
last_value: 0,
};

const feature = {
id: '4f7060d7-7960-4c68-b435-8952bf3f40bf',
device_id: '4756151c-369e-4772-8bf7-943a6ac70583',
name: 'Motion sensor',
category: DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR,
type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
};

await homekitHandler.sendState(accessory, feature, event);

expect(updateCharacteristic.args[0]).eql(['MOTIONDETECTED', 0]);
});

it('should notify light brightness', async () => {
const updateValue = stub().returns();
const accessory = {
Expand Down

0 comments on commit 173a47b

Please sign in to comment.