Skip to content

Commit

Permalink
Nest devices won't move back to Default Room after a failed connection.
Browse files Browse the repository at this point in the history
  • Loading branch information
adriancable committed Sep 2, 2020
1 parent e5c24ef commit 924b168
Show file tree
Hide file tree
Showing 5 changed files with 350 additions and 328 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)

Nest plug-in for [Homebridge](https://github.com/nfarina/homebridge) using the native Nest API. See what's new in [release 4.4.6](https://github.com/chrisjshull/homebridge-nest/releases/tag/v4.4.6).
Nest plug-in for [Homebridge](https://github.com/nfarina/homebridge) using the native Nest API. See what's new in [release 4.4.7](https://github.com/chrisjshull/homebridge-nest/releases/tag/v4.4.7).

Integrate your Nest Thermostat (including Nest Temperature Sensors), Nest Protect, and Nest x Yale Lock devices into your HomeKit system. Both Nest Accounts (pre-August 2019) and Google Accounts are supported.

Expand Down
183 changes: 94 additions & 89 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,99 @@ class NestPlatform {
this.log = log;
this.api = api;
this.accessoryLookup = {};
this.cachedAccessories = [];

api.on('didFinishLaunching', async () => {
this.log('Fetching Nest devices.');

const generateAccessories = function(data) {
const foundAccessories = [];

const loadDevices = function(DeviceType) {
const disableFlags = {
'thermostat': 'Thermostat.Disable',
'temp_sensor': 'TempSensor.Disable',
'protect': 'Protect.Disable',
'home_away_sensor': 'HomeAway.Disable',
'lock': 'Lock.Disable'
};

const devices = (data.devices && data.devices[DeviceType.deviceGroup]) || {};
for (const deviceId of Object.keys(devices)) {
const device = devices[deviceId];
const serialNumber = device.serial_number;
if (!this.optionSet(disableFlags[DeviceType.deviceType], serialNumber, deviceId)) {
const structureId = device.structure_id;
if (this.config.structureId && this.config.structureId !== structureId) {
this.log('Skipping device ' + deviceId + ' because it is not in the required structure. Has ' + structureId + ', looking for ' + this.config.structureId + '.');
continue;
}
const structure = data.structures[structureId];
const accessory = new DeviceType(this.conn, this.log, device, structure, this);
this.accessoryLookup[deviceId] = accessory;
foundAccessories.push(accessory);
}
}
}.bind(this);

loadDevices(ThermostatAccessory);
loadDevices(HomeAwayAccessory);
loadDevices(TempSensorAccessory);
loadDevices(ProtectAccessory);
loadDevices(LockAccessory);

return foundAccessories;
}.bind(this);

const updateAccessories = function(data, accList) {
accList.map(function(acc) {
const device = data.devices[acc.deviceGroup][acc.deviceId];
if (device) {
const structureId = device.structure_id;
const structure = data.structures[structureId];
acc.updateData(device, structure);
}
});
};

const handleUpdates = function(data) {
if (Object.keys(this.accessoryLookup).length > 0) {
updateAccessories(data, this.accessoryLookup);
}
}.bind(this);

try {
this.conn = await this.setupConnection(this.optionSet('Debug.Verbose'), this.optionSet('Nest.FieldTest.Enable'));
await this.conn.subscribe(handleUpdates);
await this.conn.observe(handleUpdates);

let initialState = this.conn.apiResponseToObjectTree(this.conn.currentState);
this.accessoryLookup = generateAccessories(initialState);

this.api.unregisterPlatformAccessories('homebridge-nest', 'Nest', this.cachedAccessories);
this.cachedAccessories = [];
this.api.registerPlatformAccessories('homebridge-nest', 'Nest', this.accessoryLookup.map(el => el.accessory));

let accessoriesMounted = this.accessoryLookup.map(el => el.constructor.name);

if (this.config.readyCallback) {
axios.post(this.config.readyCallback, {
thermostat_count: accessoriesMounted.filter(el => el == 'NestThermostatAccessory').length,
tempsensor_count: accessoriesMounted.filter(el => el == 'NestTempSensorAccessory').length,
protect_count: accessoriesMounted.filter(el => el == 'NestProtectAccessory').length,
lock_count: accessoriesMounted.filter(el => el == 'NestLockAccessory').length
}).catch(() => { });
}
} catch(err) {
this.log.error(err);
this.log.error('NOTE: Because we couldn\'t connect to the Nest service, your Nest devices in HomeKit will not be responsive.');
this.cachedAccessories.forEach(el => el.updateReachability(false));
}
});
}

configureAccessory(accessory) {
this.cachedAccessories.push(accessory);
}

optionSet(key, serialNumber, deviceId) {
Expand All @@ -52,99 +145,11 @@ class NestPlatform {
throw('Unable to authenticate with Google/Nest.');
}
}

async accessories(callback) {
this.log('Fetching Nest devices.');

const generateAccessories = function(data) {
const foundAccessories = [];

const loadDevices = function(DeviceType) {
const disableFlags = {
'thermostat': 'Thermostat.Disable',
'temp_sensor': 'TempSensor.Disable',
'protect': 'Protect.Disable',
'home_away_sensor': 'HomeAway.Disable',
'lock': 'Lock.Disable'
};

const devices = (data.devices && data.devices[DeviceType.deviceGroup]) || {};
for (const deviceId of Object.keys(devices)) {
const device = devices[deviceId];
const serialNumber = device.serial_number;
if (!this.optionSet(disableFlags[DeviceType.deviceType], serialNumber, deviceId)) {
const structureId = device.structure_id;
if (this.config.structureId && this.config.structureId !== structureId) {
this.log('Skipping device ' + deviceId + ' because it is not in the required structure. Has ' + structureId + ', looking for ' + this.config.structureId + '.');
continue;
}
const structure = data.structures[structureId];
const accessory = new DeviceType(this.conn, this.log, device, structure, this);
this.accessoryLookup[deviceId] = accessory;
foundAccessories.push(accessory);
}
}
}.bind(this);

loadDevices(ThermostatAccessory);
loadDevices(HomeAwayAccessory);
loadDevices(TempSensorAccessory);
loadDevices(ProtectAccessory);
loadDevices(LockAccessory);

return foundAccessories;
}.bind(this);

const updateAccessories = function(data, accList) {
accList.map(function(acc) {
const device = data.devices[acc.deviceGroup][acc.deviceId];
if (device) {
const structureId = device.structure_id;
const structure = data.structures[structureId];
acc.updateData(device, structure);
}
});
};

const handleUpdates = function(data) {
if (Object.keys(this.accessoryLookup).length > 0) {
updateAccessories(data, this.accessoryLookup);
}
}.bind(this);

try {
this.conn = await this.setupConnection(this.optionSet('Debug.Verbose'), this.optionSet('Nest.FieldTest.Enable'));
await this.conn.subscribe(handleUpdates);
await this.conn.observe(handleUpdates);

let initialState = this.conn.apiResponseToObjectTree(this.conn.currentState);
this.accessoryLookup = generateAccessories(initialState);
if (callback) {
callback(Array.from(this.accessoryLookup));
}

let accessoriesMounted = this.accessoryLookup.map(el => el.constructor.name);

if (this.config.readyCallback) {
axios.post(this.config.readyCallback, {
thermostat_count: accessoriesMounted.filter(el => el == 'NestThermostatAccessory').length,
tempsensor_count: accessoriesMounted.filter(el => el == 'NestTempSensorAccessory').length,
protect_count: accessoriesMounted.filter(el => el == 'NestProtectAccessory').length,
lock_count: accessoriesMounted.filter(el => el == 'NestLockAccessory').length
}).catch(() => { });
}
} catch(err) {
this.log.error(err);
if (callback) {
callback([]);
}
}
}
}

module.exports = function(homebridge) {
const exportedTypes = {
Accessory: homebridge.hap.Accessory,
Accessory: homebridge.platformAccessory,
Service: homebridge.hap.Service,
Characteristic: homebridge.hap.Characteristic,
hap: homebridge.hap,
Expand Down
Loading

0 comments on commit 924b168

Please sign in to comment.