@smarterhomeapp/homebridge-vantage 1.0.1 → 1.0.3
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/README.md +7 -5
- package/dist/platform.js +1 -1
- package/dist/settings.d.ts +1 -1
- package/dist/settings.js +1 -1
- package/dist/vantageInfusion.d.ts +4 -0
- package/dist/vantageInfusion.js +61 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Homebridge Vantage Controls
|
|
2
|
+
[](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
|
|
2
3
|
|
|
3
|
-
A [Homebridge](https://homebridge.io/) plugin for Vantage Controls InFusion system.
|
|
4
|
+
A [Homebridge](https://homebridge.io/) plugin for Vantage Controls InFusion system.
|
|
5
|
+
This plugin replaces the one sold on smarterhome.io allowing anyone to download on the platform of their choice.
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
@@ -20,7 +22,7 @@ npm install -g homebridge
|
|
|
20
22
|
|
|
21
23
|
2. Install this plugin:
|
|
22
24
|
```bash
|
|
23
|
-
npm install -g homebridge-vantage
|
|
25
|
+
npm install -g @smarterhomeapp/homebridge-vantage
|
|
24
26
|
```
|
|
25
27
|
|
|
26
28
|
3. Add the platform to your `config.json`:
|
|
@@ -74,7 +76,7 @@ npm install -g homebridge-vantage
|
|
|
74
76
|
|
|
75
77
|
1. Clone the repository:
|
|
76
78
|
```bash
|
|
77
|
-
git clone https://github.com/
|
|
79
|
+
git clone https://github.com/smarterhomeapp/homebridge-vantage.git
|
|
78
80
|
cd homebridge-vantage
|
|
79
81
|
```
|
|
80
82
|
|
|
@@ -125,5 +127,5 @@ MIT License - see LICENSE file for details.
|
|
|
125
127
|
## Support
|
|
126
128
|
|
|
127
129
|
For issues and questions:
|
|
128
|
-
- [GitHub Issues](https://github.com/
|
|
129
|
-
- [Homebridge Community](https://github.com/homebridge/homebridge)
|
|
130
|
+
- [GitHub Issues](https://github.com/smarterhomeapp/homebridge-vantage/issues)
|
|
131
|
+
- [Homebridge Community](https://github.com/homebridge/homebridge)
|
package/dist/platform.js
CHANGED
|
@@ -219,7 +219,7 @@ class VantagePlatform {
|
|
|
219
219
|
const svc = acc.getService(S.Thermostat);
|
|
220
220
|
if (!svc || !dev)
|
|
221
221
|
return;
|
|
222
|
-
this.log.
|
|
222
|
+
this.log.debug(`thermostatIndoorModeChange (VID=${vid}, Name=${dev.name}, Mode=${mode}, TargetTemp=${targetTemp})`);
|
|
223
223
|
// this.log.info(`Before update - dev.mode=${dev.mode}, dev.targetTemp=${dev.targetTemp}, dev.heating=${dev.heating}, dev.cooling=${dev.cooling}`);
|
|
224
224
|
if (targetTemp === -1) {
|
|
225
225
|
// Only update mode when targetTemp is -1 (mode change without temperature)
|
package/dist/settings.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PLUGIN_NAME = "homebridge-vantage";
|
|
1
|
+
export declare const PLUGIN_NAME = "@smarterhomeapp/homebridge-vantage";
|
|
2
2
|
export declare const PLATFORM_NAME = "VantageControls";
|
package/dist/settings.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PLATFORM_NAME = exports.PLUGIN_NAME = void 0;
|
|
4
|
-
exports.PLUGIN_NAME = 'homebridge-vantage';
|
|
4
|
+
exports.PLUGIN_NAME = '@smarterhomeapp/homebridge-vantage';
|
|
5
5
|
exports.PLATFORM_NAME = 'VantageControls';
|
|
@@ -29,6 +29,10 @@ export declare class VantageInfusion extends EventEmitter {
|
|
|
29
29
|
/** XML/config discovery; returns devices (replaces old Discover/DiscoverSSL) */
|
|
30
30
|
discoverDevices(): Promise<VantageDevice[]>;
|
|
31
31
|
private processConfigurationXml;
|
|
32
|
+
/** Escape text for XML (same as sanitize in index.js). */
|
|
33
|
+
private static escapeXml;
|
|
34
|
+
/** Build cache XML from readObjects (same structure + sanitization as original index.js). */
|
|
35
|
+
private buildCacheXml;
|
|
32
36
|
private pullConfigurationXml;
|
|
33
37
|
setBrightness(vid: string, level: number): Promise<void>;
|
|
34
38
|
setHue(vid: string, hue: number): Promise<void>;
|
package/dist/vantageInfusion.js
CHANGED
|
@@ -48,6 +48,7 @@ const TYPE_THERMO = [
|
|
|
48
48
|
'Tekmar.tN4_Gateway_482_Zone_-_Slab_Only_CHILD',
|
|
49
49
|
'Tekmar.tN4_Gateway_482_Zone_CHILD',
|
|
50
50
|
'Legrand.MH_HVAC_Control_CHILD',
|
|
51
|
+
'Vantage.HVAC-IU-Zone_CHILD'
|
|
51
52
|
];
|
|
52
53
|
const TYPE_BLIND = [
|
|
53
54
|
'Blind',
|
|
@@ -93,8 +94,13 @@ class VantageInfusion extends events_1.EventEmitter {
|
|
|
93
94
|
this.isInsecureCfg = false;
|
|
94
95
|
}
|
|
95
96
|
else {
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
// Probe sequentially to avoid controller session limits
|
|
98
|
+
const cmdResult = await this.portUsable(3001, 'STATUS ALL\n');
|
|
99
|
+
// brief backoff before probing config port
|
|
100
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
101
|
+
const cfgResult = await this.portUsable(2001, '<IIntrospection><GetInterfaces><call></call></GetInterfaces></IIntrospection>\n');
|
|
102
|
+
this.isInsecureCmd = !!cmdResult;
|
|
103
|
+
this.isInsecureCfg = !!cfgResult;
|
|
98
104
|
}
|
|
99
105
|
// Legacy-style port logs
|
|
100
106
|
this.opts.log.info(this.isInsecureCmd ? 'Using insecure port: 3001' : 'Using SSL port: 3010');
|
|
@@ -104,21 +110,46 @@ class VantageInfusion extends events_1.EventEmitter {
|
|
|
104
110
|
portUsable(port, probe) {
|
|
105
111
|
return new Promise((resolve) => {
|
|
106
112
|
let sawData = false;
|
|
113
|
+
this.opts.log.debug(`Testing ${this.opts.ipaddress}:${port} with probe: "${probe.trim()}"`);
|
|
107
114
|
const sock = net.connect({ host: this.opts.ipaddress, port }, () => {
|
|
115
|
+
this.opts.log.debug(`Connected to ${this.opts.ipaddress}:${port}`);
|
|
116
|
+
// improve send behavior
|
|
117
|
+
sock.setNoDelay(true);
|
|
118
|
+
// keep a post-connect timeout; fail if no reply in time
|
|
119
|
+
sock.setTimeout(8000);
|
|
120
|
+
// write immediately
|
|
121
|
+
this.opts.log.debug(`Sending initial probe on port ${port}`);
|
|
108
122
|
sock.write(probe);
|
|
123
|
+
// send a second probe shortly after to coax a response
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
if (!sawData) {
|
|
126
|
+
this.opts.log.debug(`Re-sending probe on port ${port}`);
|
|
127
|
+
sock.write(probe);
|
|
128
|
+
}
|
|
129
|
+
}, 150);
|
|
130
|
+
});
|
|
131
|
+
sock.once('connect', () => {
|
|
132
|
+
this.opts.log.debug(`Port ${port} connection established`);
|
|
109
133
|
});
|
|
110
|
-
sock.
|
|
111
|
-
|
|
112
|
-
|
|
134
|
+
sock.on('data', (data) => {
|
|
135
|
+
const text = data.toString();
|
|
136
|
+
this.opts.log.debug(`Port ${port} received data: ${text.slice(0, 200).replace(/\r/g, '\\r').replace(/\n/g, '\\n')}`);
|
|
113
137
|
sawData = true;
|
|
114
138
|
resolve(true);
|
|
115
139
|
sock.destroy();
|
|
116
140
|
});
|
|
141
|
+
sock.on('timeout', () => {
|
|
142
|
+
this.opts.log.debug(`Port ${port} post-connect timeout`);
|
|
143
|
+
sock.destroy();
|
|
144
|
+
});
|
|
117
145
|
sock.on('close', () => {
|
|
146
|
+
this.opts.log.debug(`Port ${port} closed, sawData: ${sawData}`);
|
|
118
147
|
if (!sawData)
|
|
119
148
|
resolve(false);
|
|
120
149
|
});
|
|
121
|
-
sock.on('error', () => {
|
|
150
|
+
sock.on('error', (err) => {
|
|
151
|
+
const msg = err instanceof Error ? `${err.code || ''} ${err.message}` : String(err);
|
|
152
|
+
this.opts.log.debug(`Port ${port} error: ${msg}`);
|
|
122
153
|
/* resolve on close path */
|
|
123
154
|
});
|
|
124
155
|
});
|
|
@@ -383,6 +414,25 @@ class VantageInfusion extends events_1.EventEmitter {
|
|
|
383
414
|
}
|
|
384
415
|
return filtered;
|
|
385
416
|
}
|
|
417
|
+
/** Escape text for XML (same as sanitize in index.js). */
|
|
418
|
+
static escapeXml(s) {
|
|
419
|
+
return String(s)
|
|
420
|
+
.replace(/&/g, '&')
|
|
421
|
+
.replace(/</g, '<')
|
|
422
|
+
.replace(/>/g, '>')
|
|
423
|
+
.replace(/"/g, '"')
|
|
424
|
+
.replace(/'/g, ''');
|
|
425
|
+
}
|
|
426
|
+
/** Build cache XML from readObjects (same structure + sanitization as original index.js). */
|
|
427
|
+
buildCacheXml(readObjects) {
|
|
428
|
+
const frag = readObjects.map((o) => {
|
|
429
|
+
const k = Object.keys(o)[0];
|
|
430
|
+
const v = o[k];
|
|
431
|
+
const body = Object.keys(v).map((kk) => `<${kk}>${VantageInfusion.escapeXml(String(v[kk]))}</${kk}>`).join('');
|
|
432
|
+
return `<Object><${k}>${body}</${k}></Object>`;
|
|
433
|
+
}).join('');
|
|
434
|
+
return `<Project><Objects>${frag}</Objects></Project>`;
|
|
435
|
+
}
|
|
386
436
|
pullConfigurationXml() {
|
|
387
437
|
return new Promise((resolve) => {
|
|
388
438
|
const finishOnce = (socket, xml) => {
|
|
@@ -426,15 +476,7 @@ class VantageInfusion extends events_1.EventEmitter {
|
|
|
426
476
|
return;
|
|
427
477
|
}
|
|
428
478
|
if (readObjects.length && Date.now() - lastProgress > 2000) {
|
|
429
|
-
|
|
430
|
-
const xml = '<Project><Objects>' +
|
|
431
|
-
readObjects.map((o) => {
|
|
432
|
-
const k = Object.keys(o)[0];
|
|
433
|
-
const v = o[k];
|
|
434
|
-
const body = Object.keys(v).map((kk) => `<${kk}>${String(v[kk])}</${kk}>`).join('');
|
|
435
|
-
return `<Object><${k}>${body}</${k}></Object>`;
|
|
436
|
-
}).join('') +
|
|
437
|
-
'</Objects></Project>';
|
|
479
|
+
const xml = this.buildCacheXml(readObjects);
|
|
438
480
|
clearInterval(watchdog);
|
|
439
481
|
finishOnce(socket, xml);
|
|
440
482
|
}
|
|
@@ -542,14 +584,7 @@ class VantageInfusion extends events_1.EventEmitter {
|
|
|
542
584
|
}
|
|
543
585
|
// ----- END CONDITION -----
|
|
544
586
|
if (shouldBreak) {
|
|
545
|
-
const xml =
|
|
546
|
-
readObjects.map((o) => {
|
|
547
|
-
const k = Object.keys(o)[0];
|
|
548
|
-
const v = o[k];
|
|
549
|
-
const body = Object.keys(v).map((kk) => `<${kk}>${String(v[kk])}</${kk}>`).join('');
|
|
550
|
-
return `<Object><${k}>${body}</${k}></Object>`;
|
|
551
|
-
}).join('') +
|
|
552
|
-
'</Objects></Project>';
|
|
587
|
+
const xml = this.buildCacheXml(readObjects);
|
|
553
588
|
clearLoginFallback();
|
|
554
589
|
clearInterval(watchdog);
|
|
555
590
|
finishOnce(socket, xml);
|
|
@@ -559,30 +594,16 @@ class VantageInfusion extends events_1.EventEmitter {
|
|
|
559
594
|
socket.on('end', () => {
|
|
560
595
|
this.opts.log.info("ending" + shouldBreak);
|
|
561
596
|
if (!finishOnce._done && readObjects.length) {
|
|
562
|
-
const xml =
|
|
563
|
-
readObjects.map((o) => {
|
|
564
|
-
const k = Object.keys(o)[0];
|
|
565
|
-
const v = o[k];
|
|
566
|
-
const body = Object.keys(v).map((kk) => `<${kk}>${String(v[kk])}</${kk}>`).join('');
|
|
567
|
-
return `<Object><${k}>${body}</${k}></Object>`;
|
|
568
|
-
}).join('') +
|
|
569
|
-
'</Objects></Project>';
|
|
597
|
+
const xml = this.buildCacheXml(readObjects);
|
|
570
598
|
clearLoginFallback();
|
|
571
599
|
clearInterval(watchdog);
|
|
572
600
|
finishOnce(socket, xml);
|
|
573
601
|
}
|
|
574
602
|
});
|
|
575
603
|
socket.on('close', () => {
|
|
576
|
-
this.opts.log.
|
|
604
|
+
this.opts.log.debug("closing " + shouldBreak);
|
|
577
605
|
if (!finishOnce._done && readObjects.length) {
|
|
578
|
-
const xml =
|
|
579
|
-
readObjects.map((o) => {
|
|
580
|
-
const k = Object.keys(o)[0];
|
|
581
|
-
const v = o[k];
|
|
582
|
-
const body = Object.keys(v).map((kk) => `<${kk}>${String(v[kk])}</${kk}>`).join('');
|
|
583
|
-
return `<Object><${k}>${body}</${k}></Object>`;
|
|
584
|
-
}).join('') +
|
|
585
|
-
'</Objects></Project>';
|
|
606
|
+
const xml = this.buildCacheXml(readObjects);
|
|
586
607
|
clearLoginFallback();
|
|
587
608
|
clearInterval(watchdog);
|
|
588
609
|
finishOnce(socket, xml);
|