Skip to content

Commit

Permalink
1.2.0
Browse files Browse the repository at this point in the history
* New way of parsing the JSON response regarding the status of the Shelly Uni.
* New ability of suppressing future rings for a number of seconds after an initial ring took place.
* New possibility of specifying the order of the buttons to be pressed
* Bug fixes
  • Loading branch information
denisgabriel5 committed Jun 30, 2024
1 parent 15e5f7c commit 271b30b
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 41 deletions.
66 changes: 51 additions & 15 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,18 @@
"timeout": {
"title": "Timeout",
"type": "number",
"placeholder": 10,
"minimum": 1,
"default": 10,
"minimum": 5,
"maximum": 60,
"required": false,
"required": true,
"description": "The number of seconds between the unlocking and locking notifications. Defaults to 10 seconds."
},
"intercomType": {
"title": "Intercom",
"type": "string",
"required": true,
"default": "form",
"description": "Select your intercom model.",
"oneOf": [
{
"title": "None",
"enum": [
"none"
]
},
{
"title": "Shelly Uni",
"enum": [
Expand All @@ -72,6 +65,27 @@
"functionBody": "return model.intercomType === \"shellyUni\";"
}
},
"shellyUniStatusJsonPath": {
"title": "Status JSON Path",
"type": "string",
"required": true,
"placeholder": "field1.0.field2",
"description": "Path in JSON structure to the field that changes upon ringing.",
"condition": {
"functionBody": "return model.intercomType === \"shellyUni\";"
}
},
"shellyUniStatusThreshold": {
"title": "Status Threshold",
"type": "number",
"required": true,
"minimum": 1,
"maximum": 100,
"description": "The minimum value of the field that changes upon ringing.",
"condition": {
"functionBody": "return model.intercomType === \"shellyUni\";"
}
},
"shellyUniTalkUrl": {
"title": "Talk URL",
"type": "string",
Expand All @@ -90,14 +104,36 @@
"functionBody": "return model.intercomType === \"shellyUni\";"
}
},
"buttonsTimeout": {
"shellyUniButtonsOrder": {
"title": "Buttons pressing order",
"type": "string",
"required": true,
"default": "open-talk",
"placeholder": "open-talk-talk",
"description": "Some intercoms require different pressing order. The default one is pressing the Talk button, then the Open button, but others might require an additional press of the Talk or Open button.",
"condition": {
"functionBody": "return model.intercomType === \"shellyUni\";"
}
},
"shellyUniButtonsTimeout": {
"title": "Buttons timeout",
"type": "number",
"placeholder": 1,
"default": 1,
"minimum": 1,
"maximum": 10,
"required": false,
"description": "The number of seconds between \"pressing\" the Talk button and Open button. Defaults to 1 second.",
"maximum": 5,
"required": true,
"description": "The number of seconds between \"pressing\" the buttons. Defaults to 1 second.",
"condition": {
"functionBody": "return model.intercomType === \"shellyUni\";"
}
},
"shellyUniRingSuppressionTimeout": {
"title": "Ring suppression timeout",
"type": "number",
"default": 0,
"minimum": 0,
"required": true,
"description": "The number of seconds to ignore any other changing in the status of the Shelly Uni (changing that implies that the intercom is ringing).",
"condition": {
"functionBody": "return model.intercomType === \"shellyUni\";"
}
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"displayName": "Intercom",
"name": "homebridge-intercom",
"version": "1.1.2",
"version": "1.2.0",
"description": "Manage your old intercom via Homebridge. \nIt consists of two accessories: a doorbell (for checking and notifyng if the intercom rings) and a lock mechanism (for opening the intercom door).",
"license": "Apache-2.0",
"homepage": "https://github.com/denisgabriel5/homebridge-intercom",
Expand Down
6 changes: 5 additions & 1 deletion src/intercomPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ export interface IntercomConfig extends PlatformConfig {
timeout?: number;
intercomType?: string;
shellyUniStatusUrl?: string;
shellyUniStatusJsonPath?: string;
shellyUniStatusThreshold?: string;
shellyUniTalkUrl?: string;
shellyUniOpenUrl?: string;
buttonsTimeout?: number;
shellyUniButtonsTimeout?: number;
shellyUniButtonsOrder?: string;
shellyUniRingSuppressionTimeout?: number;
}

/**
Expand Down
18 changes: 15 additions & 3 deletions src/shellyUni/shellyUniDoorbell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class ShellyUniDoorbell {
private readonly Characteristic: typeof Characteristic;
private displayName = 'Doorbell';
private ringSensorService;
private ringSuppressed;

public service: Service;

Expand All @@ -32,22 +33,33 @@ export class ShellyUniDoorbell {
// create handlers for required characteristics
this.ringSensorService.getCharacteristic(this.Characteristic.OccupancyDetected)
.onGet(this.handleOccupancyDetectedGet.bind(this));
this.ringSuppressed = false;

this.parent.platform.log.debug('Started checking the intercom');

// continously check the status of the intercom
setInterval(async () => {
const status = (await axios.get(this.parent.config.shellyUniStatusUrl!)).data;
const statusData = (await axios.get(this.parent.config.shellyUniStatusUrl!)).data;
const status = this.parent.config.shellyUniStatusJsonPath!.split('.').reduce((k, v) => {
return k && k[v];
}, statusData);

if (status['adcs'][0]['voltage'] > 1 && !this.ringSensorService.getCharacteristic(this.Characteristic.OccupancyDetected).value) {
if (status > this.parent.config.shellyUniStatusThreshold! &&
!this.ringSensorService.getCharacteristic(this.Characteristic.OccupancyDetected).value) {
this.parent.platform.log.debug('Intercom rang');

this.service.updateCharacteristic(this.Characteristic.ProgrammableSwitchEvent, this.ring());
this.ringSensorService.updateCharacteristic(this.Characteristic.OccupancyDetected,
this.Characteristic.OccupancyDetected.OCCUPANCY_DETECTED);

this.ringSuppressed = true;

setTimeout(async () => {
this.ringSuppressed = false;
}, this.parent.config.shellyUniRingSuppressionTimeout! * 1000);
}

if (status['adcs'][0]['voltage'] === 0) {
if (status < this.parent.config.shellyUniStatusThreshold! && !this.ringSuppressed) {
this.ringSensorService.updateCharacteristic(this.Characteristic.OccupancyDetected,
this.Characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED);
}
Expand Down
61 changes: 41 additions & 20 deletions src/shellyUni/shellyUniLockMechanism.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ export class ShellyUniLockMechanism {
private readonly Service: typeof Service;
private readonly Characteristic: typeof Characteristic;
private displayName = 'LockMechanism';
// private targetState: CharacteristicValue;
// private currentState: CharacteristicValue;
public service: Service;

constructor(
Expand Down Expand Up @@ -59,35 +57,58 @@ export class ShellyUniLockMechanism {
/**
* Handle requests to set the "Lock Target State" characteristic
*/
handleLockTargetStateSet(value: CharacteristicValue) {
async handleLockTargetStateSet(value: CharacteristicValue) {
this.parent.platform.log.debug('Triggered SET LockTargetState: ', value);

// the door locks automatially so we ignore locking requests altogether
if (value === this.Characteristic.LockCurrentState.SECURED) {
return;
}

// in order to open the intercom door you must press the talking button and then the open door button
// so press the talk button with the following setTimeout
setTimeout(async () => {
await axios.post(this.parent.config.shellyUniTalkUrl!);
this.parent.platform.log.debug('Intercom talk button pressed');
}, 0);

// and after roughly 1 second press the second button and also mark the intercom as open/unlocked/unsecured
setTimeout(async () => {
await axios.post(this.parent.config.shellyUniOpenUrl!);
this.parent.platform.log.debug('Intercom open button pressed');
this.service.updateCharacteristic(this.Characteristic.LockTargetState, this.Characteristic.LockCurrentState.UNSECURED);
this.service.updateCharacteristic(this.Characteristic.LockCurrentState, this.Characteristic.LockCurrentState.UNSECURED);
this.parent.platform.log.debug('Intercom opened');
}, this.parent.config.buttonsTimeout! * 1000);

// in the end mark the intercom as closed/locked/secured
// press the buttons in the specified order
const buttons = this.parent.config.shellyUniButtonsOrder!.split('-');

for (let i = 0; i < buttons.length; i++) {
switch (buttons[i]) {
case 'open':
axios.get(this.parent.config.shellyUniOpenUrl!);
this.parent.platform.log.debug('Intercom Open button pressed');
break;

case 'talk':
axios.get(this.parent.config.shellyUniTalkUrl!);
this.parent.platform.log.debug('Intercom Talk button pressed');
break;

default:
this.parent.platform.log.error(`Button ${buttons[i]} is wrong!`);
break;
}

if (i === buttons.length - 1) {
// mark the intercom as open/unlocked/unsecured
this.service.updateCharacteristic(this.Characteristic.LockTargetState, this.Characteristic.LockCurrentState.UNSECURED);
this.service.updateCharacteristic(this.Characteristic.LockCurrentState, this.Characteristic.LockCurrentState.UNSECURED);
this.parent.platform.log.debug('Intercom opened');

break;
} else {
await this.sleep(this.parent.config.shellyUniButtonsTimeout! * 1000);
}
}

// in the end, mark the intercom as closed/locked/secured
setTimeout(() => {
this.service.updateCharacteristic(this.Characteristic.LockTargetState, this.Characteristic.LockCurrentState.SECURED);
this.service.updateCharacteristic(this.Characteristic.LockCurrentState, this.Characteristic.LockCurrentState.SECURED);
this.parent.platform.log.debug('Intercom closed');
}, this.parent.config.timeout! * 1000);
}

/**
* Delays the execution for a number of specified seconds
*/
sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}

0 comments on commit 271b30b

Please sign in to comment.