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 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,
@@ -15,7 +15,7 @@ var LogLevel;
15
15
  exports.logSettings = {
16
16
  "*": LogLevel.log,
17
17
  "master": LogLevel.log,
18
- "protocol": LogLevel.noLog,
18
+ "protocol": LogLevel.debug,
19
19
  "webapp": LogLevel.log,
20
20
  "p1": LogLevel.log,
21
21
  "shelly": LogLevel.log,
@@ -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.noLog,
13
+ "protocol": LogLevel.debug,
14
14
  "webapp": LogLevel.log,
15
15
  "p1": LogLevel.log,
16
16
  "shelly": LogLevel.log,
@@ -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 Schedule
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) {
@@ -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 Schedule
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
- status?: number | boolean;
273
- value?: number | boolean | string
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.2",
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.hbGetState = exports.hbSetState = exports.hbLogin = exports.hbAccessories = exports.hbService = exports.hbName = void 0;
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
- values["value"] = parseInt(data["Brightness"]);
234
+ return parseInt(data["Brightness"]);
191
235
  }
192
236
  if (service.includes("On")) {
193
- values["state"] = parseInt(data["On"]);
237
+ return parseInt(data["On"]);
194
238
  }
195
239
  if (service.includes("TargetPosition")) {
196
- values["value"] = parseInt(data["TargetPosition"]);
240
+ return parseInt(data["TargetPosition"]);
197
241
  }
198
- return values;
242
+ return undefined;
199
243
  }
200
244
  // send a status change to HB Accessory
201
- function hbSetState(server, id, service, value, state, token) {
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 hbGetState(server, id, service, token) {
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
- return hbValue(respBody.values, service);
275
+ ;
225
276
  });
226
277
  }
227
- exports.hbGetState = hbGetState;
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 hbValue(data: Record<string, any>, service: Array<string>): {value?: number, state?: number} {
192
- const values = {};
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
- values["value"] = parseInt(data["Brightness"]);
240
+ return parseInt(data["Brightness"]);
195
241
  }
196
242
 
197
243
  if (service.includes("On")) {
198
- values["state"] = parseInt(data["On"])
244
+ return parseInt(data["On"])
199
245
  }
200
246
 
201
247
  if (service.includes("TargetPosition")) {
202
- values["value"] = parseInt(data["TargetPosition"]);
248
+ return parseInt(data["TargetPosition"]);
203
249
  }
204
- return values
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, state: number, token: string) : Promise<void> {
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 hbGetState(server: string, id: string, service: Array<string>, token: string) : Promise<{value?: number, state?: number}> {
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
- return hbValue(respBody.values, service);
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) {
@@ -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.value = link.unit.value;
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 { value, state } = yield (0, HB_1.hbGetState)(this.config.apiHost + ":" + this.config.apiPort, link.accId, link.accService, this.token);
412
- (0, logger_1.debug)("smartapp", "Received HB value for accessory: " + link.accName + " -> " + value + " / " + state + " from accessory");
413
- if ((typeof value != "undefined") && (value !== link.value)) { // || state !== link.status
414
- (0, logger_1.log)("smartapp", " -> Setting value of Duotecno unit: " + link.unit.getDisplayName() + " to " + value + " of HB accessory: " + link.accName);
415
- link.value = value;
416
- // link.status = state;
417
- link.unit.setState(value);
418
- }
419
- else {
420
- (0, logger_1.debug)("smartapp", " -> No change for unit: " + link.unit.getDisplayName() + " to " + value);
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
- if (link.value !== u.value) { // || link.status !== u.status
433
- (0, logger_1.log)("smartapp", " -> Setting HB value for accessory: " + link.accName + " to " + u.value + " / " + u.status + " of Duotecno unit: " + u.getDisplayName());
434
- link.value = u.value;
435
- link.status = u.status;
436
- yield (0, HB_1.hbSetState)(this.config.apiHost + ":" + this.config.apiPort, link.accId, link.accService, u.value, u.status, this.token);
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", " -> No change for accessory: " + link.accName + " to " + u.value + " / " + u.status);
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, link.unit.status, this.token);
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);
@@ -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, hbGetState, hbLogin, hbName, hbService, hbSetState, hbSubscribe } from "./HB";
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.value = link.unit.value;
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 {value, state} = await hbGetState(this.config.apiHost +":"+ this.config.apiPort, link.accId, link.accService, this.token);
463
- debug("smartapp", "Received HB value for accessory: " + link.accName + " -> " + value + " / " + state + " from accessory");
464
- if ((typeof value != "undefined") && (value !== link.value)) { // || state !== link.status
465
- log("smartapp", " -> Setting value of Duotecno unit: " + link.unit.getDisplayName() + " to " + value + " of HB accessory: " + link.accName);
466
- link.value = value;
467
- // link.status = state;
468
- link.unit.setState(value);
469
- } else {
470
- debug("smartapp", " -> No change for unit: " + link.unit.getDisplayName() + " to " + value);
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
- if (link.value !== u.value) { // || link.status !== u.status
484
- log("smartapp", " -> Setting HB value for accessory: " + link.accName + " to " + u.value + " / " + u.status + " of Duotecno unit: " + u.getDisplayName());
485
- link.value = u.value;
486
- link.status = u.status;
487
- await hbSetState(this.config.apiHost +":"+ this.config.apiPort, link.accId, link.accService, u.value, u.status, this.token);
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", " -> No change for accessory: " + link.accName + " to " + u.value + " / " + u.status);
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, link.unit.status, this.token)
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.masterAddress == link.masterAddress) && (u.masterPort == link.masterPort) && (u.logicalNodeAddress == link.logicalNodeAddress) && (u.logicalAddress == link.logicalAddress)) ? "selected" : "" %>
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>