From 54e33522566798add2e837884bab4086ab1aa5b9 Mon Sep 17 00:00:00 2001 From: David Parry Date: Sat, 23 Dec 2017 18:55:33 +1100 Subject: [PATCH 1/8] add UUIDs to Characteristic and Service definitions --- fakegato-history.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index b062fce..e808f8d 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -1,12 +1,13 @@ 'use strict'; var homebridge; -var Characteristic; +var Characteristic, Service; module.exports = function(pHomebridge) { if (pHomebridge && !homebridge) { homebridge = pHomebridge; Characteristic = homebridge.hap.Characteristic; + Service = homebridge.hap.Service; } var hexToBase64 = function(val) { @@ -50,6 +51,8 @@ module.exports = function(pHomebridge) { } } + S2R1Characteristic.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52'; + class S2R2Characteristic extends Characteristic { constructor() { super('S2R2', 'E863F117-079E-48FF-8F27-9C2605A29F52'); @@ -62,6 +65,8 @@ module.exports = function(pHomebridge) { } } + S2R2Characteristic.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52'; + class S2W1Characteristic extends Characteristic { constructor() { super('S2W1', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); @@ -74,6 +79,8 @@ module.exports = function(pHomebridge) { } } + S2W1Characteristic.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52'; + class S2W2Characteristic extends Characteristic { constructor() { super('S2W2', 'E863F121-079E-48FF-8F27-9C2605A29F52'); @@ -86,7 +93,9 @@ module.exports = function(pHomebridge) { } } - class FakeGatoHistoryService extends homebridge.hap.Service { + S2W2Characteristic.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52'; + + class FakeGatoHistoryService extends Service { constructor(accessoryType, accessory, size) { if (typeof size === 'undefined') { size = 4032; } @@ -281,5 +290,7 @@ module.exports = function(pHomebridge) { } + FakeGatoHistoryService = 'E863F007-079E-48FF-8F27-9C2605A29F52'; + return FakeGatoHistoryService; } From 7cf5b9e7e967a3663e698ab49467bcdf6d87fcf6 Mon Sep 17 00:00:00 2001 From: David Parry Date: Sat, 23 Dec 2017 18:58:25 +1100 Subject: [PATCH 2/8] whitespace cleanup --- fakegato-history.js | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index e808f8d..09b3059 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -36,7 +36,6 @@ module.exports = function(pHomebridge) { return ('0000000000000' + s).slice(-1 * len); } return s; - } class S2R1Characteristic extends Characteristic { @@ -122,8 +121,6 @@ module.exports = function(pHomebridge) { this.accessoryType117 = "0f"; break; } - - this.accessoryType=accessoryType; this.firstEntry = 0; @@ -139,7 +136,7 @@ module.exports = function(pHomebridge) { this.dataStream=''; this.addCharacteristic(S2R1Characteristic); - + this.addCharacteristic(S2R2Characteristic) .on('get', (callback) => { if ((this.currentEntry Date: Sat, 23 Dec 2017 19:02:15 +1100 Subject: [PATCH 3/8] replace accessoryType strings with constants --- fakegato-history.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index 09b3059..4b29b53 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -1,5 +1,9 @@ 'use strict'; +const TYPE_ENERGY = 'energy', + TYPE_ROOM = 'room', + TYPE_WEATHER = 'weather'; + var homebridge; var Characteristic, Service; @@ -108,15 +112,15 @@ module.exports = function(pHomebridge) { this.log = accessory.log; switch (accessoryType) { - case "weather": + case TYPE_WEATHER: this.accessoryType116 = "03"; this.accessoryType117 = "07"; break; - case "energy": + case TYPE_ENERGY: this.accessoryType116 = "07"; this.accessoryType117 = "1f"; break; - case "room": + case TYPE_ROOM: this.accessoryType116 = "04"; this.accessoryType117 = "0f"; break; @@ -158,7 +162,7 @@ module.exports = function(pHomebridge) { { switch (this.accessoryType) { - case "weather": + case TYPE_WEATHER: this.log.debug(this.accessoryType + " Entry: " + this.currentEntry + ", Address: " + this.memoryAddress); this.dataStream = this.dataStream + " 10 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + numToHex(swap32(this.history[this.memoryAddress].time-this.refTime-978307200),8) @@ -167,7 +171,7 @@ module.exports = function(pHomebridge) { + numToHex(swap16(this.history[this.memoryAddress].humidity*100),4) + numToHex(swap16(this.history[this.memoryAddress].pressure*10),4); break; - case "energy": + case TYPE_ENERGY: this.log.debug(this.accessoryType + " Entry: " + this.currentEntry + ", Address: " + this.memoryAddress); this.dataStream = this.dataStream + " 14 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + numToHex(swap32(this.history[this.memoryAddress].time-this.refTime-978307200),8) @@ -237,10 +241,10 @@ module.exports = function(pHomebridge) { this.refTime=entry.time-978307200; switch (this.accessoryType) { - case "weather": + case TYPE_WEATHER: this.history[this.lastEntry]= {time: entry.time, temp:0, pressure:0, humidity:0}; break; - case "energy": + case TYPE_ENERGY: this.history[this.lastEntry]= {time: entry.time, power:0xFFFF}; break; } From 92f890d8053b34b7dc03044acfb7d7d41295d6d2 Mon Sep 17 00:00:00 2001 From: David Parry Date: Sat, 23 Dec 2017 20:25:17 +1100 Subject: [PATCH 4/8] use Format instead of string concatenation --- fakegato-history.js | 83 ++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index 4b29b53..f8bbf7b 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -1,5 +1,7 @@ 'use strict'; +const Format = require('util').format; + const TYPE_ENERGY = 'energy', TYPE_ROOM = 'room', TYPE_WEATHER = 'weather'; @@ -150,9 +152,15 @@ module.exports = function(pHomebridge) { if ((this.history[this.memoryAddress].temp==0 && this.history[this.memoryAddress].pressure==0 && this.history[this.memoryAddress].humidity==0) || (this.history[this.memoryAddress].power==0xFFFF) || (this.setTime==true)) - { - this.log.debug("Data "+ this.accessoryType + ": 15" + numToHex(swap16(this.currentEntry),4) + "0000 0000 0000 81" + numToHex(swap32(this.refTime),8) +"0000 0000 00 0000"); - callback(null,hexToBase64('15' + numToHex(swap16(this.currentEntry),4) +' 0000 0000 0000 81' + numToHex(swap32(this.refTime),8) + '0000 0000 00 0000')); + { + var val = Format( + '15%s0000 0000 0000 81%s0000 0000 00 0000', + numToHex(swap16(this.currentEntry),4), + numToHex(swap32(this.refTime),8) + ); + + this.log.debug("Data %s: %s", this.accessoryType, val); + callback(null, hexToBase64(val)); this.setTime=false; this.currentEntry++; } @@ -163,40 +171,44 @@ module.exports = function(pHomebridge) { switch (this.accessoryType) { case TYPE_WEATHER: - this.log.debug(this.accessoryType + " Entry: " + this.currentEntry + ", Address: " + this.memoryAddress); - this.dataStream = this.dataStream + " 10 " + numToHex(swap16(this.currentEntry),4) + " 0000 " - + numToHex(swap32(this.history[this.memoryAddress].time-this.refTime-978307200),8) - + this.accessoryType117 - + numToHex(swap16(this.history[this.memoryAddress].temp*100),4) - + numToHex(swap16(this.history[this.memoryAddress].humidity*100),4) - + numToHex(swap16(this.history[this.memoryAddress].pressure*10),4); + this.log.debug("%s Entry: %s, Address: %s", this.accessoryType, this.currentEntry, this.memoryAddress); + this.dataStream += Format( + " 10 %s 0000 %s%s%s%s%s", + numToHex(swap16(this.currentEntry),4), + numToHex(swap32(this.history[this.memoryAddress].time-this.refTime-978307200),8), + this.accessoryType117, + numToHex(swap16(this.history[this.memoryAddress].temp*100),4), + numToHex(swap16(this.history[this.memoryAddress].humidity*100),4), + numToHex(swap16(this.history[this.memoryAddress].pressure*10),4) + ); break; case TYPE_ENERGY: - this.log.debug(this.accessoryType + " Entry: " + this.currentEntry + ", Address: " + this.memoryAddress); - this.dataStream = this.dataStream + " 14 " + numToHex(swap16(this.currentEntry),4) + " 0000 " - + numToHex(swap32(this.history[this.memoryAddress].time-this.refTime-978307200),8) - + this.accessoryType117 - + "0000 0000" - + numToHex(swap16(this.history[this.memoryAddress].power*10),4) - + "0000 0000"; + this.log.debug("%s Entry: %s, Address: %s", this.accessoryType, this.currentEntry, this.memoryAddress); + this.dataStream += Format( + " 14 %s 0000 %s%s0000 0000%s0000 0000", + numToHex(swap16(this.currentEntry),4), + numToHex(swap32(this.history[this.memoryAddress].time-this.refTime-978307200),8), + this.accessoryType117, + numToHex(swap16(this.history[this.memoryAddress].power*10),4) + ); break; } this.currentEntry++; this.memoryAddress = entry2address (this.currentEntry); - if (this.currentEntry==this.lastEntry) + if (this.currentEntry == this.lastEntry) { break; } } - this.log.debug("Data " + this.accessoryType + ": " + this.dataStream); - callback(null,hexToBase64(this.dataStream)); + this.log.debug("Data %s: %s", this.accessoryType, this.dataStream); + callback(null, hexToBase64(this.dataStream)); this.dataStream=''; } } else { this.transfer=false; - callback(null,hexToBase64('00')); + callback(null, hexToBase64('00')); } }); @@ -254,30 +266,39 @@ module.exports = function(pHomebridge) { this.history[entry2address(this.lastEntry)] = (entry); - this.getCharacteristic(S2R1Characteristic) - .setValue(hexToBase64(numToHex(swap32(entry.time-this.refTime-978307200),8) + '00000000' + numToHex(swap32(this.refTime),8) + '0401020202' + this.accessoryType116 +'020f03' + numToHex(swap16(this.usedMemory),4) + numToHex(swap16(this.memorySize),4) + numToHex(swap32(this.firstEntry),8) + '000000000101')); - this.log.debug("First entry " + this.accessoryType + ": " + this.firstEntry.toString(16)); - this.log.debug("Last entry " + this.accessoryType + ": " + this.lastEntry.toString(16)); - this.log.debug("Used memory " + this.accessoryType + ": " + this.usedMemory.toString(16)); - this.log.debug("116 " + this.accessoryType + ": " + numToHex(swap32(entry.time-this.refTime-978307200),8) + '00000000' + numToHex(swap32(this.refTime),8) + '0401020202' + this.accessoryType116 +'020f03 ' + numToHex(swap16(this.usedMemory),4) + numToHex(swap16(this.memorySize),4) + numToHex(swap32(this.firstEntry),8) + '000000000101'); + var val = Format( + '%s00000000%s0401020202%s020f03%s%s%s000000000101', + numToHex(swap32(entry.time-this.refTime-978307200),8), + numToHex(swap32(this.refTime),8), this.accessoryType116, + numToHex(swap16(this.usedMemory),4), + numToHex(swap16(this.memorySize),4), + numToHex(swap32(this.firstEntry),8) + ); + + this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val)); + + this.log.debug("First entry %s: %s", this.accessoryType, this.firstEntry.toString(16)); + this.log.debug("Last entry %s: %s", this.accessoryType, this.lastEntry.toString(16)); + this.log.debug("Used memory %s: %s", this.accessoryType, this.usedMemory.toString(16)); + this.log.debug("116 %s: %s", this.accessoryType, val); } setCurrentS2W1(val, callback) { callback(null,val); - this.log.debug("Data request " + this.accessoryType + ": "+ base64ToHex(val)); + this.log.debug("Data request %s: %s", this.accessoryType, base64ToHex(val)); var valHex = base64ToHex(val); var substring = valHex.substring(4,12); var valInt = parseInt(substring,16); var address = swap32(valInt); var hexAddress= address.toString('16'); - this.log.debug("Address requested " + this.accessoryType + ": "+ hexAddress); + this.log.debug("Address requested %s: %s", this.accessoryType, hexAddress); //if (this.transfer==false) - { + //{ //this.transfer=true; this.sendHistory(address); - } + //} } setCurrentS2W2(val, callback) { From 2bb202b6ea2cd1bd5c259ba796ca99f6ae2d70de Mon Sep 17 00:00:00 2001 From: David Parry Date: Sat, 23 Dec 2017 20:52:44 +1100 Subject: [PATCH 5/8] move epoch offset to constant; other minor cleanup --- fakegato-history.js | 150 +++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 79 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index f8bbf7b..1035cd8 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -2,6 +2,8 @@ const Format = require('util').format; +const EPOCH_OFFSET = 978307200; + const TYPE_ENERGY = 'energy', TYPE_ROOM = 'room', TYPE_WEATHER = 'weather'; @@ -10,10 +12,10 @@ var homebridge; var Characteristic, Service; module.exports = function(pHomebridge) { - if (pHomebridge && !homebridge) { - homebridge = pHomebridge; - Characteristic = homebridge.hap.Characteristic; - Service = homebridge.hap.Service; + if (pHomebridge && !homebridge) { + homebridge = pHomebridge; + Characteristic = homebridge.hap.Characteristic; + Service = homebridge.hap.Service; } var hexToBase64 = function(val) { @@ -29,12 +31,12 @@ module.exports = function(pHomebridge) { | ((val & 0xFF00) << 8) | ((val >>> 8) & 0xFF00) | ((val >>> 24) & 0xFF); - }, hexToHPA = function(val) { + }, hexToHPA = function(val) { return parseInt(swap16(val), 10); }, hPAtoHex = function(val) { return swap16(Math.round(val)).toString(16); }, numToHex = function(val, len) { - var s = Number(val>>>0).toString(16); + var s = Number(val >>> 0).toString(16); if(s.length % 2 != 0) { s = '0' + s; } @@ -112,8 +114,7 @@ module.exports = function(pHomebridge) { }.bind(this); this.log = accessory.log; - switch (accessoryType) - { + switch (accessoryType) { case TYPE_WEATHER: this.accessoryType116 = "03"; this.accessoryType117 = "07"; @@ -128,31 +129,30 @@ module.exports = function(pHomebridge) { break; } - this.accessoryType=accessoryType; + this.accessoryType = accessoryType; this.firstEntry = 0; this.lastEntry = 0; this.history = []; this.memorySize = size; - this.usedMemory=0; + this.usedMemory = 0; this.currentEntry = 1; - this.transfer=false; - this.setTime=true; - this.refTime=0; - this.memoryAddress=0; - this.dataStream=''; + this.transfer = false; + this.setTime = true; + this.refTime = 0; + this.memoryAddress = 0; + this.dataStream = ''; this.addCharacteristic(S2R1Characteristic); this.addCharacteristic(S2R2Characteristic) .on('get', (callback) => { - if ((this.currentEntry Date: Sat, 23 Dec 2017 21:20:17 +1100 Subject: [PATCH 6/8] bug fix --- fakegato-history.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fakegato-history.js b/fakegato-history.js index 1035cd8..ae5c4f7 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -300,7 +300,7 @@ module.exports = function(pHomebridge) { } - FakeGatoHistoryService = 'E863F007-079E-48FF-8F27-9C2605A29F52'; + FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52'; return FakeGatoHistoryService; } From 83dba9d39d44dbbe65622170b661f6db42411150 Mon Sep 17 00:00:00 2001 From: David Parry Date: Sun, 24 Dec 2017 10:11:36 +1100 Subject: [PATCH 7/8] fix known bug --- README.md | 2 +- fakegato-history.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e30828..84eb2e6 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ For Energy accessories it is also worth to add the custom characteristic E863F11 - [ ] Periodic sending of reference time stamp (seems not really needed if the time of your homebridge machine is correct) ### Known bugs -- There is a delay of one entry between the history and the upload to Eve.app, i.e. entry n will be uploaded only when entry n+1 is added to the history +- ~~There is a delay of one entry between the history and the upload to Eve.app, i.e. entry n will be uploaded only when entry n+1 is added to the history~~ ### How to contribute diff --git a/fakegato-history.js b/fakegato-history.js index ae5c4f7..9484021 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -192,7 +192,7 @@ module.exports = function(pHomebridge) { } this.currentEntry++; this.memoryAddress = entry2address(this.currentEntry); - if (this.currentEntry == this.lastEntry) { + if (this.currentEntry > this.lastEntry) { break; } } From 69f2306b3e852d8e7d8289f5ff2d804c0ce225aa Mon Sep 17 00:00:00 2001 From: David Parry Date: Sun, 24 Dec 2017 12:57:37 +1100 Subject: [PATCH 8/8] remove duplicate UUID strings --- fakegato-history.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index 9484021..9f7d465 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -48,7 +48,7 @@ module.exports = function(pHomebridge) { class S2R1Characteristic extends Characteristic { constructor() { - super('S2R1', 'E863F116-079E-48FF-8F27-9C2605A29F52'); + super('S2R1', S2R1Characteristic.UUID); this.setProps({ format: Characteristic.Formats.DATA, perms: [ @@ -62,7 +62,7 @@ module.exports = function(pHomebridge) { class S2R2Characteristic extends Characteristic { constructor() { - super('S2R2', 'E863F117-079E-48FF-8F27-9C2605A29F52'); + super('S2R2', S2R2Characteristic.UUID); this.setProps({ format: Characteristic.Formats.DATA, perms: [ @@ -76,7 +76,7 @@ module.exports = function(pHomebridge) { class S2W1Characteristic extends Characteristic { constructor() { - super('S2W1', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); + super('S2W1', S2W1Characteristic.UUID); this.setProps({ format: Characteristic.Formats.DATA, perms: [ @@ -90,7 +90,7 @@ module.exports = function(pHomebridge) { class S2W2Characteristic extends Characteristic { constructor() { - super('S2W2', 'E863F121-079E-48FF-8F27-9C2605A29F52'); + super('S2W2', S2W2Characteristic.UUID); this.setProps({ format: Characteristic.Formats.DATA, perms: [ @@ -106,7 +106,7 @@ module.exports = function(pHomebridge) { constructor(accessoryType, accessory, size) { if (typeof size === 'undefined') { size = 4032; } - super(accessory.displayName + " History", 'E863F007-079E-48FF-8F27-9C2605A29F52'); + super(accessory.displayName + " History", FakeGatoHistoryService.UUID); var entry2address = function(val) { var temp = val % this.memorySize;