mirror of
https://github.com/adrianjagielak/home-assistant-futurehome.git
synced 2025-09-13 15:47:08 +00:00
Add demo mode
This commit is contained in:
parent
8546610ffd
commit
8a3f7e72bb
@ -1,6 +1,6 @@
|
|||||||
# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config
|
# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config
|
||||||
name: Futurehome
|
name: Futurehome
|
||||||
version: "0.0.15"
|
version: "0.0.16"
|
||||||
slug: futurehome
|
slug: futurehome
|
||||||
description: Local Futurehome Smarthub integration
|
description: Local Futurehome Smarthub integration
|
||||||
url: "https://github.com/adrianjagielak/home-assistant-futurehome"
|
url: "https://github.com/adrianjagielak/home-assistant-futurehome"
|
||||||
@ -19,10 +19,12 @@ options:
|
|||||||
hub_ip: ""
|
hub_ip: ""
|
||||||
username: ""
|
username: ""
|
||||||
password: ""
|
password: ""
|
||||||
|
demo_mode: false
|
||||||
|
|
||||||
schema:
|
schema:
|
||||||
hub_ip: "str?"
|
hub_ip: "str?"
|
||||||
username: "str"
|
username: "str?"
|
||||||
password: "str"
|
password: "str?"
|
||||||
|
demo_mode: "bool?"
|
||||||
|
|
||||||
image: "ghcr.io/adrianjagielak/{arch}-home-assistant-futurehome"
|
image: "ghcr.io/adrianjagielak/{arch}-home-assistant-futurehome"
|
||||||
|
@ -8,6 +8,7 @@ set -e
|
|||||||
export FH_HUB_IP=$(bashio::config 'hub_ip')
|
export FH_HUB_IP=$(bashio::config 'hub_ip')
|
||||||
export FH_USERNAME=$(bashio::config 'username')
|
export FH_USERNAME=$(bashio::config 'username')
|
||||||
export FH_PASSWORD=$(bashio::config 'password')
|
export FH_PASSWORD=$(bashio::config 'password')
|
||||||
|
export DEMO_MODE=$(bashio::config 'demo_mode')
|
||||||
|
|
||||||
export MQTT_HOST=$(bashio::services mqtt "host")
|
export MQTT_HOST=$(bashio::services mqtt "host")
|
||||||
export MQTT_PORT=$(bashio::services mqtt "port")
|
export MQTT_PORT=$(bashio::services mqtt "port")
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { MqttClient } from "mqtt";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import { IMqttClient } from "./mqtt/interface";
|
||||||
|
|
||||||
export function exposeSmarthubTools(
|
export function exposeSmarthubTools(
|
||||||
ha: MqttClient,
|
ha: IMqttClient,
|
||||||
fimp: MqttClient,
|
fimp: IMqttClient,
|
||||||
hubAddr = "pt:j1/mt:cmd/rt:app/rn:zb/ad:1"
|
hubAddr = "pt:j1/mt:cmd/rt:app/rn:zb/ad:1"
|
||||||
) {
|
) {
|
||||||
const base = "homeassistant/switch/fh_zb_pairing";
|
const base = "homeassistant/switch/fh_zb_pairing";
|
||||||
@ -22,7 +22,7 @@ export function exposeSmarthubTools(
|
|||||||
stat_t: `${base}/state`,
|
stat_t: `${base}/state`,
|
||||||
device,
|
device,
|
||||||
}),
|
}),
|
||||||
{ retain: true }
|
{ retain: true, qos: 2 }
|
||||||
);
|
);
|
||||||
|
|
||||||
// // keep last known state locally
|
// // keep last known state locally
|
||||||
@ -35,7 +35,7 @@ export function exposeSmarthubTools(
|
|||||||
|
|
||||||
// // optimistic update so the UI flips instantly
|
// // optimistic update so the UI flips instantly
|
||||||
// pairingOn = turnOn;
|
// pairingOn = turnOn;
|
||||||
ha.publish(`${base}/state`, turnOn ? "ON" : "OFF", { retain: true });
|
ha.publish(`${base}/state`, turnOn ? "ON" : "OFF", { retain: true, qos: 2 });
|
||||||
|
|
||||||
// placeholder FIMP message – adjust to real API if different
|
// placeholder FIMP message – adjust to real API if different
|
||||||
fimp.publish(
|
fimp.publish(
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import mqtt, { MqttClient } from "mqtt";
|
import { DemoFimpMqttClient } from "./mqtt/demo_client";
|
||||||
|
import { IMqttClient } from "./mqtt/interface";
|
||||||
|
import { RealMqttClient } from "./mqtt/real_client";
|
||||||
|
|
||||||
export function connectHub(opts: { hubIp: string; username: string; password: string; }): Promise<MqttClient> {
|
export function connectHub(opts: { hubIp: string; username: string; password: string; demo: boolean; }): Promise<IMqttClient> { const url = `mqtt://${opts.hubIp || "futurehome-smarthub.local"}`;
|
||||||
const url = `mqtt://${opts.hubIp || "futurehome-smarthub.local"}`;
|
return makeClient(url, 1884, opts.username, opts.password, opts.demo);
|
||||||
return makeClient(url, 1884, opts.username, opts.password);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function connectHA(opts: { mqttHost: string; mqttPort: number; mqttUsername: string; mqttPassword: string; }): Promise<{ ha: MqttClient; retainedMessages: RetainedMessage[] }> {
|
export async function connectHA(opts: { mqttHost: string; mqttPort: number; mqttUsername: string; mqttPassword: string; }): Promise<{ ha: IMqttClient; retainedMessages: RetainedMessage[] }> {
|
||||||
const url = `mqtt://${opts.mqttHost}`;
|
const url = `mqtt://${opts.mqttHost}`;
|
||||||
let ha = await makeClient(url, opts.mqttPort, opts.mqttUsername, opts.mqttPassword);
|
let ha = await makeClient(url, opts.mqttPort, opts.mqttUsername, opts.mqttPassword, false);
|
||||||
let retainedMessages = await waitForHARetainedMessages(ha)
|
let retainedMessages = await waitForHARetainedMessages(ha)
|
||||||
|
|
||||||
return { ha, retainedMessages };
|
return { ha, retainedMessages };
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeClient(url: string, port: number, username: string, password: string): Promise<MqttClient> {
|
function makeClient(url: string, port: number, username: string, password: string, demo: boolean): Promise<IMqttClient> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const client = mqtt.connect(url, { port, username, password, protocolVersion: 4 });
|
const client = demo ? new DemoFimpMqttClient() : new RealMqttClient();
|
||||||
|
client.connect(url, { port, username, password, protocolVersion: 4 });
|
||||||
client.once("connect", () => resolve(client));
|
client.once("connect", () => resolve(client));
|
||||||
client.once("error", reject);
|
client.once("error", reject);
|
||||||
});
|
});
|
||||||
@ -24,7 +26,7 @@ function makeClient(url: string, port: number, username: string, password: strin
|
|||||||
type RetainedMessage = { topic: string; message: string };
|
type RetainedMessage = { topic: string; message: string };
|
||||||
|
|
||||||
async function waitForHARetainedMessages(
|
async function waitForHARetainedMessages(
|
||||||
client: MqttClient,
|
client: IMqttClient,
|
||||||
timeoutMs = 3000
|
timeoutMs = 3000
|
||||||
): Promise<RetainedMessage[]> {
|
): Promise<RetainedMessage[]> {
|
||||||
const topicPattern = /^homeassistant\/device\/futurehome.*$/;
|
const topicPattern = /^homeassistant\/device\/futurehome.*$/;
|
||||||
@ -32,7 +34,7 @@ async function waitForHARetainedMessages(
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const retainedMessages: RetainedMessage[] = [];
|
const retainedMessages: RetainedMessage[] = [];
|
||||||
|
|
||||||
const messageHandler = (topic: string, message: Buffer, packet: any) => {
|
const messageHandler = (topic: string, message: Buffer, packet: { retain?: boolean }) => {
|
||||||
if (packet.retain && topicPattern.test(topic)) {
|
if (packet.retain && topicPattern.test(topic)) {
|
||||||
retainedMessages.push({ topic, message: message.toString() });
|
retainedMessages.push({ topic, message: message.toString() });
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { MqttClient } from "mqtt/*";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { log } from "../logger";
|
import { log } from "../logger";
|
||||||
|
import { IMqttClient } from "../mqtt/interface";
|
||||||
|
|
||||||
let fimp: MqttClient | undefined = undefined;
|
let fimp: IMqttClient | undefined = undefined;
|
||||||
|
|
||||||
export function setFimp(client: MqttClient) {
|
export function setFimp(client: IMqttClient) {
|
||||||
fimp = client;
|
fimp = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,14 +57,6 @@ export async function sendFimpMsg({
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// For example for "cmd.foo.set" we would expect to get "evt.foo.report" back (plus the service name must match).
|
|
||||||
let possibleResponseType: string | null = null;
|
|
||||||
if (cmd.split('.').length === 3) {
|
|
||||||
possibleResponseType = cmd.split('.').map(
|
|
||||||
(part, index, array) => index === 0 ? 'evt' : (index === array.length - 1 ? 'report' : part),
|
|
||||||
).join('.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
fimp?.removeListener('message', onResponse);
|
fimp?.removeListener('message', onResponse);
|
||||||
@ -112,16 +104,6 @@ export async function sendFimpMsg({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(adrianjagielak): is this needed?
|
|
||||||
// if (possibleResponseType != null && msg.type === possibleResponseType && msg.serv === parameters.service) {
|
|
||||||
// log.debug(`Received FIMP response for message ${uid} (matched using possible response type "${possibleResponseType}").`);
|
|
||||||
//
|
|
||||||
// clearTimeout(timeout);
|
|
||||||
// effectiveMqttClient.removeListener('message', onResponse);
|
|
||||||
// resolve(msg);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
const hasValidType = msg.type != null && msg.type.startsWith('evt.');
|
const hasValidType = msg.type != null && msg.type.startsWith('evt.');
|
||||||
const reqCmdParts = cmd.split('.');
|
const reqCmdParts = cmd.split('.');
|
||||||
const resCmdParts = msg.type?.split('.') ?? [];
|
const resCmdParts = msg.type?.split('.') ?? [];
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { MqttClient } from "mqtt/*";
|
import { IMqttClient } from "../mqtt/interface";
|
||||||
import { CommandHandlers } from "./publish_device";
|
import { CommandHandlers } from "./publish_device";
|
||||||
|
|
||||||
export let ha: MqttClient | undefined = undefined;
|
export let ha: IMqttClient | undefined = undefined;
|
||||||
|
|
||||||
export function setHa(client: MqttClient) {
|
export function setHa(client: IMqttClient) {
|
||||||
ha = client;
|
ha = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,24 +11,33 @@ import { VinculumPd7Device } from "./fimp/vinculum_pd7_device";
|
|||||||
import { haUpdateAvailability } from "./ha/update_availability";
|
import { haUpdateAvailability } from "./ha/update_availability";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const hubIp = process.env.FH_HUB_IP || "";
|
const hubIp = process.env.FH_HUB_IP || '';
|
||||||
const hubUsername = process.env.FH_USERNAME || "";
|
const hubUsername = process.env.FH_USERNAME || '';
|
||||||
const hubPassword = process.env.FH_PASSWORD || "";
|
const hubPassword = process.env.FH_PASSWORD || '';
|
||||||
|
const demoMode = (process.env.DEMO_MODE || '').toLowerCase().includes('true');
|
||||||
|
|
||||||
const mqttHost = process.env.MQTT_HOST || "";
|
const mqttHost = process.env.MQTT_HOST || '';
|
||||||
const mqttPort = Number(process.env.MQTT_PORT || "1883");
|
const mqttPort = Number(process.env.MQTT_PORT || '1883');
|
||||||
const mqttUsername = process.env.MQTT_USER || "";
|
const mqttUsername = process.env.MQTT_USER || '';
|
||||||
const mqttPassword = process.env.MQTT_PWD || "";
|
const mqttPassword = process.env.MQTT_PWD || '';
|
||||||
|
|
||||||
// 1) Connect to HA broker (for discovery + state)
|
// 1) Connect to HA broker (for discovery + state + availability + commands)
|
||||||
log.info("Connecting to HA broker...");
|
log.info("Connecting to HA broker...");
|
||||||
const { ha, retainedMessages } = await connectHA({ mqttHost, mqttPort, mqttUsername, mqttPassword, });
|
const { ha, retainedMessages } = await connectHA({ mqttHost, mqttPort, mqttUsername, mqttPassword, });
|
||||||
setHa(ha);
|
setHa(ha);
|
||||||
log.info("Connected to HA broker");
|
log.info("Connected to HA broker");
|
||||||
|
|
||||||
|
if (!demoMode && (!hubUsername || !hubPassword)) {
|
||||||
|
log.info("Empty username or password in non-demo mode. Removing all Futurehome devices from Home Assistant...");
|
||||||
|
retainedMessages.forEach((retainedMessage) => {
|
||||||
|
ha?.publish(retainedMessage.topic, '', { retain: true, qos: 2 });
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 2) Connect to Futurehome hub (FIMP traffic)
|
// 2) Connect to Futurehome hub (FIMP traffic)
|
||||||
log.info("Connecting to Futurehome hub...");
|
log.info("Connecting to Futurehome hub...");
|
||||||
const fimp = await connectHub({ hubIp, username: hubUsername, password: hubPassword });
|
const fimp = await connectHub({ hubIp, username: hubUsername, password: hubPassword, demo: demoMode });
|
||||||
fimp.subscribe("#");
|
fimp.subscribe("#");
|
||||||
setFimp(fimp);
|
setFimp(fimp);
|
||||||
log.info("Connected to Futurehome hub");
|
log.info("Connected to Futurehome hub");
|
||||||
@ -39,6 +48,7 @@ import { haUpdateAvailability } from "./ha/update_availability";
|
|||||||
cmd: 'cmd.pd7.request',
|
cmd: 'cmd.pd7.request',
|
||||||
val: { cmd: "get", component: null, param: { components: ['house'] } },
|
val: { cmd: "get", component: null, param: { components: ['house'] } },
|
||||||
val_t: 'object',
|
val_t: 'object',
|
||||||
|
timeoutMs: 30000,
|
||||||
});
|
});
|
||||||
let hubId = house.val.param.house.hubId;
|
let hubId = house.val.param.house.hubId;
|
||||||
|
|
||||||
@ -48,6 +58,7 @@ import { haUpdateAvailability } from "./ha/update_availability";
|
|||||||
cmd: 'cmd.pd7.request',
|
cmd: 'cmd.pd7.request',
|
||||||
val: { cmd: "get", component: null, param: { components: ['device'] } },
|
val: { cmd: "get", component: null, param: { components: ['device'] } },
|
||||||
val_t: 'object',
|
val_t: 'object',
|
||||||
|
timeoutMs: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const haConfig = retainedMessages.filter(msg => msg.topic.endsWith("/config"));
|
const haConfig = retainedMessages.filter(msg => msg.topic.endsWith("/config"));
|
||||||
@ -160,6 +171,7 @@ import { haUpdateAvailability } from "./ha/update_availability";
|
|||||||
cmd: 'cmd.pd7.request',
|
cmd: 'cmd.pd7.request',
|
||||||
val: { cmd: "get", component: null, param: { components: ['state'] } },
|
val: { cmd: "get", component: null, param: { components: ['state'] } },
|
||||||
val_t: 'object',
|
val_t: 'object',
|
||||||
|
timeoutMs: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
ha.on('message', (topic, buf) => {
|
ha.on('message', (topic, buf) => {
|
||||||
|
95
futurehome/src/mqtt/demo_client.ts
Normal file
95
futurehome/src/mqtt/demo_client.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { OnErrorCallback, OnMessageCallback } from 'mqtt/*';
|
||||||
|
import { IMqttClient } from './interface';
|
||||||
|
import { Buffer } from 'buffer';
|
||||||
|
import { FimpResponse } from '../fimp/fimp';
|
||||||
|
import demo_data__state from './demo_data/state.json';
|
||||||
|
import demo_data__device from './demo_data/device.json';
|
||||||
|
|
||||||
|
export class DemoFimpMqttClient implements IMqttClient {
|
||||||
|
private messageHandlers = new Set<OnMessageCallback>();
|
||||||
|
private errorHandlers = new Set<OnErrorCallback>();
|
||||||
|
private onceConnectHandlers: (() => void)[] = [];
|
||||||
|
private onceErrorHandlers: OnErrorCallback[] = [];
|
||||||
|
|
||||||
|
connect(url: string, options: {
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
protocolVersion: 4;
|
||||||
|
}): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.onceConnectHandlers.forEach((h) => h());
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(topicObject: string, opts?: { qos: 0 | 1 | 2 }, callback?: (err: Error | null) => void): void;
|
||||||
|
subscribe(topic: string, opts?: any, callback?: any): void { }
|
||||||
|
|
||||||
|
publish(topic: string, value: string, options: {
|
||||||
|
retain?: boolean;
|
||||||
|
qos: 0 | 1 | 2;
|
||||||
|
}): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
const msg = JSON.parse(value)
|
||||||
|
|
||||||
|
const sendResponse = (response: FimpResponse) => {
|
||||||
|
response.corid = response.corid ?? msg.uid;
|
||||||
|
const buffer = Buffer.from(JSON.stringify(response));
|
||||||
|
for (const handler of this.messageHandlers) {
|
||||||
|
handler(topic, buffer, { retain: false } as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.serv == 'vinculum' && msg.type == 'cmd.pd7.request' && msg.val?.param?.components?.includes('house')) {
|
||||||
|
sendResponse({ type: 'evt.pd7.response', val: { param: { house: { hubId: '000000004c38b232' } } } })
|
||||||
|
} else if (msg.serv == 'vinculum' && msg.type == 'cmd.pd7.request' && msg.val?.param?.components?.includes('device')) {
|
||||||
|
sendResponse({ type: 'evt.pd7.response', val: { param: { device: demo_data__device } } });
|
||||||
|
} else if (msg.serv == 'vinculum' && msg.type == 'cmd.pd7.request' && msg.val?.param?.components?.includes('state')) {
|
||||||
|
sendResponse({ type: 'evt.pd7.response', val: { param: { state: { devices: demo_data__state } } } })
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
on(event: 'message', handler: OnMessageCallback): void;
|
||||||
|
on(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
on(event: any, handler: any): void {
|
||||||
|
if (event === 'message') {
|
||||||
|
this.messageHandlers.add(handler);
|
||||||
|
} else if (event === 'error') {
|
||||||
|
this.errorHandlers.add(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
off(event: 'message', handler: OnMessageCallback): void;
|
||||||
|
off(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
off(event: any, handler: any): void {
|
||||||
|
if (event === 'message') {
|
||||||
|
this.messageHandlers.delete(handler);
|
||||||
|
} else if (event === 'error') {
|
||||||
|
this.errorHandlers.delete(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeListener(event: 'message', handler: OnMessageCallback): void {
|
||||||
|
this.off(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
once(event: 'connect', handler: () => void): void;
|
||||||
|
once(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
once(event: any, handler: any): void {
|
||||||
|
if (event === 'connect') {
|
||||||
|
this.onceConnectHandlers.push(handler);
|
||||||
|
} else if (event === 'error') {
|
||||||
|
this.onceErrorHandlers.push(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simulateError(message: string) {
|
||||||
|
const err = new Error(message);
|
||||||
|
for (const handler of this.errorHandlers) {
|
||||||
|
handler(err);
|
||||||
|
}
|
||||||
|
this.onceErrorHandlers.forEach((h) => h(err));
|
||||||
|
this.onceErrorHandlers = [];
|
||||||
|
}
|
||||||
|
}
|
2105
futurehome/src/mqtt/demo_data/device.json
Normal file
2105
futurehome/src/mqtt/demo_data/device.json
Normal file
File diff suppressed because it is too large
Load Diff
1141
futurehome/src/mqtt/demo_data/state.json
Normal file
1141
futurehome/src/mqtt/demo_data/state.json
Normal file
File diff suppressed because it is too large
Load Diff
29
futurehome/src/mqtt/interface.ts
Normal file
29
futurehome/src/mqtt/interface.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { IPublishPacket, OnErrorCallback, OnMessageCallback } from "mqtt/*";
|
||||||
|
|
||||||
|
export interface IMqttClient {
|
||||||
|
connect(url: string, options: {
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
protocolVersion: 4;
|
||||||
|
}): void;
|
||||||
|
|
||||||
|
subscribe(topic: string): void;
|
||||||
|
subscribe(topicObject: string, opts?: { qos: 0 | 1 | 2 }, callback?: (err: Error | null) => void): void;
|
||||||
|
|
||||||
|
publish(topic: string, value: string, options: {
|
||||||
|
retain?: boolean;
|
||||||
|
qos: 0 | 1 | 2;
|
||||||
|
}): void;
|
||||||
|
|
||||||
|
on(event: 'message', handler: OnMessageCallback): void;
|
||||||
|
on(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
|
||||||
|
off(event: 'message', handler: OnMessageCallback): void;
|
||||||
|
off(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
|
||||||
|
removeListener(event: 'message', handler: (topic: string, payload: Buffer, packet: IPublishPacket) => void): void;
|
||||||
|
|
||||||
|
once(event: 'connect', handler: () => void): void;
|
||||||
|
once(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
}
|
57
futurehome/src/mqtt/real_client.ts
Normal file
57
futurehome/src/mqtt/real_client.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { connect, IPublishPacket, MqttClient, OnErrorCallback, OnMessageCallback } from 'mqtt';
|
||||||
|
import { IMqttClient } from './interface';
|
||||||
|
|
||||||
|
export class RealMqttClient implements IMqttClient {
|
||||||
|
private client: MqttClient;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.client = {} as MqttClient; // gets initialized in connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(url: string, options: {
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
protocolVersion: 4;
|
||||||
|
}): void {
|
||||||
|
this.client = connect(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(topicObject: string, opts?: { qos: 0 | 1 | 2 }, callback?: (err: Error | null) => void): void;
|
||||||
|
subscribe(topic: string, opts?: any, callback?: any): void {
|
||||||
|
if (opts) {
|
||||||
|
this.client.subscribe(topic, opts, callback);
|
||||||
|
} else {
|
||||||
|
this.client.subscribe(topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publish(topic: string, value: string, options: {
|
||||||
|
retain?: boolean;
|
||||||
|
qos: 0 | 1 | 2;
|
||||||
|
}): void {
|
||||||
|
this.client.publish(topic, value, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
on(event: 'message', handler: OnMessageCallback): void;
|
||||||
|
on(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
on(event: any, handler: any): void {
|
||||||
|
this.client.on(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
off(event: 'message', handler: OnMessageCallback): void;
|
||||||
|
off(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
off(event: any, handler: any): void {
|
||||||
|
this.client.off(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeListener(event: 'message', handler: OnMessageCallback): void {
|
||||||
|
this.client.removeListener(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
once(event: 'connect', handler: () => void): void;
|
||||||
|
once(event: 'error', handler: OnErrorCallback): void;
|
||||||
|
once(event: any, handler: any): void {
|
||||||
|
this.client.once(event, handler);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user