Skip to content

Commit

Permalink
Added support for automatic configuration on https://manager.lightwav…
Browse files Browse the repository at this point in the history
  • Loading branch information
rooi committed Apr 18, 2021
1 parent c6a891b commit 506f57b
Show file tree
Hide file tree
Showing 3 changed files with 338 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Note: This plugin communicates with the KlikAanKlikUit ICS-1000 or Lightwave Lin
Set the correct manager_host in the configuration:
- web.trustsmartcloud.com
- lightwaverfhost.co.uk
- control-api.lightwaverf.com

# Installation

Expand Down
336 changes: 336 additions & 0 deletions lib/lightwaverf.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,16 @@ LightwaveRF.prototype.getDevices = function(roomsString,devicesString,typesStrin
* Connect to the server and obtain the configuration
*/
LightwaveRF.prototype.getConfiguration = function(email,pin,manager_host, manager_host_path,callback){

if(manager_host === "control-api.lightwaverf.com") {
this.getConfigurationV2(email, pin, manager_host, callback);
} else {
this.getConfigurationV1(email, pin, manager_host, manager_host_path, callback)
}
}


LightwaveRF.prototype.getConfigurationV1 = function(email,pin,manager_host, manager_host_path,callback) {
// An object of options to indicate where to post to
var post_options = {
//host: 'lightwaverfhost.co.uk',
Expand Down Expand Up @@ -519,4 +529,330 @@ LightwaveRF.prototype.getConfiguration = function(email,pin,manager_host, manage
post_req.end();
}

/**
* New lightwaveRF server methods
*/
LightwaveRF.prototype.getConfigurationV2 = function(user, pin, host, callback)
{
var host_url = "https://" + host;//control-api.lightwaverf.com';
this.log("getConfigurationV2 " + host_url);
this.getApplicationKey(user, pin, host_url, callback);
}

/**
* Connect to the server and obtain the application key
*/
LightwaveRF.prototype.getApplicationKey = function(user, pin, host, callback)
{
this.log.debug('Getting Application Key from LightWave');

https.get(host + '/v1/user?password=' + pin + '&username=' + user, function(res) {

const { statusCode } = res;
const contentType = res.headers['content-type'];

let error;
// Any 2xx status code signals a successful response but
// here we're only checking for 200.
if (statusCode !== 200) {
error = "Request Failed.\nStatus Code: " + statusCode;
} else if (!/^application\/json/.test(contentType)) {
error = "Invalid content-type.\nExpected application/json but received " + contentType;
}
if (error) {
this.log.error(error);
// Consume response data to free up memory
res.resume();
if(callback) callback(error);
return;
}

res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
this.log.debug("getApplicationKey parsedData = ");
this.log.debug(parsedData);

this.application_key = parsedData.application_key;

this.getToken(this.application_key, host, callback);

} catch (e) {
this.log.error(e);
if(callback) callback(error);
}
});
}.bind(this)).on('error', (e) => {
this.log.error("Got error: " + e);
if(callback) callback(error);
});

}

/**
* Connect to the server and obtain the token
*/
LightwaveRF.prototype.getToken = function(application_key, host, callback)
{
this.log.debug('Getting token from LightWave');

https.get(host + '/v1/auth?application_key=' + application_key, function (res) {

const { statusCode } = res;
const contentType = res.headers['content-type'];

let error;
// Any 2xx status code signals a successful response but
// here we're only checking for 200.
if (statusCode !== 200) {
error = "Request Failed.\nStatus Code: " + statusCode;
} else if (!/^application\/json/.test(contentType)) {
error = "Invalid content-type.\nExpected application/json but received " + contentType;
}
if (error) {
this.log.error(error);
// Consume response data to free up memory
res.resume();
if(callback) callback(error);
return;
}

res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
this.log.debug("getToken parsedData = ");
this.log.debug(parsedData);

this.token = parsedData.token;

this.getDeviceTypes(this.token, host, callback);

} catch (e) {
this.log.error(e);
if(callback) callback(error);
}
});
}.bind(this)).on('error', (e) => {
this.log.error("Got error: " + e);
if(callback) callback(error);
});
}

/**
* Connect to the server and obtain the device types
*/
LightwaveRF.prototype.getDeviceTypes = function(token, host, callback)
{
this.log.debug('Getting device types from LightWave');

var options = {
headers: {
'X-LWRF-token': token,
'X-LWRF-platform': 'ios',
'X-LWRF-skin': 'lightwaverf'
}
};

https.get(host + '/v1/device_type?nested=1', options, function (res) {

const { statusCode } = res;
const contentType = res.headers['content-type'];

let error;
// Any 2xx status code signals a successful response but
// here we're only checking for 200.
if (statusCode !== 200) {
error = "Request Failed.\nStatus Code: " + statusCode;
} else if (!/^application\/json/.test(contentType)) {
error = "Invalid content-type.\nExpected application/json but received " + contentType;
}
if (error) {
this.log.error(error);
// Consume response data to free up memory
res.resume();
if(callback) callback(error);
return;
}

res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
this.log.debug("getDeviceTypes parsedData = ");
this.log.debug(parsedData);

this.getUserProfile(this.token, host, callback);

} catch (e) {
this.log.error(e);
if(callback) callback(error);
}
});
}.bind(this)).on('error', (e) => {
this.log.error("Got error: " + e);
if(callback) callback(error);
});
}

/**
* Connect to the server and obtain the device types
*/
LightwaveRF.prototype.getUserProfile = function(token, host, callback)
{
this.log.debug('Getting user profile from LightWave');

var options = {
headers: {
'X-LWRF-token': token,
'X-LWRF-platform': 'ios',
'X-LWRF-skin': 'lightwaverf'
}
};

https.get(host + '/v1/user_profile?nested=1', options, function (res) {

const { statusCode } = res;
const contentType = res.headers['content-type'];

let error;
// Any 2xx status code signals a successful response but
// here we're only checking for 200.
if (statusCode !== 200) {
error = "Request Failed.\nStatus Code: " + statusCode;
} else if (!/^application\/json/.test(contentType)) {
error = "Invalid content-type.\nExpected application/json but received " + contentType;
}
if (error) {
this.log.error(error);
// Consume response data to free up memory
res.resume();
if(callback) callback(error);
return;
}

res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
this.log.debug("getUserProfile parsedData = ");
this.log.debug(parsedData);

this.parseRooms(parsedData, callback);

} catch (e) {
this.log.error(e);
if(callback) callback(error);
}
});
}.bind(this)).on('error', (e) => {
this.log.error("Got error: " + e);
if(callback) callback(error);
});
}

/**
* Parse the response
*/
LightwaveRF.prototype.parseRooms = function(lightwaveResponse, callback)
{
if(!lightwaveResponse.content.estates) {
this.log.warn("No estates found. Please create an estate for lightwaverf: " + lightwaveResponse.content);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0]) {
this.log.warn("No estates[0] empty. Please create an estate for lightwaverf: " + lightwaveResponse.content);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0].locations) {
this.log.warn("No locations found. Please create a location for lightwaverf: " + lightwaveResponse.content.estates[0]);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0].locations[0]) {
this.log.warn("No estates[0].locations[0] empty. Please create a location for lightwaverf and assign rooms: " + lightwaveResponse.content.estates[0]);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0].locations[0].zones) {
this.log.warn("No zones found. Please create a zone for lightwaverf: " + lightwaveResponse.content.estates[0].locations[0]);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0].locations[0].zones[0]) {
this.log.warn("No estates[0].zones[0] empty. Please create a zone for lightwaverf and assign rooms: " + lightwaveResponse.content.estates[0].locations[0].zones[0]);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0].locations[0].zones[0].rooms) {
this.log.warn("No rooms found. Please create a room for lightwaverf. And assign it to: " + lightwaveResponse.content.estates[0].locations[0].zones[0]);
if(callback) callback(1);
} else if(!lightwaveResponse.content.estates[0].locations[0].zones[0].rooms[0]) {
this.log.warn("No estates[0].zones[0].rooms[0] empty. Please create a room for lightwaverf and assign it to: " + lightwaveResponse.content.estates[0].locations[0].zones[0]);
if(callback) callback(1);
}
else {

this.log.debug("Parsing lightwaveResponse: " + lightwaveResponse.content.estates[0].locations[0].zones[0].rooms[0].devices);

var home = lightwaveResponse.content.estates[0].locations[0].zones[0];

var rooms = [];
for(var i=0; i < home.rooms.length; i++) {
var r = home.rooms[i];
var room = {
name: r.name,
number: r.room_number,
status: r.name,
active: r.active === 1,
devices: []
};

rooms.push(room);

this.log.debug("Room " + room.name + " with " + (r.devices ? r.devices.length : "0 ") + " devices");

for (var j = 0; j < (r.devices ? r.devices.length: 0); j++) {
var d = r.devices[j];

var device = {
name: d.name,
status: d.name,
number: d.device_number,
active: d.active === 1,
mood: false
};

this.log.debug("Adding device " + device)
room.devices.push(device);

// Get device types
// O: On/Off Switch
// D: Dimmer
// R: Radiator(s)
// P: Open/Close
// I: Inactive (i.e. not configured)
// m: Mood (inactive)
// M: Mood (active)
// o: All Off
var dType = "";
if(d.active === 0) dType = "I";
else if(d.device_type_id === 1) dType = "O";
else if(d.device_type_id === 2) dType = "D";
else if(d.device_type_id === 3) dType = "P";
else if(d.device_type_id === 11) dType = "O";
else if(d.device_type_id === 12) dType = "O";

this.devices.push({roomId:r.room_number,roomName:r.name,
deviceId:d.device_number,deviceName:d.name,
deviceType:dType});

}
}

this.log.debug('Rooms:' + rooms)

if(callback) callback(this.devices, this);
}
};

module.exports = LightwaveRF;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "homebridge-lightwaverf",
"version": "0.3.9",
"version": "0.4.0",
"description": "LightwaveRF plugin for homebridge: https://github.com/nfarina/homebridge",
"license": "ISC",
"keywords": [
Expand Down

0 comments on commit 506f57b

Please sign in to comment.