@homebridge-plugins/homebridge-lutron-caseta-leap
Version:
Homebridge support for Lutron
132 lines • 5.84 kB
JavaScript
import { HomebridgePluginUiServer } from '@homebridge/plugin-ui-utils';
import { BridgeFinder, LeapClient, PairingClient } from 'lutron-leap';
import forge from 'node-forge';
class PluginUiServer extends HomebridgePluginUiServer {
finder;
constructor() {
super();
this.finder = new BridgeFinder();
this.finder.on('discovered', (bridgeInfo) => {
this.pushEvent('discovered', bridgeInfo);
});
this.onRequest('/search', this.findBridges.bind(this));
this.onRequest('/connect', this.doConnect.bind(this));
this.onRequest('/associate', this.doAssociate.bind(this));
this.ready();
}
async findBridges() {
this.finder.beginSearching();
}
async doConnect({ secrets, bridgeid, ipAddr }) {
// console.log('Got request to connect', bridgeid, 'at', ipAddr, ' with secrets', JSON.stringify(secrets))
this.pushEvent('toast', { message: `Got request to connect ${bridgeid} at ${ipAddr} with secrets ${JSON.stringify(secrets)}` });
try {
const client = new LeapClient(ipAddr, 8081, secrets.ca, secrets.key, secrets.cert);
await client.connect();
// console.log('client connected to', bridgeid, ipAddr)
this.pushEvent('toast', { message: `client connected to ${bridgeid}, ${ipAddr}` });
}
catch (e) {
// console.log('failed to connect to', bridgeid, e)
this.pushEvent('toast', { message: `failed to connect to ${bridgeid}, ${e.message ?? e}` });
this.pushEvent('failed', { bridgeid, reason: e.message });
throw e;
}
this.pushEvent('connected', bridgeid);
}
async doAssociate({ bridgeid, ipAddr }) {
// console.info('Got request to associate with', bridgeid, 'at', ipAddr)
this.pushEvent('toast', { message: `Got request to associate with ${bridgeid} at ${ipAddr}` });
const client = new PairingClient(ipAddr, 8083);
try {
await client.connect();
// console.info('association phase connected', bridgeid, ipAddr)
this.pushEvent('toast', { message: `Association phase connected: ${bridgeid} at ${ipAddr}` });
}
catch (e) {
// console.warn('failed to associate', bridgeid, ipAddr, e)
this.pushEvent('toast', { message: `failed to associate: ${bridgeid}, ${ipAddr}, ${e.message ?? e}` });
throw new Error('Initial associate failed!');
}
try {
await new Promise((resolve, reject) => {
const t = setTimeout(() => reject(new Error('timed out')), 30000);
client.once('message', (response) => {
// console.log('got message', response)
this.pushEvent('toast', { message: `got message ${response}` });
const res = response;
if (res.Body.Status.Permissions.includes('PhysicalAccess')) {
// console.log('Physical access confirmed')
this.pushEvent('toast', { message: `Physical access confirmed` });
clearTimeout(t);
resolve();
}
else {
// console.log('unexpected pairing result', response)
this.pushEvent('toast', { message: `unexpected pairing result, ${response}` });
reject(response);
}
});
});
}
catch (e) {
// console.log('waiting for button push failed', e)
this.pushEvent('toast', { message: `waiting for button push failed, ${e.message ?? e}` });
throw e;
}
const keys = await new Promise((resolve, reject) => {
forge.pki.rsa.generateKeyPair({ bits: 2048 }, (err, keyPair) => {
if (err !== undefined) {
resolve(keyPair);
}
else {
reject(err);
}
});
});
const csr = forge.pki.createCertificationRequest();
csr.publicKey = keys.publicKey;
csr.setSubject([
{
name: 'commonName',
value: 'homebridge-lutron',
},
]);
csr.sign(keys.privateKey);
const csrText = forge.pki.certificationRequestToPem(csr);
let certResult;
try {
certResult = await new Promise((resolve, reject) => {
const t = setTimeout(() => reject(new Error('CSR response timed out')), 5000);
client.once('message', (response) => {
// console.log('got cert request result', JSON.stringify(response))
this.pushEvent('toast', { message: `got cert request result ${JSON.stringify(response)}, ${t}` });
resolve(response);
});
client.requestPair(csrText);
});
if (certResult.Header.StatusCode !== '200 OK') {
throw new Error(`bad CSR response: ${JSON.stringify(certResult)}`);
}
}
catch (e) {
// console.log('CSR failed', e)
this.pushEvent('toast', { message: `CSR failed, ${e.message ?? e}` });
throw e;
}
this.pushEvent('associated', {
bridgeid,
ipAddr,
secrets: {
bridgeid,
ca: certResult.Body.SigningResult.RootCertificate,
cert: certResult.Body.SigningResult.Certificate,
key: forge.pki.privateKeyToPem(keys.privateKey),
},
});
}
}
(() => {
return new PluginUiServer();
})();
//# sourceMappingURL=server.js.map