Skip to content

Commit

Permalink
Send state: off messages (#142)
Browse files Browse the repository at this point in the history
* Add "state": "on" to the MQTT messages
Fixes #139

* Send state: off mqtt messages
Fixes #141

* Send state: off mqtt messages
Fixes #141

* 1.7.0

* Update changelog
  • Loading branch information
neilenns authored Jun 7, 2020
1 parent bb752f6 commit 2a6ca13
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 6 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Change Log

## Unreleased
## Version 1.7.0

- Add a `state` property to the MQTT messages sent on motion detection. This
makes it easier to build binary motion sensors based on the MQTT messages in Home Assistant
by using `value_template: 'value_json.state'`. The delay before sending an `off` state is
configurable with the new `offDelay` setting on `mqtt` triggers. Resolves [issue 139](https://github.com/danecreekphotography/node-deepstackai-trigger/issues/139) and [issue 141](https://github.com/danecreekphotography/node-deepstackai-trigger/issues/141).

- Add a `"state": "on"` property to the MQTT messages sent on motion detection. This
makes it easier to build binary motion sensors based on the MQTT messages in Home Assistant
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,6 +1,6 @@
{
"name": "node-deepstackai-trigger",
"version": "1.6.0",
"version": "1.7.0",
"description": "Detects motion using DeepStack AI and calls registered triggers based on trigger rules.",
"main": "dist/src/main.js",
"files": [
Expand Down
3 changes: 2 additions & 1 deletion sampleConfiguration/triggers.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"triggerUris": ["http://localhost:81/admin?trigger&camera=Dog"]
},
"mqtt": {
"topic": "aimotion/triggers/dog"
"topic": "aimotion/triggers/dog",
"offDelay": 5
},
"telegram": {
"chatIds": [1],
Expand Down
1 change: 1 addition & 0 deletions src/handlers/mqttManager/IMqttConfigJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
*--------------------------------------------------------------------------------------------*/
export default interface IMqttConfigJson {
topic: string;
offDelay: number;
}
4 changes: 4 additions & 0 deletions src/handlers/mqttManager/MqttConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
export default class MqttConfig {
public topic: string;
public enabled: boolean;
public offDelay: number;

constructor(init?: Partial<MqttConfig>) {
Object.assign(this, init);

// Default for enabled is true if it isn't specified in the config file
this.enabled = init?.enabled ?? true;

// Default offDelay is 30 seconds if not specified
this.offDelay = init?.offDelay ?? 30;
}
}
23 changes: 22 additions & 1 deletion src/handlers/mqttManager/MqttManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import MQTT from "async-mqtt";
import MQTT, { IPublishPacket } from "async-mqtt";
import * as fs from "fs";
import * as JSONC from "jsonc-parser";
import path from "path";
Expand All @@ -17,6 +17,7 @@ import IMqttManagerConfigJson from "./IMqttManagerConfigJson";

let isEnabled = false;
let mqttClient: MQTT.AsyncClient;
const timers = new Map<string, NodeJS.Timeout>();

/**
* Takes a path to a configuration file and loads all of the triggers from it.
Expand Down Expand Up @@ -94,6 +95,22 @@ export async function processTrigger(

log.info("MQTT Manager", `${fileName}: Publishing event to ${trigger.mqttConfig.topic}`);

// If an off delay is configured set up a timer to send the off message in the requested number of seconds
if (trigger?.mqttConfig?.offDelay) {
const existingTimer = timers.get(trigger.mqttConfig.topic);

// Cancel any timer that may still be running for the same topic
if (existingTimer) {
clearTimeout(existingTimer);
}

// Set the new timer
timers.set(
trigger.mqttConfig.topic,
setTimeout(publishOffEvent, trigger.mqttConfig.offDelay * 1000, trigger.mqttConfig.topic),
);
}

// Even though this only calls one topic the way this gets used elsewhere
// the expectation is it returns an array.
return [
Expand All @@ -109,6 +126,10 @@ export async function processTrigger(
];
}

async function publishOffEvent(topic: string): Promise<IPublishPacket> {
return await mqttClient.publish(topic, JSON.stringify({ state: "off" }));
}

/**
* Loads a trigger configuration file
* @param configFilePath The path to the configuration file
Expand Down
6 changes: 6 additions & 0 deletions src/schemas/mqttHandlerConfiguration.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
"minLength": 1,
"examples": ["aimotion/trigger/dog"]
},
"offDelay": {
"description": "Number of seconds of no motion to wait before sending an MQTT state off message. Set to 0 to disable sending off messages. Default is 30 seconds.",
"type": "number",
"default": 30,
"examples": ["0", "300"]
},
"enabled": {
"description": "Enables the MQTT handler on this trigger. Default is true.",
"type": "boolean",
Expand Down
15 changes: 14 additions & 1 deletion tests/handlers/MqttConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import MqttConfig from "../../src/handlers/mqttManager/MqttConfig";

test("Verify MQTT handler configuration", () => {
// Empty constructor should default to enabled true
// Empty constructor should default to enabled true and offDelay 30
let config = new MqttConfig();
expect(config.enabled).toBe(true);
expect(config.offDelay).toBe(30);

// Undefined enabled should be true
config = new MqttConfig({ enabled: undefined });
Expand All @@ -20,4 +21,16 @@ test("Verify MQTT handler configuration", () => {
// Explicitly set enabled false should be false
config = new MqttConfig({ enabled: false });
expect(config.enabled).toBe(false);

// Undefined offDelay should default to 30
config = new MqttConfig({ offDelay: undefined });
expect(config.offDelay).toBe(30);

// 0 offDelay should be 0
config = new MqttConfig({ offDelay: 0 });
expect(config.offDelay).toBe(0);

// 60 offDelay should be 60
config = new MqttConfig({ offDelay: 60 });
expect(config.offDelay).toBe(60);
});

0 comments on commit 2a6ca13

Please sign in to comment.