npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ha-javascript-proxy

v1.0.0-rc.1

Published

A typed, reactive wrapper around home-assistant-js-websocket

Readme

ha-javascript-proxy

A typed, reactive wrapper around home-assistant-js-websocket — because life's too short to guess entity attribute names.

Install

npm install ha-javascript-proxy home-assistant-js-websocket

[!WARNING] Node.js 18 or later is required.

Quick Start

import { createConnection } from 'ha-javascript-proxy';

const conn = createConnection({
  host: 'homeassistant.local',
  token: 'YOUR_LONG_LIVED_ACCESS_TOKEN',
});
await conn.ready();

const light = await conn.getEntity('light.bedroom');
if (light) {
  console.log(light.state);                 // 'on' | 'off'
  console.log(light.attributes.brightness); // number | null | undefined
  await light.toggle();
}

[!TIP] Generate a long-lived access token in your HA profile under Security → Long-lived access tokens.


API Reference

createConnection(options)

Returns a Connection object synchronously. Call conn.ready() before accessing entities, services, or config.

const conn = createConnection({ host: 'homeassistant.local', token: '...' });
await conn.ready();

Options:

| Field | Type | Required | Description | |-------|------|----------|-------------| | host | string | ✓ | Hostname or full URL (http://... or https://...) | | token | string | ✓ | Long-lived access token | | port | number | — | Port override (default: 80/443 based on protocol) |


Connection

conn.ready(): Promise<void>

Resolves when the WebSocket handshake and HA config fetch complete. Must be awaited before using entities or services.

conn.isReady: boolean

Synchronous readiness check. true after conn.ready() resolves.

conn.config: HAConfig

The current HA configuration. Throws if called before conn.ready().

console.log(conn.config.version);      // '2024.3.0'
console.log(conn.config.locationName); // 'Home'
console.log(conn.config.timezone);     // 'Europe/Paris'

conn.socket

EventEmitter for raw connection lifecycle events.

conn.socket.on('ready', () => console.log('Connected'));
conn.socket.on('disconnected', () => console.log('Connection lost'));
conn.socket.on('reconnect-error', (code) => console.log('Reconnect failed:', code));

conn.homeassistant

EventEmitter + service proxy for the homeassistant domain.

conn.homeassistant.on('change', (state) => console.log('HA state:', state));
await conn.homeassistant.restart();
await conn.homeassistant.checkConfig();

Entities

conn.getEntity(entityId): Promise<EntityProxy | undefined>

Returns a typed, reactive entity proxy. Returns undefined if the entity does not exist.

All native HA domains are automatically covered — entity.state and entity.attributes are typed for each domain. Unrecognised domains fall back to entity.state: string.

const light = await conn.getEntity('light.bedroom');
if (light) {
  console.log(light.entityId);              // 'light.bedroom'
  console.log(light.state);                 // 'on' | 'off' | 'unavailable' | 'unknown'
  console.log(light.lastChanged);           // Date
  console.log(light.lastUpdated);           // Date
  console.log(light.attributes.brightness); // number | null | undefined
}

Common attributes (available on every entity regardless of domain):

| Attribute | Type | Description | |-----------|------|-------------| | friendlyName | string \| undefined | Display name from HA | | icon | string \| undefined | MDI icon (mdi:lightbulb) | | unitOfMeasurement | string \| undefined | Unit (e.g. °C, %) | | deviceClass | string \| undefined | Device class (e.g. motion, temperature) | | entityPicture | string \| undefined | Entity picture URL |

Entity events:

light.on('change', (newState, oldState) => {
  console.log(`Light changed from ${oldState} to ${newState}`);
});
light.on('update', () => {
  // Fires on any state or attribute change
});

Calling services:

// camelCase proxy — snake_case HA actions mapped automatically:
await light.turnOn({ brightness: 128 });
await light.toggle();

// Explicit callService — action without domain prefix:
await light.callService('turn_on', { brightness: 128 });

Feature support:

entity.supportsFeature(feature) tests whether the entity's supported_features bitmask includes a given capability.

import { LightFeatures } from 'ha-javascript-proxy';

if (light.supportsFeature(LightFeatures.EFFECT)) {
  await light.setEffect('rainbow');
}

Feature constant objects are exported per domain: LightFeatures, CoverFeatures, FanFeatures, and more. Entities whose domain defines no Feature constants return true from supportsFeature() (permissive fallback).

State constants:

import { State } from 'ha-javascript-proxy';

if (light.state === State.ON) { /* ... */ }
if (sensor.state === State.UNAVAILABLE) { /* ... */ }

State mirrors homeassistant/const.py — use State.ON, State.OFF, State.UNAVAILABLE, State.UNKNOWN, State.PLAYING, etc.


Services

conn.callService(name, params?, target?): Promise<unknown>

Calls any HA service directly. Service name format: 'domain.service'.

await conn.callService('light.turn_on', { brightness_pct: 50 }, { entity_id: 'light.bedroom' });
await conn.callService('homeassistant.restart');

Registry

conn.registry

Access HA registry data. All methods return Promise and require conn.ready().

| Method | Returns | |--------|---------| | conn.registry.getAreas() | Promise<AreaRegistryEntry[]> | | conn.registry.getDevices() | Promise<DeviceRegistryEntry[]> | | conn.registry.getEntityRegistry() | Promise<EntityRegistryEntry[]> | | conn.registry.getFloorRegistry() | Promise<FloorRegistryEntry[]> | | conn.registry.getLabelRegistry() | Promise<LabelRegistryEntry[]> |

const areas = await conn.registry.getAreas();
// [{ areaId: 'living_room', name: 'Living Room', aliases: [], ... }]

[!NOTE] getFloorRegistry() and getLabelRegistry() require HA 2024.4+. They return [] on older instances.


Events Reference

Entity events

const light = await conn.getEntity('light.bedroom');

light?.on('change', (newState, oldState) => {
  console.log(`State: ${oldState} → ${newState}`);
});

light?.on('update', () => {
  // Fires on any change — state or attributes
  console.log('Attributes updated:', light.attributes);
});

Socket events

conn.socket.on('ready', () => {
  console.log('WebSocket connected');
});

conn.socket.on('disconnected', () => {
  console.log('WebSocket disconnected');
});

conn.socket.on('reconnect-error', (code) => {
  console.log('Reconnect failed with code:', code);
});

Homeassistant events

conn.homeassistant.on('change', (state, oldState) => {
  console.log(`HA state: ${oldState} → ${state}`);
  // state: 'RUNNING' | 'NOT_RUNNING' | 'STARTING' | 'STOPPING' | 'FINAL_WRITE'
});

conn.homeassistant.on('update', () => {
  // Fires on any config update (component loaded, core_config_updated)
});

License

MIT