13 KiB
Home Assistant Node.js API Reference
This document provides guidance on using the Home Assistant WebSocket API with Node.js using the home-assistant-js-websocket library.
RECOMMENDED APPROACH: For monitoring entity states, always prefer using subscribeEntities from home-assistant-js-websocket instead of manually subscribing to state_changed events. See Subscribe to All Entity State Changes.
Installation
For Node.js 22+, you only need to install the library (built-in WebSocket support):
npm install home-assistant-js-websocket
For older Node.js versions (< 22), also install the ws package:
npm install home-assistant-js-websocket ws
Authentication with Long-Lived Access Token
import {
createConnection,
createLongLivedTokenAuth,
subscribeEntities,
callService,
} from "home-assistant-js-websocket";
const auth = createLongLivedTokenAuth(
"http://homeassistant.local:8123",
"YOUR_LONG_LIVED_ACCESS_TOKEN"
);
const connection = await createConnection({ auth });
console.log("Connected to Home Assistant!");
Connection Validation
Get Home Assistant Configuration and Version
After connecting, you can retrieve configuration information including the Home Assistant version:
import { getConfig } from "home-assistant-js-websocket";
const config = await getConfig(connection);
console.log(`Home Assistant Version: ${config.version}`);
console.log(`Location: ${config.location_name}`);
console.log(`Time Zone: ${config.time_zone}`);
console.log(`Components loaded: ${config.components.length}`);
The config object contains:
version: Home Assistant version (e.g., "2024.1.0")location_name: Name of the instancetime_zone: Configured time zoneunit_system: Units for measurements (length, mass, temperature, volume)components: Array of all loaded integrationslatitude,longitude,elevation: Location data
Getting Entity States
Subscribe to All Entity State Changes
PREFERRED METHOD: Use subscribeEntities for real-time entity state monitoring.
Function Signature:
export const subscribeEntities = (
conn: Connection,
onChange: (state: HassEntities) => void,
): UnsubscribeFunc => entitiesColl(conn).subscribe(onChange);
Why use subscribeEntities:
- Automatically maintains a complete, up-to-date map of all entities
- More efficient than manually tracking state_changed events
- Handles entity additions, deletions, and updates automatically
- Provides clean HassEntities object indexed by entity_id
Example:
import { subscribeEntities } from "home-assistant-js-websocket";
const unsubscribe = subscribeEntities(connection, (entities) => {
// Called whenever any entity state changes
// 'entities' is a complete map of all entity states
console.log("Entities updated:", entities);
// Access specific entity by ID
const light = entities["light.living_room"];
if (light) {
console.log(`Light state: ${light.state}`);
console.log(`Brightness: ${light.attributes.brightness}`);
}
// Monitor multiple entities
const temp = entities["sensor.temperature"];
const humidity = entities["sensor.humidity"];
if (temp && humidity) {
console.log(`Temp: ${temp.state}°C, Humidity: ${humidity.state}%`);
}
});
// To stop receiving updates
// unsubscribe();
Get Current States Once
import { getStates } from "home-assistant-js-websocket";
const states = await getStates(connection);
for (const state of states) {
console.log(`${state.entity_id}: ${state.state}`);
}
Get Specific Entity State
import { getStates } from "home-assistant-js-websocket";
const states = await getStates(connection);
const light = states.find(s => s.entity_id === "light.living_room");
if (light) {
console.log(`State: ${light.state}`);
console.log(`Attributes:`, light.attributes);
}
Calling Services
Turn on a Light
await callService(connection, "light", "turn_on", {
entity_id: "light.living_room",
brightness: 255,
rgb_color: [255, 0, 0], // Red
});
Turn off a Switch
await callService(connection, "switch", "turn_off", {
entity_id: "switch.bedroom_fan",
});
Set Thermostat Temperature
await callService(connection, "climate", "set_temperature", {
entity_id: "climate.living_room",
temperature: 22,
});
Send Notification
await callService(connection, "notify", "notify", {
message: "Hello from Node.js!",
title: "Notification Title",
});
Common Service Patterns
// Light control
await callService(connection, "light", "turn_on", {
entity_id: "light.bedroom",
brightness_pct: 50,
});
// Switch control
await callService(connection, "switch", "toggle", {
entity_id: "switch.living_room_lamp",
});
// Cover control
await callService(connection, "cover", "open_cover", {
entity_id: "cover.garage_door",
});
// Media player control
await callService(connection, "media_player", "play_media", {
entity_id: "media_player.living_room",
media_content_id: "https://example.com/song.mp3",
media_content_type: "music",
});
Automation Engine Commands (RECOMMENDED)
IMPORTANT: These commands form the core of how you should interact with Home Assistant. They leverage the automation engine and keep your code minimal by using native Home Assistant syntax.
subscribe_trigger - Listen for Specific Events
PREFERRED METHOD for listening to specific state changes, time patterns, webhooks, etc.
// Subscribe to a state trigger
const unsubscribe = await connection.subscribeMessage(
(message) => {
console.log("Trigger fired!", message);
console.log("Variables:", message.variables);
},
{
type: "subscribe_trigger",
trigger: {
platform: "state",
entity_id: "binary_sensor.motion_sensor",
to: "on"
},
variables: {
custom_var: "value"
}
}
);
// Unsubscribe when done
// unsubscribe();
More trigger examples:
// Time pattern trigger
await connection.subscribeMessage(
(message) => console.log("Every 5 minutes!", message),
{
type: "subscribe_trigger",
trigger: {
platform: "time_pattern",
minutes: "/5"
}
}
);
// Numeric state trigger
await connection.subscribeMessage(
(message) => console.log("Temperature above 25°C!", message),
{
type: "subscribe_trigger",
trigger: {
platform: "numeric_state",
entity_id: "sensor.temperature",
above: 25
}
}
);
// Template trigger
await connection.subscribeMessage(
(message) => console.log("Sun is up!", message),
{
type: "subscribe_trigger",
trigger: {
platform: "template",
value_template: "{{ states('sun.sun') == 'above_horizon' }}"
}
}
);
test_condition - Test Conditions Server-Side
Test conditions without implementing logic in your code:
// Test a numeric state condition
const result = await connection.sendMessagePromise({
type: "test_condition",
condition: {
condition: "numeric_state",
entity_id: "sensor.temperature",
above: 20
}
});
if (result.result) {
console.log("Temperature is above 20°C");
}
More condition examples:
// State condition
const result = await connection.sendMessagePromise({
type: "test_condition",
condition: {
condition: "state",
entity_id: "light.living_room",
state: "on"
}
});
// Time condition
const result = await connection.sendMessagePromise({
type: "test_condition",
condition: {
condition: "time",
after: "18:00:00",
before: "23:00:00"
}
});
// Template condition
const result = await connection.sendMessagePromise({
type: "test_condition",
condition: {
condition: "template",
value_template: "{{ is_state('sun.sun', 'above_horizon') }}"
}
});
// And/Or conditions
const result = await connection.sendMessagePromise({
type: "test_condition",
condition: {
condition: "and",
conditions: [
{
condition: "state",
entity_id: "binary_sensor.motion",
state: "on"
},
{
condition: "numeric_state",
entity_id: "sensor.light_level",
below: 100
}
]
}
});
execute_script - Execute Multiple Actions
MOST POWERFUL METHOD: Execute sequences of actions using Home Assistant's native syntax.
// Simple sequence
const result = await connection.sendMessagePromise({
type: "execute_script",
sequence: [
{
service: "light.turn_on",
target: { entity_id: "light.living_room" },
data: { brightness: 255 }
},
{
delay: { seconds: 5 }
},
{
service: "light.turn_off",
target: { entity_id: "light.living_room" }
}
]
});
Advanced: Using wait_for_trigger
// Turn on light and wait for motion to stop
const result = await connection.sendMessagePromise({
type: "execute_script",
sequence: [
{
service: "light.turn_on",
target: { entity_id: "light.living_room" }
},
{
wait_for_trigger: [
{
platform: "state",
entity_id: "binary_sensor.motion",
to: "off",
for: { minutes: 5 }
}
],
timeout: { hours: 2 }
},
{
service: "light.turn_off",
target: { entity_id: "light.living_room" }
}
]
});
Getting response data from service calls:
// Call a service and get the response
const result = await connection.sendMessagePromise({
type: "execute_script",
sequence: [
{
service: "weather.get_forecasts",
target: { entity_id: "weather.home" },
data: { type: "daily" },
response_variable: "weather_data"
},
{
stop: "Done",
response_variable: "weather_data"
}
]
});
console.log("Weather forecast:", result.response_variable);
Complex automation example:
// Full automation logic in execute_script
const result = await connection.sendMessagePromise({
type: "execute_script",
sequence: [
// Check if it's dark
{
condition: "numeric_state",
entity_id: "sensor.light_level",
below: 100
},
// Turn on lights
{
service: "light.turn_on",
target: { area_id: "living_room" },
data: { brightness_pct: 50 }
},
// Wait for motion to stop for 10 minutes
{
wait_for_trigger: [
{
platform: "state",
entity_id: "binary_sensor.motion",
to: "off",
for: { minutes: 10 }
}
],
timeout: { hours: 4 }
},
// Turn off lights
{
service: "light.turn_off",
target: { area_id: "living_room" }
}
]
});
Error Handling
import {
createConnection,
createLongLivedTokenAuth,
ERR_INVALID_AUTH,
ERR_CONNECTION_LOST,
} from "home-assistant-js-websocket";
try {
const auth = createLongLivedTokenAuth(url, token);
const connection = await createConnection({ auth });
console.log("Connected successfully!");
} catch (err) {
if (err === ERR_INVALID_AUTH) {
console.error("Invalid authentication - check your token");
} else if (err === ERR_CONNECTION_LOST) {
console.error("Connection lost - check your URL and network");
} else {
console.error("Connection failed:", err);
}
}
Complete Example
import {
createConnection,
createLongLivedTokenAuth,
getConfig,
subscribeEntities,
callService,
} from "home-assistant-js-websocket";
async function main() {
// Connect
const auth = createLongLivedTokenAuth(
"http://homeassistant.local:8123",
"YOUR_TOKEN"
);
const connection = await createConnection({ auth });
console.log("✓ Connected to Home Assistant");
// Get configuration and version
const config = await getConfig(connection);
console.log(`✓ Home Assistant ${config.version}`);
console.log(` Location: ${config.location_name}`);
// Subscribe to entity changes
subscribeEntities(connection, (entities) => {
const temp = entities["sensor.living_room_temperature"];
if (temp) {
console.log(`Temperature: ${temp.state}°C`);
// Auto-control based on temperature
if (parseFloat(temp.state) > 25) {
callService(connection, "switch", "turn_on", {
entity_id: "switch.fan",
});
}
}
});
// Call a service
await callService(connection, "light", "turn_on", {
entity_id: "light.living_room",
});
console.log("✓ Light turned on");
}
main().catch(console.error);
Using with Node.js < 22
For older Node.js versions, configure the WebSocket implementation:
import ws from "ws";
const connection = await createConnection({
auth,
createSocket: (auth) => {
return new ws(auth.wsUrl, {
rejectUnauthorized: false, // Only for self-signed certs
});
},
});
Official Documentation
For complete library documentation, see: