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.8 to 0.4.0

changelog.md

541

fakegato-history.js

@@ -6,2 +6,3 @@ /*jshint esversion: 6,node: true,-W041: false */

const FakeGatoTimer = require('./fakegato-timer').FakeGatoTimer;
const FakeGatoStorage = require('./fakegato-storage').FakeGatoStorage;
const moment = require('moment');

@@ -65,2 +66,6 @@

return val.charAt(0).toUpperCase() + val.substr(1);
},
precisionRound = function (number, precision) {
var factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
};

@@ -136,9 +141,9 @@

FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52';
var thisAccessory={};
class FakeGatoHistory extends Service {
constructor(accessoryType, accessory, size, minutes) {
constructor(accessoryType, accessory, optionalParams) {
super(accessory.displayName + " History", FakeGatoHistoryService.UUID);
var entry2address = function (val) {
var entry2address = function (val) { // not used ?
var temp = val % this.memorySize;

@@ -148,13 +153,57 @@ return temp;

this.size = size || 4032 ;
this.minutes = minutes || 10; // Optional timer length
this.accessoryName = accessory.displayName;
this.log = accessory.log;
if (homebridge.globalFakeGatoTimer === undefined)
homebridge.globalFakeGatoTimer = new FakeGatoTimer({
minutes: this.minutes,
log: this.log
if(typeof(optionalParams) === 'object') {
this.size = optionalParams.size || 4032;
this.minutes = optionalParams.minutes || 10; // Optional timer length
this.storage = optionalParams.storage; // 'fs' or 'googleDrive'
this.path = optionalParams.path || optionalParams.folder;
this.disableTimer = optionalParams.disableTimer || false;
} else {
this.size = optionalParams || 4032;
this.minutes = 10;
this.disableTimer = false;
}
thisAccessory = accessory;
this.accessoryName = thisAccessory.displayName;
this.log = thisAccessory.log || {};
if (!this.log.debug) {
this.log.debug = function() {};
}
if(!this.disableTimer) {
if (homebridge.globalFakeGatoTimer === undefined)
homebridge.globalFakeGatoTimer = new FakeGatoTimer({
minutes: this.minutes,
log: this.log
});
}
if(this.storage !== undefined) {
this.loaded=false;
if (homebridge.globalFakeGatoStorage === undefined) {
homebridge.globalFakeGatoStorage = new FakeGatoStorage({
log: this.log
});
}
homebridge.globalFakeGatoStorage.addWriter(this,{
storage: this.storage,
path: this.path,
keyPath: optionalParams.keyPath || homebridge.user.storagePath() || undefined,
onReady:function(){
this.load(function(err,loaded){
//this.log.debug("Loaded",loaded);
//this.registerEvents();
if(err) this.log.debug('Load error :',err);
else {
if(loaded) this.log.debug('History Loaded from Persistant Storage');
this.loaded=true;
}
}.bind(this));
}.bind(this)
});
}
switch (accessoryType) {

@@ -164,30 +213,49 @@ case TYPE_WEATHER:

this.accessoryType117 = "07";
if(!this.disableTimer) {
homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback
var backLog = params.backLog || [];
var previousAvrg = params.previousAvrg || {};
var timer = params.timer;
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
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];
for (var h in backLog) {
if (backLog.hasOwnProperty(h)) { // only valid keys
for (let 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] = precisionRound(calc.sum[key] / calc.num[key],2);
}
}
}
}
}
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 ?
});
calc.avrg.time = moment().unix(); // set the time of the avrg
for (let key in previousAvrg) { // each record of previous average
if (previousAvrg.hasOwnProperty(key) && key != 'time') { // except time
if( !backLog.length ||//calc.avrg[key] == 0 || // zero value
calc.avrg[key] === undefined) // no key (meaning no value received for this key yet)
{
calc.avrg[key]=previousAvrg[key];
}
}
}
if(Object.keys(calc.avrg).length > 1) {
fakegato._addEntry(calc.avrg);
timer.emptyData(fakegato);
}
return calc.avrg;
});
}
break;

@@ -197,2 +265,47 @@ case TYPE_ENERGY:

this.accessoryType117 = "1f";
if(!this.disableTimer) {
homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback
var backLog = params.backLog || [];
var previousAvrg = params.previousAvrg || {};
var timer = params.timer;
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
for (var h in backLog) {
if (backLog.hasOwnProperty(h)) { // only valid keys
for (let 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] = precisionRound(calc.sum[key] / calc.num[key],2);
}
}
}
}
calc.avrg.time = moment().unix(); // set the time of the avrg
for (let key in previousAvrg) { // each record of previous average
if (previousAvrg.hasOwnProperty(key) && key != 'time') { // except time
if( !backLog.length ||//calc.avrg[key] == 0 || // zero value
calc.avrg[key] === undefined) // no key (meaning no value received for this key yet)
{
calc.avrg[key]=previousAvrg[key];
}
}
}
fakegato._addEntry(calc.avrg);
timer.emptyData(fakegato);
return calc.avrg;
});
}
break;

@@ -202,30 +315,49 @@ case TYPE_ROOM:

this.accessoryType117 = "0f";
if(!this.disableTimer) {
homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback
var backLog = params.backLog || [];
var previousAvrg = params.previousAvrg || {};
var timer = params.timer;
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var calc = {
sum: {},
num: {},
avrg: {}
};
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];
for (var h in backLog) {
if (backLog.hasOwnProperty(h)) { // only valid keys
for (let 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] = precisionRound(calc.sum[key] / calc.num[key],2);
}
}
}
}
}
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 ?
});
calc.avrg.time = moment().unix(); // set the time of the avrg
for (let key in previousAvrg) { // each record of previous average
if (previousAvrg.hasOwnProperty(key) && key != 'time') { // except time
if( !backLog.length ||//calc.avrg[key] == 0 || // zero value
calc.avrg[key] === undefined) // no key (meaning no value received for this key yet)
{
calc.avrg[key]=previousAvrg[key];
}
}
}
if(Object.keys(calc.avrg).length > 1) {
fakegato._addEntry(calc.avrg);
timer.emptyData(fakegato);
}
return calc.avrg;
});
}
break;

@@ -235,19 +367,25 @@ case TYPE_DOOR:

this.accessoryType117 = "01";
if(!this.disableTimer) {
homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback
var backLog = params.backLog || [];
var immediate = params.immediate;
var fakegato = this.service;
var actualEntry={};
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var actualEntry={};
if(backLog.length) {
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);
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);
});
fakegato._addEntry(actualEntry);
}
});
}
break;

@@ -257,19 +395,25 @@ case TYPE_MOTION:

this.accessoryType117 = "02";
if(!this.disableTimer) {
homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback
var backLog = params.backLog || [];
var immediate = params.immediate;
var fakegato = this.service;
var actualEntry={};
homebridge.globalFakeGatoTimer.subscribe(this, function (backLog, timer, immediate) { // callback
var fakegato = this.service;
var actualEntry={};
if(backLog.length) {
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);
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);
});
fakegato._addEntry(actualEntry);
}
});
}
break;

@@ -285,3 +429,3 @@ case TYPE_THERMO:

this.lastEntry = 0;
this.history = [];
this.history = ["noValue"];
this.memorySize = this.size;

@@ -295,10 +439,20 @@ this.usedMemory = 0;

this.dataStream = '';
this.IntervalID = null;
if ( typeof accessory.getService === "function" ) {
this.saving=false;
this.registerEvents();
if(this.storage === undefined) {
this.loaded=true;
}
}
registerEvents() {
this.log.debug('Registring Events',thisAccessory.displayName);
if ( typeof thisAccessory.getService === "function" ) {
// Platform API
this.service = accessory.getService(FakeGatoHistoryService);
this.log.debug('Platform',thisAccessory.displayName);
this.service = thisAccessory.getService(FakeGatoHistoryService);
if (this.service === undefined) {
this.service = accessory.addService(FakeGatoHistoryService, ucfirst(accessoryType) + ' History', accessoryType);
this.service = thisAccessory.addService(FakeGatoHistoryService, ucfirst(thisAccessory.displayName) + ' History', this.accessoryType);
}

@@ -318,2 +472,3 @@

// Accessory API
this.log.debug('Accessory',thisAccessory.displayName);

@@ -343,11 +498,17 @@ this.addCharacteristic(S2R1Characteristic);

addEntry(entry) {
var selfService = this;
switch (this.accessoryType) {
case TYPE_DOOR:
case TYPE_MOTION:
homebridge.globalFakeGatoTimer.addData({entry: entry, service: this, immediateCallback: true});
if(!this.disableTimer)
homebridge.globalFakeGatoTimer.addData({entry: entry, service: this, immediateCallback: true});
else
this._addEntry(entry);
break;
case TYPE_WEATHER:
case TYPE_ROOM:
homebridge.globalFakeGatoTimer.addData({entry: entry, service: this});
case TYPE_ENERGY:
if(!this.disableTimer)
homebridge.globalFakeGatoTimer.addData({entry: entry, service: this});
else
this._addEntry(entry);
break;

@@ -362,64 +523,135 @@ default:

_addEntry(entry) {
if(this.loaded) {
var entry2address = function (val) {
return val % this.memorySize;
}
.bind(this);
var val;
var entry2address = function (val) {
return val % this.memorySize;
}
.bind(this);
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;
if (this.refTime == 0) {
this.refTime = entry.time - EPOCH_OFFSET;
this.history[this.lastEntry] = {
time: entry.time,
setRefTime: 1
};
this.initialTime=entry.time;
this.lastEntry++;
this.usedMemory++;
}
if (this.usedMemory < this.memorySize) {
this.usedMemory++;
this.firstEntry = 0;
this.lastEntry = this.usedMemory;
this.history[entry2address(this.lastEntry)] = (entry);
if (this.usedMemory < this.memorySize) {
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+1), 4),
numToHex(swap16(this.memorySize), 4),
numToHex(swap32(this.firstEntry), 8));
} else {
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+1), 8));
}
if (this.service === undefined) { // Accessory API
this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val));
}
else { // Platform API
this.service.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);
if(this.storage !== undefined) this.save();
} else {
this.firstEntry++;
this.lastEntry = this.firstEntry + this.usedMemory;
setTimeout(function(){ // retry in 100ms
this._addEntry(entry);
}.bind(this),100);
}
}
getInitialTime() {
return this.initialTime;
}
save() {
if(this.loaded) {
if (this.refTime == 0) {
this.refTime = entry.time - EPOCH_OFFSET;
this.history[this.lastEntry] = {
time: entry.time,
setRefTime: 1
};
this.lastEntry++;
this.usedMemory++;
}
let data = {
firstEntry:this.firstEntry,
lastEntry :this.lastEntry,
usedMemory:this.usedMemory,
refTime :this.refTime,
initialTime:this.initialTime,
history :this.history
};
homebridge.globalFakeGatoStorage.write({
service: this,
data:typeof(data) === "object" ? JSON.stringify(data) : data
});
this.history[entry2address(this.lastEntry)] = (entry);
if (this.usedMemory < this.memorySize) {
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+1), 4),
numToHex(swap16(this.memorySize), 4),
numToHex(swap32(this.firstEntry), 8));
} else {
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+1), 8));
}
if (this.service === undefined) {
this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val));
}
else {
this.service.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val));
setTimeout(function(){ // retry in 100ms
this.save();
}.bind(this),100);
}
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);
}
load(cb) {
this.log.debug("Loading...");
homebridge.globalFakeGatoStorage.read({
service: this,
callback: function(err,data){
if(!err) {
if(data) {
try {
this.log.debug("read data from",this.accessoryName,":",data);
let jsonFile = typeof(data) === "object" ? data : JSON.parse(data);
this.firstEntry = jsonFile.firstEntry;
this.lastEntry = jsonFile.lastEntry;
this.usedMemory = jsonFile.usedMemory;
this.refTime = jsonFile.refTime;
this.initialTime= jsonFile.initialTime;
this.history = jsonFile.history;
} catch (e) {
this.log.debug("**ERROR fetching persisting data restart from zero - invalid JSON**",e);
cb(e,false);
}
cb(null,true);
}
} else {
// file don't exists
cb(null,false);
}
}.bind(this)
});
}
cleanPersist() {
this.log.debug("Cleaning...");
homebridge.globalFakeGatoStorage.remove({
service: this
});
}
getCurrentS2R2(callback) {

@@ -433,3 +665,3 @@ var entry2address = function(val) {

if ((this.history[this.memoryAddress].setRefTime == 1) || (this.setTime == true)) {
var val = Format(

@@ -444,3 +676,2 @@ '15%s 0100 0000 81%s0000 0000 00 0000',

this.currentEntry = this.currentEntry + 1;
}

@@ -514,3 +745,3 @@ else {

}
};
}

@@ -517,0 +748,0 @@

@@ -5,2 +5,3 @@ /*jshint esversion: 6,node: true,-W041: false */

const DEBUG = true;
var debug = require('debug')('FakeGatoTimer');

@@ -17,5 +18,4 @@ class FakeGatoTimer {

this.log = params.log || {};
if (!params.log || !params.log.debug) {
if(DEBUG) this.log.debug = console.log;
else this.log.debug = function(){};
if (!this.log.debug) {
this.log.debug = DEBUG ? console.log : function() {};
}

@@ -31,3 +31,4 @@ }

'backLog': [],
'previousBackLog': []
'previousBackLog': [],
'previousAvrg': {}
};

@@ -61,3 +62,3 @@

start() {
this.log.debug("**Start Global Fakegato-Timer - ",this.minutes,"min**");
this.log.debug("**Start Global Fakegato-Timer - "+this.minutes+"min**");
if (this.running)

@@ -83,4 +84,10 @@ this.stop();

let service = this.subscribedServices[s];
if (typeof(service.callback) == 'function' && service.backLog.length)
service.callback(service.backLog, this, false);
if (typeof(service.callback) == 'function') {
service.previousAvrg=service.callback({
'backLog':service.backLog,
'previousAvrg':service.previousAvrg,
'timer':this,
'immediate':false
});
}
}

@@ -94,3 +101,7 @@ }

if (typeof(service.callback) == 'function' && service.backLog.length)
service.callback(service.backLog, this, true);
service.callback({
'backLog':service.backLog,
'timer':this,
'immediate':true
});
}

@@ -121,3 +132,3 @@ addData(params) {

source.previousBackLog = source.backLog;
if(source.backLog.length) source.previousBackLog = source.backLog;
source.backLog = [];

@@ -124,0 +135,0 @@ }

{
"name": "fakegato-history",
"version": "0.3.8",
"version": "0.4.0",
"description": "Module emulating Elgato Eve history for homebridge plugins",

@@ -15,3 +15,6 @@ "main": "fakegato-history.js",

"dependencies": {
"moment": "*"
"moment": "*",
"google-auth-library": "^0.10.0",
"googleapis": "^18.0.0",
"debug": "^2.2.0"
},

@@ -18,0 +21,0 @@ "author": "simont77",

# fakegato-history
Module to emulate Elgato Eve history service in Homebridge accessories, so that it will show in Eve.app (Home.app does not support it). Still work in progress. Use at your own risk, no guarantee is provided.
More details on communication protocol and custom Characteristics here: https://gist.github.com/simont77/3f4d4330fa55b83f8ca96388d9004e7d
More details on communication protocol and custom Characteristics in the Wiki.
Your plugin should expose the corresponding custom Elgato services and characteristics in order for the history to be seen in Eve.app. For a weather example see https://github.com/simont77/homebridge-weather-station-extended, for an energy example see https://github.com/simont77/homebridge-myhome/blob/master/index.js (MHPowerMeter class). For other types see the gist above.
Note that if your Eve.app is controlling more than one accessory for each type, the serial number should be unique, otherwise Eve.app will merge the histories. Including hostname is recommended as well, for running multiple copies of the same plugin on different machines (i.e. production and development), i.e.:
Your plugin should expose the corresponding custom Elgato services and characteristics in order for the history to be seen in Eve.app. For a weather example see https://github.com/simont77/homebridge-weather-station-extended, for an energy example see https://github.com/simont77/homebridge-myhome/blob/master/index.js (MHPowerMeter class). For other types see the Wiki.
Avoid the use of "/" in characteristics of the Information Service (e.g. serial number, manifacturer, etc.), since this may cause data to not appear in the history. Note that if your Eve.app is controlling more than one accessory for each type, the serial number should be unique, otherwise Eve.app will merge the histories. Adding hostname is recommended as well, for running multiple copies of the same plugin on different machines (i.e. production and development), i.e.:

@@ -30,3 +30,7 @@ .setCharacteristic(Characteristic.SerialNumber, hostname + "-" + this.deviceID)

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.
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. You may opt for managing yourself the Timer and disabling the embedded one by using that constructor:
```
this.loggingService = new FakeGatoHistoryService(accessoryType, Accessory, {size:length,disableTimer:true});
```
then you'll have to addEntry yourself data every 10min.

@@ -41,7 +45,7 @@ Depending on your accessory type:

* Add entries to history of accessory emulating **Eve Energy** (Outlet service) using something like this every 10 minutes:
* Add entries to history of accessory emulating **Eve Energy** (Outlet service) using something like this:
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. 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)
Power is in Watt. Entries are internally averaged and sent every 10 minutes using the global fakegato timer. To have good accuracy, your entries should be in any case periodic, in order to avoid error with the average.

@@ -72,6 +76,41 @@ * Add entries to history of accessory emulating **Eve Room** (TempSensor, HumiditySensor and AirQuality Services) using something like this:

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 Wiki. 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 Door and Motion you may want to add characteristic E863F11A for setting the time of last activation. Value is the number of second from reset of fakegato-history. You can get this time using the function getInitialTime()
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.
### History Persistance
It is possible to persist data to disk or to Google Drive to avoid loosing part of the history not yet downloaded by Eve on restart or system crash. Data is saved every 10min for "weather" and "room", on every event and every 10 minutes for "door" and "motion", on every event for other types.
#### File System
In order to enable persistance on local disk, when instantiating the FakeGatoHistoryService, the third argument become an object with these attributes:
```
this.loggingService = new FakeGatoHistoryService(accessoryType, Accessory, {
size:length, // optional - if you still need to specify the length
storage:'fs',
path:'/place/to/store/my/persistence/' // if empty it will be used the -U homebridge option if present or .homebridge
});
```
Data will be saved in json files, one for each persisted accessory, with filename in the form *hostname_accessoryDisplayName_persist.json*. In order to reset the persisted data, simply delete these files.
#### Google Drive
In order to enable persistance on Google Drive, when instantiating the FakeGatoHistoryService, the third argument become an object with these attributes :
```
this.loggingService = new FakeGatoHistoryService(accessoryType, Accessory, {
size:length, // optional - if you still need to specify the length
storage:'googleDrive',
folder:'fakegatoFolder', // folder on Google drive to persist data, 'fakegato' if empty
keyPath:'/place/to/store/my/keys/' // where to find client_secret.json, if empty it will be used the -U homebridge option if present or .homebridge
});
```
For the setup of Google Drive, please follow the Google Drive Quickstart for Node.js instructions from https://developers.google.com/drive/v3/web/quickstart/nodejs, except for these changes:
* In Step 1-h the working directory should be the .homebridge directory
* Skip Step 2 and 3
* In step 4, use the quickstartGoogleDrive.js included with this module. You need to run the command from fakegato-hisory directory. Then just follow steps a to c.
##### Additional notes for Google Drive
* Pay attention so that your plugin does not issue multiple addEntry calls for the same accessory at the same time (this may results in unproper behaeviour of Google Drive to the its asynchronous nature)
### TODO

@@ -82,10 +121,10 @@

- [x] Add other accessory types. Help from people with access to real Eve accessory is needed. Dump of custom Characteristics during data transfer is required.
- [ ] Make history persistent
- [x] Make history persistent
- [x] Adjustable history length
- [ ] Addition and management of other history related characteristics
- [ ] Periodic sending of reference time stamp (seems not really needed if the time of your homebridge machine is correct)
### Known bugs
- ~~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.

@@ -92,0 +131,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