Integration SDK API
Types exported by @novon/integration-sdk and the community constants.
DeviceDescriptor
Definition
interface DeviceDescriptor {
/** Stable per-device id (serial, MAC). Entities sharing it group under one device. */
uniqueId?: string;
manufacturer?: string;
model?: string;
name?: string;
swVersion?: string;
hwVersion?: string;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
uniqueId | string | yes | Stable per-device id (serial, MAC). Entities sharing it group under one device. |
manufacturer | string | yes | — |
model | string | yes | — |
name | string | yes | — |
swVersion | string | yes | — |
hwVersion | string | yes | — |
libs/integration-sdk/src/index.ts:46
EntityDescriptor
Per-platform attribute conventions the hub maps onto the real entity: sensor state: number|string; attributes.unitOfMeasurement, stateClass, batteryLevel, isLow binary_sensor state: 'on'|'off'|boolean; attributes.batteryLevel, isLow switch state: 'on'|'off'|boolean light state: 'on'|'off'|boolean; attributes.brightnessPercent, colorMode, kelvin, rgbColor, supportedColorModes, minColorTempKelvin, maxColorTempKelvin cover state: 'open'|'closed'|'opening'|'closing'; attributes.currentPosition, currentTiltPosition lock state: 'locked'|'unlocked'|boolean; attributes.batteryLevel, isLow select state: current option; attributes.options: string[] Any other primitive attribute is passed through as an extra attribute.
Definition
interface EntityDescriptor {
/** Stable id within this integration (never changes for the same physical thing). */
uniqueId: string;
platform: Platform;
name: string;
deviceClass?: string | null;
/** Platform feature bitmask (e.g. cover SET_POSITION). Omit for the default. */
supportedFeatures?: number;
state?: EntityState;
attributes?: Record<string, unknown>;
available?: boolean;
entityCategory?: 'config' | 'diagnostic' | null;
device?: DeviceDescriptor;
/**
* Handle a service call aimed at THIS entity (turnOn, setCoverPosition,
* selectOption, …). Falls back to the integration's `handleService`.
*/
onService?: (service: string, data: Record<string, unknown>, ctx: NovonSdk) => void | Promise<void>;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
uniqueId | string | no | Stable id within this integration (never changes for the same physical thing). |
platform | Platform | no | — |
name | string | no | — |
deviceClass | string | null | yes | — |
supportedFeatures | number | yes | Platform feature bitmask (e.g. cover SET_POSITION). Omit for the default. |
state | EntityState | yes | — |
attributes | Record<string, unknown> | yes | — |
available | boolean | yes | — |
entityCategory | 'config' | 'diagnostic' | null | yes | — |
device | DeviceDescriptor | yes | — |
onService | (service: string, data: Record<string, unknown>, ctx: NovonSdk) => void | Promise<void> | yes | Handle a service call aimed at THIS entity (turnOn, setCoverPosition, selectOption, …). Falls back to the integration's handleService. |
libs/integration-sdk/src/index.ts:68
EntityUpdate
Definition
interface EntityUpdate {
state?: EntityState;
attributes?: Record<string, unknown>;
available?: boolean;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
state | EntityState | yes | — |
attributes | Record<string, unknown> | yes | — |
available | boolean | yes | — |
libs/integration-sdk/src/index.ts:88
HttpRequestOptions
----- the novon global ---------------------------------------------------------
Definition
interface HttpRequestOptions {
url?: string;
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD';
headers?: Record<string, string>;
/** A string is sent as-is; an object is JSON-encoded with a JSON content-type. */
body?: string | Record<string, unknown> | unknown[];
/** Capped by the hub (30 s). Default 15 s. */
timeoutMs?: number;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
url | string | yes | — |
method | 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | yes | — |
headers | Record<string, string> | yes | — |
body | string | Record<string, unknown> | unknown[] | yes | A string is sent as-is; an object is JSON-encoded with a JSON content-type. |
timeoutMs | number | yes | Capped by the hub (30 s). Default 15 s. |
libs/integration-sdk/src/index.ts:96
HttpResponse
Definition
interface HttpResponse {
ok: boolean;
status: number;
headers: Record<string, string>;
body: string;
text(): string;
json<T = unknown>(): T;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
ok | boolean | no | — |
status | number | no | — |
headers | Record<string, string> | no | — |
body | string | no | — |
text() | text(): string; | no | — |
json() | json<T = unknown>(): T; | no | — |
libs/integration-sdk/src/index.ts:106
EntryContext
Definition
interface EntryContext {
entryId: string;
title: string;
domain: string;
version: string;
/** Values of config-flow inputs scoped `data` (identity: host, credentials). */
data: Record<string, unknown>;
/** Values of inputs scoped `options` (tunables; editable after install). */
options: Record<string, unknown>;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
entryId | string | no | — |
title | string | no | — |
domain | string | no | — |
version | string | no | — |
data | Record<string, unknown> | no | Values of config-flow inputs scoped data (identity: host, credentials). |
options | Record<string, unknown> | no | Values of inputs scoped options (tunables; editable after install). |
libs/integration-sdk/src/index.ts:115
ServiceCallInfo
Definition
interface ServiceCallInfo {
uniqueId: string;
platform?: Platform;
service: string;
data: Record<string, unknown>;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
uniqueId | string | no | — |
platform | Platform | yes | — |
service | string | no | — |
data | Record<string, unknown> | no | — |
libs/integration-sdk/src/index.ts:126
IntegrationDefinition
Definition
interface IntegrationDefinition {
/**
* Called once per config entry when it loads (boot, install, reload).
* Connect to the device, register entities with `ctx.entities.add`, start
* polling with `setInterval`. Throw `ctx.notReady('...')` to have the hub
* retry later with backoff; any other throw marks the entry FAILED.
*/
setupEntry(ctx: NovonSdk): void | Promise<void>;
/** Called before the entry unloads. Timers are cleared for you. */
unloadEntry?(ctx: NovonSdk): void | Promise<void>;
/** Service call for an entity that has no `onService` of its own. */
handleService?(call: ServiceCallInfo, ctx: NovonSdk): void | Promise<void>;
/**
* The user changed the entry's options. Return normally to keep running with
* `ctx.entry` already updated. When absent, the hub RELOADS the entry.
*/
optionsUpdated?(ctx: NovonSdk, previous: { data: Record<string, unknown>; options: Record<string, unknown> }): void | Promise<void>;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
setupEntry() | setupEntry(ctx: NovonSdk): void | Promise<void>; | no | Called once per config entry when it loads (boot, install, reload). Connect to the device, register entities with ctx.entities.add, start polling with setInterval. Throw ctx.notReady('...') to have the hub retry later with backoff; any other throw marks the entry FAILED. |
unloadEntry() | unloadEntry?(ctx: NovonSdk): void | Promise<void>; | yes | Called before the entry unloads. Timers are cleared for you. |
handleService() | handleService?(call: ServiceCallInfo, ctx: NovonSdk): void | Promise<void>; | yes | Service call for an entity that has no onService of its own. |
optionsUpdated() | optionsUpdated?(ctx: NovonSdk, previous: { data: Record<string, unknown>; options: Record<string, unknown> }): void | Promise<void>; | yes | The user changed the entry's options. Return normally to keep running with ctx.entry already updated. When absent, the hub RELOADS the entry. |
libs/integration-sdk/src/index.ts:133
NovonSdk
Definition
interface NovonSdk {
defineIntegration(definition: IntegrationDefinition): IntegrationDefinition;
/** The config entry this isolate serves (set before `setupEntry`). */
readonly entry: EntryContext;
entities: {
add(descriptors: EntityDescriptor | EntityDescriptor[]): Promise<void>;
update(uniqueId: string, patch: EntityUpdate): void;
remove(uniqueId: string): Promise<void>;
list(): string[];
};
/** Outbound HTTP(S). Requires the `http` permission. Loopback / link-local are refused. */
http(url: string, init?: Omit<HttpRequestOptions, 'url'>): Promise<HttpResponse>;
http(options: HttpRequestOptions): Promise<HttpResponse>;
/** Persistent per-entry key/value storage (JSON values ≤ 64 KiB). Requires `kv`. */
kv: {
get<T = unknown>(key: string): T | undefined | null;
set(key: string, value: unknown): void;
delete(key: string): void;
};
/** Build the error that makes the hub retry setup later (device offline, …). */
notReady(message?: string): Error;
sleep(ms: number): Promise<void>;
}Members
| Name | Type | Optional | Description |
|---|---|---|---|
entry | EntryContext | no | The config entry this isolate serves (set before setupEntry). |
entities | { add(descriptors: EntityDescriptor | EntityDescriptor[]): Promise<void>; update(uniqueId: string, patch: EntityUpdate): void; remove(uniqueId: string): Promise<void>; list(): string[]; } | no | — |
kv | { get<T = unknown>(key: string): T | undefined | null; set(key: string, value: unknown): void; delete(key: string): void; } | no | Persistent per-entry key/value storage (JSON values ≤ 64 KiB). Requires kv. |
defineIntegration() | defineIntegration(definition: IntegrationDefinition): IntegrationDefinition; | no | — |
http() | http(url: string, init?: Omit<HttpRequestOptions, 'url'>): Promise<HttpResponse>; | no | Outbound HTTP(S). Requires the http permission. Loopback / link-local are refused. |
http() | http(options: HttpRequestOptions): Promise<HttpResponse>; | no | — |
notReady() | notReady(message?: string): Error; | no | Build the error that makes the hub retry setup later (device offline, …). |
sleep() | sleep(ms: number): Promise<void>; | no | — |
libs/integration-sdk/src/index.ts:152
Platform
Entity platforms a community integration can host, as string literals.
Definition
type Platform = 'sensor' | 'binary_sensor' | 'switch' | 'light' | 'cover' | 'lock' | 'select';libs/integration-sdk/src/index.ts:42
EntityState
Definition
type EntityState = string | number | boolean | null;libs/integration-sdk/src/index.ts:44
Ambient globals
Inside the hub's isolate these names exist without an import:
// Ambient declarations for code that runs INSIDE the hub's isolate.
//
// Reference this file from an integration's tsconfig ("types" or a
// `/// <reference types="@novon/integration-sdk/globals" />` line) so `novon`,
// `console` and the timers type-check without importing anything — the
// bundle must not import at runtime; the hub injects these globals.
import type { NovonSdk } from './index';
declare global {
const novon: NovonSdk;
function setTimeout(handler: (...args: unknown[]) => void, timeoutMs?: number, ...args: unknown[]): number;
function setInterval(handler: (...args: unknown[]) => void, intervalMs?: number, ...args: unknown[]): number;
function clearTimeout(id: number | undefined): void;
function clearInterval(id: number | undefined): void;
const console: {
log(...args: unknown[]): void;
info(...args: unknown[]): void;
warn(...args: unknown[]): void;
error(...args: unknown[]): void;
debug(...args: unknown[]): void;
};
}
export {};Constants
| Constant | Value |
|---|---|
supportedPlatforms | sensor, binary_sensor, switch, light, cover, lock, select |
permissions | http, kv, timers |
formInputTypes | string, password, text, email, number, boolean, enum, time, entity |
iotClasses | LocalPush, LocalPoll, CloudPoll, CloudPush |
bundleMaxBytes | 2097152 |
domainRegex | ^x_[a-z0-9]+(?:_[a-z0-9]+)*$ |
domainMaxLength | 64 |