Skip to content

Commit

Permalink
Update README
Browse files Browse the repository at this point in the history
  • Loading branch information
alexciesielski committed Mar 31, 2020
1 parent bd3c4cb commit 474d29d
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 56 deletions.
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ ENV LANG C.UTF-8

COPY run.sh /
WORKDIR /usr/
COPY . .
COPY example example
COPY lib lib
COPY package.json package-lock.json tsconfig.json config.json ./


# Setup base
RUN apk add --no-cache jq nodejs npm
Expand Down
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@ rxjs wrapper for [home-assistant-js-websocket](https://github.com/home-assistant

### Local Development

`npm run dev`
1. Create a `.env` file with two properties `HOST` and `ACCESS_TOKEN`.

### Local Docker Development
```
HOST=http://homeassistant.local:8123
ACCESS_TOKEN=<long-lived-access-token>
```

2. Run the development server

```
npm run dev
```

#### Local build

`docker build --build-arg BUILD_FROM="homeassistant/amd64-base:latest" -t ha-rxjs .`

#### Local run

`docker run --rm -e SUPERVISOR_TOKEN="<long-lived-access-token>" ha-rxjs`
`docker run --rm --env-file=.env ha-rxjs`
22 changes: 5 additions & 17 deletions example/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
import dotenv from 'dotenv';
import { filter, take, tap } from 'rxjs/operators';
import { filter, switchMap, take, tap } from 'rxjs/operators';
import { HomeAssistantRXJS } from '../lib';

dotenv.config();
const host = process.env.HOST ?? 'http://homeassistant:8123';
const token = process.env.ACCESS_TOKEN;

if (!token) {
throw new Error(
'No access token (SUPERVISOR_TOKEN or ACCESS_TOKEN) found in environment variables.',
);
}

console.log(`Initializing HA with ${token} at ${host}`);
const harxjs = new HomeAssistantRXJS(host, token);
const harxjs = new HomeAssistantRXJS();

harxjs.services$
.pipe(
filter(config => Object.keys(config).length > 0),
filter(x => !!x),
take(1),
tap(console.log),
tap(() => harxjs.destroy()),
tap(x => console.log('connected')),
switchMap(() => harxjs.destroy()),
)
.subscribe();
43 changes: 37 additions & 6 deletions lib/connection/create-socket.ts → lib/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,51 @@ https://github.com/home-assistant/home-assistant-js-websocket/blob/master/lib/so

// import * as ha from 'home-assistant-js-websocket';
import {
Auth,
createConnection,
ERR_CANNOT_CONNECT,
ERR_INVALID_AUTH,
MSG_TYPE_AUTH_INVALID,
MSG_TYPE_AUTH_OK,
MSG_TYPE_AUTH_REQUIRED,
} from 'home-assistant-js-websocket';
import WebSocket from 'ws';
import { HomeAssistantRXJSOptions } from '..';

export async function connectToHA() {
const connection = await createConnection({
createSocket: () =>
createSocket({ wsUrl: getWsURL(), token: getToken() }, true),
});

return connection;
}

function getWsURL() {
const host = process.env.HOST;
return host
? `ws${host.substr(4)}/api/websocket`
: 'ws://supervisor/core/websocket';
}

function getToken() {
const token = process.env.ACCESS_TOKEN || process.env.SUPERVISOR_TOKEN;

if (!token) {
throw new Error(
'No access token (SUPERVISOR_TOKEN or ACCESS_TOKEN) found in environment variables.',
);
}

return token;
}

export function createSocket(
auth: Auth,
auth: HomeAssistantRXJSOptions,
ignoreCertificates: boolean,
): Promise<any> {
// Convert from http:// -> ws://, https:// -> wss://
console.log(`URL ${auth.wsUrl}`);
console.log(`Token ${auth.token}`);

const url = auth.wsUrl;

console.log(
Expand Down Expand Up @@ -100,13 +131,13 @@ export function createSocket(
// Auth is mandatory, so we can send the auth message right away.
const handleOpen = async () => {
try {
if (auth.expired) {
/* if (auth.expired) {
await auth.refreshAccessToken();
}
} */
socket.send(
JSON.stringify({
type: 'auth',
access_token: auth.accessToken,
access_token: auth.token,
}),
);
} catch (err) {
Expand Down
5 changes: 1 addition & 4 deletions lib/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ export class HomeAssistantEntities {
subscriber.next(entities),
);

subscriber.add(() => {
subscriber.complete();
unsubscribe();
});
subscriber.add(() => unsubscribe());
}),
),
tap(entities => this.entities.next(entities)),
Expand Down
53 changes: 32 additions & 21 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
import dotenv from 'dotenv';
import {
createConnection,
createLongLivedTokenAuth,
Connection,
HassConfig,
subscribeConfig,
} from 'home-assistant-js-websocket';
import { BehaviorSubject, from, Observable, Subject } from 'rxjs';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import {
filter,
map,
switchMap,
switchMapTo,
take,
takeUntil,
tap,
} from 'rxjs/operators';
import { createSocket } from './connection/create-socket';
import { connectToHA } from './connection';
import { HomeAssistantEntities } from './entities';
import { HomeAssistantServices } from './services';

export interface HomeAssistantRXJSOptions {
token: string;
wsUrl: string;
}

export class HomeAssistantRXJS {
constructor(public host: string, private token: string) {
process.on('SIGTERM', () => this.destroy().subscribe(process.exit(0)));
constructor() {
this.initialize();
}

private readonly destroy$ = new Subject<void>();
readonly connection$ = from(this.connectoToHA(this.host, this.token)).pipe(

private readonly connection = new BehaviorSubject<Connection | null>(null);
readonly connection$ = this.connection.pipe(
filter(connection => !!connection),
// next line is to satisfy TS strictNullChecks
map(connection => connection as Connection),
);

readonly services = new HomeAssistantServices(
Expand All @@ -43,14 +53,26 @@ export class HomeAssistantRXJS {
readonly config$ = this.getConfig();

destroy() {
this.destroy$.next();
this.destroy$.complete();
return this.connection$.pipe(
take(1),
tap(() => console.log('Closing connection')),
tap(connection => connection.close()),
tap(() => {
this.destroy$.next();
this.destroy$.complete();
}),
// tap(() => process.exit(0)),
);
}

private async initialize() {
process.on('SIGTERM', () => this.destroy().subscribe(process.exit(0)));
dotenv.config();

const connection = await connectToHA();
this.connection.next(connection);
}

private getConfig() {
return this.connection$.pipe(
switchMap(
Expand All @@ -60,22 +82,11 @@ export class HomeAssistantRXJS {
subscriber.next(config),
);

subscriber.add(() => {
subscriber.complete();
unsubscribe();
});
subscriber.add(() => unsubscribe());
}),
),
switchMapTo(this.config.asObservable()),
takeUntil(this.destroy$),
);
}

private connectoToHA(host: string, token: string) {
const auth = createLongLivedTokenAuth(host, token);

return createConnection({
createSocket: () => createSocket(auth, true),
});
}
}
5 changes: 1 addition & 4 deletions lib/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ export class HomeAssistantServices {
subscriber.next(services),
);

subscriber.add(() => {
subscriber.complete();
unsubscribe();
});
subscriber.add(() => unsubscribe());
}),
),
tap(services => this.services.next(services)),
Expand Down

0 comments on commit 474d29d

Please sign in to comment.