New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

fakegato-history

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fakegato-history - npm Package Compare versions

Comparing version 0.3.4 to 0.3.5

fakegato-timer.js

709

fakegato-history.js

@@ -0,4 +1,7 @@

/*jshint esversion: 6,node: true,-W041: false */
'use strict';
const Format = require('util').format;
const FakeGatoTimer = require('./fakegato-timer').FakeGatoTimer;
const moment = require('moment');

@@ -10,5 +13,5 @@ const EPOCH_OFFSET = 978307200;

TYPE_WEATHER = 'weather',
TYPE_DOOR = 'door',
TYPE_MOTION = 'motion',
TYPE_THERMO = 'thermo';
TYPE_DOOR = 'door',
TYPE_MOTION = 'motion',
TYPE_THERMO = 'thermo';

@@ -18,324 +21,442 @@ var homebridge;

module.exports = function(pHomebridge) {
if (pHomebridge && !homebridge) {
homebridge = pHomebridge;
Characteristic = homebridge.hap.Characteristic;
Service = homebridge.hap.Service;
}
var hexToBase64 = function(val) {
return new Buffer((''+val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64');
}, base64ToHex = function(val) {
if(!val) return val;
return new Buffer(val, 'base64').toString('hex');
}, swap16 = function (val) {
return ((val & 0xFF) << 8)
| ((val >>> 8) & 0xFF);
}, swap32 = function (val) {
return ((val & 0xFF) << 24)
| ((val & 0xFF00) << 8)
| ((val >>> 8) & 0xFF00)
| ((val >>> 24) & 0xFF);
}, 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);
if(s.length % 2 != 0) {
s = '0' + s;
}
if(len) {
return ('0000000000000' + s).slice(-1 * len);
}
return s;
}
module.exports = function (pHomebridge) {
if (pHomebridge && !homebridge) {
homebridge = pHomebridge;
Characteristic = homebridge.hap.Characteristic;
Service = homebridge.hap.Service;
}
class S2R1Characteristic extends Characteristic {
constructor() {
super('S2R1', S2R1Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
]
});
}
}
S2R1Characteristic.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52';
var hexToBase64 = function (val) {
return new Buffer(('' + val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64');
},
base64ToHex = function (val) {
if (!val)
return val;
return new Buffer(val, 'base64').toString('hex');
},
swap16 = function (val) {
return ((val & 0xFF) << 8)
| ((val >>> 8) & 0xFF);
},
swap32 = function (val) {
return ((val & 0xFF) << 24)
| ((val & 0xFF00) << 8)
| ((val >>> 8) & 0xFF00)
| ((val >>> 24) & 0xFF);
},
hexToHPA = function (val) { //unused
return parseInt(swap16(val), 10);
},
hPAtoHex = function (val) { //unused
return swap16(Math.round(val)).toString(16);
},
numToHex = function (val, len) {
var s = Number(val >>> 0).toString(16);
if (s.length % 2 != 0) {
s = '0' + s;
}
if (len) {
return ('0000000000000' + s).slice(-1 * len);
}
return s;
};
class S2R2Characteristic extends Characteristic {
constructor() {
super('S2R2', S2R2Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
]
});
}
}
class S2R1Characteristic extends Characteristic {
constructor() {
super('S2R1', S2R1Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
]
});
}
}
S2R2Characteristic.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52';
S2R1Characteristic.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52';
class S2W1Characteristic extends Characteristic {
constructor() {
super('S2W1', S2W1Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
]
});
}
}
class S2R2Characteristic extends Characteristic {
constructor() {
super('S2R2', S2R2Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN
]
});
}
}
S2W1Characteristic.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52';
S2R2Characteristic.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52';
class S2W2Characteristic extends Characteristic {
constructor() {
super('S2W2', S2W2Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
]
});
}
}
class S2W1Characteristic extends Characteristic {
constructor() {
super('S2W1', S2W1Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
]
});
}
}
S2W2Characteristic.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52';
S2W1Characteristic.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52';
class FakeGatoHistoryService extends Service {
constructor(accessoryType, accessory, size) {
if (typeof size === 'undefined') { size = 4032; }
super(accessory.displayName + " History", FakeGatoHistoryService.UUID);
class S2W2Characteristic extends Characteristic {
constructor() {
super('S2W2', S2W2Characteristic.UUID);
this.setProps({
format: Characteristic.Formats.DATA,
perms: [
Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN
]
});
}
}
var entry2address = function(val) {
var temp = val % this.memorySize;
return temp;
}.bind(this);
this.accessoryName = accessory.displayName;
this.log = accessory.log;
switch (accessoryType) {
case TYPE_WEATHER:
this.accessoryType116 = "03 0102 0202 0302";
this.accessoryType117 = "07";
break;
case TYPE_ENERGY:
this.accessoryType116 = "04 0102 0202 0702 0f03";
this.accessoryType117 = "1f";
break;
case TYPE_ROOM:
this.accessoryType116 = "04 0102 0202 0402 0f03";
this.accessoryType117 = "0f";
break;
case TYPE_DOOR:
this.accessoryType116 = "01 0601";
this.accessoryType117 = "01";
break;
case TYPE_MOTION:
this.accessoryType116 = "02 1301 1c01";
this.accessoryType117 = "02";
break;
case TYPE_THERMO:
this.accessoryType116 = "05 0102 1102 1001 1201 1d01";
this.accessoryType117 = "1f";
break;
}
S2W2Characteristic.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52';
this.accessoryType = accessoryType;
this.firstEntry = 0;
this.lastEntry = 0;
this.history = [];
this.memorySize = size;
this.usedMemory = 0;
this.currentEntry = 1;
this.transfer = false;
this.setTime = true;
this.refTime = 0;
this.memoryAddress = 0;
this.dataStream = '';
class FakeGatoHistoryService extends Service {
constructor(accessoryType, accessory, size) {
if (typeof size === 'undefined') {
size = 4032;
}
this.addCharacteristic(S2R1Characteristic);
super(accessory.displayName + " History", FakeGatoHistoryService.UUID);
this.addCharacteristic(S2R2Characteristic)
.on('get', (callback) => {
if ((this.currentEntry < this.lastEntry) && (this.transfer == true)) {
this.memoryAddress = entry2address(this.currentEntry);
if ((this.history[this.memoryAddress].setRefTime == 1) || (this.setTime == true)) {
var entry2address = function (val) {
var temp = val % this.memorySize;
return temp;
}.bind(this);
this.accessoryName = accessory.displayName;
this.log = accessory.log;
var val = Format(
'15%s 0000 0000 81%s0000 0000 00 0000',
numToHex(swap32(this.currentEntry),8),
numToHex(swap32(this.refTime),8)
);
if (homebridge.globalFakeGatoTimer === undefined)
homebridge.globalFakeGatoTimer = new FakeGatoTimer({
minutes: 10,
log: this.log
});
this.log.debug("Data %s: %s", this.accessoryName, val);
callback(null, hexToBase64(val));
this.setTime=false;
this.currentEntry++;
}
else {
for (var i = 0;i < 11;i++) {
this.log.debug("%s Entry: %s, Address: %s", this.accessoryName, this.currentEntry, this.memoryAddress);
switch (this.accessoryType) {
case TYPE_WEATHER:
this.dataStream += Format(
" 10 %s%s%s%s%s%s",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 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.dataStream += Format(
" 14 %s%s%s0000 0000%s0000 0000",
numToHex(swap32(this.currentEntry),8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
this.accessoryType117,
numToHex(swap16(this.history[this.memoryAddress].power * 10), 4)
);
break;
case TYPE_ROOM:
this.dataStream += Format(
" 13 %s%s%s%s%s%s0000 00",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 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].ppm), 4)
);
break;
case TYPE_DOOR:
case TYPE_MOTION:
this.dataStream += Format(
" 0b %s%s%s%s",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
this.accessoryType117,
numToHex(this.history[this.memoryAddress].status, 2)
);
break;
case TYPE_THERMO:
this.dataStream += Format(
" 11 %s%s%s%s%s%s 0000",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
this.accessoryType117,
numToHex(swap16(this.history[this.memoryAddress].currentTemp * 100), 4),
numToHex(swap16(this.history[this.memoryAddress].setTemp*100), 4),
numToHex(this.history[this.memoryAddress].valvePosition, 2)
);
break;
}
this.currentEntry++;
this.memoryAddress = entry2address(this.currentEntry);
if (this.currentEntry > this.lastEntry) {
break;
}
}
this.log.debug("Data %s: %s", this.accessoryName, this.dataStream);
callback(null, hexToBase64(this.dataStream));
this.dataStream = '';
}
}
else {
this.transfer = false;
callback(null, hexToBase64('00'));
}
});
switch (accessoryType) {
case TYPE_WEATHER:
this.accessoryType116 = "03 0102 0202 0302";
this.accessoryType117 = "07";
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
this.addCharacteristic(S2W1Characteristic)
.on('set', this.setCurrentS2W1.bind(this));
for (var h in backLog) {
if (backLog.hasOwnProperty(h)) { // only valid keys
for (var key in backLog[h]) { // each record
if (backLog[h].hasOwnProperty(key) && key != 'time') { // except time
if (!calc.sum[key])
calc.sum[key] = 0;
if (!calc.num[key])
calc.num[key] = 0;
calc.sum[key] += backLog[h][key];
calc.num[key]++;
calc.avrg[key] = calc.sum[key] / calc.num[key];
}
}
}
}
calc.avrg.time = moment().unix(); // set the time of the avrg
fakegato._addEntry(calc.avrg);
timer.emptyData(fakegato);// should i ? or repeat the last datas ?
});
break;
case TYPE_ENERGY:
this.accessoryType116 = "04 0102 0202 0702 0f03";
this.accessoryType117 = "1f";
break;
case TYPE_ROOM:
this.accessoryType116 = "04 0102 0202 0402 0f03";
this.accessoryType117 = "0f";
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
this.addCharacteristic(S2W2Characteristic)
.on('set', this.setCurrentS2W2.bind(this));
}
for (var h in backLog) {
if (backLog.hasOwnProperty(h)) { // only valid keys
for (var key in backLog[h]) { // each record
if (backLog[h].hasOwnProperty(key) && key != 'time') { // except time
if (!calc.sum[key])
calc.sum[key] = 0;
if (!calc.num[key])
calc.num[key] = 0;
calc.sum[key] += backLog[h][key];
calc.num[key]++;
calc.avrg[key] = calc.sum[key] / calc.num[key];
}
}
}
}
calc.avrg.time = moment().unix(); // set the time of the avrg
fakegato._addEntry(calc.avrg);
timer.emptyData(fakegato); // should i ? or repeat the last datas ?
});
break;
case TYPE_DOOR:
this.accessoryType116 = "01 0601";
this.accessoryType117 = "01";
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var actualEntry={};
if(!immediate) {
actualEntry.time = moment().unix();
actualEntry.status = backLog[0].status;
}
else {
actualEntry.time = backLog[0].time;
actualEntry.status = backLog[0].status;
}
fakegato.log.debug('**Fakegato-timer callbackDoor: ', fakegato.accessoryName, ', immediate: ',immediate,', entry: ',actualEntry);
fakegato._addEntry(actualEntry);
});
break;
case TYPE_MOTION:
this.accessoryType116 = "02 1301 1c01";
this.accessoryType117 = "02";
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var actualEntry={};
if(!immediate) {
actualEntry.time = moment().unix();
actualEntry.status = backLog[0].status;
}
else {
actualEntry.time = backLog[0].time;
actualEntry.status = backLog[0].status;
}
fakegato.log.debug('**Fakegato-timer callbackMotion: ', fakegato.accessoryName, ', immediate: ',immediate,', entry: ',actualEntry);
fakegato._addEntry(actualEntry);
});
break;
case TYPE_THERMO:
this.accessoryType116 = "05 0102 1102 1001 1201 1d01";
this.accessoryType117 = "1f";
break;
}
sendHistory(address){
var hexAddress= address.toString('16');
if (address != 0) {
this.currentEntry = address;
}
else {
this.currentEntry = 1;
}
this.transfer=true;
}
this.accessoryType = accessoryType;
this.firstEntry = 0;
this.lastEntry = 0;
this.history = [];
this.memorySize = size;
this.usedMemory = 0;
this.currentEntry = 1;
this.transfer = false;
this.setTime = true;
this.refTime = 0;
this.memoryAddress = 0;
this.dataStream = '';
this.IntervalID = null;
//in order to be consistent with Eve, entry address start from 1
addEntry(entry){
this.addCharacteristic(S2R1Characteristic);
var entry2address = function(val) {
return val % this.memorySize;
}.bind(this);
this.addCharacteristic(S2R2Characteristic)
.on('get', (callback) => {
if ((this.currentEntry < this.lastEntry) && (this.transfer == true)) {
this.memoryAddress = entry2address(this.currentEntry);
if ((this.history[this.memoryAddress].setRefTime == 1) || (this.setTime == true)) {
if (this.usedMemory < this.memorySize) {
this.usedMemory++;
this.firstEntry = 0;
this.lastEntry = this.usedMemory;
}
else {
this.firstEntry++;
this.lastEntry = this.firstEntry + this.usedMemory;
}
var val = Format(
'15%s 0000 0000 81%s0000 0000 00 0000',
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.refTime), 8));
if (this.refTime == 0) {
this.refTime = entry.time - EPOCH_OFFSET;
this.history[this.lastEntry]= {time: entry.time, setRefTime: 1};
this.lastEntry++;
this.usedMemory++;
}
this.log.debug("Data %s: %s", this.accessoryName, val);
callback(null, hexToBase64(val));
this.setTime = false;
this.currentEntry++;
} else {
for (var i = 0; i < 11; i++) {
this.log.debug("%s Entry: %s, Address: %s", this.accessoryName, this.currentEntry, this.memoryAddress);
switch (this.accessoryType) {
case TYPE_WEATHER:
this.dataStream += Format(
" 10 %s%s%s%s%s%s",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 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.dataStream += Format(
" 14 %s%s%s0000 0000%s0000 0000",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
this.accessoryType117,
numToHex(swap16(this.history[this.memoryAddress].power * 10), 4));
break;
case TYPE_ROOM:
this.dataStream += Format(
" 13 %s%s%s%s%s%s0000 00",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 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].ppm), 4));
break;
case TYPE_DOOR:
case TYPE_MOTION:
this.dataStream += Format(
" 0b %s%s%s%s",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
this.accessoryType117,
numToHex(this.history[this.memoryAddress].status, 2));
break;
case TYPE_THERMO:
this.dataStream += Format(
" 11 %s%s%s%s%s%s 0000",
numToHex(swap32(this.currentEntry), 8),
numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8),
this.accessoryType117,
numToHex(swap16(this.history[this.memoryAddress].currentTemp * 100), 4),
numToHex(swap16(this.history[this.memoryAddress].setTemp * 100), 4),
numToHex(this.history[this.memoryAddress].valvePosition, 2));
break;
}
this.currentEntry++;
this.memoryAddress = entry2address(this.currentEntry);
if (this.currentEntry > this.lastEntry) {
break;
}
}
this.log.debug("Data %s: %s", this.accessoryName, this.dataStream);
callback(null, hexToBase64(this.dataStream));
this.dataStream = '';
}
} else {
this.transfer = false;
callback(null, hexToBase64('00'));
}
});
this.history[entry2address(this.lastEntry)] = (entry);
this.addCharacteristic(S2W1Characteristic)
.on('set', this.setCurrentS2W1.bind(this));
var val = Format(
'%s00000000%s%s%s%s%s000000000101',
numToHex(swap32(entry.time - this.refTime - EPOCH_OFFSET), 8),
numToHex(swap32(this.refTime), 8),
this.accessoryType116,
numToHex(swap16(this.usedMemory), 4),
numToHex(swap16(this.memorySize), 4),
numToHex(swap32(this.firstEntry), 8)
);
this.addCharacteristic(S2W2Characteristic)
.on('set', this.setCurrentS2W2.bind(this));
}
this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val));
sendHistory(address) {
var hexAddress = address.toString('16'); // unused
if (address != 0) {
this.currentEntry = address;
} else {
this.currentEntry = 1;
}
this.transfer = true;
}
this.log.debug("First entry %s: %s", this.accessoryName, this.firstEntry.toString(16));
this.log.debug("Last entry %s: %s", this.accessoryName, this.lastEntry.toString(16));
this.log.debug("Used memory %s: %s", this.accessoryName, this.usedMemory.toString(16));
this.log.debug("116 %s: %s", this.accessoryName, val);
}
addEntry(entry) {
var selfService = this;
switch (this.accessoryType) {
case TYPE_DOOR:
case TYPE_MOTION:
homebridge.globalFakeGatoTimer.addData({entry: entry, service: this, immediateCallback: true});
break;
case TYPE_WEATHER:
case TYPE_ROOM:
homebridge.globalFakeGatoTimer.addData({entry: entry, service: this});
break;
default:
this._addEntry(entry);
break;
}
}
setCurrentS2W1(val, callback) {
callback(null,val);
this.log.debug("Data request %s: %s", this.accessoryName, 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');
//in order to be consistent with Eve, entry address start from 1
_addEntry(entry) {
this.log.debug("Address requested %s: %s", this.accessoryName, hexAddress);
this.sendHistory(address);
}
var entry2address = function (val) {
return val % this.memorySize;
}
.bind(this);
setCurrentS2W2(val, callback) {
this.log.debug("Clock adjust %s: %s", this.accessoryName, base64ToHex(val));
callback(null, val);
}
if (this.usedMemory < this.memorySize) {
this.usedMemory++;
this.firstEntry = 0;
this.lastEntry = this.usedMemory;
} else {
this.firstEntry++;
this.lastEntry = this.firstEntry + this.usedMemory;
}
}
if (this.refTime == 0) {
this.refTime = entry.time - EPOCH_OFFSET;
this.history[this.lastEntry] = {
time: entry.time,
setRefTime: 1
};
this.lastEntry++;
this.usedMemory++;
}
FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52';
this.history[entry2address(this.lastEntry)] = (entry);
return FakeGatoHistoryService;
}
var val = Format(
'%s00000000%s%s%s%s%s000000000101',
numToHex(swap32(entry.time - this.refTime - EPOCH_OFFSET), 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.accessoryName, this.firstEntry.toString(16));
this.log.debug("Last entry %s: %s", this.accessoryName, this.lastEntry.toString(16));
this.log.debug("Used memory %s: %s", this.accessoryName, this.usedMemory.toString(16));
this.log.debug("116 %s: %s", this.accessoryName, val);
}
setCurrentS2W1(val, callback) {
callback(null, val);
this.log.debug("Data request %s: %s", this.accessoryName, 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 %s: %s", this.accessoryName, hexAddress);
this.sendHistory(address);
}
setCurrentS2W2(val, callback) {
this.log.debug("Clock adjust %s: %s", this.accessoryName, base64ToHex(val));
callback(null, val);
}
}
FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52';
return FakeGatoHistoryService;
};
{
"name": "fakegato-history",
"version": "0.3.4",
"version": "0.3.5",
"description": "Module emulating Elgato Eve history for homebridge plugins",

@@ -14,2 +14,5 @@ "main": "fakegato-history.js",

},
"dependencies": {
"moment": "*"
},
"author": "simont77",

@@ -16,0 +19,0 @@ "license": "MIT",

@@ -23,42 +23,47 @@ # fakegato-history

Remember to return the fakagato service in getServices function.
Eve.app requires at least an entry every 10 minutes to avoid holes in the history. Depending on the accessory type, fakegato-history may add extra entries every 10 minutes or may average the entries from the plugin and send data every 10 minutes. This is done using a single global timer shared among all accessories using fakegato.
Depending on your accessory type:
* Add entries to history of accessory emulating Eve Weather using something like this every 10 minutes:
* Add entries to history of accessory emulating **Eve Weather** (TempSensor Service) using something like this:
this.loggingService.addEntry({time: moment().unix(), temp:this.temperature, pressure:this.airPressure, humidity:this.humidity});
AiPressure is in mbar, Temperature in Celsius, Humidity in %.
AiPressure is in mbar, Temperature in Celsius, Humidity in %. Entries are internally averaged and sent every 10 minutes using the global fakegato timer. Your entries should be in any case periodic, in order to avoid error with the average. Average is done independently on each quantity (i.e. you may different periods, and entries with only one or two quantities)
* Add entries to history of accessory emulating Eve Energy using something like this every 10 minutes:
* Add entries to history of accessory emulating **Eve Energy** (Outlet service) using something like this every 10 minutes:
this.loggingService.addEntry({time: moment().unix(), power: this.power});
Power should be the average power in W over 10 minutes period. To have good accuracy, it is strongly advised not to use a single instantaneous measurement, but to average many few seconds measurements over 10 minutes.
Power should be the average power in W over 10 minutes period. To have good accuracy, it is strongly advised not to use a single instantaneous measurement, but to average many few seconds measurements over 10 minutes. Fakegato does not use the internal timer for Energy, entries are added to the history as received from the plugin (this is done because the plugin may already have its own average for TotalComsumption calculation)
* Add entries to history of accessory emulating Eve Room using something like this every 10 minutes:
* Add entries to history of accessory emulating **Eve Room** (TempSensor, HumiditySensor and AirQuality Services) using something like this:
this.loggingService.addEntry({time: moment().unix(), temp:this.temperature, humidity:this.humidity, ppm:this.ppm});
Temperature in Celsius, Humidity in %.
Temperature in Celsius, Humidity in %. Entries are internally averaged and sent every 10 minutes using the global fakegato timer. Your entries should be in any case periodic, in order to avoid error with the average. Average is done independently on each quantity (i.e. you may different periods, and entries with only one or two quantities)
* Add entries to history of accessory emulating Eve Door using something like this on every status change:
* Add entries to history of accessory emulating **Eve Door** (ContactSensor service) using something like this on every status change:
this.loggingService.addEntry({time: moment().unix(), status: this.status});
Status can be 1 for ‘open’ or 0 for ‘close’.
Status can be 1 for ‘open’ or 0 for ‘close’. Entries are of type "event", so entries received from the plugin will be added to the history as is. In addition to that, fakegato will add extra entries every 10 minutes repeating the last known state, in order to avoid the appearance of holes in the history.
* Add entries to history of accessory emulating Eve Motion using something like this on every status change:
* Add entries to history of accessory emulating **Eve Motion** (MotionSensor service) using something like this on every status change:
this.loggingService.addEntry({time: moment().unix(), status: this.status});
Status can be 1 for ‘detected’ or 0 for ‘cleared’.
Status can be 1 for ‘detected’ or 0 for ‘cleared’. Entries are of type "event", so entries received from the plugin will be added to the history as is. In addition to that, fakegato will add extra entries every 10 minutes repeating the last known state, in order to avoid the appearance of holes in the history.
* Add entries to history of accessory emulating Eve Thermo using something like this every 10 minutes:
* Add entries to history of accessory emulating **Eve Thermo** (Thermostat service) using something like this every 10 minutes:
this.loggingService.addEntry({time: moment().unix(), currentTemp:this.currentTemp, setTemp:this.setTemp, valvePosition:this.valvePosition});
currentTemp and setTemp in Celsius, valvePosition in %.
currentTemp and setTemp in Celsius, valvePosition in %. Fakegato does not use the internal timer for Energy, entries are added to the history as received from the plugin (Thermo accessory is under development). For setTemp to show, you have to add all the 3 extra thermo characteristics (see gist), and enable set temperature visualization under accessory options in Eve.app.
For Energy and Door accessories it is also worth to add the custom characteristic E863F112 for resetting, respectively, the Total Consumption accumulated value or the Aperture Counter (not the history). See the gist above. The value of this characteristic is changed whenever the reset button is tapped on Eve, so it can be used to reset the locally stored value. The value seems to be the number of seconds from 1.1.2001. I left this characteristics out of fakegato-history because it is not part of the common history service.
For Energy and Door accessories it is also worth to add the custom characteristic E863F112 for resetting, respectively, the Total Consumption accumulated value or the Aperture Counter (not the history). See the gist above. The value of this characteristic is changed whenever the reset button is tapped on Eve, so it can be used to reset the locally stored value. The meaning of the exact value is still unknown. I left this characteristics out of fakegato-history because it is not part of the common history service.
If your "weather" or "room" plugin don't send addEntry for a short time (supposedly less than 1h - need feedback), the graph will draw a straight line from the last data received to the new data received. Instead, if your plugin don't send addEntry for "weather" and "room" for a long time (supposedly more than few hours - need feedback), the graph will show "no data for the period". Take this in consideration if your sensor does not send entries if the difference from the previuos one is small, you will end up with holes in the history. This is not currently addresses by fakegato, you should add extra entries if needed. Note that if you do not send a new entry at least every 10 minutes, the average will be 0, and you will a zero entry. This will be fixed soon.

@@ -75,4 +80,5 @@ ### TODO

### 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~~
- Currenly not fully compatible with Platforms using Homebridge API v2 format.
- Currenly not fully compatible with dynamic Platforms using Homebridge API v2 format.
- Currently valve position history in thermo is not working
- In "weather" and "room" if you do not send at least an entry every 10 minutes you will get zeros in the history.

@@ -79,0 +85,0 @@ ### How to contribute

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc