@marcel2215/homebridge-supla-plugin 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +176 -0
- package/README.md +31 -0
- package/config.json +3 -0
- package/config.schema.json +52 -0
- package/dist/Accesories/ActionTriggerAccessory.d.ts +13 -0
- package/dist/Accesories/ActionTriggerAccessory.d.ts.map +1 -0
- package/dist/Accesories/ActionTriggerAccessory.js +43 -0
- package/dist/Accesories/ActionTriggerAccessory.js.map +1 -0
- package/dist/Accesories/AirQualityAccessory.d.ts +18 -0
- package/dist/Accesories/AirQualityAccessory.d.ts.map +1 -0
- package/dist/Accesories/AirQualityAccessory.js +91 -0
- package/dist/Accesories/AirQualityAccessory.js.map +1 -0
- package/dist/Accesories/ContactSensorAccessory.d.ts +14 -0
- package/dist/Accesories/ContactSensorAccessory.d.ts.map +1 -0
- package/dist/Accesories/ContactSensorAccessory.js +40 -0
- package/dist/Accesories/ContactSensorAccessory.js.map +1 -0
- package/dist/Accesories/DimmerAccessory.d.ts +20 -0
- package/dist/Accesories/DimmerAccessory.d.ts.map +1 -0
- package/dist/Accesories/DimmerAccessory.js +73 -0
- package/dist/Accesories/DimmerAccessory.js.map +1 -0
- package/dist/Accesories/DimmerRgbLightAccessory.d.ts +28 -0
- package/dist/Accesories/DimmerRgbLightAccessory.d.ts.map +1 -0
- package/dist/Accesories/DimmerRgbLightAccessory.js +125 -0
- package/dist/Accesories/DimmerRgbLightAccessory.js.map +1 -0
- package/dist/Accesories/ElectricityMeterAccessory.d.ts +17 -0
- package/dist/Accesories/ElectricityMeterAccessory.d.ts.map +1 -0
- package/dist/Accesories/ElectricityMeterAccessory.js +65 -0
- package/dist/Accesories/ElectricityMeterAccessory.js.map +1 -0
- package/dist/Accesories/FacadeBlindAccessory.d.ts +29 -0
- package/dist/Accesories/FacadeBlindAccessory.d.ts.map +1 -0
- package/dist/Accesories/FacadeBlindAccessory.js +123 -0
- package/dist/Accesories/FacadeBlindAccessory.js.map +1 -0
- package/dist/Accesories/GarageDoorOpenerAccesory.d.ts +17 -0
- package/dist/Accesories/GarageDoorOpenerAccesory.d.ts.map +1 -0
- package/dist/Accesories/GarageDoorOpenerAccesory.js +63 -0
- package/dist/Accesories/GarageDoorOpenerAccesory.js.map +1 -0
- package/dist/Accesories/LeakSensorAccessory.d.ts +14 -0
- package/dist/Accesories/LeakSensorAccessory.d.ts.map +1 -0
- package/dist/Accesories/LeakSensorAccessory.js +40 -0
- package/dist/Accesories/LeakSensorAccessory.js.map +1 -0
- package/dist/Accesories/LightBulbAccesory.d.ts +17 -0
- package/dist/Accesories/LightBulbAccesory.d.ts.map +1 -0
- package/dist/Accesories/LightBulbAccesory.js +56 -0
- package/dist/Accesories/LightBulbAccesory.js.map +1 -0
- package/dist/Accesories/PressureAccessory.d.ts +15 -0
- package/dist/Accesories/PressureAccessory.d.ts.map +1 -0
- package/dist/Accesories/PressureAccessory.js +43 -0
- package/dist/Accesories/PressureAccessory.js.map +1 -0
- package/dist/Accesories/RGBLightBulbAccesory.d.ts +24 -0
- package/dist/Accesories/RGBLightBulbAccesory.d.ts.map +1 -0
- package/dist/Accesories/RGBLightBulbAccesory.js +97 -0
- package/dist/Accesories/RGBLightBulbAccesory.js.map +1 -0
- package/dist/Accesories/RollerShutterAccessory.d.ts +22 -0
- package/dist/Accesories/RollerShutterAccessory.d.ts.map +1 -0
- package/dist/Accesories/RollerShutterAccessory.js +85 -0
- package/dist/Accesories/RollerShutterAccessory.js.map +1 -0
- package/dist/Accesories/SwitchAccessory.d.ts +17 -0
- package/dist/Accesories/SwitchAccessory.d.ts.map +1 -0
- package/dist/Accesories/SwitchAccessory.js +55 -0
- package/dist/Accesories/SwitchAccessory.js.map +1 -0
- package/dist/Accesories/TemperatureAccessory.d.ts +15 -0
- package/dist/Accesories/TemperatureAccessory.d.ts.map +1 -0
- package/dist/Accesories/TemperatureAccessory.js +43 -0
- package/dist/Accesories/TemperatureAccessory.js.map +1 -0
- package/dist/Accesories/TemperatureHumidityAccessory.d.ts +18 -0
- package/dist/Accesories/TemperatureHumidityAccessory.d.ts.map +1 -0
- package/dist/Accesories/TemperatureHumidityAccessory.js +62 -0
- package/dist/Accesories/TemperatureHumidityAccessory.js.map +1 -0
- package/dist/Accesories/ThermostatAccessory.d.ts +28 -0
- package/dist/Accesories/ThermostatAccessory.d.ts.map +1 -0
- package/dist/Accesories/ThermostatAccessory.js +166 -0
- package/dist/Accesories/ThermostatAccessory.js.map +1 -0
- package/dist/Accesories/ValveAccessory.d.ts +18 -0
- package/dist/Accesories/ValveAccessory.d.ts.map +1 -0
- package/dist/Accesories/ValveAccessory.js +63 -0
- package/dist/Accesories/ValveAccessory.js.map +1 -0
- package/dist/Accesories/WicketAccesory.d.ts +16 -0
- package/dist/Accesories/WicketAccesory.d.ts.map +1 -0
- package/dist/Accesories/WicketAccesory.js +51 -0
- package/dist/Accesories/WicketAccesory.js.map +1 -0
- package/dist/Heplers/ColorConverters.d.ts +17 -0
- package/dist/Heplers/ColorConverters.d.ts.map +1 -0
- package/dist/Heplers/ColorConverters.js +107 -0
- package/dist/Heplers/ColorConverters.js.map +1 -0
- package/dist/Heplers/SuplaChannelContext.d.ts +10 -0
- package/dist/Heplers/SuplaChannelContext.d.ts.map +1 -0
- package/dist/Heplers/SuplaChannelContext.js +15 -0
- package/dist/Heplers/SuplaChannelContext.js.map +1 -0
- package/dist/Heplers/SuplaMqttClient.d.ts +15 -0
- package/dist/Heplers/SuplaMqttClient.d.ts.map +1 -0
- package/dist/Heplers/SuplaMqttClient.js +169 -0
- package/dist/Heplers/SuplaMqttClient.js.map +1 -0
- package/dist/Heplers/SuplaMqttClientContext.d.ts +11 -0
- package/dist/Heplers/SuplaMqttClientContext.d.ts.map +1 -0
- package/dist/Heplers/SuplaMqttClientContext.js +16 -0
- package/dist/Heplers/SuplaMqttClientContext.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +36 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +320 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.d.ts +9 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +12 -0
- package/dist/settings.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuplaChannelContext.js","sourceRoot":"","sources":["../../src/Heplers/SuplaChannelContext.ts"],"names":[],"mappings":";;;AAAA,MAAa,mBAAmB;IAC9B,YACS,KAAa,EACb,WAAmB,EACnB,eAAuB,EACvB,cAAsB,EACtB,QAAgB,EAChB,SAAiB;QALjB,UAAK,GAAL,KAAK,CAAQ;QACb,gBAAW,GAAX,WAAW,CAAQ;QACnB,oBAAe,GAAf,eAAe,CAAQ;QACvB,mBAAc,GAAd,cAAc,CAAQ;QACtB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,cAAS,GAAT,SAAS,CAAQ;IAE1B,CAAC;CACF;AAVD,kDAUC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MqttClient } from 'mqtt';
|
|
2
|
+
import { Logger } from 'homebridge';
|
|
3
|
+
import { SuplaMqttClientContext } from './SuplaMqttClientContext';
|
|
4
|
+
import { SuplaChannelContext } from './SuplaChannelContext';
|
|
5
|
+
export declare class SuplaMqttClient {
|
|
6
|
+
private readonly context;
|
|
7
|
+
private readonly log;
|
|
8
|
+
client: MqttClient;
|
|
9
|
+
constructor(context: SuplaMqttClientContext, log: Logger);
|
|
10
|
+
discoverChannelsAsync(): Promise<Array<SuplaChannelContext>>;
|
|
11
|
+
private resolveProtocol;
|
|
12
|
+
private resolveIncludeHidden;
|
|
13
|
+
private escapeRegex;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=SuplaMqttClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuplaMqttClient.d.ts","sourceRoot":"","sources":["../../src/Heplers/SuplaMqttClient.ts"],"names":[],"mappings":"AAAA,OAAa,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;AACtC,OAAO,EAAC,MAAM,EAAC,MAAM,YAAY,CAAC;AAClC,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAE1D,qBAAa,eAAe;IAGxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAHf,MAAM,EAAE,UAAU,CAAC;gBAEP,OAAO,EAAG,sBAAsB,EAChC,GAAG,EAAG,MAAM;IAoClB,qBAAqB,IAAK,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAyH1E,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,WAAW;CAGpB"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SuplaMqttClient = void 0;
|
|
7
|
+
const mqtt_1 = __importDefault(require("mqtt"));
|
|
8
|
+
const SuplaChannelContext_1 = require("./SuplaChannelContext");
|
|
9
|
+
class SuplaMqttClient {
|
|
10
|
+
constructor(context, log) {
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.log = log;
|
|
13
|
+
const options = {
|
|
14
|
+
username: context.username,
|
|
15
|
+
password: context.password,
|
|
16
|
+
};
|
|
17
|
+
const protocol = this.resolveProtocol();
|
|
18
|
+
this.log.info(`MQTT connecting to ${protocol}://${context.host}:${context.port} as ${context.username}`);
|
|
19
|
+
if (!context.username || !context.host || !context.port) {
|
|
20
|
+
this.log.warn('MQTT config looks incomplete; check host/port/username.');
|
|
21
|
+
}
|
|
22
|
+
this.client = mqtt_1.default.connect(`${protocol}://${context.host}:${context.port}`, options);
|
|
23
|
+
this.client.setMaxListeners(0);
|
|
24
|
+
this.client.on('connect', () => {
|
|
25
|
+
this.log.info('MQTT client connected');
|
|
26
|
+
});
|
|
27
|
+
this.client.on('reconnect', () => {
|
|
28
|
+
this.log.warn('MQTT client reconnecting');
|
|
29
|
+
});
|
|
30
|
+
this.client.on('close', () => {
|
|
31
|
+
this.log.warn('MQTT client closed');
|
|
32
|
+
});
|
|
33
|
+
this.client.on('offline', () => {
|
|
34
|
+
this.log.warn('MQTT client offline');
|
|
35
|
+
});
|
|
36
|
+
this.client.on('end', () => {
|
|
37
|
+
this.log.warn('MQTT client disconnected');
|
|
38
|
+
});
|
|
39
|
+
this.client.on('error', (error) => {
|
|
40
|
+
this.log.error(`MQTT client error: ${error.message}`);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async discoverChannelsAsync() {
|
|
44
|
+
var _a, _b, _c, _d;
|
|
45
|
+
const subscriptionTopic = `supla/${this.context.username}/devices/+/channels/#`;
|
|
46
|
+
const includeHidden = this.resolveIncludeHidden();
|
|
47
|
+
const usernamePattern = this.escapeRegex(this.context.username);
|
|
48
|
+
this.log.info('Discovering channels via MQTT');
|
|
49
|
+
this.log.debug(`Discovery subscribe topic: ${subscriptionTopic} includeHidden=${includeHidden}`);
|
|
50
|
+
const channelMap = new Map();
|
|
51
|
+
let resolveDone;
|
|
52
|
+
const discoveryDone = new Promise((resolve) => {
|
|
53
|
+
resolveDone = resolve;
|
|
54
|
+
});
|
|
55
|
+
let quietTimer;
|
|
56
|
+
const maxWaitMs = 4000;
|
|
57
|
+
const quietWindowMs = 1000;
|
|
58
|
+
const maxTimer = setTimeout(() => resolveDone === null || resolveDone === void 0 ? void 0 : resolveDone(), maxWaitMs);
|
|
59
|
+
const messageHandler = (topic, message) => {
|
|
60
|
+
var _a;
|
|
61
|
+
const match = topic.match(new RegExp(`^supla/${usernamePattern}/devices/(\\d+)/channels/(\\d+)/(.*)$`));
|
|
62
|
+
if (!match) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const [, deviceId, channelId, suffix] = match;
|
|
66
|
+
const key = `${deviceId}:${channelId}`;
|
|
67
|
+
const entry = (_a = channelMap.get(key)) !== null && _a !== void 0 ? _a : { deviceId, channelId };
|
|
68
|
+
const value = message.toString();
|
|
69
|
+
switch (suffix) {
|
|
70
|
+
case 'type':
|
|
71
|
+
entry.channelType = value;
|
|
72
|
+
break;
|
|
73
|
+
case 'function':
|
|
74
|
+
entry.channelFunction = value;
|
|
75
|
+
break;
|
|
76
|
+
case 'caption':
|
|
77
|
+
entry.channelCaption = value;
|
|
78
|
+
break;
|
|
79
|
+
case 'hidden':
|
|
80
|
+
entry.hidden = value;
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
channelMap.set(key, entry);
|
|
86
|
+
if (quietTimer) {
|
|
87
|
+
clearTimeout(quietTimer);
|
|
88
|
+
}
|
|
89
|
+
quietTimer = setTimeout(() => resolveDone === null || resolveDone === void 0 ? void 0 : resolveDone(), quietWindowMs);
|
|
90
|
+
};
|
|
91
|
+
this.client.subscribe(subscriptionTopic, (err) => {
|
|
92
|
+
if (err) {
|
|
93
|
+
this.log.error(`MQTT subscribe failed for ${subscriptionTopic}: ${err.message}`);
|
|
94
|
+
resolveDone === null || resolveDone === void 0 ? void 0 : resolveDone();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
this.client.on('message', messageHandler);
|
|
98
|
+
await discoveryDone;
|
|
99
|
+
clearTimeout(maxTimer);
|
|
100
|
+
if (quietTimer) {
|
|
101
|
+
clearTimeout(quietTimer);
|
|
102
|
+
}
|
|
103
|
+
this.client.removeListener('message', messageHandler);
|
|
104
|
+
this.client.unsubscribe(subscriptionTopic, (err) => {
|
|
105
|
+
if (err) {
|
|
106
|
+
this.log.error(`MQTT unsubscribe failed for ${subscriptionTopic}: ${err.message}`);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const result = [];
|
|
110
|
+
let skippedHidden = 0;
|
|
111
|
+
for (const entry of channelMap.values()) {
|
|
112
|
+
const hiddenValue = (_a = entry.hidden) !== null && _a !== void 0 ? _a : 'false';
|
|
113
|
+
const hidden = typeof hiddenValue === 'string'
|
|
114
|
+
? hiddenValue.toLowerCase() === 'true'
|
|
115
|
+
: Boolean(hiddenValue);
|
|
116
|
+
if (hidden && !includeHidden) {
|
|
117
|
+
skippedHidden += 1;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const channelType = (_b = entry.channelType) !== null && _b !== void 0 ? _b : 'UNKNOWN';
|
|
121
|
+
const channelFunction = (_c = entry.channelFunction) !== null && _c !== void 0 ? _c : 'UNKNOWN';
|
|
122
|
+
const caption = (_d = entry.channelCaption) !== null && _d !== void 0 ? _d : `Device ${entry.deviceId} Channel ${entry.channelId}`;
|
|
123
|
+
const topic = `supla/${this.context.username}/devices/${entry.deviceId}/channels/${entry.channelId}`;
|
|
124
|
+
if (channelFunction === 'UNKNOWN' || channelType === 'UNKNOWN') {
|
|
125
|
+
this.log.warn(`Channel ${entry.deviceId}/${entry.channelId} missing metadata (function=${channelFunction}, type=${channelType})`);
|
|
126
|
+
}
|
|
127
|
+
this.log.debug(`Discovered channel ${caption} (${entry.deviceId}/${entry.channelId}) function=${channelFunction} type=${channelType}`);
|
|
128
|
+
result.push(new SuplaChannelContext_1.SuplaChannelContext(topic, channelType, channelFunction, caption, entry.deviceId, entry.channelId));
|
|
129
|
+
}
|
|
130
|
+
if (channelMap.size === 0) {
|
|
131
|
+
this.log.warn(`No channels discovered within ${maxWaitMs}ms. Check MQTT ACLs, username, or retained topics.`);
|
|
132
|
+
}
|
|
133
|
+
if (skippedHidden > 0 && !includeHidden) {
|
|
134
|
+
this.log.info(`Skipped ${skippedHidden} hidden channel(s). Set includeHidden=true to include them.`);
|
|
135
|
+
}
|
|
136
|
+
this.log.info(`MQTT discovery complete. Channels discovered: ${result.length}`);
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
resolveProtocol() {
|
|
140
|
+
var _a;
|
|
141
|
+
const rawProtocol = ((_a = this.context.protocol) !== null && _a !== void 0 ? _a : '').toString().toLowerCase();
|
|
142
|
+
const tlsFlag = this.context.tls;
|
|
143
|
+
const tlsEnabled = typeof tlsFlag === 'string'
|
|
144
|
+
? ['1', 'true', 'on', 'yes'].includes(tlsFlag.toLowerCase())
|
|
145
|
+
: Boolean(tlsFlag);
|
|
146
|
+
if (!rawProtocol) {
|
|
147
|
+
return tlsEnabled ? 'mqtts' : 'mqtt';
|
|
148
|
+
}
|
|
149
|
+
if (tlsEnabled && rawProtocol === 'mqtt') {
|
|
150
|
+
return 'mqtts';
|
|
151
|
+
}
|
|
152
|
+
if (tlsEnabled && rawProtocol === 'ws') {
|
|
153
|
+
return 'wss';
|
|
154
|
+
}
|
|
155
|
+
return rawProtocol;
|
|
156
|
+
}
|
|
157
|
+
resolveIncludeHidden() {
|
|
158
|
+
const raw = this.context.includeHidden;
|
|
159
|
+
if (typeof raw === 'string') {
|
|
160
|
+
return ['1', 'true', 'on', 'yes'].includes(raw.toLowerCase());
|
|
161
|
+
}
|
|
162
|
+
return Boolean(raw);
|
|
163
|
+
}
|
|
164
|
+
escapeRegex(value) {
|
|
165
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.SuplaMqttClient = SuplaMqttClient;
|
|
169
|
+
//# sourceMappingURL=SuplaMqttClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuplaMqttClient.js","sourceRoot":"","sources":["../../src/Heplers/SuplaMqttClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class SuplaMqttClientContext {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
username: string;
|
|
5
|
+
password: string;
|
|
6
|
+
protocol?: string | undefined;
|
|
7
|
+
tls?: string | boolean | undefined;
|
|
8
|
+
includeHidden?: string | boolean | undefined;
|
|
9
|
+
constructor(host: string, port: number, username: string, password: string, protocol?: string | undefined, tls?: string | boolean | undefined, includeHidden?: string | boolean | undefined);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=SuplaMqttClientContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuplaMqttClientContext.d.ts","sourceRoot":"","sources":["../../src/Heplers/SuplaMqttClientContext.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAsB;IAExB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,QAAQ,CAAC;IACT,GAAG,CAAC;IACJ,aAAa,CAAC;gBANd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,oBAAQ,EACjB,GAAG,CAAC,8BAAkB,EACtB,aAAa,CAAC,8BAAkB;CAG1C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SuplaMqttClientContext = void 0;
|
|
4
|
+
class SuplaMqttClientContext {
|
|
5
|
+
constructor(host, port, username, password, protocol, tls, includeHidden) {
|
|
6
|
+
this.host = host;
|
|
7
|
+
this.port = port;
|
|
8
|
+
this.username = username;
|
|
9
|
+
this.password = password;
|
|
10
|
+
this.protocol = protocol;
|
|
11
|
+
this.tls = tls;
|
|
12
|
+
this.includeHidden = includeHidden;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.SuplaMqttClientContext = SuplaMqttClientContext;
|
|
16
|
+
//# sourceMappingURL=SuplaMqttClientContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuplaMqttClientContext.js","sourceRoot":"","sources":["../../src/Heplers/SuplaMqttClientContext.ts"],"names":[],"mappings":";;;AAAA,MAAa,sBAAsB;IACjC,YACS,IAAY,EACZ,IAAY,EACZ,QAAgB,EAChB,QAAgB,EAChB,QAAiB,EACjB,GAAsB,EACtB,aAAgC;QANhC,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAQ;QACZ,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAS;QACjB,QAAG,GAAH,GAAG,CAAmB;QACtB,kBAAa,GAAb,aAAa,CAAmB;IAEzC,CAAC;CACF;AAXD,wDAWC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAKjC;;GAEG;8BACY,GAAG;AAAlB,kBAEE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,yCAA2C;AAC3C,yCAA2C;AAK3C,iBAAS,CAAC,GAAQ,EAAE,EAAE;IACpB,GAAG,CAAC,gBAAgB,CAAC,wBAAa,EAAE,wBAAa,CAAC,CAAC;AACrD,CAAC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge';
|
|
2
|
+
import { SuplaMqttClient } from './Heplers/SuplaMqttClient';
|
|
3
|
+
import { SuplaChannelContext } from './Heplers/SuplaChannelContext';
|
|
4
|
+
/**
|
|
5
|
+
* HomebridgePlatform
|
|
6
|
+
* This class is the main constructor for your plugin, this is where you should
|
|
7
|
+
* parse the user config and discover/register accessories with Homebridge.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SuplaPlatform implements DynamicPlatformPlugin {
|
|
10
|
+
readonly log: Logger;
|
|
11
|
+
readonly config: PlatformConfig;
|
|
12
|
+
readonly api: API;
|
|
13
|
+
readonly Service: typeof Service;
|
|
14
|
+
readonly Characteristic: typeof Characteristic;
|
|
15
|
+
MqttClient: SuplaMqttClient;
|
|
16
|
+
readonly accessories: PlatformAccessory[];
|
|
17
|
+
constructor(log: Logger, config: PlatformConfig, api: API);
|
|
18
|
+
/**
|
|
19
|
+
* This function is invoked when homebridge restores cached accessories from disk at startup.
|
|
20
|
+
* It should be used to setup event handlers for characteristics and update respective values.
|
|
21
|
+
*/
|
|
22
|
+
configureAccessory(accessory: PlatformAccessory): void;
|
|
23
|
+
/**
|
|
24
|
+
* This is an example method showing how to register discovered accessories.
|
|
25
|
+
* Accessories must only be registered once, previously created accessories
|
|
26
|
+
* must not be registered again to prevent "duplicate UUID" errors.
|
|
27
|
+
*/
|
|
28
|
+
discoverDevices(channelsOverride?: Array<SuplaChannelContext>): void;
|
|
29
|
+
private loadChannelsFromConfig;
|
|
30
|
+
private persistChannels;
|
|
31
|
+
private normalizeChannelContext;
|
|
32
|
+
private getChannelUuid;
|
|
33
|
+
private setupAccessory;
|
|
34
|
+
private isLeakSensorChannel;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAM5H,OAAO,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAI1D,OAAO,EAAC,mBAAmB,EAAC,MAAM,+BAA+B,CAAC;AAkBlE;;;;GAIG;AACH,qBAAa,aAAc,YAAW,qBAAqB;aAQvC,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAT1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAwB;IAC/D,SAAgB,cAAc,EAAE,OAAO,cAAc,CAA+B;IAC7E,UAAU,EAAG,eAAe,CAAC;IAEpC,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;gBAGpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAmB1B;;;OAGG;IACH,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAO/C;;;;OAIG;IACH,eAAe,CAAC,gBAAgB,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC;IAqD7D,OAAO,CAAC,sBAAsB;IAqB9B,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,uBAAuB;IAmC/B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAiHtB,OAAO,CAAC,mBAAmB;CAI5B"}
|
package/dist/platform.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.SuplaPlatform = void 0;
|
|
27
|
+
const settings_1 = require("./settings");
|
|
28
|
+
const GarageDoorOpenerAccesory_1 = require("./Accesories/GarageDoorOpenerAccesory");
|
|
29
|
+
const LightBulbAccesory_1 = require("./Accesories/LightBulbAccesory");
|
|
30
|
+
const fs = __importStar(require("fs"));
|
|
31
|
+
const SuplaMqttClient_1 = require("./Heplers/SuplaMqttClient");
|
|
32
|
+
const RGBLightBulbAccesory_1 = require("./Accesories/RGBLightBulbAccesory");
|
|
33
|
+
const WicketAccesory_1 = require("./Accesories/WicketAccesory");
|
|
34
|
+
const SuplaChannelContext_1 = require("./Heplers/SuplaChannelContext");
|
|
35
|
+
const DimmerAccessory_1 = require("./Accesories/DimmerAccessory");
|
|
36
|
+
const SwitchAccessory_1 = require("./Accesories/SwitchAccessory");
|
|
37
|
+
const RollerShutterAccessory_1 = require("./Accesories/RollerShutterAccessory");
|
|
38
|
+
const FacadeBlindAccessory_1 = require("./Accesories/FacadeBlindAccessory");
|
|
39
|
+
const ContactSensorAccessory_1 = require("./Accesories/ContactSensorAccessory");
|
|
40
|
+
const LeakSensorAccessory_1 = require("./Accesories/LeakSensorAccessory");
|
|
41
|
+
const TemperatureAccessory_1 = require("./Accesories/TemperatureAccessory");
|
|
42
|
+
const TemperatureHumidityAccessory_1 = require("./Accesories/TemperatureHumidityAccessory");
|
|
43
|
+
const AirQualityAccessory_1 = require("./Accesories/AirQualityAccessory");
|
|
44
|
+
const PressureAccessory_1 = require("./Accesories/PressureAccessory");
|
|
45
|
+
const ValveAccessory_1 = require("./Accesories/ValveAccessory");
|
|
46
|
+
const ThermostatAccessory_1 = require("./Accesories/ThermostatAccessory");
|
|
47
|
+
const ElectricityMeterAccessory_1 = require("./Accesories/ElectricityMeterAccessory");
|
|
48
|
+
const DimmerRgbLightAccessory_1 = require("./Accesories/DimmerRgbLightAccessory");
|
|
49
|
+
const ActionTriggerAccessory_1 = require("./Accesories/ActionTriggerAccessory");
|
|
50
|
+
/**
|
|
51
|
+
* HomebridgePlatform
|
|
52
|
+
* This class is the main constructor for your plugin, this is where you should
|
|
53
|
+
* parse the user config and discover/register accessories with Homebridge.
|
|
54
|
+
*/
|
|
55
|
+
class SuplaPlatform {
|
|
56
|
+
constructor(log, config, api) {
|
|
57
|
+
this.log = log;
|
|
58
|
+
this.config = config;
|
|
59
|
+
this.api = api;
|
|
60
|
+
this.Service = this.api.hap.Service;
|
|
61
|
+
this.Characteristic = this.api.hap.Characteristic;
|
|
62
|
+
this.accessories = [];
|
|
63
|
+
this.log.debug('Finished initializing platform:', this.config.name);
|
|
64
|
+
this.api.on('didFinishLaunching', () => {
|
|
65
|
+
log.debug('Executed didFinishLaunching callback');
|
|
66
|
+
const mqttSettings = this.config;
|
|
67
|
+
this.MqttClient = new SuplaMqttClient_1.SuplaMqttClient(mqttSettings, this.log);
|
|
68
|
+
this.discoverDevices();
|
|
69
|
+
this.MqttClient.discoverChannelsAsync().then((channels) => {
|
|
70
|
+
this.persistChannels(channels);
|
|
71
|
+
this.discoverDevices(channels);
|
|
72
|
+
this.log.info('Channels discovered and saved to config file');
|
|
73
|
+
}).catch((error) => {
|
|
74
|
+
this.log.error(`Channel discovery failed: ${error.message}`);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* This function is invoked when homebridge restores cached accessories from disk at startup.
|
|
80
|
+
* It should be used to setup event handlers for characteristics and update respective values.
|
|
81
|
+
*/
|
|
82
|
+
configureAccessory(accessory) {
|
|
83
|
+
this.log.info('Loading accessory from cache:', accessory.displayName);
|
|
84
|
+
// add the restored accessory to the accessories cache so we can track if it has already been registered
|
|
85
|
+
this.accessories.push(accessory);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* This is an example method showing how to register discovered accessories.
|
|
89
|
+
* Accessories must only be registered once, previously created accessories
|
|
90
|
+
* must not be registered again to prevent "duplicate UUID" errors.
|
|
91
|
+
*/
|
|
92
|
+
discoverDevices(channelsOverride) {
|
|
93
|
+
const rawChannels = channelsOverride !== null && channelsOverride !== void 0 ? channelsOverride : this.loadChannelsFromConfig();
|
|
94
|
+
const channels = rawChannels.map(channel => this.normalizeChannelContext(channel));
|
|
95
|
+
this.log.info('Channels discovered:', channels.length);
|
|
96
|
+
this.log.debug(`Discovery mode: ${channelsOverride ? 'live' : 'cached'} channels`);
|
|
97
|
+
const channelUuids = new Set(channels.map(channel => this.getChannelUuid(channel)));
|
|
98
|
+
const shouldPrune = channelsOverride !== undefined && channels.length > 0;
|
|
99
|
+
// loop over the discovered devices and register each one if it has not already been registered
|
|
100
|
+
for (const channel of channels) {
|
|
101
|
+
const uuid = this.getChannelUuid(channel);
|
|
102
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
|
|
103
|
+
if (existingAccessory) {
|
|
104
|
+
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
|
|
105
|
+
existingAccessory.context.device = channel;
|
|
106
|
+
this.log.debug(`Restoring channel ${channel.channelCaption} (${channel.deviceId}/${channel.channelId}) ` +
|
|
107
|
+
`function=${channel.channelFunction} type=${channel.channelType}`);
|
|
108
|
+
this.setupAccessory(channel, existingAccessory);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
this.log.info('Adding new accessory:', channel.channelCaption);
|
|
112
|
+
this.log.debug(`Registering channel ${channel.channelCaption} (${channel.deviceId}/${channel.channelId}) ` +
|
|
113
|
+
`function=${channel.channelFunction} type=${channel.channelType}`);
|
|
114
|
+
const accessory = new this.api.platformAccessory(channel.channelCaption, uuid);
|
|
115
|
+
accessory.context.device = channel;
|
|
116
|
+
if (this.setupAccessory(channel, accessory)) {
|
|
117
|
+
this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
|
|
118
|
+
this.accessories.push(accessory);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (shouldPrune) {
|
|
122
|
+
const accessoriesToRemove = this.accessories.filter(accessory => !channelUuids.has(accessory.UUID));
|
|
123
|
+
for (const accessory of accessoriesToRemove) {
|
|
124
|
+
this.log.info('Removing existing accessory from cache:', accessory.displayName);
|
|
125
|
+
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
|
|
126
|
+
const index = this.accessories.indexOf(accessory);
|
|
127
|
+
if (index !== -1) {
|
|
128
|
+
this.accessories.splice(index, 1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
loadChannelsFromConfig() {
|
|
134
|
+
const rawChannels = this.config.channels;
|
|
135
|
+
if (!rawChannels) {
|
|
136
|
+
this.log.debug('No cached channels found in config.');
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
if (Array.isArray(rawChannels)) {
|
|
140
|
+
return rawChannels;
|
|
141
|
+
}
|
|
142
|
+
if (typeof rawChannels === 'string') {
|
|
143
|
+
try {
|
|
144
|
+
return JSON.parse(rawChannels);
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
this.log.warn(`Failed to parse cached channels: ${e.message}`);
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
this.log.warn('Cached channels format is invalid; expected string or array.');
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
persistChannels(channels) {
|
|
155
|
+
var _a;
|
|
156
|
+
try {
|
|
157
|
+
const configPath = this.api.user.configPath();
|
|
158
|
+
const config = JSON.parse(fs.readFileSync(configPath).toString());
|
|
159
|
+
const platformConfig = (_a = config.platforms) === null || _a === void 0 ? void 0 : _a.find((platform) => platform.platform === 'SuplaPlatform');
|
|
160
|
+
if (!platformConfig) {
|
|
161
|
+
this.log.warn('Failed to save channels: SuplaPlatform not found in config.');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
platformConfig.channels = JSON.stringify(channels);
|
|
165
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
166
|
+
this.log.debug(`Saved ${channels.length} channels to config.`);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
this.log.error(`Failed to save channels: ${error.message}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
normalizeChannelContext(channel) {
|
|
173
|
+
var _a;
|
|
174
|
+
const topic = (_a = channel.topic) !== null && _a !== void 0 ? _a : '';
|
|
175
|
+
let deviceId = channel.deviceId;
|
|
176
|
+
let channelId = channel.channelId;
|
|
177
|
+
if (!deviceId || !channelId) {
|
|
178
|
+
const match = topic.match(/devices\/([0-9]+)\/channels\/([0-9]+)$/);
|
|
179
|
+
if (match) {
|
|
180
|
+
deviceId = match[1];
|
|
181
|
+
channelId = match[2];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!deviceId) {
|
|
185
|
+
deviceId = 'unknown';
|
|
186
|
+
}
|
|
187
|
+
if (!channelId) {
|
|
188
|
+
channelId = 'unknown';
|
|
189
|
+
}
|
|
190
|
+
const caption = channel.channelCaption || `Device ${deviceId} Channel ${channelId}`;
|
|
191
|
+
const channelType = channel.channelType || 'UNKNOWN';
|
|
192
|
+
const channelFunction = channel.channelFunction || 'UNKNOWN';
|
|
193
|
+
const mqttContext = this.config;
|
|
194
|
+
const baseTopic = topic || `supla/${mqttContext.username}/devices/${deviceId}/channels/${channelId}`;
|
|
195
|
+
if (deviceId === 'unknown' || channelId === 'unknown') {
|
|
196
|
+
this.log.warn(`Channel missing device/channel id for topic ${topic}`);
|
|
197
|
+
}
|
|
198
|
+
return new SuplaChannelContext_1.SuplaChannelContext(baseTopic, channelType, channelFunction, caption, deviceId, channelId);
|
|
199
|
+
}
|
|
200
|
+
getChannelUuid(channel) {
|
|
201
|
+
const key = channel.deviceId && channel.channelId
|
|
202
|
+
? `${channel.deviceId}:${channel.channelId}`
|
|
203
|
+
: (channel.topic || channel.channelCaption);
|
|
204
|
+
return this.api.hap.uuid.generate(key);
|
|
205
|
+
}
|
|
206
|
+
setupAccessory(channel, accessory) {
|
|
207
|
+
this.log.debug(`Mapping channel ${channel.channelCaption} (${channel.deviceId}/${channel.channelId}) ` +
|
|
208
|
+
`function=${channel.channelFunction} type=${channel.channelType}`);
|
|
209
|
+
switch (channel.channelFunction) {
|
|
210
|
+
case 'CONTROLLINGTHEGARAGEDOOR':
|
|
211
|
+
case 'CONTROLLINGTHEGATE':
|
|
212
|
+
new GarageDoorOpenerAccesory_1.GarageDoorOpenerAccesory(this, accessory, channel);
|
|
213
|
+
return true;
|
|
214
|
+
case 'LIGHTSWITCH':
|
|
215
|
+
new LightBulbAccesory_1.LightAccesory(this, accessory, channel);
|
|
216
|
+
return true;
|
|
217
|
+
case 'POWERSWITCH':
|
|
218
|
+
new SwitchAccessory_1.SwitchAccessory(this, accessory, channel);
|
|
219
|
+
return true;
|
|
220
|
+
case 'CONTROLLINGTHEGATEWAYLOCK':
|
|
221
|
+
new WicketAccesory_1.WicketAccesory(this, accessory, channel);
|
|
222
|
+
return true;
|
|
223
|
+
case 'RGBLIGHTING':
|
|
224
|
+
new RGBLightBulbAccesory_1.RGBLightAccesory(this, accessory, channel);
|
|
225
|
+
return true;
|
|
226
|
+
case 'DIMMER':
|
|
227
|
+
new DimmerAccessory_1.DimmerAccessory(this, accessory, channel);
|
|
228
|
+
return true;
|
|
229
|
+
case 'DIMMERANDRGBLIGHTING':
|
|
230
|
+
new DimmerRgbLightAccessory_1.DimmerRgbLightAccessory(this, accessory, channel);
|
|
231
|
+
return true;
|
|
232
|
+
case 'CONTROLLINGTHEROLLERSHUTTER':
|
|
233
|
+
new RollerShutterAccessory_1.RollerShutterAccessory(this, accessory, channel);
|
|
234
|
+
return true;
|
|
235
|
+
case 'CONTROLLINGTHEFACADEBLIND':
|
|
236
|
+
new FacadeBlindAccessory_1.FacadeBlindAccessory(this, accessory, channel);
|
|
237
|
+
return true;
|
|
238
|
+
case 'OPENINGSENSOR_GATE':
|
|
239
|
+
case 'OPENINGSENSOR_GATEWAY':
|
|
240
|
+
case 'OPENINGSENSOR_WINDOW':
|
|
241
|
+
new ContactSensorAccessory_1.ContactSensorAccessory(this, accessory, channel);
|
|
242
|
+
return true;
|
|
243
|
+
case 'GENERAL_PURPOSE_MEASUREMENT':
|
|
244
|
+
new AirQualityAccessory_1.AirQualityAccessory(this, accessory, channel);
|
|
245
|
+
return true;
|
|
246
|
+
case 'THERMOMETER':
|
|
247
|
+
new TemperatureAccessory_1.TemperatureAccessory(this, accessory, channel);
|
|
248
|
+
return true;
|
|
249
|
+
case 'HUMIDITYANDTEMPERATURE':
|
|
250
|
+
new TemperatureHumidityAccessory_1.TemperatureHumidityAccessory(this, accessory, channel);
|
|
251
|
+
return true;
|
|
252
|
+
case 'PRESSURESENSOR':
|
|
253
|
+
new PressureAccessory_1.PressureAccessory(this, accessory, channel);
|
|
254
|
+
return true;
|
|
255
|
+
case 'VALVEOPENCLOSE':
|
|
256
|
+
new ValveAccessory_1.ValveAccessory(this, accessory, channel);
|
|
257
|
+
return true;
|
|
258
|
+
case 'HVAC_THERMOSTAT':
|
|
259
|
+
new ThermostatAccessory_1.ThermostatAccessory(this, accessory, channel);
|
|
260
|
+
return true;
|
|
261
|
+
case 'ELECTRICITYMETER':
|
|
262
|
+
new ElectricityMeterAccessory_1.ElectricityMeterAccessory(this, accessory, channel);
|
|
263
|
+
return true;
|
|
264
|
+
case 'ACTION_TRIGGER':
|
|
265
|
+
new ActionTriggerAccessory_1.ActionTriggerAccessory(this, accessory, channel);
|
|
266
|
+
return true;
|
|
267
|
+
default:
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
switch (channel.channelType) {
|
|
271
|
+
case 'DIMMERANDRGBLED':
|
|
272
|
+
new DimmerRgbLightAccessory_1.DimmerRgbLightAccessory(this, accessory, channel);
|
|
273
|
+
return true;
|
|
274
|
+
case 'DIMMER':
|
|
275
|
+
new DimmerAccessory_1.DimmerAccessory(this, accessory, channel);
|
|
276
|
+
return true;
|
|
277
|
+
case 'RELAY':
|
|
278
|
+
new SwitchAccessory_1.SwitchAccessory(this, accessory, channel);
|
|
279
|
+
return true;
|
|
280
|
+
case 'BINARYSENSOR':
|
|
281
|
+
if (this.isLeakSensorChannel(channel)) {
|
|
282
|
+
new LeakSensorAccessory_1.LeakSensorAccessory(this, accessory, channel);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
new ContactSensorAccessory_1.ContactSensorAccessory(this, accessory, channel);
|
|
286
|
+
}
|
|
287
|
+
return true;
|
|
288
|
+
case 'THERMOMETER':
|
|
289
|
+
case 'THERMOMETERDS18B20':
|
|
290
|
+
new TemperatureAccessory_1.TemperatureAccessory(this, accessory, channel);
|
|
291
|
+
return true;
|
|
292
|
+
case 'HUMIDITYANDTEMPSENSOR':
|
|
293
|
+
new TemperatureHumidityAccessory_1.TemperatureHumidityAccessory(this, accessory, channel);
|
|
294
|
+
return true;
|
|
295
|
+
case 'GENERAL_PURPOSE_MEASUREMENT':
|
|
296
|
+
new AirQualityAccessory_1.AirQualityAccessory(this, accessory, channel);
|
|
297
|
+
return true;
|
|
298
|
+
case 'PRESSURESENSOR':
|
|
299
|
+
new PressureAccessory_1.PressureAccessory(this, accessory, channel);
|
|
300
|
+
return true;
|
|
301
|
+
case 'ELECTRICITYMETER':
|
|
302
|
+
new ElectricityMeterAccessory_1.ElectricityMeterAccessory(this, accessory, channel);
|
|
303
|
+
return true;
|
|
304
|
+
case 'ACTION_TRIGGER':
|
|
305
|
+
new ActionTriggerAccessory_1.ActionTriggerAccessory(this, accessory, channel);
|
|
306
|
+
return true;
|
|
307
|
+
default:
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
this.log.warn(`Unsupported channel ${channel.channelCaption} (${channel.channelFunction}/${channel.channelType})`);
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
isLeakSensorChannel(channel) {
|
|
314
|
+
var _a;
|
|
315
|
+
const caption = ((_a = channel.channelCaption) !== null && _a !== void 0 ? _a : '').toLowerCase();
|
|
316
|
+
return ['leak', 'flood', 'water', 'zalania'].some(term => caption.includes(term));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
exports.SuplaPlatform = SuplaPlatform;
|
|
320
|
+
//# sourceMappingURL=platform.js.map
|