homebridge-smartsystem 6.7.2 → 6.7.4
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 +2 -0
- package/config.json +12 -16
- package/duotecno/logger.js +1 -1
- package/duotecno/logger.ts +1 -1
- package/duotecno/protocol.js +7 -8
- package/duotecno/protocol.ts +7 -9
- package/duotecno/types.ts +2 -2
- package/package.json +1 -1
- package/server/HB.js +64 -13
- package/server/HB.ts +64 -13
- package/server/smartapp.js +20 -19
- package/server/smartapp.ts +23 -19
- package/server/views/link-details.ejs +1 -1
package/README.md
CHANGED
|
@@ -298,6 +298,8 @@ Homebridge UI version
|
|
|
298
298
|
- 1: updated the readme file
|
|
299
299
|
- 2: use HB Accessory characteristics in set/get, ignore status for the moment
|
|
300
300
|
- 2: remember/show username in login screen + set focus to password
|
|
301
|
+
- 3: do dimmers/up-downs
|
|
302
|
+
- 4: better up-down values to and from HB
|
|
301
303
|
|
|
302
304
|
## Hardware
|
|
303
305
|
A Raspberry Pi that connects to a Duotecno IP Node
|
package/config.json
CHANGED
|
@@ -270,22 +270,6 @@
|
|
|
270
270
|
"ObstructionDetected"
|
|
271
271
|
],
|
|
272
272
|
"type": "accessory"
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
"logicalNodeAddress": 3,
|
|
276
|
-
"logicalAddress": 30,
|
|
277
|
-
"masterAddress": "192.168.0.97",
|
|
278
|
-
"masterPort": 5001,
|
|
279
|
-
"name": "dimmers",
|
|
280
|
-
"displayName": "dimmers",
|
|
281
|
-
"extendedType": 0,
|
|
282
|
-
"accId": "da32bb657ad68d3fd63004015406e0cbde28355fc950204cec2fcd90d835e044",
|
|
283
|
-
"accName": "Somfy Dimmer",
|
|
284
|
-
"accService": [
|
|
285
|
-
"On",
|
|
286
|
-
"Brightness"
|
|
287
|
-
],
|
|
288
|
-
"type": "accessory"
|
|
289
273
|
}
|
|
290
274
|
]
|
|
291
275
|
},
|
|
@@ -373,6 +357,18 @@
|
|
|
373
357
|
"used": "Y",
|
|
374
358
|
"group": 0
|
|
375
359
|
},
|
|
360
|
+
{
|
|
361
|
+
"logicalNodeAddress": 3,
|
|
362
|
+
"logicalAddress": 28,
|
|
363
|
+
"masterAddress": "192.168.0.97",
|
|
364
|
+
"masterPort": 5001,
|
|
365
|
+
"name": "Garage $",
|
|
366
|
+
"displayName": "Garage ",
|
|
367
|
+
"extendedType": 8,
|
|
368
|
+
"active": "N",
|
|
369
|
+
"used": "Y",
|
|
370
|
+
"group": 0
|
|
371
|
+
},
|
|
376
372
|
{
|
|
377
373
|
"logicalNodeAddress": 3,
|
|
378
374
|
"logicalAddress": 31,
|
package/duotecno/logger.js
CHANGED
package/duotecno/logger.ts
CHANGED
|
@@ -10,7 +10,7 @@ export enum LogLevel { noLog = 0, log = 1, debug = 2 };
|
|
|
10
10
|
export const logSettings = {
|
|
11
11
|
"*": LogLevel.log,
|
|
12
12
|
"master": LogLevel.log,
|
|
13
|
-
"protocol": LogLevel.
|
|
13
|
+
"protocol": LogLevel.debug,
|
|
14
14
|
"webapp": LogLevel.log,
|
|
15
15
|
"p1": LogLevel.log,
|
|
16
16
|
"shelly": LogLevel.log,
|
package/duotecno/protocol.js
CHANGED
|
@@ -41,13 +41,15 @@ var Cmd;
|
|
|
41
41
|
Cmd[Cmd["Heartbeat"] = 215] = "Heartbeat";
|
|
42
42
|
Cmd[Cmd["DatabaseInfo"] = 209] = "DatabaseInfo";
|
|
43
43
|
Cmd[Cmd["SetSchedule"] = 217] = "SetSchedule";
|
|
44
|
+
Cmd[Cmd["reqSchedule"] = 218] = "reqSchedule";
|
|
45
|
+
Cmd[Cmd["reqNodeManagement"] = 220] = "reqNodeManagement";
|
|
44
46
|
Cmd[Cmd["Register"] = 224] = "Register";
|
|
45
47
|
})(Cmd || (Cmd = {}));
|
|
46
|
-
// for Set Switch/Dimmer/Control
|
|
48
|
+
// for Set Switch/Dimmer/Control/Motor/Sensor = 162, 163, 168, 182, 136
|
|
47
49
|
const reqDim = 3;
|
|
48
50
|
const reqOff = 9;
|
|
49
51
|
const reqOn = 10;
|
|
50
|
-
// for Login
|
|
52
|
+
// for Login = 214
|
|
51
53
|
const reqDisconnect = 0;
|
|
52
54
|
const reqConnect = 3;
|
|
53
55
|
// for DatabaseInfo = 209;
|
|
@@ -55,10 +57,7 @@ const reqDBInfo = 0;
|
|
|
55
57
|
const reqNodeInfo = 1;
|
|
56
58
|
const reqUnitInfo = 2;
|
|
57
59
|
const reqUnitStatus = 3;
|
|
58
|
-
// for
|
|
59
|
-
const reqSchedule = 218;
|
|
60
|
-
// for versions et al
|
|
61
|
-
const reqNodeManagement = 220;
|
|
60
|
+
// for reqNodeMgt, versions et al
|
|
62
61
|
var reqNodeAttributes;
|
|
63
62
|
(function (reqNodeAttributes) {
|
|
64
63
|
reqNodeAttributes[reqNodeAttributes["masterSupported"] = 0] = "masterSupported";
|
|
@@ -671,10 +670,10 @@ exports.Protocol = {
|
|
|
671
670
|
return [Cmd.DatabaseInfo, reqUnitStatus, node.logicalAddress, unit.logicalAddress, unit.type];
|
|
672
671
|
},
|
|
673
672
|
buildRequestSchedule() {
|
|
674
|
-
return [reqSchedule, 0];
|
|
673
|
+
return [Cmd.reqSchedule, 0];
|
|
675
674
|
},
|
|
676
675
|
buildRequestNodeMgt(method = reqNodeAttributes.nodeProtocol) {
|
|
677
|
-
return [reqNodeManagement, method];
|
|
676
|
+
return [Cmd.reqNodeManagement, method];
|
|
678
677
|
},
|
|
679
678
|
getCmdAndMethod: function (unit, value) {
|
|
680
679
|
switch (unit.type) {
|
package/duotecno/protocol.ts
CHANGED
|
@@ -38,15 +38,17 @@ enum Cmd {
|
|
|
38
38
|
Heartbeat = 215,
|
|
39
39
|
DatabaseInfo = 209,
|
|
40
40
|
SetSchedule = 217,
|
|
41
|
+
reqSchedule = 218,
|
|
42
|
+
reqNodeManagement = 220,
|
|
41
43
|
Register = 224
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
// for Set Switch/Dimmer/Control
|
|
46
|
+
// for Set Switch/Dimmer/Control/Motor/Sensor = 162, 163, 168, 182, 136
|
|
45
47
|
const reqDim = 3;
|
|
46
48
|
const reqOff = 9;
|
|
47
49
|
const reqOn = 10;
|
|
48
50
|
|
|
49
|
-
// for Login
|
|
51
|
+
// for Login = 214
|
|
50
52
|
const reqDisconnect = 0;
|
|
51
53
|
const reqConnect = 3;
|
|
52
54
|
|
|
@@ -56,11 +58,7 @@ const reqNodeInfo = 1;
|
|
|
56
58
|
const reqUnitInfo = 2;
|
|
57
59
|
const reqUnitStatus = 3;
|
|
58
60
|
|
|
59
|
-
// for
|
|
60
|
-
const reqSchedule = 218;
|
|
61
|
-
|
|
62
|
-
// for versions et al
|
|
63
|
-
const reqNodeManagement = 220;
|
|
61
|
+
// for reqNodeMgt, versions et al
|
|
64
62
|
export enum reqNodeAttributes {
|
|
65
63
|
masterSupported = 0,
|
|
66
64
|
isMaster = 4,
|
|
@@ -782,10 +780,10 @@ export const Protocol = {
|
|
|
782
780
|
},
|
|
783
781
|
|
|
784
782
|
buildRequestSchedule(): Message {
|
|
785
|
-
return [reqSchedule, 0];
|
|
783
|
+
return [Cmd.reqSchedule, 0];
|
|
786
784
|
},
|
|
787
785
|
buildRequestNodeMgt(method = reqNodeAttributes.nodeProtocol): Message {
|
|
788
|
-
return [reqNodeManagement, method];
|
|
786
|
+
return [Cmd.reqNodeManagement, method];
|
|
789
787
|
},
|
|
790
788
|
|
|
791
789
|
getCmdAndMethod: function(unit: Unit, value: number | boolean): CmdSet {
|
package/duotecno/types.ts
CHANGED
|
@@ -269,8 +269,8 @@ export interface Link extends UnitDef{
|
|
|
269
269
|
accService: Array<string>; // e.g. ["On", "Brightness"], ["TargetPosition", "CurrentPosition", ...]
|
|
270
270
|
type: LinkType;
|
|
271
271
|
unit?: Unit;
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
dtValue?: number | boolean | string;
|
|
273
|
+
hbValue?: number | boolean | string
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
export const kEmptyLink: Link = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-smartsystem",
|
|
3
3
|
"displayname": "Duotecno Bridge",
|
|
4
|
-
"version": "6.7.
|
|
4
|
+
"version": "6.7.4",
|
|
5
5
|
"description": "SmartServer (Proxy Websockets to TCP sockets, Smappee MQTT, Duotecno IP Nodes, Homekit interface)",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"author": "Johan Coppieters",
|
package/server/HB.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.hbUnsubscribe = exports.hbSubscribe = exports.
|
|
12
|
+
exports.hbUnsubscribe = exports.hbSubscribe = exports.hbGetValue = exports.hbSetState = exports.dt2hbvalue = exports.hb2dtvalue = exports.hbLogin = exports.hbAccessories = exports.hbService = exports.hbName = void 0;
|
|
13
13
|
const logger_1 = require("../duotecno/logger");
|
|
14
14
|
const HA_API_1 = require("./HA-API");
|
|
15
15
|
let gAccessories = [];
|
|
@@ -168,37 +168,81 @@ function hbLogin(server, username, password) {
|
|
|
168
168
|
}
|
|
169
169
|
exports.hbLogin = hbLogin;
|
|
170
170
|
function hbLoad(value, service) {
|
|
171
|
+
function hbvalue(value) {
|
|
172
|
+
if (typeof value === "boolean") {
|
|
173
|
+
return (value) ? 100 : 0;
|
|
174
|
+
}
|
|
175
|
+
else if (typeof value === "number") {
|
|
176
|
+
if (value <= 2) {
|
|
177
|
+
return 0;
|
|
178
|
+
}
|
|
179
|
+
else if (value >= 98) {
|
|
180
|
+
return 100;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
return Math.round(value);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
171
187
|
const data = {};
|
|
172
188
|
if (service.includes("On")) {
|
|
173
189
|
data["value"] = value;
|
|
174
190
|
data["characteristicType"] = "On";
|
|
175
191
|
}
|
|
176
192
|
if (service.includes("Brightness")) {
|
|
177
|
-
data["value"] = value;
|
|
193
|
+
data["value"] = hbvalue(value);
|
|
178
194
|
data["characteristicType"] = "Brightness";
|
|
179
195
|
}
|
|
180
196
|
if (service.includes("TargetPosition")) {
|
|
181
|
-
data["value"] = value;
|
|
197
|
+
data["value"] = hbvalue(value);
|
|
182
198
|
data["characteristicType"] = "TargetPosition";
|
|
183
199
|
}
|
|
184
200
|
;
|
|
185
201
|
return data;
|
|
186
202
|
}
|
|
203
|
+
function hb2dtvalue(unit, value) {
|
|
204
|
+
let dtTarget;
|
|
205
|
+
let dtValue;
|
|
206
|
+
if (typeof value === "boolean")
|
|
207
|
+
value = (value) ? 99 : 1;
|
|
208
|
+
value = Math.round(value);
|
|
209
|
+
if (unit.isUpDown()) {
|
|
210
|
+
dtTarget = (value >= 50) ? 4 : 5; // 4 = up, 5 = down
|
|
211
|
+
dtValue = (value >= 50) ? 2 : 1; // 2 = idle-up, 1 = idle-down
|
|
212
|
+
}
|
|
213
|
+
if (unit.isDimmer())
|
|
214
|
+
dtTarget = dtValue = (value <= 1) ? 1 : (value >= 99) ? 100 : value;
|
|
215
|
+
if (unit.isSwitch() || unit.isMood())
|
|
216
|
+
dtTarget = dtValue = (value > 50) ? 1 : 0;
|
|
217
|
+
return { dtTarget, dtValue };
|
|
218
|
+
}
|
|
219
|
+
exports.hb2dtvalue = hb2dtvalue;
|
|
220
|
+
function dt2hbvalue(unit, dontChangeValue) {
|
|
221
|
+
let value = (typeof unit.value === "boolean") ? (unit.value ? 100 : 0) : Math.round(unit.value);
|
|
222
|
+
// status Motor: 0 = stopped, 1 stopped/down, 2 = stopped/up, 3 = busy/down, 4 = busy/up
|
|
223
|
+
if (unit.isUpDown())
|
|
224
|
+
return ((value === 1) || (value === 3)) ? 0 : ((value === 2) || (value === 4)) ? 100 : dontChangeValue;
|
|
225
|
+
if (unit.isDimmer())
|
|
226
|
+
return (value <= 2) ? 0 : (value >= 99) ? 100 : value;
|
|
227
|
+
if (unit.isSwitch() || unit.isMood())
|
|
228
|
+
return (value) ? 1 : 0;
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
231
|
+
exports.dt2hbvalue = dt2hbvalue;
|
|
187
232
|
function hbValue(data, service) {
|
|
188
|
-
const values = {};
|
|
189
233
|
if (service.includes("Brightness")) {
|
|
190
|
-
|
|
234
|
+
return parseInt(data["Brightness"]);
|
|
191
235
|
}
|
|
192
236
|
if (service.includes("On")) {
|
|
193
|
-
|
|
237
|
+
return parseInt(data["On"]);
|
|
194
238
|
}
|
|
195
239
|
if (service.includes("TargetPosition")) {
|
|
196
|
-
|
|
240
|
+
return parseInt(data["TargetPosition"]);
|
|
197
241
|
}
|
|
198
|
-
return
|
|
242
|
+
return undefined;
|
|
199
243
|
}
|
|
200
244
|
// send a status change to HB Accessory
|
|
201
|
-
function hbSetState(server, id, service, value,
|
|
245
|
+
function hbSetState(server, id, service, value, token) {
|
|
202
246
|
return __awaiter(this, void 0, void 0, function* () {
|
|
203
247
|
const data = hbLoad(value, service);
|
|
204
248
|
(0, logger_1.log)("HB", "hbSetState: " + id + " -> " + JSON.stringify(data));
|
|
@@ -212,19 +256,26 @@ function hbSetState(server, id, service, value, state, token) {
|
|
|
212
256
|
}
|
|
213
257
|
exports.hbSetState = hbSetState;
|
|
214
258
|
// send a status change to HB Accessory
|
|
215
|
-
function
|
|
259
|
+
function hbGetValue(server, id, service, token) {
|
|
216
260
|
return __awaiter(this, void 0, void 0, function* () {
|
|
217
261
|
const respBody = yield (0, HA_API_1.httpRequest)(server + "/api/accessories/" + id, 'GET', "", HA_API_1.ContentType.json, {
|
|
218
262
|
Authorization: 'Bearer ' + token
|
|
219
263
|
});
|
|
220
264
|
if (respBody && respBody.error) {
|
|
221
265
|
(0, logger_1.log)("HB", "hbGetState: " + id + " -> error: " + JSON.stringify(respBody));
|
|
222
|
-
return
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
else if (respBody && respBody.values) {
|
|
269
|
+
return hbValue(respBody.values, service);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
(0, logger_1.log)("HB", "hbGetState: " + id + " -> no values?? : " + JSON.stringify(respBody));
|
|
273
|
+
return undefined;
|
|
223
274
|
}
|
|
224
|
-
|
|
275
|
+
;
|
|
225
276
|
});
|
|
226
277
|
}
|
|
227
|
-
exports.
|
|
278
|
+
exports.hbGetValue = hbGetValue;
|
|
228
279
|
function hbSubscribe(callback) {
|
|
229
280
|
if (timer) {
|
|
230
281
|
clearInterval(timer);
|
package/server/HB.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { err, log } from "../duotecno/logger";
|
|
2
|
+
import { Unit } from "../duotecno/protocol";
|
|
2
3
|
import { ContentType, httpRequest } from "./HA-API";
|
|
3
4
|
|
|
4
5
|
export interface HBAccessory {
|
|
@@ -170,42 +171,87 @@ export async function hbLogin(server: string, username: string, password: string
|
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
|
|
173
175
|
function hbLoad(value: number | boolean, service: Array<string>): Record<string, number | boolean> {
|
|
176
|
+
function hbvalue(value: number | boolean): number {
|
|
177
|
+
if (typeof value === "boolean") {
|
|
178
|
+
return (value) ? 100 : 0;
|
|
179
|
+
} else if (typeof value === "number") {
|
|
180
|
+
if (value <= 2) {
|
|
181
|
+
return 0;
|
|
182
|
+
} else if (value >= 98) {
|
|
183
|
+
return 100;
|
|
184
|
+
} else {
|
|
185
|
+
return Math.round(value);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
174
190
|
const data = {};
|
|
175
191
|
|
|
176
192
|
if (service.includes("On")) {
|
|
177
193
|
data["value"] = value;
|
|
178
194
|
data["characteristicType"] = "On";
|
|
179
195
|
}
|
|
196
|
+
|
|
180
197
|
if (service.includes("Brightness")) {
|
|
181
|
-
data["value"] = value;
|
|
198
|
+
data["value"] = hbvalue(value);
|
|
182
199
|
data["characteristicType"] = "Brightness";
|
|
183
200
|
}
|
|
201
|
+
|
|
184
202
|
if (service.includes("TargetPosition")) {
|
|
185
|
-
data["value"] = value;
|
|
203
|
+
data["value"] = hbvalue(value);
|
|
186
204
|
data["characteristicType"] = "TargetPosition";
|
|
187
205
|
};
|
|
188
206
|
return data;
|
|
189
207
|
}
|
|
190
208
|
|
|
191
|
-
function
|
|
192
|
-
|
|
209
|
+
export function hb2dtvalue(unit: Unit, value: number | boolean): {dtValue: number, dtTarget: number} {
|
|
210
|
+
let dtTarget;
|
|
211
|
+
let dtValue;
|
|
212
|
+
|
|
213
|
+
if (typeof value === "boolean") value = (value) ? 99 : 1;
|
|
214
|
+
value = Math.round(value);
|
|
215
|
+
|
|
216
|
+
if (unit.isUpDown()) {
|
|
217
|
+
dtTarget = (value >= 50) ? 4 : 5; // 4 = up, 5 = down
|
|
218
|
+
dtValue = (value >= 50) ? 2 : 1; // 2 = idle-up, 1 = idle-down
|
|
219
|
+
}
|
|
220
|
+
if (unit.isDimmer()) dtTarget = dtValue = (value <= 1) ? 1 : (value >= 99) ? 100 : value;
|
|
221
|
+
if (unit.isSwitch() || unit.isMood()) dtTarget = dtValue = (value > 50) ? 1 : 0;
|
|
222
|
+
|
|
223
|
+
return {dtTarget, dtValue};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function dt2hbvalue(unit: Unit, dontChangeValue: number): number {
|
|
227
|
+
let value = (typeof unit.value === "boolean") ? (unit.value ? 100 : 0) : Math.round(unit.value);
|
|
228
|
+
|
|
229
|
+
// status Motor: 0 = stopped, 1 stopped/down, 2 = stopped/up, 3 = busy/down, 4 = busy/up
|
|
230
|
+
if (unit.isUpDown()) return ((value === 1) || (value === 3)) ? 0 : ((value === 2) || (value === 4)) ? 100 : dontChangeValue;
|
|
231
|
+
|
|
232
|
+
if (unit.isDimmer()) return (value <= 2) ? 0 : (value >= 99) ? 100 : value;
|
|
233
|
+
if (unit.isSwitch() || unit.isMood()) return (value) ? 1 : 0;
|
|
234
|
+
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function hbValue(data: Record<string, any>, service: Array<string>): number {
|
|
193
239
|
if (service.includes("Brightness")) {
|
|
194
|
-
|
|
240
|
+
return parseInt(data["Brightness"]);
|
|
195
241
|
}
|
|
196
242
|
|
|
197
243
|
if (service.includes("On")) {
|
|
198
|
-
|
|
244
|
+
return parseInt(data["On"])
|
|
199
245
|
}
|
|
200
246
|
|
|
201
247
|
if (service.includes("TargetPosition")) {
|
|
202
|
-
|
|
248
|
+
return parseInt(data["TargetPosition"]);
|
|
203
249
|
}
|
|
204
|
-
return
|
|
250
|
+
return undefined
|
|
205
251
|
}
|
|
206
252
|
|
|
207
253
|
// send a status change to HB Accessory
|
|
208
|
-
export async function hbSetState(server: string, id: string, service: Array<string>, value: number | boolean,
|
|
254
|
+
export async function hbSetState(server: string, id: string, service: Array<string>, value: number | boolean, token: string) : Promise<void> {
|
|
209
255
|
const data = hbLoad(value, service);
|
|
210
256
|
|
|
211
257
|
log("HB", "hbSetState: " + id + " -> " + JSON.stringify(data));
|
|
@@ -219,16 +265,21 @@ export async function hbSetState(server: string, id: string, service: Array<stri
|
|
|
219
265
|
}
|
|
220
266
|
|
|
221
267
|
// send a status change to HB Accessory
|
|
222
|
-
export async function
|
|
268
|
+
export async function hbGetValue(server: string, id: string, service: Array<string>, token: string) : Promise<number> {
|
|
223
269
|
const respBody = await httpRequest(server + "/api/accessories/"+id, 'GET', "", ContentType.json, {
|
|
224
270
|
Authorization: 'Bearer ' + token
|
|
225
271
|
});
|
|
226
272
|
if (respBody && respBody.error) {
|
|
227
273
|
log("HB", "hbGetState: " + id + " -> error: " + JSON.stringify(respBody));
|
|
228
|
-
return
|
|
229
|
-
|
|
274
|
+
return undefined;
|
|
275
|
+
|
|
276
|
+
} else if (respBody && respBody.values) {
|
|
277
|
+
return hbValue(respBody.values, service);
|
|
230
278
|
|
|
231
|
-
|
|
279
|
+
} else {
|
|
280
|
+
log("HB", "hbGetState: " + id + " -> no values?? : " + JSON.stringify(respBody));
|
|
281
|
+
return undefined;
|
|
282
|
+
};
|
|
232
283
|
}
|
|
233
284
|
|
|
234
285
|
export function hbSubscribe(callback) {
|
package/server/smartapp.js
CHANGED
|
@@ -396,8 +396,7 @@ class SmartApp extends webapp_1.WebApp {
|
|
|
396
396
|
this.links.forEach(link => {
|
|
397
397
|
link.unit || (link.unit = this.system.findUnit(this.system.findMaster(link.masterAddress, link.masterPort), link.logicalNodeAddress, link.logicalAddress));
|
|
398
398
|
if (link.unit) {
|
|
399
|
-
link.
|
|
400
|
-
link.status = link.unit.status;
|
|
399
|
+
link.dtValue = link.unit.value;
|
|
401
400
|
}
|
|
402
401
|
else {
|
|
403
402
|
(0, logger_1.log)("smartapp", "** error ** missing unit: " + (0, types_1.hex)(link.logicalNodeAddress) + "/" + (0, types_1.hex)(link.logicalAddress) + " **");
|
|
@@ -408,16 +407,18 @@ class SmartApp extends webapp_1.WebApp {
|
|
|
408
407
|
if (this.links.length && (yield this.checkToken())) {
|
|
409
408
|
for (const link of this.links) {
|
|
410
409
|
if ((link.type === types_1.LinkType.kAccessory) && link.unit) {
|
|
411
|
-
const
|
|
412
|
-
(0, logger_1.debug)("smartapp", "Received HB value for accessory: " + link.accName + " -> " +
|
|
413
|
-
if (
|
|
414
|
-
(0,
|
|
415
|
-
link.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
410
|
+
const hbValue = yield (0, HB_1.hbGetValue)(this.config.apiHost + ":" + this.config.apiPort, link.accId, link.accService, this.token);
|
|
411
|
+
(0, logger_1.debug)("smartapp", "Received HB value for accessory: " + link.accName + " -> " + hbValue + " from accessory");
|
|
412
|
+
if (typeof hbValue != "undefined") {
|
|
413
|
+
const { dtValue, dtTarget } = (0, HB_1.hb2dtvalue)(link.unit, hbValue);
|
|
414
|
+
if (dtValue !== link.dtValue) { // || state !== link.status
|
|
415
|
+
(0, logger_1.log)("smartapp", "-> Setting value of Duotecno unit: " + link.unit.getDisplayName() + " to " + dtTarget + " of HB accessory: " + link.accName + " with value " + hbValue);
|
|
416
|
+
link.dtValue = dtValue;
|
|
417
|
+
link.unit.setState(dtTarget);
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
(0, logger_1.debug)("smartapp", "-> No change for unit: " + link.unit.getDisplayName() + " to " + dtValue);
|
|
421
|
+
}
|
|
421
422
|
}
|
|
422
423
|
}
|
|
423
424
|
}
|
|
@@ -429,14 +430,14 @@ class SmartApp extends webapp_1.WebApp {
|
|
|
429
430
|
(0, logger_1.debug)("smartapp", "Received DT value from unit: " + u.getDisplayName() + " -> " + u.value + " / " + u.status + " from unit");
|
|
430
431
|
for (const link of this.links) {
|
|
431
432
|
if (u.isUnit(link.masterAddress, link.masterPort, link.logicalNodeAddress, link.logicalAddress)) {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
link.value
|
|
435
|
-
link.
|
|
436
|
-
yield (0, HB_1.hbSetState)(this.config.apiHost + ":" + this.config.apiPort, link.accId, link.accService,
|
|
433
|
+
const hbValue = (0, HB_1.dt2hbvalue)(u, link.hbValue);
|
|
434
|
+
if ((typeof hbValue != "undefined") && (hbValue !== link.hbValue)) {
|
|
435
|
+
(0, logger_1.log)("smartapp", "-> Setting HB value for accessory: " + link.accName + " to " + hbValue + " of Duotecno unit: " + u.getDisplayName() + " with value " + u.value);
|
|
436
|
+
link.hbValue = hbValue;
|
|
437
|
+
yield (0, HB_1.hbSetState)(this.config.apiHost + ":" + this.config.apiPort, link.accId, link.accService, hbValue, this.token);
|
|
437
438
|
}
|
|
438
439
|
else {
|
|
439
|
-
(0, logger_1.debug)("smartapp", "
|
|
440
|
+
(0, logger_1.debug)("smartapp", "-> No change for accessory: " + link.accName + " to " + u.value + " / " + u.status);
|
|
440
441
|
}
|
|
441
442
|
}
|
|
442
443
|
}
|
|
@@ -554,7 +555,7 @@ class SmartApp extends webapp_1.WebApp {
|
|
|
554
555
|
else {
|
|
555
556
|
if (link.type == types_1.LinkType.kAccessory) {
|
|
556
557
|
if (yield this.checkToken())
|
|
557
|
-
yield (0, HB_1.hbSetState)(this.config.apiHost + ":" + this.config.apiPort, link.id, link.service, link.unit.value,
|
|
558
|
+
yield (0, HB_1.hbSetState)(this.config.apiHost + ":" + this.config.apiPort, link.id, link.service, link.unit.value, this.token);
|
|
558
559
|
}
|
|
559
560
|
else {
|
|
560
561
|
(0, logger_1.err)("smartapp", "Don't know how to set a link of type " + link.type);
|
package/server/smartapp.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { Shelly } from './shelly';
|
|
|
22
22
|
import { P1 } from './p1';
|
|
23
23
|
import { setToken } from "../duotecno/config";
|
|
24
24
|
import { PowerBase } from "./powerbase";
|
|
25
|
-
import { hbAccessories,
|
|
25
|
+
import { dt2hbvalue, hb2dtvalue, hbAccessories, hbGetValue, hbLogin, hbName, hbService, hbSetState, hbSubscribe } from "./HB";
|
|
26
26
|
import { httpRequest, ContentType } from "./HA-API";
|
|
27
27
|
|
|
28
28
|
const kMaster = {name: "master", type: "string", default: "0.0.0.0:5001"} as const;
|
|
@@ -447,8 +447,7 @@ export class SmartApp extends WebApp {
|
|
|
447
447
|
link.unit ||= this.system.findUnit(this.system.findMaster(link.masterAddress, link.masterPort),
|
|
448
448
|
link.logicalNodeAddress, link.logicalAddress);
|
|
449
449
|
if (link.unit) {
|
|
450
|
-
link.
|
|
451
|
-
link.status = link.unit.status;
|
|
450
|
+
link.dtValue = link.unit.value;
|
|
452
451
|
} else {
|
|
453
452
|
log("smartapp", "** error ** missing unit: " + hex(link.logicalNodeAddress)+"/"+hex(link.logicalAddress) + " **");
|
|
454
453
|
}
|
|
@@ -459,15 +458,19 @@ export class SmartApp extends WebApp {
|
|
|
459
458
|
if (this.links.length && await this.checkToken()) {
|
|
460
459
|
for (const link of this.links) {
|
|
461
460
|
if ((link.type === LinkType.kAccessory) && link.unit) {
|
|
462
|
-
const
|
|
463
|
-
debug("smartapp", "Received HB value for accessory: " + link.accName + " -> " +
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
link.
|
|
467
|
-
|
|
468
|
-
link.
|
|
469
|
-
|
|
470
|
-
|
|
461
|
+
const hbValue = await hbGetValue(this.config.apiHost +":"+ this.config.apiPort, link.accId, link.accService, this.token);
|
|
462
|
+
debug("smartapp", "Received HB value for accessory: " + link.accName + " -> " + hbValue + " from accessory");
|
|
463
|
+
|
|
464
|
+
if (typeof hbValue != "undefined") {
|
|
465
|
+
const {dtValue, dtTarget} = hb2dtvalue(link.unit, hbValue);
|
|
466
|
+
|
|
467
|
+
if (dtValue !== link.dtValue) { // || state !== link.status
|
|
468
|
+
log("smartapp", "-> Setting value of Duotecno unit: " + link.unit.getDisplayName() + " to " + dtTarget + " of HB accessory: " + link.accName + " with value " + hbValue);
|
|
469
|
+
link.dtValue = dtValue;
|
|
470
|
+
link.unit.setState(dtTarget);
|
|
471
|
+
} else {
|
|
472
|
+
debug("smartapp", "-> No change for unit: " + link.unit.getDisplayName() + " to " + dtValue);
|
|
473
|
+
}
|
|
471
474
|
}
|
|
472
475
|
}
|
|
473
476
|
}
|
|
@@ -480,14 +483,15 @@ export class SmartApp extends WebApp {
|
|
|
480
483
|
debug("smartapp", "Received DT value from unit: " + u.getDisplayName() + " -> " + u.value + " / " + u.status + " from unit");
|
|
481
484
|
for (const link of this.links) {
|
|
482
485
|
if (u.isUnit(link.masterAddress, link.masterPort, link.logicalNodeAddress, link.logicalAddress)) {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
link.
|
|
487
|
-
|
|
486
|
+
const hbValue = dt2hbvalue(u, link.hbValue as number);
|
|
487
|
+
|
|
488
|
+
if ((typeof hbValue != "undefined") && (hbValue !== link.hbValue)) {
|
|
489
|
+
log("smartapp", "-> Setting HB value for accessory: " + link.accName + " to " + hbValue + " of Duotecno unit: " + u.getDisplayName() + " with value " + u.value);
|
|
490
|
+
link.hbValue = hbValue;
|
|
491
|
+
await hbSetState(this.config.apiHost +":"+ this.config.apiPort, link.accId, link.accService, hbValue, this.token);
|
|
488
492
|
|
|
489
493
|
} else {
|
|
490
|
-
debug("smartapp", "
|
|
494
|
+
debug("smartapp", "-> No change for accessory: " + link.accName + " to " + u.value + " / " + u.status);
|
|
491
495
|
}
|
|
492
496
|
}
|
|
493
497
|
};
|
|
@@ -615,7 +619,7 @@ export class SmartApp extends WebApp {
|
|
|
615
619
|
} else {
|
|
616
620
|
if (link.type == LinkType.kAccessory) {
|
|
617
621
|
if (await this.checkToken())
|
|
618
|
-
await hbSetState(this.config.apiHost +":"+ this.config.apiPort, link.id, link.service, link.unit.value,
|
|
622
|
+
await hbSetState(this.config.apiHost +":"+ this.config.apiPort, link.id, link.service, link.unit.value, this.token)
|
|
619
623
|
|
|
620
624
|
} else {
|
|
621
625
|
err("smartapp", "Don't know how to set a link of type " + link.type);
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
<option value="">Select a unit</option>
|
|
61
61
|
<% for (let u of units) { %>
|
|
62
62
|
<option value="<%= u.node.master.getURL()+"-"+u.logicalNodeAddress+"/"+u.logicalAddress %>"
|
|
63
|
-
<%= ((u.
|
|
63
|
+
<%= ((u.node.master.config.address == link.masterAddress) && (u.node.master.config.port == link.masterPort) && (u.logicalNodeAddress == link.logicalNodeAddress) && (u.logicalAddress == link.logicalAddress)) ? "selected" : "" %>
|
|
64
64
|
><%= u.name %></option>
|
|
65
65
|
<% } %>
|
|
66
66
|
</select>
|