Skip to content

Commit

Permalink
Add suppport for MQTT message matching via RegExp
Browse files Browse the repository at this point in the history
  • Loading branch information
tjmehta committed Dec 31, 2022
1 parent dfbf2cb commit 4cfde7d
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 21 deletions.
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,14 @@ Other users have been sharing configurations that work for them on our GitHub si
### Camera MQTT Parameters

- `motionTopic`: The MQTT topic to watch for motion alerts.
- `motionMessage`: The message to watch for to trigger motion alerts. Will use the name of the camera if blank.
- `motionMessage`: The message to watch for to trigger motion alerts. Will use the name of the camera if both `motionMessage` and `motionMessageRegExp` are blank.
- `motionMessageRegExp`: A RegExp string to match messages on the motion mqtt topic and trigger motion alerts. Ex: '".*"' will match any message.
- `motionResetTopic`: The MQTT topic to watch for motion resets.
- `motionResetMessage`: The message to watch for to trigger motion resets. Will use the name of the camera if blank.
- `motionResetMessage`: The message to watch for to trigger motion resets. Will use the name of the camera if both `motionResetMessage` and `motionResetMessageRegExp` are blank.
- `motionResetMessageRegExp`: A RegExp string to match messages on the motionReset mqtt topic and trigger motion alerts. Ex: '"/.*/"' will match any message.
- `doorbellTopic`: The MQTT topic to watch for doorbell alerts.
- `doorbellMessage`: The message to watch for to trigger doorbell alerts. Will use the name of the camera if blank.
- `doorbellMessage`: The message to watch for to trigger doorbell alerts. Will use the name of the camera if both `doorbellMessage` and `doorbellMessageRegExp` are blank.
- `doorbellMessageRegExp`: A RegExp string to match messages on the doorbell mqtt topic and trigger motion alerts. Ex: '".*"' will match any message.

#### Camera MQTT Example

Expand All @@ -165,6 +168,30 @@ Other users have been sharing configurations that work for them on our GitHub si
}
```

#### Camera MQTT Example with RegExp Message Matching

```json
{
"platform": "Camera-ffmpeg",
"cameras": [
{
"name": "Camera Name",
"videoConfig": {
"source": "-i rtsp://myfancy_rtsp_stream"
},
"mqtt": {
"motionTopic": "home/camera",
"motionMessageRegExp": "ON", // will match any message that contains "ON"
"motionResetTopic": "home/camera",
"motionResetMessageRegExp": "OFF", // will match any message that contains "OFF"
"doorbellTopic": "home/doobell",
"doorbellMessageRegExp": ".*" // will match all messages
}
}
]
}
```

### Automation Parameters

- `mqtt`: Defines the hostname or IP of the MQTT broker to connect to for MQTT-based automation. If not set, MQTT support is not started. See the project site for [more information on using MQTT](https://sunoo.github.io/homebridge-camera-ffmpeg/automation/mqtt.html).
Expand Down
3 changes: 3 additions & 0 deletions src/configTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ export type VideoConfig = {
export type MqttCameraConfig = {
motionTopic?: string;
motionMessage?: string;
motionMessageRegExp?: string;
motionResetTopic?: string;
motionResetMessage?: string;
motionResetMessageRegExp?: string;
doorbellTopic?: string;
doorbellMessage?: string;
doorbellMessageRegExp?: string;
};
80 changes: 62 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import {
PlatformAccessoryEvent,
PlatformConfig
} from 'homebridge';
import http from 'http';
import mqtt from 'mqtt';
import { AutomationReturn } from './autoTypes';
import { CameraConfig, FfmpegPlatformConfig } from './configTypes';

import { AutomationReturn } from './autoTypes';
import { Logger } from './logger';
import { StreamingDelegate } from './streamingDelegate';
import http from 'http';
import mqtt from 'mqtt';

const version = require('../package.json').version; // eslint-disable-line @typescript-eslint/no-var-requires

let hap: HAP;
Expand All @@ -40,7 +42,10 @@ class FfmpegPlatform implements DynamicPlatformPlugin {
private readonly accessories: Array<PlatformAccessory> = [];
private readonly motionTimers: Map<string, NodeJS.Timeout> = new Map();
private readonly doorbellTimers: Map<string, NodeJS.Timeout> = new Map();
private readonly mqttActions: Map<string, Map<string, Array<MqttAction>>> = new Map();
private readonly mqttActions: Map<string, {
messageMap: Map<string, Array<MqttAction>> | undefined,
reMap: Map<RegExp, Array<MqttAction>> | undefined,
}> = new Map();

constructor(log: Logging, config: PlatformConfig, api: API) {
this.log = new Logger(log);
Expand Down Expand Up @@ -92,12 +97,22 @@ class FfmpegPlatform implements DynamicPlatformPlugin {
api.on(APIEvent.DID_FINISH_LAUNCHING, this.didFinishLaunching.bind(this));
}

addMqttAction(topic: string, message: string, details: MqttAction): void {
const messageMap = this.mqttActions.get(topic) || new Map();
const actionArray = messageMap.get(message) || [];
actionArray.push(details);
messageMap.set(message, actionArray);
this.mqttActions.set(topic, messageMap);
addMqttAction(topic: string, message: string | RegExp, details: MqttAction): void {
let { messageMap, reMap } = this.mqttActions.get(topic) || { messageMap: undefined, reMap: undefined };
let actionArray

if (typeof message === 'string') {
actionArray = messageMap?.get(message) || []
messageMap = messageMap || new Map()
actionArray.push(details);
messageMap.set(message, actionArray);
} else { // RegExp
actionArray = reMap?.get(message) || []
reMap = reMap || new Map()
actionArray.push(details);
reMap.set(message, actionArray)
}
this.mqttActions.set(topic, {messageMap, reMap});
}

setupAccessory(accessory: PlatformAccessory, cameraConfig: CameraConfig): void {
Expand Down Expand Up @@ -171,16 +186,32 @@ class FfmpegPlatform implements DynamicPlatformPlugin {
if (this.config.mqtt) {
if (cameraConfig.mqtt) {
if (cameraConfig.mqtt.motionTopic) {
this.addMqttAction(cameraConfig.mqtt.motionTopic, cameraConfig.mqtt.motionMessage || cameraConfig.name!,
{accessory: accessory, active: true, doorbell: false});
if (cameraConfig.mqtt.motionMessageRegExp) {
this.addMqttAction(cameraConfig.mqtt.motionTopic, new RegExp(cameraConfig.mqtt.motionMessageRegExp),
{accessory: accessory, active: true, doorbell: false});
} else {
this.addMqttAction(cameraConfig.mqtt.motionTopic, cameraConfig.mqtt.motionMessage || cameraConfig.name!,
{accessory: accessory, active: true, doorbell: false});
}
}
if (cameraConfig.mqtt.motionResetTopic) {
this.addMqttAction(cameraConfig.mqtt.motionResetTopic, cameraConfig.mqtt.motionResetMessage || cameraConfig.name!,
{accessory: accessory, active: false, doorbell: false});
if (cameraConfig.mqtt.motionResetMessageRegExp) {
this.addMqttAction(cameraConfig.mqtt.motionResetTopic, new RegExp(cameraConfig.mqtt.motionResetMessageRegExp),
{accessory: accessory, active: false, doorbell: false});
} else {
this.addMqttAction(cameraConfig.mqtt.motionResetTopic, cameraConfig.mqtt.motionResetMessage || cameraConfig.name!,
{accessory: accessory, active: false, doorbell: false});
}

}
if (cameraConfig.mqtt.doorbellTopic) {
this.addMqttAction(cameraConfig.mqtt.doorbellTopic, cameraConfig.mqtt.doorbellMessage || cameraConfig.name!,
{accessory: accessory, active: true, doorbell: true});
if (cameraConfig.mqtt.doorbellMessageRegExp) {
this.addMqttAction(cameraConfig.mqtt.doorbellTopic, new RegExp(cameraConfig.mqtt.doorbellMessageRegExp),
{accessory: accessory, active: true, doorbell: true});
} else {
this.addMqttAction(cameraConfig.mqtt.doorbellTopic, cameraConfig.mqtt.doorbellMessage || cameraConfig.name!,
{accessory: accessory, active: true, doorbell: true});
}
}
}
}
Expand Down Expand Up @@ -367,7 +398,7 @@ class FfmpegPlatform implements DynamicPlatformPlugin {
}
});
client.on('message', (topic: string, message: Buffer) => {
const messageMap = this.mqttActions.get(topic);
const { messageMap, reMap } = this.mqttActions.get(topic) || { messageMap: undefined, reMap: undefined };
if (messageMap) {
const actionArray = messageMap.get(message.toString());
if (actionArray) {
Expand All @@ -380,6 +411,19 @@ class FfmpegPlatform implements DynamicPlatformPlugin {
}
}
}
if (reMap) {
for (const [re, actionArray] of reMap) {
if (re.test(message.toString())) {
for (const action of actionArray) {
if (action.doorbell) {
this.doorbellHandler(action.accessory, action.active);
} else {
this.motionHandler(action.accessory, action.active);
}
}
}
}
}
});
}
if (this.config.porthttp) {
Expand Down Expand Up @@ -421,4 +465,4 @@ export = (api: API): void => {
Accessory = api.platformAccessory;

api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, FfmpegPlatform);
};
};

0 comments on commit 4cfde7d

Please sign in to comment.