Skip to content

Instantly share code, notes, and snippets.

@0ff

0ff/ElgatoEve.js Secret

Created October 27, 2015 09:05
Show Gist options
  • Save 0ff/668f4b7753c80ad7b60b to your computer and use it in GitHub Desktop.
Save 0ff/668f4b7753c80ad7b60b to your computer and use it in GitHub Desktop.
This gist contains a homebridge.js accessory that tries to mimic the elgato eve weather and it's history.
var Service = require("HAP-NodeJS").Service;
var Characteristic = require("HAP-NodeJS").Characteristic;
var request = require("request");
var inherits = require('util').inherits;
var debug = require('debug')('Eve');
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);
}, 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).toString(16);
if(s.length % 2 != 0) {
s = '0' + s;
}
if(len) {
return ('0000000000000' + s).slice(-1 * len);
}
return s;
}
module.exports = {
accessory: EveAccessory
}
function EveAccessory(log, config) {
this.log = log;
}
function EveLogEntry(type, id, timestamp, sensorDatapoints) {
this.type = type;
this.id = id;
this.timestamp = timestamp;
if(type == 0x10) {
this.sensorDatapoints = sensorDatapoints;
} else {
}
}
EveLogEntry.prototype.toHex = function() {
var bytes = [this.type, this.id, 0x00, 0x00, 0x00, numToHex(parseInt(hPAtoHex(this.timestamp), 16), 4), 0x00, 0x00 ];
if(this.type == 0x10) {
bytes.push((this.sensorDatapoints.length * 2) + 1);
bytes.push.apply(bytes, this.sensorDatapoints.map(function(s) {
return hPAtoHex(s);
}));
}
var bytesAsStrings = bytes.map(function(s) { return typeof s === 'string' ? s :numToHex(s); });
// console.log(bytes, bytesAsStrings)
return new Buffer(bytesAsStrings.join(''), 'hex').toString('hex');
}
var _eve = {
EveService1: [
{
uuid: 'E863F10F-079E-48FF-8F27-9C2605A29F52',
desc: 'Air Pressure Sensor',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64(hPAtoHex(1234))
},
{
/*
Some kind of internal temp sensor? Returns 18.7 which is eq to first saved temp
Temp low maybe?
*/
uuid: 'E863F111-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64('4e07')
},
{
uuid: 'E863F112-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE],
format: Characteristic.Formats.DATA,
value: hexToBase64('00000000')
},
{
uuid: 'E863F11B-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64('64')
},
{
uuid: 'E863F11E-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE],
format: Characteristic.Formats.DATA,
value: hexToBase64('01be00be 00f44fb8 0a000000')
},
{
/*
Some kind of internal temp sensor? Returns 21.01 which is well in range of temps
Temp max maybe?
*/
uuid: 'E863F124-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64('3508')
},
{
/*
Some kind of internal hum sensor? Returns 65.32 which is well in range of hum
*/
uuid: 'E863F12A-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64('8419')
},
{
/*
Some kind of internal hum sensor? Returns 65.32 which is well in range of hum
*/
uuid: 'E863F12B-079E-48FF-8F27-9C2605A29F52',
desc: '',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64('8419')
}
],
EveService2: [
{
uuid: 'E863F116-079E-48FF-8F27-9C2605A29F52',
desc: 'Read Trunk 1',
perms: [Characteristic.Perms.READ],
format: Characteristic.Formats.DATA,
value: hexToBase64('01010000 FF000000 3C0F0000 03010202 0203021D 00F50F00 00000000 000000')
},
{
uuid: 'E863F117-079E-48FF-8F27-9C2605A29F52',
desc: 'Read Trunk 2',
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE],
format: Characteristic.Formats.DATA,
value: hexToBase64(
'1500 0000 0000 0000 0080 0000 0000 0000 0000 0000 00' +
new EveLogEntry(0x10, 1, 0, [1870, 7214, 9900]).toHex()
+ new EveLogEntry(0x10, 2, 600, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 3, 1200, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 4, 1800, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 5, 2400, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 6, 3000, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 7, 3600, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 8, 3601, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 9, 3602, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 10, 3603, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 11, 3604, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 12, 3605, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 13, 3606, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 14, 3607, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 15, 3608, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 16, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 17, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 18, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 19, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 20, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 21, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 22, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 23, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 24, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 25, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 26, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 27, 3609, [1870, 7214, 1234]).toHex()
+ new EveLogEntry(0x10, 28, 3609, [1870, 7214, 1234]).toHex()
// new EveLogEntry(0x10, 3, 1800, [1870, 7214, 9900]).toHex() +
// new EveLogEntry(0x10, 4, 2400, [1870, 7214, 9900]).toHex() +
// new EveLogEntry(0x10, 5, 3000, [1870, 7214, 9900]).toHex() +
// new EveLogEntry(0x10, 6, 3600, [1870, 7214, 9900]).toHex() +
// new EveLogEntry(0x10, 7, 4200, [1870, 7214, 9900]).toHex()
// '1001 0000 0001 0000 0007 4e07 2e1c ac26' +
// '1502 0000 00c8 0000 0081 3ce1 c21b 0000 0000 0000 00' +
// '1003 0000 0059 0200 0007 6507 b919 a226' +
// '1004 0000 00b2 0400 0007 e807 671d ac26' +
// '1005 0000 0009 0700 0007 E807 671D 3930'
)
},
{
uuid: 'E863F11C-079E-48FF-8F27-9C2605A29F52',
desc: 'Write Trunk 1',
perms: [Characteristic.Perms.WRITE],
format: Characteristic.Formats.DATA,
value: null
},
{
uuid: 'E863F121-079E-48FF-8F27-9C2605A29F52',
desc: 'Write Trunk 2',
perms: [Characteristic.Perms.WRITE],
format: Characteristic.Formats.DATA,
value: null
},
]
}
var Eve = {},
makeCharacteristicFromEveDesc = function(s) {
var id = s.uuid.split('-')[0];
Eve[id] = function() {
var name = (s.desc && (id + ': ' + s.desc)) || id;
Characteristic.call(this, name, s.uuid);
this.setProps({
format: s.format,
perms: s.perms
});
this.value = s.value;
var self = this;
this.on('get', function(cb) {
debug('[%s] was read', name, base64ToHex(self.value));
cb(null, self.value);
});
this.on('set', function(val, cb) {
debug('[%s] was written: %s', name, base64ToHex(val));
cb(null, val);
});
};
inherits(Eve[id], Characteristic);
};
_eve.EveService1.forEach(function(s) {
return makeCharacteristicFromEveDesc(s);
});
_eve.EveService2.forEach(function(s) {
return makeCharacteristicFromEveDesc(s);
});
function EveService1(displayName, subtype) {
Service.call(this, displayName, 'E863F001-079E-48FF-8F27-9C2605A29F52', subtype);
// Required Characteristics
this.addCharacteristic(Characteristic.CurrentTemperature);
this.addCharacteristic(Characteristic.CurrentRelativeHumidity);
this.addCharacteristic(Eve.E863F11E);
this.addCharacteristic(Eve.E863F10F);
// this.addCharacteristic(Eve.E863F111);
this.addCharacteristic(Eve.E863F112);
this.addCharacteristic(Eve.E863F11B);
// this.addCharacteristic(Eve.E863F124);
// this.addCharacteristic(Eve.E863F12A);
// this.addCharacteristic(Eve.E863F12B);
}
inherits(EveService1, Service);
function EveService2(displayName, subtype) {
Service.call(this, displayName, 'E863F007-079E-48FF-8F27-9C2605A29F52', subtype);
this.addCharacteristic(Eve.E863F116);
this.addCharacteristic(Eve.E863F117);
this.addCharacteristic(Eve.E863F11C);
this.addCharacteristic(Eve.E863F121);
}
inherits(EveService2, Service);
EveAccessory.prototype = {
identify: function(callback) {
this.log("Identify requested!");
callback(); // success
},
getServices: function() {
// you can OPTIONALLY create an information service if you wish to override
// the default values for things like serial number, model, etc.
this.informationService = new Service.AccessoryInformation();
this.informationService
.setCharacteristic(Characteristic.Manufacturer, "Fakegato")
.setCharacteristic(Characteristic.Model, "Eve Weather")
this.service1 = new EveService1();
this.service2 = new EveService2();
return [this.informationService, this.service1, this.service2];
}
};
@simont77
Copy link

@0ff
Hi, I'm experimenting a bit starting from your gist and the one from @gomfunkel. If you want you may have a look at my recent findings here https://gist.github.com/simont77/3f4d4330fa55b83f8ca96388d9004e7d. I don't know if you already discovered all of them, maybe we can join our efforts to close the ring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment