Skip to content

Commit dbe9df6

Browse files
committed
Duration simulator for valves
1 parent 87b5689 commit dbe9df6

15 files changed

Lines changed: 269 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
All notable changes to homebridge-dummy will be documented in this file.
44

5-
## 1.5.17-beta.0 ()
5+
## 1.5.17-beta.1 ()
6+
7+
### Added
8+
- 'Simulate Duration' option to enable auto-shutoff for [`Valves`](https://github.com/mpatfield/homebridge-easy-mqtt/wiki/Valve) that do not have duration topics
9+
- Minimum and Maximum 'Default Run Time' for [`Valve`](https://github.com/mpatfield/homebridge-easy-mqtt/wiki/Valve) accessory type
610

711
### Fixed
812
- Potential crash on launch

config.schema.template.json

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,20 @@
199199
"enum": ["GENERIC_VALVE", "IRRIGATION", "SHOWER_HEAD", "WATER_FAUCET"],
200200
"enumNames": ["${config.enumNames.valveGeneric}", "${config.enumNames.valveIrrigation}", "${config.enumNames.valveShower}", "${config.enumNames.valveFaucet}"]
201201
},
202+
"minimumDuration": {
203+
"type": "integer",
204+
"title": "${config.title.minimumDuration}",
205+
"minimum": 5
206+
},
207+
"maximumDuration": {
208+
"type": "integer",
209+
"title": "${config.title.maximumDuration}",
210+
"minimum": 5
211+
},
212+
"simulateDuration": {
213+
"type": "boolean",
214+
"title": "${config.title.simulateDuration}"
215+
},
202216
"autoReset": {
203217
"type": "object",
204218
"properties": {
@@ -1905,9 +1919,18 @@
19051919
{
19061920
"key": "accessories[].valveType",
19071921
"flex": "0 0 33%"
1922+
},
1923+
{
1924+
"key": "accessories[].minimumDuration",
1925+
"flex": "0 0 33%"
1926+
},
1927+
{
1928+
"key": "accessories[].maximumDuration",
1929+
"flex": "0 0 33%"
19081930
}
19091931
]
1910-
}
1932+
},
1933+
"accessories[].simulateDuration"
19111934
]
19121935
},
19131936
"accessories[].mqtt.broker",

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"displayName": "Homebridge Easy MQTT",
55
"description": "Homebridge plugin for MQTT devices",
66
"type": "module",
7-
"version": "1.5.17-beta.0",
7+
"version": "1.5.17-beta.1",
88
"homepage": "https://github.com/mpatfield/homebridge-easy-mqtt#readme",
99
"repository": {
1010
"type": "git",

src/accessory/abstract/common.ts

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ export abstract class Common<C extends Assertable> {
3434
public readonly name: string,
3535
) {}
3636

37+
public teardown() {
38+
if (this.timeout !== undefined && this.timeoutCallback !== undefined) {
39+
this.log.warning(strings.autoReset.teardown, this.name);
40+
clearTimeout(this.timeout);
41+
this.timeoutCallback();
42+
}
43+
}
44+
3745
protected abstract get service(): Service;
3846
protected abstract get Characteristic(): CharacteristicType;
3947
protected abstract get HapStatusError(): HapStatusErrorType;
@@ -47,6 +55,7 @@ export abstract class Common<C extends Assertable> {
4755
protected abstract get useStoredProperties(): boolean;
4856

4957
private timeout?: NodeJS.Timeout;
58+
private timeoutCallback?: () => (void);
5059

5160
protected abstract publish(rawTopic: string, value: PrimitiveTypes): void;
5261

@@ -232,30 +241,33 @@ export abstract class Common<C extends Assertable> {
232241
return characteristic;
233242
}
234243

235-
protected bindOnUpdateNumeric(key: CharacteristicKey, logTemplate: string, callback?: NumberCallback): OnUpdateHandler {
236-
return (async (_topic: string, value: PrimitiveTypes) => {
244+
protected onUpdateNumeric(key: CharacteristicKey, value: PrimitiveTypes, logTemplate?: string, callback?: NumberCallback) {
237245

238-
if (typeof value !== 'number') {
239-
this.log.error(strings.characteristic.badValue, this.name, key, `'${value.toString()}'`);
240-
return;
241-
}
246+
if (typeof value !== 'number') {
247+
this.log.error(strings.characteristic.badValue, this.name, key, `'${value.toString()}'`);
248+
return;
249+
}
242250

243-
const characteristic = this.service.getCharacteristic(this.characteristicFromKey(key));
244-
const minValue = characteristic.props.minValue;
245-
const maxValue = characteristic.props.maxValue;
246-
if (minValue !== undefined && value < minValue) {
247-
this.logIfDesired(LogType.WARNING, strings.characteristic.outOfRange, key, `'${value.toString()}'`, `'${minValue.toString()}'`);
248-
value = minValue;
249-
} else if (maxValue !== undefined && value > maxValue) {
250-
this.logIfDesired(LogType.WARNING, strings.characteristic.outOfRange, key, `'${value.toString()}'`, `'${maxValue.toString()}'`);
251-
value = maxValue;
252-
}
251+
const characteristic = this.service.getCharacteristic(this.characteristicFromKey(key));
252+
const minValue = characteristic.props.minValue;
253+
const maxValue = characteristic.props.maxValue;
254+
if (minValue !== undefined && value < minValue) {
255+
this.logIfDesired(LogType.WARNING, strings.characteristic.outOfRange, key, `'${value.toString()}'`, `'${minValue.toString()}'`);
256+
value = minValue;
257+
} else if (maxValue !== undefined && value > maxValue) {
258+
this.logIfDesired(LogType.WARNING, strings.characteristic.outOfRange, key, `'${value.toString()}'`, `'${maxValue.toString()}'`);
259+
value = maxValue;
260+
}
253261

254-
const logString = logTemplate.replace('%d', value.toString());
255-
this.onUpdate(key, value, logString);
262+
const logString = logTemplate !== undefined ? logTemplate.replace('%d', value.toString()) : undefined;
263+
this.onUpdate(key, value, logString);
256264

257-
callback?.(value);
265+
callback?.(value);
266+
}
258267

268+
protected bindOnUpdateNumeric(key: CharacteristicKey, logTemplate: string, callback?: NumberCallback): OnUpdateHandler {
269+
return (async (_topic: string, value: PrimitiveTypes) => {
270+
this.onUpdateNumeric(key, value, logTemplate, callback);
259271
}).bind(this);
260272
}
261273

@@ -413,36 +425,43 @@ export abstract class Common<C extends Assertable> {
413425
}).bind(this);
414426
}
415427

416-
protected bindOnSetBoolean(
417-
key: CharacteristicKey, setTopicKey: keyof C,
428+
protected onSetBoolean(
429+
key: CharacteristicKey, value: CharacteristicValue, setTopicKey: keyof C,
418430
trueValueKey: keyof C, falseValueKey: keyof C, trueValue: CharacteristicValue,
419431
trueLog: string, falseLog: string, callback?: BooleanCallback,
420432
) {
421-
return (async (value: CharacteristicValue) => {
422433

423-
if (!this.assert(setTopicKey, trueValueKey, falseValueKey)) {
424-
return;
425-
}
434+
if (!this.assert(setTopicKey, trueValueKey, falseValueKey)) {
435+
return;
436+
}
426437

427-
if (!setTopicKey.toString().startsWith('topic')) {
428-
throw new Error(`Trying to fetch topic with unexpected property name '${setTopicKey.toString()}'`);
429-
}
438+
if (!setTopicKey.toString().startsWith('topic')) {
439+
throw new Error(`Trying to fetch topic with unexpected property name '${setTopicKey.toString()}'`);
440+
}
430441

431-
if (!trueValueKey.toString().startsWith('value')) {
432-
throw new Error(`Trying to fetch value with unexpected property name '${trueValueKey.toString()}'`);
433-
}
442+
if (!trueValueKey.toString().startsWith('value')) {
443+
throw new Error(`Trying to fetch value with unexpected property name '${trueValueKey.toString()}'`);
444+
}
434445

435-
if (!falseValueKey.toString().startsWith('value')) {
436-
throw new Error(`Trying to fetch value with unexpected property name '${falseValueKey.toString()}'`);
437-
}
446+
if (!falseValueKey.toString().startsWith('value')) {
447+
throw new Error(`Trying to fetch value with unexpected property name '${falseValueKey.toString()}'`);
448+
}
438449

439-
const booleanValue = value === trueValue;
440-
const logString = booleanValue ? trueLog : falseLog;
441-
const publish = booleanValue ? this.getPrimitiveValue(trueValueKey)! : this.getPrimitiveValue(falseValueKey)!;
442-
this.onSet(key, value, publish, setTopicKey, logString);
450+
const booleanValue = value === trueValue;
451+
const logString = booleanValue ? trueLog : falseLog;
452+
const publish = booleanValue ? this.getPrimitiveValue(trueValueKey)! : this.getPrimitiveValue(falseValueKey)!;
453+
this.onSet(key, value, publish, setTopicKey, logString);
443454

444-
callback?.(booleanValue);
455+
callback?.(booleanValue);
456+
}
445457

458+
protected bindOnSetBoolean(
459+
key: CharacteristicKey, setTopicKey: keyof C,
460+
trueValueKey: keyof C, falseValueKey: keyof C, trueValue: CharacteristicValue,
461+
trueLog: string, falseLog: string, callback?: BooleanCallback,
462+
) {
463+
return (async (value: CharacteristicValue) => {
464+
this.onSetBoolean(key, value, setTopicKey, trueValueKey, falseValueKey, trueValue, trueLog, falseLog, callback);
446465
}).bind(this);
447466
}
448467

@@ -528,20 +547,24 @@ export abstract class Common<C extends Assertable> {
528547
return this.Characteristic[key];
529548
}
530549

531-
protected startTimeout(callback: () => void) {
550+
protected startTimeout(callback: () => void, config?: TimeoutConfig) {
532551

533552
if (this.timeout !== undefined) {
534553
this.logIfDesired(strings.autoReset.reset);
535554
}
536555

537556
clearTimeout(this.timeout);
538557
this.timeout = undefined;
558+
this.timeoutCallback = undefined;
539559

540-
if ( !('autoReset' in this.config) || this.config.autoReset === undefined) {
541-
return;
542-
}
560+
if (config === undefined) {
543561

544-
const config = this.config.autoReset as TimeoutConfig;
562+
if ( !('autoReset' in this.config) || this.config.autoReset === undefined) {
563+
return;
564+
}
565+
566+
config = this.config.autoReset as TimeoutConfig;
567+
}
545568

546569
if (!assert(this.log, this.name, config, 'time', 'units')) {
547570
return;
@@ -569,8 +592,10 @@ export abstract class Common<C extends Assertable> {
569592
break;
570593
}
571594

595+
this.timeoutCallback = callback;
572596
this.timeout = setTimeout(() => {
573597
this.timeout = undefined;
598+
this.timeoutCallback = undefined;
574599
callback();
575600
}, delay);
576601

src/accessory/abstract/mqtt.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ export abstract class MQTTAccessory<C extends MQTTAccessoryConfig> extends Commo
136136
this.mqttClient?.publish(this.identifier, topic, value);
137137
}
138138

139-
public teardown() {
139+
override teardown() {
140+
super.teardown();
140141
this.mqttClient?.teardown();
141142
}
142143

0 commit comments

Comments
 (0)