Skip to content

Commit

Permalink
mqtt: support default external brokers
Browse files Browse the repository at this point in the history
  • Loading branch information
koush committed Dec 14, 2023
1 parent 18ae09e commit 99d1dc7
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 38 deletions.
4 changes: 2 additions & 2 deletions plugins/mqtt/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 plugins/mqtt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@
"@scrypted/common": "file:../../common",
"@types/nunjucks": "^3.2.0"
},
"version": "0.0.75"
"version": "0.0.76"
}
36 changes: 32 additions & 4 deletions plugins/mqtt/src/api/mqtt-device-base.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Settings, Setting, ScryptedDeviceBase, ScryptedInterface } from '@scrypted/sdk';
import { connect, Client } from 'mqtt';
import { ScriptableDeviceBase } from '../scrypted-eval';
import type {MqttProvider} from '../main';

export class MqttDeviceBase extends ScriptableDeviceBase implements Settings {
client: Client;
handler: any;
pathname: string;

constructor(nativeId: string) {
constructor(public provider: MqttProvider, nativeId: string) {
super(nativeId, undefined);
}

Expand Down Expand Up @@ -53,9 +54,36 @@ export class MqttDeviceBase extends ScriptableDeviceBase implements Settings {
this.client?.removeAllListeners();
this.client?.end();
this.client = undefined;
const url = new URL(this.storage.getItem('url'));
this.pathname = url.pathname.substring(1);
const urlWithoutPath = new URL(this.storage.getItem('url'));
const urlString = this.storage.getItem('url');
let url: URL;
let username: string;
let password: string;

const externalBroker = this.provider.storage.getItem('externalBroker');
if (urlString) {
this.console.log('Using device specific broker.', urlString);
url = new URL(urlString);
username = this.storage.getItem('username') || undefined;
password = this.storage.getItem('password') || undefined;
this.pathname = url.pathname.substring(1);
}
else if (externalBroker && !this.provider.isBrokerEnabled) {
this.console.log('Using external broker.', externalBroker);
url = new URL(externalBroker);
username = this.provider.storage.getItem('username') || undefined;
password = this.provider.storage.getItem('password') || undefined;
this.pathname = `${url.pathname.substring(1)}/${this.id}`;
}
else {
this.console.log('Using built in broker.');
const tcpPort = this.provider.storage.getItem('tcpPort') || '';
url = new URL(`mqtt://localhost:${tcpPort}/scrypted`);
username = this.provider.storage.getItem('username') || undefined;
password = this.provider.storage.getItem('password') || undefined;
this.pathname = `${url.pathname.substring(1)}/${this.id}`;
}

const urlWithoutPath = new URL(url);
urlWithoutPath.pathname = '';

const client = this.client = connect(urlWithoutPath.toString(), {
Expand Down
5 changes: 3 additions & 2 deletions plugins/mqtt/src/autodiscovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Client, MqttClient, connect } from "mqtt";
import { MqttDeviceBase } from "./api/mqtt-device-base";
import nunjucks from 'nunjucks';
import sdk from "@scrypted/sdk";
import type { MqttProvider } from './main';

const { deviceManager } = sdk;

Expand Down Expand Up @@ -60,8 +61,8 @@ typeMap.set('binary_sensor', {
export class MqttAutoDiscoveryProvider extends MqttDeviceBase implements DeviceProvider {
devices = new Map<string, MqttAutoDiscoveryDevice>();

constructor(nativeId: string) {
super(nativeId);
constructor(provider: MqttProvider, nativeId: string) {
super(provider, nativeId);

this.bind();
}
Expand Down
84 changes: 55 additions & 29 deletions plugins/mqtt/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const loopbackLight = filterExample('loopback-light.ts');
const { log, deviceManager, systemManager } = sdk;

class MqttDevice extends MqttDeviceBase implements Scriptable {
constructor(nativeId: string) {
super(nativeId);
constructor(provider: MqttProvider, nativeId: string) {
super(provider, nativeId);
}

async saveScript(source: ScriptSource): Promise<void> {
Expand Down Expand Up @@ -154,7 +154,7 @@ class MqttDevice extends MqttDeviceBase implements Scriptable {
}
}

const brokerProperties = ['httpPort', 'tcpPort', 'enableBroker', 'username', 'password'];
const brokerProperties = ['httpPort', 'tcpPort', 'enableBroker', 'username', 'password', 'externalBroker'];


class MqttPublisherMixin extends SettingsMixinDeviceBase<any> {
Expand Down Expand Up @@ -250,17 +250,28 @@ class MqttPublisherMixin extends SettingsMixinDeviceBase<any> {
let url: URL;
let username: string;
let password: string;

const externalBroker = this.provider.storage.getItem('externalBroker');
if (urlString) {
this.console.log('Using device specific broker.', urlString);
url = new URL(urlString);
username = this.storage.getItem('username') || undefined;
password = this.storage.getItem('password') || undefined;
this.pathname = url.pathname.substring(1);
}
else if (externalBroker && !this.provider.isBrokerEnabled) {
this.console.log('Using external broker.', externalBroker);
url = new URL(externalBroker);
username = this.provider.storage.getItem('username') || undefined;
password = this.provider.storage.getItem('password') || undefined;
this.pathname = `${url.pathname.substring(1)}/${this.id}`;
}
else {
this.console.log('Using built in broker.');
const tcpPort = this.provider.storage.getItem('tcpPort') || '';
url = new URL(`mqtt://localhost:${tcpPort}/scrypted`);
username = this.provider.storage.getItem('username') || undefined;
password = this.provider.storage.getItem('password') || undefined;
url = new URL(`mqtt://localhost:${tcpPort}/scrypted`);
this.pathname = `${url.pathname.substring(1)}/${this.id}`;
}

Expand Down Expand Up @@ -330,7 +341,7 @@ class MqttPublisherMixin extends SettingsMixinDeviceBase<any> {
}
}

class MqttProvider extends ScryptedDeviceBase implements DeviceProvider, Settings, MixinProvider, DeviceCreator {
export class MqttProvider extends ScryptedDeviceBase implements DeviceProvider, Settings, MixinProvider, DeviceCreator {
devices = new Map<string, any>();
netServer: net.Server;
httpServer: http.Server;
Expand Down Expand Up @@ -393,15 +404,25 @@ class MqttProvider extends ScryptedDeviceBase implements DeviceProvider, Setting
{
title: 'Enable MQTT Broker',
key: 'enableBroker',
description: 'Enable the Aedes MQTT Broker.',
description: 'Enable the built in Aedes MQTT Broker.',
// group: 'MQTT Broker',
type: 'boolean',
value: (this.storage.getItem('enableBroker') === 'true').toString(),
},
];

if (!this.isBrokerEnabled)
return ret;
if (!this.isBrokerEnabled) {
ret.push(
{
title: 'External Broker',
group: 'MQTT Broker',
key: 'externalBroker',
description: 'Specify the mqtt address of an external MQTT broker.',
placeholder: 'mqtt://192.168.1.100',
value: this.storage.getItem('externalBroker'),
}
)
}

ret.push(
{
Expand All @@ -418,27 +439,32 @@ class MqttProvider extends ScryptedDeviceBase implements DeviceProvider, Setting
key: 'password',
type: 'password',
description: 'Optional: Password used to authenticate with the MQTT broker.',
},
{
title: 'TCP Port',
key: 'tcpPort',
description: 'The port to use for TCP connections',
placeholder: '1883',
type: 'number',
group: 'MQTT Broker',
value: this.storage.getItem('tcpPort'),
},
{
title: 'HTTP Port',
key: 'httpPort',
description: 'The port to use for HTTP connections',
placeholder: '8888',
type: 'number',
group: 'MQTT Broker',
value: this.storage.getItem('httpPort'),
},
}
);

if (this.isBrokerEnabled) {
ret.push(
{
title: 'TCP Port',
key: 'tcpPort',
description: 'The port to use for TCP connections',
placeholder: '1883',
type: 'number',
group: 'MQTT Broker',
value: this.storage.getItem('tcpPort'),
},
{
title: 'HTTP Port',
key: 'httpPort',
description: 'The port to use for HTTP connections',
placeholder: '8888',
type: 'number',
group: 'MQTT Broker',
value: this.storage.getItem('httpPort'),
},
);
}

ret.push(...await this.storageSettings.getSettings());
return ret;
}
Expand Down Expand Up @@ -547,10 +573,10 @@ class MqttProvider extends ScryptedDeviceBase implements DeviceProvider, Setting
let ret = this.devices.get(nativeId);
if (!ret) {
if (nativeId.startsWith('autodiscovery:')) {
ret = new MqttAutoDiscoveryProvider(nativeId);
ret = new MqttAutoDiscoveryProvider(this, nativeId);
}
else if (nativeId.startsWith('0.')) {
ret = new MqttDevice(nativeId);
ret = new MqttDevice(this, nativeId);
await ret.bind();
}
if (ret)
Expand Down

0 comments on commit 99d1dc7

Please sign in to comment.