homebridge-smartsystem 6.3.3 → 6.4.1

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.
@@ -1,4 +1,4 @@
1
- import { Node, Protocol, Unit, recName, Rec, TempPreset } from "./protocol";
1
+ import { Node, Protocol, Unit, recName, Rec, TempPreset, reqNodeAttributes } from "./protocol";
2
2
  import { MasterConfig, WriteError, CommRecord, Message, Sanitizers } from "./types";
3
3
  import { log, debug } from "./logger";
4
4
  import { System } from "./system";
@@ -15,6 +15,10 @@ export class Master extends Base {
15
15
  public schedule: number;
16
16
  public date: Date;
17
17
  public lastHeartbeat: number;
18
+ public protocol: number = 0; // major * 100 + minor
19
+ public version: number = 0; // idem
20
+
21
+ public registers: {[register: number]: number} = {};
18
22
 
19
23
  public isOpen: boolean;
20
24
  public isLoggedIn: boolean;
@@ -166,6 +170,10 @@ export class Master extends Base {
166
170
 
167
171
  // incoming data
168
172
  this.buffer = "";
173
+
174
+ // init to v1.00
175
+ this.version = 100;
176
+ this.protocol = 100;
169
177
  }
170
178
 
171
179
  getName() {
@@ -398,8 +406,8 @@ export class Master extends Base {
398
406
  return false;
399
407
 
400
408
  } else {
401
- if ((next.cmd != Rec.TimeDateStatus) &&
402
- (next.cmd != Rec.Sensor))
409
+ // don't log all incoming (no time, no sensor status messages)
410
+ if ((next.cmd != Rec.TimeDateStatus) && (next.cmd != Rec.Sensor))
403
411
  this.info("received -> " + recName(next.cmd) + " -> " + ((!next.message) ?
404
412
  "--" : ((next.message instanceof Array) ? next.message.join(",") : next.message)));
405
413
 
@@ -423,6 +431,12 @@ export class Master extends Base {
423
431
 
424
432
  } else if (next.cmd === Rec.ScheduleStatus) {
425
433
  this.receiveSchedule(next.message);
434
+
435
+ } else if (next.cmd === Rec.NodeMgtInfo) {
436
+ this.receiveNodeMgtInfo(next.message);
437
+
438
+ } else if (next.cmd === Rec.Register) {
439
+ this.receiveRegister(next.message);
426
440
 
427
441
  } else {
428
442
  this.info("not handled: " + next.message);
@@ -442,6 +456,12 @@ export class Master extends Base {
442
456
  if (this.resolveLogin) {
443
457
  this.resolveLogin(this.isLoggedIn);
444
458
  this.resolveLogin = null;
459
+
460
+ // if logged in, ask protocol version
461
+ if (this.isLoggedIn) {
462
+ this.send(Protocol.buildRequestNodeMgt(reqNodeAttributes.nodeProtocol));
463
+ }
464
+
445
465
  } else {
446
466
  this.err("unexpected ConnectStatus ?");
447
467
  }
@@ -451,7 +471,48 @@ export class Master extends Base {
451
471
  // Info messages //
452
472
  ///////////////////
453
473
 
454
- receiveHeartbeat(next: Message) {
474
+ receiveNodeMgtInfo(message: Message) {
475
+ if (message[1] === reqNodeAttributes.isMaster) {
476
+ this.log("NodeMgtInfo - master " + this.getName() + " is set to master: " + message[2]);
477
+
478
+ } else if (message[1] === reqNodeAttributes.nodeInfo) {
479
+ // should be the same as the one from the DBInfo (64)
480
+ this.log("NodeMgtInfo - node info for " + this.getName() + ": " + message);
481
+
482
+ } else if (message[1] === reqNodeAttributes.masterSupported) {
483
+ this.log("NodeMgtInfo - master " + this.getName() + " can be master: " + message[2]);
484
+
485
+ } else if (message[1] === reqNodeAttributes.nodeVersion) {
486
+ console.log("*** -> " + message);
487
+ this.log("NodeMgtInfo - version " + this.getName() + ", version: " + message[2] + "." + message[3]);
488
+ this.version = message[2] * 100 + message[3];
489
+ //BUG - TODO: remove
490
+ this.protocol = message[2] * 100 + message[3];
491
+
492
+ } else if (message[1] === reqNodeAttributes.nodeProtocol) {
493
+ console.log("*** -> " + message);
494
+ this.log("NodeMgtInfo - protocol " + this.getName() + ", protocol: " + message[2] + "." + message[3]);
495
+ this.protocol = message[2] * 100 + message[3];
496
+
497
+
498
+ } else {
499
+ this.err("dropped NodeMgtInfo info message = " + message[1] + ", message: " + message);
500
+ }
501
+ }
502
+
503
+ receiveRegister(message: Message) {
504
+ const register = Protocol.makeWord(message, 2);
505
+ const value = Protocol.makeSigned(message, 4);
506
+
507
+ if ((register >=0) && (register < 1024)) {
508
+ this.registers[register] = value;
509
+ this.log("receiveRegister(" + register + ") = " + value);
510
+ } else {
511
+ this.err("Received register out of bound: " + register);
512
+ }
513
+ }
514
+
515
+ receiveHeartbeat(message: Message) {
455
516
  this.lastHeartbeat = new Date().getTime();
456
517
  //console.log("*HB* Received HB");
457
518
  this.log("Received heartbeat at " + (new Date()));
@@ -478,6 +539,7 @@ export class Master extends Base {
478
539
  this.info("received week schedule = " + this.schedule);
479
540
  }
480
541
 
542
+
481
543
  receiveDateTime(message: Message) {
482
544
  // 71,0,9,37,3,3,4,3,21,20 -> 09:37:03 Wednesday(3) 4 march 2120
483
545
  this.date = new Date( (message[8]-1) * 100 + message[9], message[7]-1, message[6],
@@ -540,7 +602,9 @@ export class Master extends Base {
540
602
  this.system.setActiveState(unit);
541
603
  }
542
604
 
543
-
605
+ //////////////////
606
+ // request info //
607
+ //////////////////
544
608
  async fetchAllUnits(node: Node) {
545
609
  for (let unitInx=0; unitInx < node.nrUnits; unitInx++) {
546
610
  await this.fetchUnit(node, unitInx);
@@ -755,6 +819,18 @@ export class Master extends Base {
755
819
  this.info("get value of " + unit.node.getName() + "-" + unit.getName());
756
820
  }
757
821
 
822
+ async requestRegisterValue(register: number) {
823
+ if (this.version >= 209) {
824
+ await this.send(Protocol.buildRegister(register));
825
+ this.info("request register: " + register);
826
+ } else {
827
+ this.err("FC_REGISTERMAP not available before protocol v2.09")
828
+ }
829
+ }
830
+
831
+ /////////////////////
832
+ // Settings values //
833
+ /////////////////////
758
834
  async setUnitStatus(unit: Unit, value: number) {
759
835
  const params = Protocol.buildSetCmd(unit.node, unit, value);
760
836
  if (params.cmd) {
@@ -762,6 +838,15 @@ export class Master extends Base {
762
838
  }
763
839
  }
764
840
 
841
+ async setRegisterValue(register: number, value: number) {
842
+ if (this.version >= 209) {
843
+ await this.send(Protocol.buildRegister(register, value));
844
+ this.info("set register: " + register + ", to: " + value);
845
+ } else {
846
+ this.err("FC_REGISTERMAP not available before protocol v2.09")
847
+ }
848
+ }
849
+
765
850
  async setSensorValue(unit: Unit, value: number) {
766
851
  this.info("SetSensorValue of " + unit.node.logicalAddress + "/" + unit.logicalAddress + " to " + value);
767
852
  await this.send(Protocol.buildSetPreset(unit.node, unit, TempPreset.sun, Math.trunc(value / 100 / 100 / 100) % 100));
@@ -798,5 +883,4 @@ export class Master extends Base {
798
883
  this.info("set temp preset of " + unit.node.getName() + "-" + unit.getName() + ": " + (inc ? "up" : "down"));
799
884
  }
800
885
 
801
-
802
886
  }
@@ -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.Protocol = exports.Unit = exports.Node = exports.recName = exports.Rec = exports.TempPreset = exports.cmdName = void 0;
12
+ exports.Protocol = exports.Unit = exports.Node = exports.recName = exports.Rec = exports.TempPreset = exports.cmdName = exports.reqNodeAttributes = void 0;
13
13
  const types_1 = require("./types");
14
14
  const logger_1 = require("./logger");
15
15
  // Duotecno master IP protocol implementation
@@ -19,21 +19,29 @@ const logger_1 = require("./logger");
19
19
  // Mar 2019 - v2 - rewrite to support multiple masters
20
20
  //
21
21
  // Dec 2019 - v3 - for app side only
22
+ // May-Nov 2021 - v4 - changes for pro-app
23
+ // Nov 2022 - Register and merge with gateway
22
24
  ///////////////////////////
23
25
  // Commands + attributes //
24
26
  ///////////////////////////
25
27
  var Cmd;
26
28
  (function (Cmd) {
27
29
  Cmd[Cmd["SetSensorValue"] = 7] = "SetSensorValue";
30
+ Cmd[Cmd["Internal"] = 9] = "Internal";
31
+ Cmd[Cmd["SetBasicAudio"] = 159] = "SetBasicAudio";
32
+ Cmd[Cmd["SetExtendedAudio"] = 208] = "SetExtendedAudio";
33
+ Cmd[Cmd["SetAVMatrix"] = 202] = "SetAVMatrix";
28
34
  Cmd[Cmd["SetSwitch"] = 163] = "SetSwitch";
29
35
  Cmd[Cmd["SetDimmer"] = 162] = "SetDimmer";
30
36
  Cmd[Cmd["SetControl"] = 168] = "SetControl";
31
37
  Cmd[Cmd["SetMotor"] = 182] = "SetMotor";
32
38
  Cmd[Cmd["SetSensor"] = 136] = "SetSensor";
39
+ Cmd[Cmd["SetDateTime"] = 170] = "SetDateTime";
33
40
  Cmd[Cmd["Login"] = 214] = "Login";
34
41
  Cmd[Cmd["Heartbeat"] = 215] = "Heartbeat";
35
42
  Cmd[Cmd["DatabaseInfo"] = 209] = "DatabaseInfo";
36
43
  Cmd[Cmd["SetSchedule"] = 217] = "SetSchedule";
44
+ Cmd[Cmd["Register"] = 224] = "Register";
37
45
  })(Cmd || (Cmd = {}));
38
46
  // for Set Switch/Dimmer/Control
39
47
  const reqDim = 3;
@@ -49,6 +57,16 @@ const reqUnitInfo = 2;
49
57
  const reqUnitStatus = 3;
50
58
  // for Schedule
51
59
  const reqSchedule = 218;
60
+ // for versions et al
61
+ const reqNodeManagement = 220;
62
+ var reqNodeAttributes;
63
+ (function (reqNodeAttributes) {
64
+ reqNodeAttributes[reqNodeAttributes["masterSupported"] = 0] = "masterSupported";
65
+ reqNodeAttributes[reqNodeAttributes["isMaster"] = 4] = "isMaster";
66
+ reqNodeAttributes[reqNodeAttributes["nodeInfo"] = 5] = "nodeInfo";
67
+ reqNodeAttributes[reqNodeAttributes["nodeVersion"] = 6] = "nodeVersion";
68
+ reqNodeAttributes[reqNodeAttributes["nodeProtocol"] = 7] = "nodeProtocol";
69
+ })(reqNodeAttributes = exports.reqNodeAttributes || (exports.reqNodeAttributes = {}));
52
70
  function cmdName(cmd) {
53
71
  return Cmd[cmd] || "cmd" + cmd;
54
72
  }
@@ -80,6 +98,8 @@ var Rec;
80
98
  Rec[Rec["TimeDateStatus"] = 71] = "TimeDateStatus";
81
99
  Rec[Rec["HeartbeatStatus"] = 72] = "HeartbeatStatus";
82
100
  Rec[Rec["ScheduleStatus"] = 73] = "ScheduleStatus";
101
+ Rec[Rec["NodeMgtInfo"] = 74] = "NodeMgtInfo";
102
+ Rec[Rec["Register"] = 77] = "Register";
83
103
  // return info from recDBInfo
84
104
  Rec[Rec["Info"] = 64] = "Info";
85
105
  // return info from reqUnitStatus
@@ -151,8 +171,8 @@ class Unit {
151
171
  this.extendedType = this.extendedType || this.calcExtendedType();
152
172
  this.name = this.name || this.getSerialNr();
153
173
  // delete the "<" and ">" for power meters
154
- if (this.extendedType === types_1.UnitExtendedType.kPower)
155
- this.name = this.name.substring(1);
174
+ // if (this.extendedType === UnitExtendedType.kPower)
175
+ // this.name = this.name.substring(1);
156
176
  // make a name for homekit, without the | but add § is 'specials' to add "sfeer", etc...
157
177
  // if the display name is empty make a N[nodeAdr]-U[unitAdr] name.
158
178
  // delete all type modifiers ( $, * and ! )
@@ -229,11 +249,12 @@ class Unit {
229
249
  case types_1.UnitType.kDimmer: return "03|" + name;
230
250
  case types_1.UnitType.kSwitch: return "04|" + name;
231
251
  case types_1.UnitType.kMood: return "09|" + name;
232
- case types_1.UnitType.kInput: return "11|" + name;
252
+ case types_1.UnitType.kInput: return "10|" + name;
253
+ // case UnitType.kPower: return "11|" + name;
233
254
  case types_1.UnitType.kExtendedAudio: "12|" + name;
234
- case types_1.UnitType.kAudio: return "12|" + name;
235
- case types_1.UnitType.kAV: return "13|" + name;
236
- case types_1.UnitType.kVideo: return "14|" + name;
255
+ case types_1.UnitType.kAudio: return "13|" + name;
256
+ case types_1.UnitType.kAV: return "14|" + name;
257
+ case types_1.UnitType.kVideo: return "15|" + name;
237
258
  case types_1.UnitType.kIRTX: return "19|" + name;
238
259
  default: return "99|" + name;
239
260
  }
@@ -280,9 +301,9 @@ class Unit {
280
301
  //////////////////
281
302
  // Temp / Power //
282
303
  //////////////////
283
- if ((this.type === types_1.UnitType.kTemperature) &&
284
- ((this.name[0] === "<") || (this.name[0] === ">")))
285
- return types_1.UnitExtendedType.kPower;
304
+ //if ((this.type === UnitType.kTemperature) &&
305
+ // ((this.name[0] === "<") || (this.name[0] === ">")))
306
+ // return UnitExtendedType.kPower;
286
307
  /////////////
287
308
  // Up/Down //
288
309
  /////////////
@@ -472,12 +493,55 @@ exports.Protocol = {
472
493
  .map(val => String.fromCharCode(val))
473
494
  .join("");
474
495
  },
496
+ makeWord: function (arr, at) {
497
+ return arr[at + 0] * 256 + arr[at + 1];
498
+ },
499
+ makeSignedWord: function (arr, at) {
500
+ if (arr[at + 0] > 127)
501
+ return (arr[at + 0] - 255) * 256 +
502
+ (arr[at + 1] - 255) - 1;
503
+ else
504
+ return arr[at + 0] * 256 + arr[at + 1];
505
+ },
475
506
  makeLong: function (arr, at) {
476
507
  return arr[at + 0] * 256 * 256 * 256 +
477
508
  arr[at + 1] * 256 * 256 +
478
509
  arr[at + 2] * 256 +
479
510
  arr[at + 3];
480
511
  },
512
+ makeSigned: function (arr, at) {
513
+ if (arr[at + 0] > 127)
514
+ return (arr[at + 0] - 255) * 256 * 256 * 256 +
515
+ (arr[at + 1] - 255) * 256 * 256 +
516
+ (arr[at + 2] - 255) * 256 +
517
+ (arr[at + 3] - 255) - 1;
518
+ else
519
+ return arr[at + 0] * 256 * 256 * 256 +
520
+ arr[at + 1] * 256 * 256 +
521
+ arr[at + 2] * 256 +
522
+ arr[at + 3];
523
+ },
524
+ signedToArray: function (value) {
525
+ if (value < 0)
526
+ return [256 + Math.floor(value / 256 / 256 / 256),
527
+ 256 + Math.floor(value / 256 / 256) % 256,
528
+ 256 + Math.floor(value / 256) % 256,
529
+ 256 + Math.floor(value) % 256];
530
+ else
531
+ return [Math.floor(value / 256 / 256 / 256),
532
+ Math.floor(value / 256 / 256) % 256,
533
+ Math.floor(value / 256) % 256,
534
+ Math.floor(value) % 256];
535
+ },
536
+ signedWordToArray: function (value) {
537
+ if (value < 0)
538
+ return [256 + Math.floor(value / 256) % 256, 256 + Math.floor(value) % 256];
539
+ else
540
+ return [Math.floor(value / 256) % 256, Math.floor(value) % 256];
541
+ },
542
+ wordToArray: function (value) {
543
+ return [Math.floor(value / 256) % 256, Math.floor(value) % 256];
544
+ },
481
545
  isStatus: function (cmd) {
482
546
  return (cmd === Rec.Mood) ||
483
547
  (cmd === Rec.Dimmer) ||
@@ -529,8 +593,8 @@ exports.Protocol = {
529
593
  socket.write(data + String.fromCharCode(10));
530
594
  return types_1.WriteError.writeOK;
531
595
  }
532
- catch (err) {
533
- (0, logger_1.log)("protocol", "error sending through socket " + err.message);
596
+ catch (e) {
597
+ (0, logger_1.err)("protocol", "error sending through socket " + e.message);
534
598
  return types_1.WriteError.writeFatal;
535
599
  }
536
600
  }
@@ -609,6 +673,9 @@ exports.Protocol = {
609
673
  buildRequestSchedule() {
610
674
  return [reqSchedule, 0];
611
675
  },
676
+ buildRequestNodeMgt(method = reqNodeAttributes.nodeProtocol) {
677
+ return [reqNodeManagement, method];
678
+ },
612
679
  getCmdAndMethod: function (unit, value) {
613
680
  switch (unit.type) {
614
681
  case types_1.UnitType.kDimmer:
@@ -656,10 +723,10 @@ exports.Protocol = {
656
723
  return [Cmd.SetSensor, 13, node.logicalAddress, unit.logicalAddress, preset];
657
724
  },
658
725
  buildSetSensor(node, unit, value) {
659
- return [Cmd.SetSensorValue, 10, node.logicalAddress, unit.logicalAddress, types_1.UnitType.kTemperature, Math.floor(value / 256), value % 256];
726
+ return [Cmd.SetSensorValue, 10, node.logicalAddress, unit.logicalAddress, types_1.UnitType.kTemperature, ...this.wordToArray(value)];
660
727
  },
661
728
  buildSetPreset(node, unit, preset, value) {
662
- return [Cmd.SetSensor, 1, node.logicalAddress, unit.logicalAddress, preset, Math.floor(value / 256), value % 256];
729
+ return [Cmd.SetSensor, 1, node.logicalAddress, unit.logicalAddress, preset, ...this.wordToArray(value)];
663
730
  },
664
731
  buildIncDecPreset(node, unit, inc) {
665
732
  return [Cmd.SetSensor, (inc) ? 5 : 6, node.logicalAddress, unit.logicalAddress];
@@ -671,6 +738,16 @@ exports.Protocol = {
671
738
  buildSendSchedule(schedule) {
672
739
  return [Cmd.SetSchedule, 0, Math.max(0, Math.min(3, schedule))];
673
740
  },
741
+ buildRegister(register, value) {
742
+ if (typeof value != "undefined") {
743
+ // set register
744
+ return [Cmd.Register, 1, ...this.wordToArray(register), ...this.signedToArray(value)];
745
+ }
746
+ else {
747
+ // get register
748
+ return [Cmd.Register, 2, ...this.wordToArray(register)];
749
+ }
750
+ },
674
751
  ///////////////////
675
752
  // Received info //
676
753
  ///////////////////
@@ -678,13 +755,13 @@ exports.Protocol = {
678
755
  let kind = "-";
679
756
  if (next.cmd === Rec.Sensor) {
680
757
  // sensor -> value
681
- unit.value = next.message[9] * 256 + next.message[10]; // 10x current temperature
758
+ unit.value = this.makeWord(next.message, 9); // 10x current temperature
682
759
  unit.status = next.message[7]; // 0=idle, 1=heating, 2=cooling
683
760
  unit.preset = (next.message[6]) ? next.message[8] : -1; // 0=sun, 1=half sun, 2=moon, 3=half moon, -1 = off
684
- unit.sun = next.message[11] * 256 + next.message[12]; // 10x temperature
685
- unit.hsun = next.message[13] * 256 + next.message[14]; // 10x temperature
686
- unit.moon = next.message[15] * 256 + next.message[16]; // 10x temperature
687
- unit.hmoon = next.message[17] * 256 + next.message[18]; // 10x temperature
761
+ unit.sun = this.makeWord(next.message, 11); // 10x temperature
762
+ unit.hsun = this.makeWord(next.message, 13); // 10x temperature
763
+ unit.moon = this.makeWord(next.message, 15); // 10x temperature
764
+ unit.hmoon = this.makeWord(next.message, 17); // 10x temperature
688
765
  (0, logger_1.debug)("protocol", "received status - " + unit.getDisplayName() + ", temperature = " + unit.value / 10.0 + ", sun = " + unit.sun);
689
766
  kind = "S";
690
767
  // Dimmers, switches and moods have
@@ -737,16 +814,11 @@ exports.Protocol = {
737
814
  // only change dim value when state = 1 (ON, PIR ON, DIM STOP) for Dimmers and IRTX + for any setpoint event
738
815
  if ((((next.message[4] === 1) || (next.message[4] === 6) || (next.message[4] === 7)) && (next.message[5] === 1)) ||
739
816
  (next.message[4] === 11)) {
740
- unit.value = next.message[6] * 256 + next.message[7];
817
+ unit.value = this.makeWord(next.message, 6);
741
818
  }
742
819
  (0, logger_1.debug)("protocol", "received status - macro -> value=" + unit.value + " / status=" + unit.status);
743
820
  kind = "M";
744
821
  }
745
- // clear the timer to turn the mood off again.
746
- //if (unit.resetTimer) {
747
- // clearInterval(unit.resetTimer);
748
- // unit.resetTimer = null;
749
- //}
750
822
  this.alertSubscriber(unit);
751
823
  this.emitter.emit('update', unit, kind);
752
824
  },
@@ -1,5 +1,5 @@
1
1
  import { CommRecord, Message, Sanitizers, NodeInfo, UnitInfo, DBInfo, WriteError, hex, NodeType, UnitType, UnitExtendedType, UnitState, two } from "./types";
2
- import { debug, log } from "./logger";
2
+ import { debug, log, err } from "./logger";
3
3
  import { Master } from "./master";
4
4
  import { SmartSocket } from "./smartsocket";
5
5
  import { EventEmitter } from "events";
@@ -11,6 +11,8 @@ import { EventEmitter } from "events";
11
11
  // Mar 2019 - v2 - rewrite to support multiple masters
12
12
  //
13
13
  // Dec 2019 - v3 - for app side only
14
+ // May-Nov 2021 - v4 - changes for pro-app
15
+ // Nov 2022 - Register and merge with gateway
14
16
 
15
17
 
16
18
  ///////////////////////////
@@ -18,15 +20,25 @@ import { EventEmitter } from "events";
18
20
  ///////////////////////////
19
21
  enum Cmd {
20
22
  SetSensorValue = 7,
23
+ Internal = 9, // smartsystem defined (not Duotecno)
24
+
25
+ SetBasicAudio = 159,
26
+ SetExtendedAudio = 208,
27
+ SetAVMatrix = 202,
28
+
21
29
  SetSwitch = 163,
22
30
  SetDimmer = 162,
23
31
  SetControl = 168,
24
32
  SetMotor = 182,
25
33
  SetSensor = 136,
34
+
35
+ SetDateTime = 170,
36
+
26
37
  Login = 214,
27
38
  Heartbeat = 215,
28
39
  DatabaseInfo = 209,
29
- SetSchedule = 217
40
+ SetSchedule = 217,
41
+ Register = 224
30
42
  }
31
43
 
32
44
  // for Set Switch/Dimmer/Control
@@ -47,6 +59,16 @@ const reqUnitStatus = 3;
47
59
  // for Schedule
48
60
  const reqSchedule = 218;
49
61
 
62
+ // for versions et al
63
+ const reqNodeManagement = 220;
64
+ export enum reqNodeAttributes {
65
+ masterSupported = 0,
66
+ isMaster = 4,
67
+ nodeInfo = 5,
68
+ nodeVersion = 6,
69
+ nodeProtocol = 7
70
+ }
71
+
50
72
 
51
73
  export function cmdName(cmd: number | string) {
52
74
  return Cmd[cmd] || "cmd"+cmd;
@@ -88,6 +110,8 @@ export enum Rec {
88
110
  TimeDateStatus = 71,
89
111
  HeartbeatStatus = 72,
90
112
  ScheduleStatus = 73,
113
+ NodeMgtInfo = 74,
114
+ Register = 77,
91
115
 
92
116
  // return info from recDBInfo
93
117
  Info = 64,
@@ -207,8 +231,8 @@ export class Unit {
207
231
  this.name = this.name || this.getSerialNr();
208
232
 
209
233
  // delete the "<" and ">" for power meters
210
- if (this.extendedType === UnitExtendedType.kPower)
211
- this.name = this.name.substring(1);
234
+ // if (this.extendedType === UnitExtendedType.kPower)
235
+ // this.name = this.name.substring(1);
212
236
 
213
237
  // make a name for homekit, without the | but add § is 'specials' to add "sfeer", etc...
214
238
  // if the display name is empty make a N[nodeAdr]-U[unitAdr] name.
@@ -290,12 +314,14 @@ export class Unit {
290
314
  case UnitType.kDimmer: return "03|" + name;
291
315
  case UnitType.kSwitch: return "04|" + name;
292
316
  case UnitType.kMood: return "09|" + name;
293
- case UnitType.kInput: return "11|" + name;
317
+ case UnitType.kInput: return "10|" + name;
318
+ // case UnitType.kPower: return "11|" + name;
294
319
  case UnitType.kExtendedAudio: "12|" + name;
295
- case UnitType.kAudio: return "12|" + name;
296
- case UnitType.kAV: return "13|" + name;
297
- case UnitType.kVideo: return "14|" + name;
320
+ case UnitType.kAudio: return "13|" + name;
321
+ case UnitType.kAV: return "14|" + name;
322
+ case UnitType.kVideo: return "15|" + name;
298
323
  case UnitType.kIRTX: return "19|" + name;
324
+
299
325
  default: return "99|" + name;
300
326
  }
301
327
  }
@@ -347,9 +373,9 @@ export class Unit {
347
373
  //////////////////
348
374
  // Temp / Power //
349
375
  //////////////////
350
- if ((this.type === UnitType.kTemperature) &&
351
- ((this.name[0] === "<") || (this.name[0] === ">")))
352
- return UnitExtendedType.kPower;
376
+ //if ((this.type === UnitType.kTemperature) &&
377
+ // ((this.name[0] === "<") || (this.name[0] === ">")))
378
+ // return UnitExtendedType.kPower;
353
379
 
354
380
 
355
381
  /////////////
@@ -552,12 +578,55 @@ export const Protocol = {
552
578
  .join("");
553
579
  },
554
580
 
581
+ makeWord: function(arr: Array<number>, at: number) {
582
+ return arr[at+0] * 256 + arr[at+1];
583
+ },
584
+ makeSignedWord: function(arr: Array<number>, at: number) {
585
+ if (arr[at+0] > 127)
586
+ return (arr[at+0]-255) * 256 +
587
+ (arr[at+1]-255) - 1;
588
+ else
589
+ return arr[at+0] * 256 + arr[at+1];
590
+ },
555
591
  makeLong: function(arr: Array<number>, at: number) {
556
592
  return arr[at+0] * 256 * 256 * 256 +
557
593
  arr[at+1] * 256 * 256 +
558
594
  arr[at+2] * 256 +
559
595
  arr[at+3];
560
596
  },
597
+ makeSigned: function(arr: Array<number>, at: number) {
598
+ if (arr[at+0] > 127)
599
+ return (arr[at+0]-255) * 256 * 256 * 256 +
600
+ (arr[at+1]-255) * 256 * 256 +
601
+ (arr[at+2]-255) * 256 +
602
+ (arr[at+3]-255) - 1;
603
+ else
604
+ return arr[at+0] * 256 * 256 * 256 +
605
+ arr[at+1] * 256 * 256 +
606
+ arr[at+2] * 256 +
607
+ arr[at+3];
608
+ },
609
+ signedToArray: function(value: number) {
610
+ if (value < 0)
611
+ return [256 + Math.floor(value / 256 / 256 / 256),
612
+ 256 + Math.floor(value / 256 / 256) % 256,
613
+ 256 + Math.floor(value / 256) % 256,
614
+ 256 + Math.floor(value) % 256]
615
+ else
616
+ return [Math.floor(value / 256 / 256 / 256),
617
+ Math.floor(value / 256 / 256) % 256,
618
+ Math.floor(value / 256) % 256,
619
+ Math.floor(value) % 256];
620
+ },
621
+ signedWordToArray: function(value: number) {
622
+ if (value < 0)
623
+ return [256 + Math.floor(value / 256) % 256, 256 + Math.floor(value) % 256];
624
+ else
625
+ return [Math.floor(value / 256) % 256, Math.floor(value) % 256];
626
+ },
627
+ wordToArray: function(value: number) {
628
+ return [Math.floor(value / 256) % 256, Math.floor(value) % 256];
629
+ },
561
630
 
562
631
  isStatus: function(cmd: number): boolean {
563
632
  return (cmd === Rec.Mood) ||
@@ -617,8 +686,8 @@ export const Protocol = {
617
686
  socket.write(data+String.fromCharCode(10));
618
687
  return WriteError.writeOK;
619
688
 
620
- } catch(err) {
621
- log("protocol", "error sending through socket " + err.message);
689
+ } catch(e) {
690
+ err("protocol", "error sending through socket " + e.message);
622
691
  return WriteError.writeFatal;
623
692
  }
624
693
  } else {
@@ -715,6 +784,9 @@ export const Protocol = {
715
784
  buildRequestSchedule(): Message {
716
785
  return [reqSchedule, 0];
717
786
  },
787
+ buildRequestNodeMgt(method = reqNodeAttributes.nodeProtocol): Message {
788
+ return [reqNodeManagement, method];
789
+ },
718
790
 
719
791
  getCmdAndMethod: function(unit: Unit, value: number | boolean): CmdSet {
720
792
  switch (unit.type) {
@@ -771,10 +843,10 @@ export const Protocol = {
771
843
  return [Cmd.SetSensor, 13, node.logicalAddress, unit.logicalAddress, preset];
772
844
  },
773
845
  buildSetSensor(node: Node, unit: Unit, value: number): Message {
774
- return [Cmd.SetSensorValue, 10, node.logicalAddress, unit.logicalAddress, UnitType.kTemperature, Math.floor(value / 256), value % 256];
846
+ return [Cmd.SetSensorValue, 10, node.logicalAddress, unit.logicalAddress, UnitType.kTemperature, ...this.wordToArray(value)];
775
847
  },
776
848
  buildSetPreset(node: Node, unit: Unit, preset: number, value: number): Message {
777
- return [Cmd.SetSensor, 1, node.logicalAddress, unit.logicalAddress, preset, Math.floor(value / 256), value % 256];
849
+ return [Cmd.SetSensor, 1, node.logicalAddress, unit.logicalAddress, preset, ...this.wordToArray(value)];
778
850
  },
779
851
  buildIncDecPreset(node: Node, unit: Unit, inc: boolean): Message {
780
852
  return [Cmd.SetSensor, (inc) ? 5 : 6, node.logicalAddress, unit.logicalAddress];
@@ -788,6 +860,16 @@ export const Protocol = {
788
860
  return [Cmd.SetSchedule, 0, Math.max(0, Math.min(3, schedule))];
789
861
  },
790
862
 
863
+ buildRegister(register: number, value?: number) {
864
+ if (typeof value != "undefined") {
865
+ // set register
866
+ return [Cmd.Register, 1, ...this.wordToArray(register), ...this.signedToArray(value)];
867
+ } else {
868
+ // get register
869
+ return [Cmd.Register, 2, ...this.wordToArray(register)];
870
+ }
871
+ },
872
+
791
873
  ///////////////////
792
874
  // Received info //
793
875
  ///////////////////
@@ -796,13 +878,13 @@ export const Protocol = {
796
878
 
797
879
  if (next.cmd === Rec.Sensor) {
798
880
  // sensor -> value
799
- unit.value = next.message[9]*256 + next.message[10]; // 10x current temperature
881
+ unit.value = this.makeWord(next.message, 9); // 10x current temperature
800
882
  unit.status = next.message[7]; // 0=idle, 1=heating, 2=cooling
801
883
  unit.preset = (next.message[6]) ? next.message[8] : -1; // 0=sun, 1=half sun, 2=moon, 3=half moon, -1 = off
802
- unit.sun = next.message[11]*256 + next.message[12]; // 10x temperature
803
- unit.hsun = next.message[13]*256 + next.message[14]; // 10x temperature
804
- unit.moon = next.message[15]*256 + next.message[16]; // 10x temperature
805
- unit.hmoon = next.message[17]*256 + next.message[18]; // 10x temperature
884
+ unit.sun = this.makeWord(next.message, 11); // 10x temperature
885
+ unit.hsun = this.makeWord(next.message, 13); // 10x temperature
886
+ unit.moon = this.makeWord(next.message, 15); // 10x temperature
887
+ unit.hmoon = this.makeWord(next.message, 17); // 10x temperature
806
888
  debug("protocol", "received status - " + unit.getDisplayName() + ", temperature = " + <number>unit.value / 10.0 + ", sun = " + unit.sun);
807
889
  kind = "S";
808
890
 
@@ -858,19 +940,13 @@ export const Protocol = {
858
940
  // only change dim value when state = 1 (ON, PIR ON, DIM STOP) for Dimmers and IRTX + for any setpoint event
859
941
  if ((((next.message[4] === 1) || (next.message[4] === 6) || (next.message[4] === 7)) && (next.message[5] === 1)) ||
860
942
  (next.message[4] === 11)) {
861
- unit.value = next.message[6]*256 + next.message[7];
943
+ unit.value = this.makeWord(next.message, 6);
862
944
  }
863
945
 
864
946
  debug("protocol", "received status - macro -> value=" + unit.value + " / status=" + unit.status);
865
947
  kind = "M";
866
948
  }
867
949
 
868
- // clear the timer to turn the mood off again.
869
- //if (unit.resetTimer) {
870
- // clearInterval(unit.resetTimer);
871
- // unit.resetTimer = null;
872
- //}
873
-
874
950
  this.alertSubscriber(unit);
875
951
  this.emitter.emit('update', unit, kind);
876
952
  },