Created
July 29, 2019 03:09
-
-
Save dkebler/fe872178e0de4a5874d6a6157b9f3537 to your computer and use it in GitHub Desktop.
Access home assistant websocket api via nodej client and long lasting token
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import to from 'await-to-js' | |
import ha from 'home-assistant-js-websocket' | |
import WebSocket from 'ws' | |
import { EventEmitter } from 'events' | |
import ndb from 'debug' | |
const debug = ndb('home-assistant:ws') | |
const MSG_TYPE_AUTH_REQUIRED = 'auth_required' | |
const MSG_TYPE_AUTH_INVALID = 'auth_invalid' | |
const MSG_TYPE_AUTH_OK = 'auth_ok' | |
class HomeAssistant extends EventEmitter { | |
constructor(config) { | |
super() | |
this.config = config | |
debug('config passed to websocket constructor', this.config) | |
this.socket = {} // node websocket if access needed | |
this.conn = {} // the connection object needed for api calls | |
debug('constructor\n', this.config) | |
} | |
async connect () { | |
let [errws,ws] = await to(createSocket(this.config)) | |
if (errws) { | |
debug('socket create error', errws) | |
throw errws | |
} | |
debug('websocket ready at', ws.url) | |
let [err,conn] = await to(ha.createConnection({createSocket: () => {return ws}})) | |
if (err) { | |
debug('error in connection', err) | |
throw err | |
} | |
this.conn = conn | |
this.api = ha // to be replaced with merged api calls | |
debug('Connected to Home Assistant') | |
return 'success' | |
function createSocket (opts) { | |
return new Promise((resolve, reject) => { | |
if (!opts.hassUrl) { | |
throw ha.ERR_HASS_HOST_REQUIRED | |
} | |
const auth = JSON.stringify({ | |
type: 'auth', | |
access_token: opts.access_token | |
}) | |
let url = `${opts.hassUrl}/${opts.wssPath || 'api/websocket'}` | |
debug('[Auth Phase] Initializing', url) | |
setTimeout(() => reject(new Error('Unable to Authorize in 5 seconds')),5000) | |
let ws = new WebSocket(url,opts) | |
ws.on('error', error.bind(ws)) | |
function error(err) { | |
this.removeAllListeners('message',authorize) | |
this.removeAllListeners('error', error) | |
reject(err) | |
} | |
ws.on('message',authorize.bind(ws)) | |
function authorize(event) { | |
const message = JSON.parse(event) | |
debug('[Auth Phase] Message Received', message) | |
switch (message.type) { | |
case MSG_TYPE_AUTH_REQUIRED: | |
try { | |
debug('[Auth Phase] sending authorization\n',auth) | |
this.send(auth) | |
} catch (err) { | |
debug('sending auth error') | |
this.close() | |
reject(new Error('unable to send authorization')) | |
} | |
break | |
case MSG_TYPE_AUTH_OK: | |
this.removeAllListeners('message',authorize) | |
this.removeAllListeners('error', error) | |
resolve(this) | |
break | |
case MSG_TYPE_AUTH_INVALID: | |
this.close() | |
reject(new Error(MSG_TYPE_AUTH_INVALID)) | |
break | |
default: | |
debug('[Auth Phase] Unhandled message', message) | |
this.close() | |
reject(new Error(`unhandled authorization error, ${message}`)) | |
} | |
} // end authorize | |
}) | |
} // end createSocket | |
} | |
} // end class | |
export default HomeAssistant |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import to from 'await-to-js' | |
import Hass from './lib/homeassistant' | |
let opts = { | |
hassUrl: '<ws/http/https>://<your domain or ip>:8123', | |
access_token: 'your long lived token' | |
} | |
let hass = new Hass(opts) | |
; | |
(async () => { | |
await hass.connect() | |
// eventually do stuff now with hass like hass.subscribeEntities(handler) | |
// but for now like this | |
hass.api.subscribeEntities(hass.conn, entities => console.log('New entities!', entities)) | |
})().catch(err => { | |
console.error('FATAL: UNABLE TO START SYSTEM!\n',err) | |
process.kill(process.pid, 'SIGTERM') | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey just wanted to thank you for posting this. I was getting a little sad about all the existing libraries/documentation being so focused on front end only clients.