@nebulahome/package-sdk 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +34 -9
- package/dist/chunks/context.d.ts +46 -1
- package/dist/chunks/history.d.ts +39 -0
- package/dist/chunks/json.d.ts +1 -1
- package/dist/chunks/node-build.js +2 -2
- package/dist/chunks/node-config.js +38 -36
- package/dist/chunks/node-pack.js +1 -1
- package/dist/chunks/version.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/server.d.ts +3 -2
- package/dist/styles.css +12 -0
- package/dist/sun.d.ts +62 -0
- package/dist/sun.js +328 -0
- package/dist/testing.d.ts +16 -1
- package/dist/testing.js +79 -0
- package/dist/ui.d.ts +123 -2
- package/dist/ui.js +42 -1
- package/package.json +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
The SDK's version is the version of the package API the platform implements: a minor version adds
|
|
4
4
|
to it, a major one breaks it, and a patch leaves it as it is.
|
|
5
5
|
|
|
6
|
+
## 1.2.0
|
|
7
|
+
|
|
8
|
+
- **The past of the house.** `ctx.history.states()` and `ctx.history.telemetry()` on the server
|
|
9
|
+
read the recorded changes and the numeric readings of up to 64 entities over a window, with the
|
|
10
|
+
house's authority as `ctx.entities` has; `useStateHistory()` and `useTelemetry()` in
|
|
11
|
+
`@nebulahome/package-sdk/ui` read them with the viewer's, for a chart, an activity list or a
|
|
12
|
+
replay. Each entity's points come oldest first; a window that holds more than a read returns
|
|
13
|
+
loses its oldest points and names the entity in `truncated`. A window is two moments, or in the
|
|
14
|
+
interface the last so many milliseconds, which moves with each read; telemetry is read raw, or
|
|
15
|
+
in buckets of a minute, an hour or a day, `auto` picking by the window's length.
|
|
16
|
+
`createTestContext({ history })` and `test.setHistory()` give a unit test a past.
|
|
17
|
+
- **The areas.** `useAreas()` lists the house, its floors (with their storey) and its rooms, each
|
|
18
|
+
naming its parent by key - the key `EntityView.areaId` holds - and the house its position.
|
|
19
|
+
- **What an entity can do.** `EntityView.capabilities` holds the capabilities an entity declares,
|
|
20
|
+
with the device's limits: a cover's tilt, a thermostat's range and modes, a select's options.
|
|
21
|
+
- **Pictures.** `useEntityPicture()` gives a camera's latest still, fetched again every so often,
|
|
22
|
+
or an image entity's picture, as an address an `<img>` shows.
|
|
23
|
+
- **The sun.** `@nebulahome/package-sdk/sun`: `sunPosition`, `sunTimes`, `sunState` and
|
|
24
|
+
`sunPhaseLabel`, the platform's own formulas, for a moment the sun entities did not report.
|
|
25
|
+
- A package's id may start with a digit (`3d-home`); its entities' object ids then do too.
|
|
26
|
+
- **The MQTT broker is the platform's.** The hub runs the house's broker: `requires.services:
|
|
27
|
+
["mqtt-broker"]` is always met, `{platform.mqtt.*}` and `NEBULA_PLATFORM_MQTT_*` name it, and a
|
|
28
|
+
package that `provides` `mqtt-broker` is refused at install.
|
|
29
|
+
|
|
6
30
|
## 1.1.0
|
|
7
31
|
|
|
8
32
|
- `useTranslation()` in `@nebulahome/package-sdk/ui`: a package's page, cards and entity views
|
package/README.md
CHANGED
|
@@ -116,17 +116,42 @@ A string a catalogue lacks is said in English, and `nebulahome-package build` li
|
|
|
116
116
|
`nebula.config.ts` declares (the package's name, its cards' and settings' names, its entity types)
|
|
117
117
|
stays English: the platform shows it the same way to everyone.
|
|
118
118
|
|
|
119
|
+
## The past, the areas and the sun
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// a sensor's chart: the last 6 hours, in minutes
|
|
123
|
+
const day = useTelemetry({ entityIds: [entityId], window: { lastMs: 6 * 3_600_000 } });
|
|
124
|
+
const points = day.series[entityId] ?? []; // oldest first: { time, value, min, max }
|
|
125
|
+
|
|
126
|
+
// what a door did today, and the rooms of the house
|
|
127
|
+
const today = useStateHistory({ entityIds: [door], window: { from: midnight, to: now } });
|
|
128
|
+
const rooms = useAreas().filter((area) => area.kind === 'room');
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// on the server, with the house's authority
|
|
133
|
+
const { series } = await ctx.history.states({ entityIds, from: yesterday, to: new Date() });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
// where the sun was, for a moment the sun entities did not report
|
|
138
|
+
import { sunPosition } from '@nebulahome/package-sdk/sun';
|
|
139
|
+
|
|
140
|
+
const { elevation, azimuth } = sunPosition(at, { latitude, longitude });
|
|
141
|
+
```
|
|
142
|
+
|
|
119
143
|
## Entry points
|
|
120
144
|
|
|
121
|
-
| Import | What
|
|
122
|
-
| ------------------------- |
|
|
123
|
-
| `@nebulahome/package-sdk` | `definePackage`, `defineSettings`, `defineCard`, `defineEntityType`, `definePage`, `defineContainer`, `defineCompose`, `field`, entity id helpers, `SDK_VERSION`, the value types.
|
|
124
|
-
| `/server` | `defineServer`, and the context `start` is given: settings (live or restart), devices and entities, typed custom entities, the rest of the house, methods for the interface, services between packages.
|
|
125
|
-
| `/ui` | The props of a page, a card and an entity view; hooks for the package, its methods, its settings, the house, the viewer, the theme, its strings; navigation inside the package's page and the platform's. |
|
|
126
|
-
| `/
|
|
127
|
-
| `/
|
|
128
|
-
| `/
|
|
129
|
-
| `/
|
|
145
|
+
| Import | What |
|
|
146
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
147
|
+
| `@nebulahome/package-sdk` | `definePackage`, `defineSettings`, `defineCard`, `defineEntityType`, `definePage`, `defineContainer`, `defineCompose`, `field`, entity id helpers, `SDK_VERSION`, the value types. |
|
|
148
|
+
| `/server` | `defineServer`, and the context `start` is given: settings (live or restart), devices and entities, typed custom entities, the rest of the house and its past, methods for the interface, services between packages. |
|
|
149
|
+
| `/ui` | The props of a page, a card and an entity view; hooks for the package, its methods, its settings, the house, its areas, its past and its pictures, the viewer, the theme, its strings; navigation inside the package's page and the platform's. |
|
|
150
|
+
| `/sun` | Where the sun is at any moment, by the platform's own formulas. |
|
|
151
|
+
| `/components` | The part of the interface's design system a package may draw with. |
|
|
152
|
+
| `/vite` | `nebula()`, the Vite plugin that builds both halves: the interface in chunks with its CSS scoped to the package, the server bundled whole. |
|
|
153
|
+
| `/testing` | `createTestContext()`: run `start` in a unit test, every effect recorded. |
|
|
154
|
+
| `/styles.css` | The interface's Tailwind tokens, to `@reference`. |
|
|
130
155
|
|
|
131
156
|
The `nebulahome-package` command checks, builds and packs a package:
|
|
132
157
|
|
package/dist/chunks/context.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { G as CapabilityState, V as CapabilityCommand, X as EntityStateClass, Y as DeclaredCapabilities, a as SettingsOf, ct as EntityDomain, d as EntityTypeDefinition, et as ReportedCapabilityState, f as ValuesOf, i as SettingsDefinition, lt as EntityId, r as JsonValue, s as ArgsOf, t as JsonObject, u as CommandsOf } from "./json.js";
|
|
2
|
+
import { a as TelemetryResolution, i as TelemetryPoint, n as HistorySeries, r as StateHistoryPoint } from "./history.js";
|
|
2
3
|
//#region src/schema.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* What checks a value that crosses into a package - a method's input, a service's answer: any
|
|
@@ -163,6 +164,28 @@ type EntityFilter = {
|
|
|
163
164
|
readonly domain?: EntityDomain;
|
|
164
165
|
readonly entityIds?: readonly EntityId[];
|
|
165
166
|
};
|
|
167
|
+
/** Which entities' past `ctx.history` reads, over which window. Since 1.2. */
|
|
168
|
+
type HistoryRead = {
|
|
169
|
+
/** At most 64. */
|
|
170
|
+
readonly entityIds: readonly EntityId[];
|
|
171
|
+
/** Inclusive: a `Date` or ISO 8601. */
|
|
172
|
+
readonly from: Date | string;
|
|
173
|
+
/** Exclusive. */
|
|
174
|
+
readonly to: Date | string;
|
|
175
|
+
/** The most points of one entity, at most 10 000 (the default): the newest are kept. */
|
|
176
|
+
readonly limit?: number;
|
|
177
|
+
};
|
|
178
|
+
/** Which entities' readings `ctx.history.telemetry` reads: `auto` picks by the window's length. */
|
|
179
|
+
type TelemetryRead = HistoryRead & {
|
|
180
|
+
readonly resolution?: TelemetryResolution | 'auto';
|
|
181
|
+
};
|
|
182
|
+
/** What a read of the past found. */
|
|
183
|
+
type HistoryAnswer<TPoint> = {
|
|
184
|
+
/** Each entity's points, oldest first. */
|
|
185
|
+
readonly series: HistorySeries<TPoint>;
|
|
186
|
+
/** The entities whose window held more than the limit: their oldest points are gone. */
|
|
187
|
+
readonly truncated: readonly EntityId[];
|
|
188
|
+
};
|
|
166
189
|
/** Who may call a method: whoever may read packages, or whoever may configure them. */
|
|
167
190
|
type RpcAccess = 'read' | 'configure';
|
|
168
191
|
/** Who called a method of the package's interface. */
|
|
@@ -354,6 +377,28 @@ type ServerContext<TSettings = undefined> = {
|
|
|
354
377
|
*/
|
|
355
378
|
readonly subscribe: (filter: EntityFilter, handler: (change: StateChange) => Awaitable<void>) => Unsubscribe;
|
|
356
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* The past of the house's entities, read only, with the house's authority as `entities` has.
|
|
382
|
+
* Since 1.2.
|
|
383
|
+
*/
|
|
384
|
+
readonly history: {
|
|
385
|
+
/**
|
|
386
|
+
* The recorded changes of some entities over a window.
|
|
387
|
+
*
|
|
388
|
+
* @param read - Which entities, which window, how many points each at most.
|
|
389
|
+
* @returns Each entity's changes, oldest first.
|
|
390
|
+
*/
|
|
391
|
+
readonly states: (read: HistoryRead) => Promise<HistoryAnswer<StateHistoryPoint>>;
|
|
392
|
+
/**
|
|
393
|
+
* The numeric readings of some entities over a window, raw or in buckets.
|
|
394
|
+
*
|
|
395
|
+
* @param read - Which entities, which window, which resolution.
|
|
396
|
+
* @returns Each entity's readings, oldest first, and the resolution read.
|
|
397
|
+
*/
|
|
398
|
+
readonly telemetry: (read: TelemetryRead) => Promise<HistoryAnswer<TelemetryPoint> & {
|
|
399
|
+
readonly resolution: TelemetryResolution;
|
|
400
|
+
}>;
|
|
401
|
+
};
|
|
357
402
|
readonly rpc: {
|
|
358
403
|
/** Registers a method its interface calls; a name registered twice throws. */
|
|
359
404
|
readonly method: RpcMethod;
|
|
@@ -366,4 +411,4 @@ type ServerContext<TSettings = undefined> = {
|
|
|
366
411
|
};
|
|
367
412
|
};
|
|
368
413
|
//#endregion
|
|
369
|
-
export {
|
|
414
|
+
export { Schema as A, ServiceProvide as C, TelemetryRead as D, SyncResult as E, StandardResult as M, StandardSchemaV1 as N, Unsubscribe as O, ServiceCallFunction as S, StateChange as T, RpcCaller as _, CustomEntityInput as a, ServerSettings as b, EntityInput as c, HistoryRead as d, LogMethod as f, RpcCall as g, RpcAccess as h, CustomEntities as i, SchemaIssue as j, SafeParser as k, EntitySnapshot as l, ReportOptions as m, CapabilityEntityInput as n, DeviceInput as o, Logger as p, CustomCommand as r, EntityFilter as s, Awaitable as t, HistoryAnswer as u, RpcMethod as v, SettingsChange as w, ServiceCall as x, ServerContext as y };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { G as CapabilityState, lt as EntityId, t as JsonObject } from "./json.js";
|
|
2
|
+
//#region src/history.d.ts
|
|
3
|
+
/** How finely readings are read: every one, or a bucket of a minute, an hour or a day. */
|
|
4
|
+
type TelemetryResolution = 'raw' | '1m' | '1h' | '1d';
|
|
5
|
+
/** What caused a change, when the platform knows it. */
|
|
6
|
+
type ChangeCause = {
|
|
7
|
+
readonly type: 'automation' | 'scene' | 'user' | 'device' | 'alias' | 'startup';
|
|
8
|
+
/** Which run, scene or person; absent for a device and at startup. */
|
|
9
|
+
readonly id?: string;
|
|
10
|
+
};
|
|
11
|
+
/** One change of an entity's state. */
|
|
12
|
+
type StateHistoryPoint = {
|
|
13
|
+
/** When it changed, ISO 8601. */
|
|
14
|
+
readonly time: string;
|
|
15
|
+
/** What it became. */
|
|
16
|
+
readonly state: CapabilityState;
|
|
17
|
+
/** What it was; null for the first report the platform recorded. */
|
|
18
|
+
readonly previousState: CapabilityState | null;
|
|
19
|
+
readonly attributes: JsonObject;
|
|
20
|
+
readonly isAvailable: boolean;
|
|
21
|
+
/** Which package, integration or engine reported it. */
|
|
22
|
+
readonly source: string;
|
|
23
|
+
readonly cause?: ChangeCause;
|
|
24
|
+
};
|
|
25
|
+
/** One reading, or one bucket of readings. */
|
|
26
|
+
type TelemetryPoint = {
|
|
27
|
+
/** The reading's time, or the bucket's start, ISO 8601. */
|
|
28
|
+
readonly time: string;
|
|
29
|
+
/** The reading, or the bucket's average. */
|
|
30
|
+
readonly value: number;
|
|
31
|
+
/** A bucket's lowest, highest and how many readings it holds; absent for raw readings. */
|
|
32
|
+
readonly min?: number;
|
|
33
|
+
readonly max?: number;
|
|
34
|
+
readonly count?: number;
|
|
35
|
+
};
|
|
36
|
+
/** Each entity's points, oldest first: an entity never recorded, or not readable, has none. */
|
|
37
|
+
type HistorySeries<TPoint> = Readonly<Record<EntityId, readonly TPoint[]>>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { TelemetryResolution as a, TelemetryPoint as i, HistorySeries as n, StateHistoryPoint as r, ChangeCause as t };
|
package/dist/chunks/json.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ declare function isEntityId(value: unknown): value is EntityId;
|
|
|
33
33
|
//#region src/capabilities.d.ts
|
|
34
34
|
/** Every capability an entity may declare. */
|
|
35
35
|
type CapabilityName = 'on_off' | 'level' | 'color_hs' | 'color_temp' | 'cover' | 'lock' | 'thermostat' | 'sensor_numeric' | 'sensor_binary' | 'sensor_text' | 'media_player' | 'camera' | 'button' | 'update' | 'lawn_mower' | 'select' | 'number' | 'vacuum' | 'image' | 'custom';
|
|
36
|
-
/** How a sensor's readings add up:
|
|
36
|
+
/** How a sensor's readings add up, for statistics: a reading, a running total, or a meter. */
|
|
37
37
|
type EntityStateClass = 'measurement' | 'total' | 'total_increasing';
|
|
38
38
|
/** The modes a thermostat may be set to. */
|
|
39
39
|
type ThermostatMode = 'off' | 'heat' | 'cool' | 'auto' | 'fan_only' | 'dry';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as PackageConfigError } from "./node-problems.js";
|
|
2
|
-
import { a as isRecord$1, b as strictObject, i as generatePackage, l as
|
|
2
|
+
import { a as isRecord$1, b as strictObject, i as generatePackage, l as DEPENDENCY_ID_PATTERN, n as keepingNodeEnv, p as packageIdSchema, r as RELEASE_PATHS, x as string, y as record } from "./node-config.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { copyFile, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
@@ -6850,7 +6850,7 @@ function composeFileProblems(text, settingKeys) {
|
|
|
6850
6850
|
* the two are compared before a package is installed or started (PACKAGES_DOCS.md 11).
|
|
6851
6851
|
*/
|
|
6852
6852
|
/** The SDK's own version, `1.0.0`. */
|
|
6853
|
-
const SDK_VERSION = "1.
|
|
6853
|
+
const SDK_VERSION = "1.2.0";
|
|
6854
6854
|
//#endregion
|
|
6855
6855
|
//#region src/vite/catalogues.ts
|
|
6856
6856
|
/**
|
|
@@ -5594,6 +5594,39 @@ function superRefine(fn, params) {
|
|
|
5594
5594
|
function number(params) {
|
|
5595
5595
|
return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
|
|
5596
5596
|
}
|
|
5597
|
+
//#endregion
|
|
5598
|
+
//#region ../contracts/dist/package-id.js
|
|
5599
|
+
/**
|
|
5600
|
+
* A package's identifier, apart from the manifest: the integrations' instance ids share its
|
|
5601
|
+
* pattern, and the modules that need only the pattern must not pull the manifest's whole grammar
|
|
5602
|
+
* - and what that imports - in with it.
|
|
5603
|
+
*/
|
|
5604
|
+
/**
|
|
5605
|
+
* A package identifier: `mqtt`, `nvr`, `3d-home`. It may start with a digit; its entities' object
|
|
5606
|
+
* ids then do too (`sensor.3d_home_kitchen_temperature`).
|
|
5607
|
+
*
|
|
5608
|
+
* Mirrors `packages_id_format` in DATABASE.md. It shares one namespace with the integrations'
|
|
5609
|
+
* instance ids, since both answer `svc.<id>.command`.
|
|
5610
|
+
*/
|
|
5611
|
+
const PACKAGE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{1,63}$/;
|
|
5612
|
+
/** The reserved ids, for a quick look-up. */
|
|
5613
|
+
const RESERVED = /* @__PURE__ */ new Set([
|
|
5614
|
+
"api",
|
|
5615
|
+
"backup",
|
|
5616
|
+
"core",
|
|
5617
|
+
"derived",
|
|
5618
|
+
"hub",
|
|
5619
|
+
"logger",
|
|
5620
|
+
"nebula",
|
|
5621
|
+
"packet-manager",
|
|
5622
|
+
"platform",
|
|
5623
|
+
"proxy",
|
|
5624
|
+
"supervisor",
|
|
5625
|
+
"system",
|
|
5626
|
+
"web-ui"
|
|
5627
|
+
]);
|
|
5628
|
+
/** Validates a package identifier. */
|
|
5629
|
+
const packageIdSchema = string().regex(PACKAGE_ID_PATTERN, "Must be a package id").refine((id) => !RESERVED.has(id), { message: "Is the name of a part of the platform, which no package may take" });
|
|
5597
5630
|
/** Validates an icon identifier. */
|
|
5598
5631
|
const iconIdSchema = string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/, "Must be an icon id");
|
|
5599
5632
|
/**
|
|
@@ -6102,38 +6135,6 @@ const integrationSetupSchema = strictObject({
|
|
|
6102
6135
|
});
|
|
6103
6136
|
});
|
|
6104
6137
|
//#endregion
|
|
6105
|
-
//#region ../contracts/dist/package-id.js
|
|
6106
|
-
/**
|
|
6107
|
-
* A package's identifier, apart from the manifest: the integrations' instance ids share its
|
|
6108
|
-
* pattern, and the modules that need only the pattern must not pull the manifest's whole grammar
|
|
6109
|
-
* - and what that imports - in with it.
|
|
6110
|
-
*/
|
|
6111
|
-
/**
|
|
6112
|
-
* A package identifier: `mqtt`, `nvr`.
|
|
6113
|
-
*
|
|
6114
|
-
* Mirrors `packages_id_format` in DATABASE.md. It shares one namespace with the integrations'
|
|
6115
|
-
* instance ids, since both answer `svc.<id>.command`.
|
|
6116
|
-
*/
|
|
6117
|
-
const PACKAGE_ID_PATTERN = /^[a-z][a-z0-9-]{1,63}$/;
|
|
6118
|
-
/** The reserved ids, for a quick look-up. */
|
|
6119
|
-
const RESERVED = /* @__PURE__ */ new Set([
|
|
6120
|
-
"api",
|
|
6121
|
-
"backup",
|
|
6122
|
-
"core",
|
|
6123
|
-
"derived",
|
|
6124
|
-
"hub",
|
|
6125
|
-
"logger",
|
|
6126
|
-
"nebula",
|
|
6127
|
-
"packet-manager",
|
|
6128
|
-
"platform",
|
|
6129
|
-
"proxy",
|
|
6130
|
-
"supervisor",
|
|
6131
|
-
"system",
|
|
6132
|
-
"web-ui"
|
|
6133
|
-
]);
|
|
6134
|
-
/** Validates a package identifier. */
|
|
6135
|
-
const packageIdSchema = string().regex(PACKAGE_ID_PATTERN, "Must be a package id").refine((id) => !RESERVED.has(id), { message: "Is the name of a part of the platform, which no package may take" });
|
|
6136
|
-
//#endregion
|
|
6137
6138
|
//#region ../contracts/dist/package-requires.js
|
|
6138
6139
|
/**
|
|
6139
6140
|
* What a package - or a vendor, in its `manifest.json` - needs besides itself (PACKAGES.md 7).
|
|
@@ -6141,7 +6142,7 @@ const packageIdSchema = string().regex(PACKAGE_ID_PATTERN, "Must be a package id
|
|
|
6141
6142
|
* Apart from the manifest so that the vendors' grammar can name it without pulling the package
|
|
6142
6143
|
* manifest's whole grammar - and what that imports - in with it.
|
|
6143
6144
|
*/
|
|
6144
|
-
/** A service
|
|
6145
|
+
/** A service others require: `object-detection`, or `mqtt-broker`, which the platform runs. */
|
|
6145
6146
|
const packageServiceNameSchema = string().regex(/^[a-z][a-z0-9-]{1,63}$/, "Must be a lower-case service name");
|
|
6146
6147
|
/**
|
|
6147
6148
|
* What a package - or a vendor, in its `manifest.json` - needs besides itself: the platform, by
|
|
@@ -6173,8 +6174,9 @@ const packageRequiresSchema = strictObject({
|
|
|
6173
6174
|
* - **`ui`** is what it adds to the interface: a page of its own, cards for the dashboard, views
|
|
6174
6175
|
* for its own kinds of entity - one ES module, served same-origin and loaded on demand.
|
|
6175
6176
|
* - **`requires`** and **`provides`** are its dependencies: packages by id and version range, and
|
|
6176
|
-
* services by name - `
|
|
6177
|
-
* `manifest.json` writes `requires`
|
|
6177
|
+
* services by name - `object-detection` - that whichever package provides them satisfies, or
|
|
6178
|
+
* that the platform runs itself (`mqtt-broker`). A vendor's `manifest.json` writes `requires`
|
|
6179
|
+
* the same way.
|
|
6178
6180
|
* - **`entityTypes`** are kinds of entity no capability describes - a recording, a playlist - with
|
|
6179
6181
|
* the fields of their state and the commands they take; an entity of one has the `custom`
|
|
6180
6182
|
* capability, and the package's `entityViews` draw it.
|
|
@@ -6883,4 +6885,4 @@ async function keepingNodeEnv(run) {
|
|
|
6883
6885
|
}
|
|
6884
6886
|
}
|
|
6885
6887
|
//#endregion
|
|
6886
|
-
export { url as C, union as S, date as _, isRecord as a, strictObject as b, packageServiceNameSchema as c,
|
|
6888
|
+
export { url as C, union as S, date as _, isRecord as a, strictObject as b, packageServiceNameSchema as c, semverSchema as d, iconIdSchema as f, array as g, _enum as h, generatePackage as i, DEPENDENCY_ID_PATTERN as l, ZodISODateTime as m, keepingNodeEnv as n, PACKAGE_CATEGORIES as o, packageIdSchema as p, RELEASE_PATHS as r, packageRequiresSchema as s, githubEnvironment as t, semverRangeSchema as u, int as v, _isoDateTime as w, string as x, record as y };
|
package/dist/chunks/node-pack.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as PackageConfigError } from "./node-problems.js";
|
|
2
|
-
import { C as url, S as union, _ as date, a as isRecord, b as strictObject, c as packageServiceNameSchema, d as
|
|
2
|
+
import { C as url, S as union, _ as date, a as isRecord, b as strictObject, c as packageServiceNameSchema, d as semverSchema, f as iconIdSchema, g as array, h as _enum, m as ZodISODateTime, o as PACKAGE_CATEGORIES, p as packageIdSchema, r as RELEASE_PATHS, s as packageRequiresSchema, t as githubEnvironment, u as semverRangeSchema, v as int, w as _isoDateTime, x as string } from "./node-config.js";
|
|
3
3
|
import ro, { readFile, readdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import path, { basename, join, posix, win32 } from "node:path";
|
|
5
5
|
import { Buffer as Buffer$1 } from "buffer";
|
package/dist/chunks/version.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -152,7 +152,7 @@ type PackageUi<TCards extends readonly CardDefinition[], TTypes extends readonly
|
|
|
152
152
|
};
|
|
153
153
|
/** What every package says, whatever it runs. */
|
|
154
154
|
type PackageBase<TCards extends readonly CardDefinition[], TTypes extends readonly EntityTypeDefinition[]> = {
|
|
155
|
-
/** `^[a-
|
|
155
|
+
/** `^[a-z0-9][a-z0-9-]{1,63}$`, not one of the platform's names. */
|
|
156
156
|
readonly id: string;
|
|
157
157
|
readonly name: string;
|
|
158
158
|
readonly description: string;
|
package/dist/index.js
CHANGED
|
@@ -130,7 +130,7 @@ const ENTITY_DOMAINS = [
|
|
|
130
130
|
"alias"
|
|
131
131
|
];
|
|
132
132
|
/** The shape of an entity identifier: a domain, a dot, an object id. */
|
|
133
|
-
const ENTITY_ID_PATTERN = /^([a-z][a-z0-9_]{0,31})\.([a-
|
|
133
|
+
const ENTITY_ID_PATTERN = /^([a-z][a-z0-9_]{0,31})\.([a-z0-9][a-z0-9_]{0,63})$/;
|
|
134
134
|
/**
|
|
135
135
|
* Says whether a word is one of the platform's domains.
|
|
136
136
|
*
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { i as SettingsDefinition } from "./chunks/json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { a as TelemetryResolution, i as TelemetryPoint, n as HistorySeries, r as StateHistoryPoint, t as ChangeCause } from "./chunks/history.js";
|
|
3
|
+
import { A as Schema, C as ServiceProvide, D as TelemetryRead, E as SyncResult, M as StandardResult, N as StandardSchemaV1, O as Unsubscribe, S as ServiceCallFunction, T as StateChange, _ as RpcCaller, a as CustomEntityInput, b as ServerSettings, c as EntityInput, d as HistoryRead, f as LogMethod, g as RpcCall, h as RpcAccess, i as CustomEntities, j as SchemaIssue, k as SafeParser, l as EntitySnapshot, m as ReportOptions, n as CapabilityEntityInput, o as DeviceInput, p as Logger, r as CustomCommand, s as EntityFilter, t as Awaitable, u as HistoryAnswer, v as RpcMethod, w as SettingsChange, x as ServiceCall, y as ServerContext } from "./chunks/context.js";
|
|
3
4
|
//#region src/server/index.d.ts
|
|
4
5
|
/** What stops what `start` opened. */
|
|
5
6
|
export type Stop = () => Awaitable<void>;
|
|
@@ -27,4 +28,4 @@ export type ServerDefinition<TSettings extends SettingsDefinition | undefined =
|
|
|
27
28
|
*/
|
|
28
29
|
export declare function defineServer<TSettings extends SettingsDefinition | undefined = undefined>(server: Omit<ServerDefinition<TSettings>, 'kind' | 'sdk'>): ServerDefinition<TSettings>;
|
|
29
30
|
//#endregion
|
|
30
|
-
export type { Awaitable, CapabilityEntityInput, CustomCommand, CustomEntities, CustomEntityInput, DeviceInput, EntityFilter, EntityInput, EntitySnapshot, LogMethod, Logger, ReportOptions, RpcAccess, RpcCall, RpcCaller, RpcMethod, SafeParser, Schema, SchemaIssue, ServerContext, ServerSettings, ServiceCall, ServiceCallFunction, ServiceProvide, SettingsChange, StandardResult, StandardSchemaV1, StateChange, SyncResult, Unsubscribe };
|
|
31
|
+
export type { Awaitable, CapabilityEntityInput, ChangeCause, CustomCommand, CustomEntities, CustomEntityInput, DeviceInput, EntityFilter, EntityInput, EntitySnapshot, HistoryAnswer, HistoryRead, HistorySeries, LogMethod, Logger, ReportOptions, RpcAccess, RpcCall, RpcCaller, RpcMethod, SafeParser, Schema, SchemaIssue, ServerContext, ServerSettings, ServiceCall, ServiceCallFunction, ServiceProvide, SettingsChange, StandardResult, StandardSchemaV1, StateChange, StateHistoryPoint, SyncResult, TelemetryPoint, TelemetryRead, TelemetryResolution, Unsubscribe };
|
package/dist/styles.css
CHANGED
|
@@ -547,3 +547,15 @@
|
|
|
547
547
|
@utility tabular {
|
|
548
548
|
font-variant-numeric: tabular-nums;
|
|
549
549
|
}
|
|
550
|
+
|
|
551
|
+
/*
|
|
552
|
+
* The Matter mark's square, lit violet from its top-left corner: the broker's hero and its
|
|
553
|
+
* dialogs' lead. Over the square's own ground, so it sits on `bg-surface-raised`.
|
|
554
|
+
*/
|
|
555
|
+
@utility matter-glow {
|
|
556
|
+
background-image: radial-gradient(
|
|
557
|
+
120% 120% at 0% 0%,
|
|
558
|
+
color-mix(in srgb, var(--color-violet) 22%, transparent),
|
|
559
|
+
transparent 60%
|
|
560
|
+
);
|
|
561
|
+
}
|
package/dist/sun.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//#region src/sun.d.ts
|
|
2
|
+
/** A place on Earth, in degrees: north and east positive. */
|
|
3
|
+
export type GeoPosition = {
|
|
4
|
+
readonly latitude: number;
|
|
5
|
+
readonly longitude: number;
|
|
6
|
+
};
|
|
7
|
+
/** Where the sun stands, in degrees. */
|
|
8
|
+
export type SunPosition = {
|
|
9
|
+
/** Above the horizon, positive; below it, negative. */
|
|
10
|
+
readonly elevation: number;
|
|
11
|
+
/** Clockwise from true north: 90 east, 180 south. */
|
|
12
|
+
readonly azimuth: number;
|
|
13
|
+
};
|
|
14
|
+
/** A day's sunrise, solar noon and sunset; no rise or set on a polar day or night. */
|
|
15
|
+
export type SunTimes = {
|
|
16
|
+
readonly sunrise: Date | null;
|
|
17
|
+
readonly solarNoon: Date;
|
|
18
|
+
readonly sunset: Date | null;
|
|
19
|
+
};
|
|
20
|
+
/** Where the sun stands, and which way it goes. */
|
|
21
|
+
export type SunState = SunPosition & {
|
|
22
|
+
readonly isRising: boolean;
|
|
23
|
+
readonly isMidnightSun: boolean;
|
|
24
|
+
readonly isPolarNight: boolean;
|
|
25
|
+
};
|
|
26
|
+
/** The light the sun gives, in a word. */
|
|
27
|
+
export type SunPhaseLabel = 'day' | 'golden_hour' | 'blue_hour' | 'night' | 'polar_night';
|
|
28
|
+
/** The platform's sun entities, reported every minute while the house has a position. */
|
|
29
|
+
export declare const SUN_ELEVATION_ENTITY_ID = "sensor.system_sun_elevation";
|
|
30
|
+
export declare const SUN_AZIMUTH_ENTITY_ID = "sensor.system_sun_azimuth";
|
|
31
|
+
/**
|
|
32
|
+
* Where the sun stands at a moment, seen from a place.
|
|
33
|
+
*
|
|
34
|
+
* @param at - The moment.
|
|
35
|
+
* @param position - The place.
|
|
36
|
+
* @returns Its elevation and azimuth, in degrees.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sunPosition(at: Date, position: GeoPosition): SunPosition;
|
|
39
|
+
/**
|
|
40
|
+
* The sunrise, solar noon and sunset of the day a moment falls in, at a place.
|
|
41
|
+
*
|
|
42
|
+
* @param at - A moment of the day.
|
|
43
|
+
* @param position - The place.
|
|
44
|
+
* @returns Them; no rise or set on a polar day or night.
|
|
45
|
+
*/
|
|
46
|
+
export declare function sunTimes(at: Date, position: GeoPosition): SunTimes;
|
|
47
|
+
/**
|
|
48
|
+
* Where the sun stands at a moment, and whether it rises.
|
|
49
|
+
*
|
|
50
|
+
* @param at - The moment.
|
|
51
|
+
* @param position - The place.
|
|
52
|
+
* @returns Its position, and how its day goes.
|
|
53
|
+
*/
|
|
54
|
+
export declare function sunState(at: Date, position: GeoPosition): SunState;
|
|
55
|
+
/**
|
|
56
|
+
* The light of a moment, in a word: day, golden hour, blue hour, night.
|
|
57
|
+
*
|
|
58
|
+
* @param state - Where the sun stands.
|
|
59
|
+
* @returns The word.
|
|
60
|
+
*/
|
|
61
|
+
export declare function sunPhaseLabel(state: SunState): SunPhaseLabel;
|
|
62
|
+
//#endregion
|
package/dist/sun.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
//#region ../contracts/dist/sun.js
|
|
2
|
+
/**
|
|
3
|
+
* Where the sun is, and when it gets somewhere, worked out on this machine.
|
|
4
|
+
*
|
|
5
|
+
* The house knows its latitude and longitude and nothing else is needed: the sun's height and
|
|
6
|
+
* bearing at any instant follow from the date with a few lines of spherical astronomy, so there is
|
|
7
|
+
* no service to call and nothing leaves the house. The formulas are the ones the widely used
|
|
8
|
+
* `suncalc` library takes from the astronomy pages of aa.quae.nl, good to about a minute for any
|
|
9
|
+
* date this platform will see.
|
|
10
|
+
*
|
|
11
|
+
* Shared by `core`, which wakes automations on sun events and publishes the sun's elevation and
|
|
12
|
+
* azimuth as two entities of the system device, and by the web interface, which previews the next
|
|
13
|
+
* event under a block and today's sunrise and sunset in the first-run setup. One implementation,
|
|
14
|
+
* so the preview never disagrees with what the engine does.
|
|
15
|
+
*
|
|
16
|
+
* Elevations are geometric (no refraction); the horizon events use the standard -0.833°, which
|
|
17
|
+
* includes refraction and the sun's half-width, so "sunrise" here is the moment almanacs print.
|
|
18
|
+
*/
|
|
19
|
+
/** The elevations the named sun events are defined by, in degrees. */
|
|
20
|
+
const SUN_ANGLES = {
|
|
21
|
+
/** Sunrise and sunset: the top of the disc on the horizon, refraction included. */
|
|
22
|
+
horizon: -.833,
|
|
23
|
+
/** Civil dawn and dusk. */
|
|
24
|
+
civil: -6,
|
|
25
|
+
/** Where the blue hour gives way to the golden hour. */
|
|
26
|
+
blueToGolden: -4,
|
|
27
|
+
/** The upper edge of the golden hour. */
|
|
28
|
+
goldenTop: 6
|
|
29
|
+
};
|
|
30
|
+
const RAD = Math.PI / 180;
|
|
31
|
+
const DAY_MS = 864e5;
|
|
32
|
+
const J1970 = 2440588;
|
|
33
|
+
const J2000 = 2451545;
|
|
34
|
+
const J0 = 9e-4;
|
|
35
|
+
const OBLIQUITY = RAD * 23.4397;
|
|
36
|
+
/** How finely a crossing is pinned down: well under a second. */
|
|
37
|
+
const BISECTION_STEPS = 32;
|
|
38
|
+
/**
|
|
39
|
+
* Days since the J2000 epoch.
|
|
40
|
+
*
|
|
41
|
+
* @param ms - An instant, in Unix milliseconds.
|
|
42
|
+
* @returns The day number.
|
|
43
|
+
*/
|
|
44
|
+
function toDays(ms) {
|
|
45
|
+
return ms / DAY_MS - .5 + J1970 - J2000;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* An instant from a Julian date.
|
|
49
|
+
*
|
|
50
|
+
* @param julian - The Julian date.
|
|
51
|
+
* @returns Unix milliseconds.
|
|
52
|
+
*/
|
|
53
|
+
function fromJulian(julian) {
|
|
54
|
+
return (julian + .5 - J1970) * DAY_MS;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The sun's mean anomaly.
|
|
58
|
+
*
|
|
59
|
+
* @param days - Days since J2000.
|
|
60
|
+
* @returns Radians.
|
|
61
|
+
*/
|
|
62
|
+
function meanAnomaly(days) {
|
|
63
|
+
return RAD * (357.5291 + .98560028 * days);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The sun's ecliptic longitude.
|
|
67
|
+
*
|
|
68
|
+
* @param anomaly - Its mean anomaly.
|
|
69
|
+
* @returns Radians.
|
|
70
|
+
*/
|
|
71
|
+
function eclipticLongitude(anomaly) {
|
|
72
|
+
return anomaly + RAD * (1.9148 * Math.sin(anomaly) + .02 * Math.sin(2 * anomaly) + 3e-4 * Math.sin(3 * anomaly)) + RAD * 102.9372 + Math.PI;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The sun's height and bearing at an instant, in radians, with the bearing from the south.
|
|
76
|
+
*
|
|
77
|
+
* @param ms - The instant.
|
|
78
|
+
* @param position - Where.
|
|
79
|
+
* @returns Altitude and azimuth.
|
|
80
|
+
*/
|
|
81
|
+
function horizontal(ms, position) {
|
|
82
|
+
const lw = RAD * -position.longitude;
|
|
83
|
+
const phi = RAD * position.latitude;
|
|
84
|
+
const days = toDays(ms);
|
|
85
|
+
const longitude = eclipticLongitude(meanAnomaly(days));
|
|
86
|
+
const declination = Math.asin(Math.sin(OBLIQUITY) * Math.sin(longitude));
|
|
87
|
+
const ascension = Math.atan2(Math.sin(longitude) * Math.cos(OBLIQUITY), Math.cos(longitude));
|
|
88
|
+
const hourAngle = RAD * (280.16 + 360.9856235 * days) - lw - ascension;
|
|
89
|
+
return {
|
|
90
|
+
altitude: Math.asin(Math.sin(phi) * Math.sin(declination) + Math.cos(phi) * Math.cos(declination) * Math.cos(hourAngle)),
|
|
91
|
+
azimuth: Math.atan2(Math.sin(hourAngle), Math.cos(hourAngle) * Math.sin(phi) - Math.tan(declination) * Math.cos(phi))
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The sun's elevation at an instant.
|
|
96
|
+
*
|
|
97
|
+
* @param ms - The instant.
|
|
98
|
+
* @param position - Where.
|
|
99
|
+
* @returns Degrees above the horizon.
|
|
100
|
+
*/
|
|
101
|
+
function elevationAt(ms, position) {
|
|
102
|
+
return horizontal(ms, position).altitude / RAD;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Where the sun stands at an instant.
|
|
106
|
+
*
|
|
107
|
+
* @param at - The instant.
|
|
108
|
+
* @param position - Where.
|
|
109
|
+
* @returns Its elevation and its azimuth from north, in degrees.
|
|
110
|
+
*/
|
|
111
|
+
function sunPosition$1(at, position) {
|
|
112
|
+
const { altitude, azimuth } = horizontal(at.getTime(), position);
|
|
113
|
+
const fromNorth = (azimuth / RAD + 180) % 360;
|
|
114
|
+
return {
|
|
115
|
+
elevation: altitude / RAD,
|
|
116
|
+
azimuth: fromNorth < 0 ? fromNorth + 360 : fromNorth
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Which solar day an instant falls in: the cycle whose noon is nearest.
|
|
121
|
+
*
|
|
122
|
+
* @param ms - The instant.
|
|
123
|
+
* @param position - Where.
|
|
124
|
+
* @returns The cycle number.
|
|
125
|
+
*/
|
|
126
|
+
function cycleOf(ms, position) {
|
|
127
|
+
const lw = RAD * -position.longitude;
|
|
128
|
+
return Math.round(toDays(ms) - J0 - lw / (2 * Math.PI));
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* When the sun is highest in one solar day.
|
|
132
|
+
*
|
|
133
|
+
* @param cycle - The solar day.
|
|
134
|
+
* @param position - Where.
|
|
135
|
+
* @returns Unix milliseconds.
|
|
136
|
+
*/
|
|
137
|
+
function noonOf(cycle, position) {
|
|
138
|
+
const lw = RAD * -position.longitude;
|
|
139
|
+
const days = J0 + lw / (2 * Math.PI) + cycle;
|
|
140
|
+
const anomaly = meanAnomaly(days);
|
|
141
|
+
const longitude = eclipticLongitude(anomaly);
|
|
142
|
+
return fromJulian(J2000 + days + .0053 * Math.sin(anomaly) - .0069 * Math.sin(2 * longitude));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Finds where the elevation reaches an angle between two instants it lies on either side of.
|
|
146
|
+
*
|
|
147
|
+
* @param from - One end.
|
|
148
|
+
* @param to - The other end.
|
|
149
|
+
* @param angle - The elevation sought.
|
|
150
|
+
* @param position - Where.
|
|
151
|
+
* @returns The instant, in Unix milliseconds.
|
|
152
|
+
*/
|
|
153
|
+
function bisect(from, to, angle, position) {
|
|
154
|
+
let low = from;
|
|
155
|
+
let high = to;
|
|
156
|
+
const isLowBelow = elevationAt(low, position) < angle;
|
|
157
|
+
for (let step = 0; step < BISECTION_STEPS; step += 1) {
|
|
158
|
+
const middle = (low + high) / 2;
|
|
159
|
+
if (elevationAt(middle, position) < angle === isLowBelow) low = middle;
|
|
160
|
+
else high = middle;
|
|
161
|
+
}
|
|
162
|
+
return Math.round((low + high) / 2);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Reads one solar day.
|
|
166
|
+
*
|
|
167
|
+
* @param cycle - Which.
|
|
168
|
+
* @param position - Where.
|
|
169
|
+
* @returns Its noon and midnights.
|
|
170
|
+
*/
|
|
171
|
+
function solarDay(cycle, position) {
|
|
172
|
+
const noon = noonOf(cycle, position);
|
|
173
|
+
const midnightBefore = noon - DAY_MS / 2;
|
|
174
|
+
const midnightAfter = noon + DAY_MS / 2;
|
|
175
|
+
return {
|
|
176
|
+
noon,
|
|
177
|
+
midnightBefore,
|
|
178
|
+
midnightAfter,
|
|
179
|
+
noonElevation: elevationAt(noon, position),
|
|
180
|
+
beforeElevation: elevationAt(midnightBefore, position),
|
|
181
|
+
afterElevation: elevationAt(midnightAfter, position)
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* When the sun rises through an angle in one solar day.
|
|
186
|
+
*
|
|
187
|
+
* @param day - The day.
|
|
188
|
+
* @param angle - The elevation.
|
|
189
|
+
* @param position - Where.
|
|
190
|
+
* @returns The instant, or null when it does not cross that day.
|
|
191
|
+
*/
|
|
192
|
+
function risingThrough(day, angle, position) {
|
|
193
|
+
return day.beforeElevation < angle && day.noonElevation >= angle ? bisect(day.midnightBefore, day.noon, angle, position) : null;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* When the sun sets through an angle in one solar day.
|
|
197
|
+
*
|
|
198
|
+
* @param day - The day.
|
|
199
|
+
* @param angle - The elevation.
|
|
200
|
+
* @param position - Where.
|
|
201
|
+
* @returns The instant, or null when it does not cross that day.
|
|
202
|
+
*/
|
|
203
|
+
function settingThrough(day, angle, position) {
|
|
204
|
+
return day.noonElevation >= angle && day.afterElevation < angle ? bisect(day.noon, day.midnightAfter, angle, position) : null;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The sunrise, noon and sunset of the solar day an instant falls in.
|
|
208
|
+
*
|
|
209
|
+
* @param at - Any instant of the day.
|
|
210
|
+
* @param position - Where.
|
|
211
|
+
* @returns The three moments; sunrise or sunset is null on a day the sun does not cross the
|
|
212
|
+
* horizon.
|
|
213
|
+
*/
|
|
214
|
+
function sunTimes$1(at, position) {
|
|
215
|
+
const day = solarDay(cycleOf(at.getTime(), position), position);
|
|
216
|
+
const sunrise = risingThrough(day, SUN_ANGLES.horizon, position);
|
|
217
|
+
const sunset = settingThrough(day, SUN_ANGLES.horizon, position);
|
|
218
|
+
return {
|
|
219
|
+
sunrise: sunrise === null ? null : new Date(sunrise),
|
|
220
|
+
solarNoon: new Date(day.noon),
|
|
221
|
+
sunset: sunset === null ? null : new Date(sunset)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* What the sun is doing at an instant.
|
|
226
|
+
*
|
|
227
|
+
* @param at - The instant.
|
|
228
|
+
* @param position - Where.
|
|
229
|
+
* @returns Its position, whether it is rising, and whether today is a polar day or night.
|
|
230
|
+
*/
|
|
231
|
+
function sunState$1(at, position) {
|
|
232
|
+
const ms = at.getTime();
|
|
233
|
+
const day = solarDay(cycleOf(ms, position), position);
|
|
234
|
+
const { horizon } = SUN_ANGLES;
|
|
235
|
+
return {
|
|
236
|
+
...sunPosition$1(at, position),
|
|
237
|
+
isRising: ms < day.noon,
|
|
238
|
+
isMidnightSun: Math.min(day.beforeElevation, day.afterElevation) >= horizon,
|
|
239
|
+
isPolarNight: day.noonElevation < horizon
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* The one word for what the sun is doing, for the sun entity's attributes.
|
|
244
|
+
*
|
|
245
|
+
* @param state - What the sun is doing.
|
|
246
|
+
* @returns Day, golden hour, blue hour, night or polar night.
|
|
247
|
+
*/
|
|
248
|
+
function sunPhaseLabel$1(state) {
|
|
249
|
+
const { civil, blueToGolden, goldenTop } = SUN_ANGLES;
|
|
250
|
+
if (state.isPolarNight) return "polar_night";
|
|
251
|
+
if (state.elevation >= goldenTop) return "day";
|
|
252
|
+
if (state.elevation > blueToGolden) return "golden_hour";
|
|
253
|
+
return state.elevation > civil ? "blue_hour" : "night";
|
|
254
|
+
}
|
|
255
|
+
[{
|
|
256
|
+
reading: "elevation",
|
|
257
|
+
entityId: "sensor.system_sun_elevation",
|
|
258
|
+
name: "Sun elevation",
|
|
259
|
+
icon: "sun",
|
|
260
|
+
unitOfMeasurement: "°",
|
|
261
|
+
stateClass: "measurement",
|
|
262
|
+
displayPrecision: 1,
|
|
263
|
+
capabilities: { sensor_numeric: {} }
|
|
264
|
+
}, {
|
|
265
|
+
reading: "azimuth",
|
|
266
|
+
entityId: "sensor.system_sun_azimuth",
|
|
267
|
+
name: "Sun azimuth",
|
|
268
|
+
icon: "compass",
|
|
269
|
+
unitOfMeasurement: "°",
|
|
270
|
+
stateClass: "measurement",
|
|
271
|
+
displayPrecision: 1,
|
|
272
|
+
capabilities: { sensor_numeric: {} }
|
|
273
|
+
}].map((entity) => entity.entityId);
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/sun.ts
|
|
276
|
+
/**
|
|
277
|
+
* `@nebulahome/package-sdk/sun`: where the sun is, for a package that draws or decides by it
|
|
278
|
+
* (PACKAGES_DOCS.md 6.7). Since 1.2.
|
|
279
|
+
*
|
|
280
|
+
* The same formulas the platform runs for its sun entities and its sun triggers, so a package that
|
|
281
|
+
* works out a past or a future day agrees with what the house said live: `sensor.system_sun_*`
|
|
282
|
+
* for now, these for any other moment. The house's position is the house area's
|
|
283
|
+
* (`useAreas()` on the interface).
|
|
284
|
+
*/
|
|
285
|
+
/** The platform's sun entities, reported every minute while the house has a position. */
|
|
286
|
+
const SUN_ELEVATION_ENTITY_ID = "sensor.system_sun_elevation";
|
|
287
|
+
const SUN_AZIMUTH_ENTITY_ID = "sensor.system_sun_azimuth";
|
|
288
|
+
/**
|
|
289
|
+
* Where the sun stands at a moment, seen from a place.
|
|
290
|
+
*
|
|
291
|
+
* @param at - The moment.
|
|
292
|
+
* @param position - The place.
|
|
293
|
+
* @returns Its elevation and azimuth, in degrees.
|
|
294
|
+
*/
|
|
295
|
+
function sunPosition(at, position) {
|
|
296
|
+
return sunPosition$1(at, position);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* The sunrise, solar noon and sunset of the day a moment falls in, at a place.
|
|
300
|
+
*
|
|
301
|
+
* @param at - A moment of the day.
|
|
302
|
+
* @param position - The place.
|
|
303
|
+
* @returns Them; no rise or set on a polar day or night.
|
|
304
|
+
*/
|
|
305
|
+
function sunTimes(at, position) {
|
|
306
|
+
return sunTimes$1(at, position);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Where the sun stands at a moment, and whether it rises.
|
|
310
|
+
*
|
|
311
|
+
* @param at - The moment.
|
|
312
|
+
* @param position - The place.
|
|
313
|
+
* @returns Its position, and how its day goes.
|
|
314
|
+
*/
|
|
315
|
+
function sunState(at, position) {
|
|
316
|
+
return sunState$1(at, position);
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The light of a moment, in a word: day, golden hour, blue hour, night.
|
|
320
|
+
*
|
|
321
|
+
* @param state - Where the sun stands.
|
|
322
|
+
* @returns The word.
|
|
323
|
+
*/
|
|
324
|
+
function sunPhaseLabel(state) {
|
|
325
|
+
return sunPhaseLabel$1(state);
|
|
326
|
+
}
|
|
327
|
+
//#endregion
|
|
328
|
+
export { SUN_AZIMUTH_ENTITY_ID, SUN_ELEVATION_ENTITY_ID, sunPhaseLabel, sunPosition, sunState, sunTimes };
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { V as CapabilityCommand, et as ReportedCapabilityState, i as SettingsDefinition, lt as EntityId, r as JsonValue, t as JsonObject } from "./chunks/json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { i as TelemetryPoint, r as StateHistoryPoint } from "./chunks/history.js";
|
|
3
|
+
import { T as StateChange, _ as RpcCaller, l as EntitySnapshot, m as ReportOptions, o as DeviceInput, t as Awaitable, y as ServerContext } from "./chunks/context.js";
|
|
3
4
|
//#region src/testing/index.d.ts
|
|
4
5
|
/** What a test context starts with. */
|
|
5
6
|
export type TestContextOptions<TSettings extends SettingsDefinition | undefined> = {
|
|
@@ -13,9 +14,16 @@ export type TestContextOptions<TSettings extends SettingsDefinition | undefined>
|
|
|
13
14
|
readonly settings?: JsonObject;
|
|
14
15
|
/** Entities of the house `ctx.entities` reads. */
|
|
15
16
|
readonly entities?: readonly EntitySnapshot[];
|
|
17
|
+
/** The past `ctx.history` reads, by entity: points in any order. */
|
|
18
|
+
readonly history?: Readonly<Record<string, RecordedHistory>>;
|
|
16
19
|
readonly dataDir?: string;
|
|
17
20
|
readonly cacheDir?: string;
|
|
18
21
|
};
|
|
22
|
+
/** One entity's past, as a test gives it. */
|
|
23
|
+
export type RecordedHistory = {
|
|
24
|
+
readonly states?: readonly StateHistoryPoint[];
|
|
25
|
+
readonly telemetry?: readonly TelemetryPoint[];
|
|
26
|
+
};
|
|
19
27
|
/** One report the package made. */
|
|
20
28
|
export type RecordedReport = {
|
|
21
29
|
readonly entityId: EntityId;
|
|
@@ -96,6 +104,13 @@ export type TestContext<TSettings extends SettingsDefinition | undefined> = {
|
|
|
96
104
|
* @returns Once every handler ran.
|
|
97
105
|
*/
|
|
98
106
|
readonly emitStateChange: (change: StateChange) => Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Gives an entity a past, where `ctx.history` reads it.
|
|
109
|
+
*
|
|
110
|
+
* @param entityId - The entity.
|
|
111
|
+
* @param history - Its changes and readings, in any order.
|
|
112
|
+
*/
|
|
113
|
+
readonly setHistory: (entityId: EntityId, history: RecordedHistory) => void;
|
|
99
114
|
/**
|
|
100
115
|
* Answers a service the package calls.
|
|
101
116
|
*
|
package/dist/testing.js
CHANGED
|
@@ -38,6 +38,52 @@ async function check(schema, value) {
|
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/testing/index.ts
|
|
41
|
+
/** The most entities and points one read of the past takes, as the platform has it. */
|
|
42
|
+
const HISTORY_MAX_ENTITIES = 64;
|
|
43
|
+
const HISTORY_MAX_POINTS = 1e4;
|
|
44
|
+
/** An hour and a day, in milliseconds. */
|
|
45
|
+
const HOUR_MS = 36e5;
|
|
46
|
+
const DAY_MS = 24 * HOUR_MS;
|
|
47
|
+
/**
|
|
48
|
+
* The resolution the platform reads a window at when a read leaves it to it.
|
|
49
|
+
*
|
|
50
|
+
* @param spanMs - How long the window is.
|
|
51
|
+
* @returns Raw up to an hour, minutes up to 30 hours, hours up to 80 days, days beyond.
|
|
52
|
+
*/
|
|
53
|
+
function resolutionFor(spanMs) {
|
|
54
|
+
if (spanMs <= HOUR_MS) return "raw";
|
|
55
|
+
if (spanMs <= 30 * HOUR_MS) return "1m";
|
|
56
|
+
return spanMs <= 80 * DAY_MS ? "1h" : "1d";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reads a window of points as the platform does: checked, oldest first, the newest kept.
|
|
60
|
+
*
|
|
61
|
+
* @param read - Which entities, which window, how many points each.
|
|
62
|
+
* @param pointsOf - An entity's points, in any order.
|
|
63
|
+
* @returns Each entity's points in the window, and which lost their oldest.
|
|
64
|
+
* @throws {Error} When the read names no entity or too many, or its window is backwards.
|
|
65
|
+
*/
|
|
66
|
+
function readWindow(read, pointsOf) {
|
|
67
|
+
const from = new Date(read.from).getTime();
|
|
68
|
+
const to = new Date(read.to).getTime();
|
|
69
|
+
const limit = read.limit ?? HISTORY_MAX_POINTS;
|
|
70
|
+
if (read.entityIds.length === 0 || read.entityIds.length > HISTORY_MAX_ENTITIES) throw new Error(`A read of the past names 1 to ${String(HISTORY_MAX_ENTITIES)} entities`);
|
|
71
|
+
if (!(from < to)) throw new Error("The window starts at or after it ends");
|
|
72
|
+
const series = {};
|
|
73
|
+
const truncated = [];
|
|
74
|
+
for (const entityId of read.entityIds) {
|
|
75
|
+
const inWindow = pointsOf(entityId).filter((point) => {
|
|
76
|
+
const time = new Date(point.time).getTime();
|
|
77
|
+
return time >= from && time < to;
|
|
78
|
+
}).toSorted((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime());
|
|
79
|
+
series[entityId] = inWindow.slice(Math.max(0, inWindow.length - limit));
|
|
80
|
+
if (inWindow.length > limit) truncated.push(entityId);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
series,
|
|
84
|
+
truncated
|
|
85
|
+
};
|
|
86
|
+
}
|
|
41
87
|
/** Service names the platform keeps for itself. */
|
|
42
88
|
const RESERVED_SERVICES = /* @__PURE__ */ new Set([
|
|
43
89
|
"command",
|
|
@@ -99,6 +145,7 @@ function createTestContext(options = {}) {
|
|
|
99
145
|
const reports = [];
|
|
100
146
|
const logs = [];
|
|
101
147
|
const entities = new Map((options.entities ?? []).map((each) => [each.entityId, each]));
|
|
148
|
+
const histories = new Map(Object.entries(options.history ?? {}));
|
|
102
149
|
const methods = /* @__PURE__ */ new Map();
|
|
103
150
|
const services = /* @__PURE__ */ new Map();
|
|
104
151
|
const answers = /* @__PURE__ */ new Map();
|
|
@@ -462,6 +509,29 @@ function createTestContext(options = {}) {
|
|
|
462
509
|
};
|
|
463
510
|
}
|
|
464
511
|
},
|
|
512
|
+
history: {
|
|
513
|
+
/**
|
|
514
|
+
* The changes of some entities in a window.
|
|
515
|
+
*
|
|
516
|
+
* @param read - Which, when, how many.
|
|
517
|
+
* @returns Them, oldest first.
|
|
518
|
+
*/
|
|
519
|
+
states: async (read) => Promise.resolve(readWindow(read, (entityId) => histories.get(entityId)?.states ?? [])),
|
|
520
|
+
/**
|
|
521
|
+
* The readings of some entities in a window, as given: a test gives the buckets it wants.
|
|
522
|
+
*
|
|
523
|
+
* @param read - Which, when, how many, at which resolution.
|
|
524
|
+
* @returns Them, oldest first, and the resolution.
|
|
525
|
+
*/
|
|
526
|
+
telemetry: async (read) => {
|
|
527
|
+
const span = new Date(read.to).getTime() - new Date(read.from).getTime();
|
|
528
|
+
const resolution = read.resolution === void 0 || read.resolution === "auto" ? resolutionFor(span) : read.resolution;
|
|
529
|
+
return Promise.resolve({
|
|
530
|
+
...readWindow(read, (entityId) => histories.get(entityId)?.telemetry ?? []),
|
|
531
|
+
resolution
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
},
|
|
465
535
|
rpc: { method: rpcMethod },
|
|
466
536
|
services: {
|
|
467
537
|
provide,
|
|
@@ -578,6 +648,15 @@ function createTestContext(options = {}) {
|
|
|
578
648
|
entities.set(snapshot.entityId, snapshot);
|
|
579
649
|
},
|
|
580
650
|
/**
|
|
651
|
+
* Gives an entity a past.
|
|
652
|
+
*
|
|
653
|
+
* @param entityId - The entity.
|
|
654
|
+
* @param history - Its changes and readings.
|
|
655
|
+
*/
|
|
656
|
+
setHistory: (entityId, history) => {
|
|
657
|
+
histories.set(entityId, history);
|
|
658
|
+
},
|
|
659
|
+
/**
|
|
581
660
|
* Changes an entity of the house.
|
|
582
661
|
*
|
|
583
662
|
* @param change - The change.
|
package/dist/ui.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { G as CapabilityState, H as CapabilityCommands, S as FormValues, ct as EntityDomain, d as EntityTypeDefinition, f as ValuesOf, i as SettingsDefinition, lt as EntityId, q as CommandableCapability, r as JsonValue, s as ArgsOf, t as JsonObject, u as CommandsOf, z as ValueOfField } from "./chunks/json.js";
|
|
1
|
+
import { G as CapabilityState, H as CapabilityCommands, S as FormValues, Y as DeclaredCapabilities, ct as EntityDomain, d as EntityTypeDefinition, f as ValuesOf, i as SettingsDefinition, lt as EntityId, q as CommandableCapability, r as JsonValue, s as ArgsOf, t as JsonObject, u as CommandsOf, z as ValueOfField } from "./chunks/json.js";
|
|
2
2
|
import { a as PageProps, n as EntityViewProps, t as CardProps } from "./chunks/props.js";
|
|
3
|
+
import { a as TelemetryResolution, i as TelemetryPoint, n as HistorySeries, r as StateHistoryPoint, t as ChangeCause } from "./chunks/history.js";
|
|
3
4
|
import { AnchorHTMLAttributes, ComponentType, ReactElement, ReactNode } from "react";
|
|
4
5
|
//#region src/ui/types.d.ts
|
|
5
6
|
/** The package drawn. */
|
|
@@ -15,7 +16,13 @@ type EntityView = {
|
|
|
15
16
|
readonly name: string;
|
|
16
17
|
readonly icon: string | null;
|
|
17
18
|
readonly deviceId: string | null;
|
|
19
|
+
/** Its area's key - the entity's own, else its device's - as {@link AreaView} `key` says it. */
|
|
18
20
|
readonly areaId: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* What it declares it can do, with the device's limits: a cover's tilt, a thermostat's range
|
|
23
|
+
* and modes, a select's options. Since 1.2.
|
|
24
|
+
*/
|
|
25
|
+
readonly capabilities: DeclaredCapabilities;
|
|
19
26
|
readonly state: CapabilityState;
|
|
20
27
|
readonly attributes: JsonObject;
|
|
21
28
|
readonly isAvailable: boolean;
|
|
@@ -24,6 +31,79 @@ type EntityView = {
|
|
|
24
31
|
readonly deviceClass: string | null;
|
|
25
32
|
readonly displayPrecision: number | null;
|
|
26
33
|
};
|
|
34
|
+
/** A window of the past: between two moments (ISO 8601), or the last so many milliseconds. */
|
|
35
|
+
type HistoryWindow = {
|
|
36
|
+
readonly from: string;
|
|
37
|
+
readonly to: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly lastMs: number;
|
|
40
|
+
};
|
|
41
|
+
/** Which entities' past `useStateHistory` reads, over which window. Since 1.2. */
|
|
42
|
+
type HistoryQuery = {
|
|
43
|
+
/** At most 64. */
|
|
44
|
+
readonly entityIds: readonly EntityId[];
|
|
45
|
+
readonly window: HistoryWindow;
|
|
46
|
+
/** False holds the read back. */
|
|
47
|
+
readonly isEnabled?: boolean;
|
|
48
|
+
/** Reads it again every so often; a window of the last so many milliseconds moves with it. */
|
|
49
|
+
readonly refetchIntervalMs?: number;
|
|
50
|
+
};
|
|
51
|
+
/** Which entities' readings `useTelemetry` reads: `auto` picks the resolution by the window. */
|
|
52
|
+
type TelemetryQuery = HistoryQuery & {
|
|
53
|
+
readonly resolution?: TelemetryResolution | 'auto';
|
|
54
|
+
};
|
|
55
|
+
/** A read of the past, as it stands. */
|
|
56
|
+
type History<TPoint> = {
|
|
57
|
+
/** Each entity's points, oldest first; empty while it loads. */
|
|
58
|
+
readonly series: HistorySeries<TPoint>;
|
|
59
|
+
/** The window read, in milliseconds since the epoch; undefined before the first answer. */
|
|
60
|
+
readonly window: {
|
|
61
|
+
readonly from: number;
|
|
62
|
+
readonly to: number;
|
|
63
|
+
} | undefined;
|
|
64
|
+
/** The entities whose window held more than one read returns: their oldest points are gone. */
|
|
65
|
+
readonly truncated: readonly EntityId[];
|
|
66
|
+
readonly isLoading: boolean;
|
|
67
|
+
readonly error: Error | null;
|
|
68
|
+
/** Reads it again. */
|
|
69
|
+
readonly refetch: () => void;
|
|
70
|
+
};
|
|
71
|
+
/** A read of readings, and the resolution it was read at. */
|
|
72
|
+
type Telemetry = History<TelemetryPoint> & {
|
|
73
|
+
readonly resolution: TelemetryResolution;
|
|
74
|
+
};
|
|
75
|
+
/** What kind of place an area is. */
|
|
76
|
+
type AreaKind = 'house' | 'floor' | 'room';
|
|
77
|
+
/** One area of the house: the house itself, a floor, a room. Since 1.2. */
|
|
78
|
+
type AreaView = {
|
|
79
|
+
/** What `EntityView.areaId` names it by. */
|
|
80
|
+
readonly key: string;
|
|
81
|
+
readonly name: string;
|
|
82
|
+
readonly kind: AreaKind;
|
|
83
|
+
/** The floor a room is on, the house a floor is in; null for the house. */
|
|
84
|
+
readonly parentKey: string | null;
|
|
85
|
+
readonly icon: string | null;
|
|
86
|
+
readonly sortOrder: number;
|
|
87
|
+
/** A floor's storey: 0 the ground floor, -1 the one below; null for the rest. */
|
|
88
|
+
readonly level: number | null;
|
|
89
|
+
/** The house's position, when the owner has set it; null for the rest. */
|
|
90
|
+
readonly latitude: number | null;
|
|
91
|
+
readonly longitude: number | null;
|
|
92
|
+
};
|
|
93
|
+
/** How a picture is fetched. */
|
|
94
|
+
type PictureOptions = {
|
|
95
|
+
/** A camera's still is fetched again this often; 15 seconds when not said, at least 2. */
|
|
96
|
+
readonly refreshMs?: number;
|
|
97
|
+
/** False holds it back. */
|
|
98
|
+
readonly isEnabled?: boolean;
|
|
99
|
+
};
|
|
100
|
+
/** A camera's latest still, or an image entity's picture, as an address an `<img>` shows. */
|
|
101
|
+
type EntityPicture = {
|
|
102
|
+
/** Null before there is one, or when the entity has none. */
|
|
103
|
+
readonly url: string | null;
|
|
104
|
+
readonly isLoading: boolean;
|
|
105
|
+
readonly error: Error | null;
|
|
106
|
+
};
|
|
27
107
|
/** Which entities `useEntities` reads. */
|
|
28
108
|
type EntitiesFilter = {
|
|
29
109
|
/** Whose: the package's own (the default), anyone's, or another package's by id. */
|
|
@@ -208,6 +288,14 @@ type UiHost = {
|
|
|
208
288
|
readonly useLocale: () => Locale;
|
|
209
289
|
/** Since 1.1. */
|
|
210
290
|
readonly useTranslation: () => Translation;
|
|
291
|
+
/** Since 1.2. */
|
|
292
|
+
readonly useStateHistory: (query: HistoryQuery) => History<StateHistoryPoint>;
|
|
293
|
+
/** Since 1.2. */
|
|
294
|
+
readonly useTelemetry: (query: TelemetryQuery) => Telemetry;
|
|
295
|
+
/** Since 1.2. */
|
|
296
|
+
readonly useAreas: () => readonly AreaView[];
|
|
297
|
+
/** Since 1.2. */
|
|
298
|
+
readonly useEntityPicture: (entityId: EntityId, options?: PictureOptions) => EntityPicture;
|
|
211
299
|
readonly useTheme: () => Theme;
|
|
212
300
|
readonly usePortalContainer: () => HTMLElement | null;
|
|
213
301
|
readonly usePackageRoute: () => PackageRoute;
|
|
@@ -306,6 +394,39 @@ export declare function useLocale(): Locale;
|
|
|
306
394
|
* @returns `t`, and the language it speaks.
|
|
307
395
|
*/
|
|
308
396
|
export declare function useTranslation(): Translation;
|
|
397
|
+
/**
|
|
398
|
+
* The recorded changes of some entities over a window, live as the window moves: what a chart of
|
|
399
|
+
* an on/off thing, an activity list or a replay of a day is drawn from. Read with the viewer's
|
|
400
|
+
* permissions: an entity they may not read has no points.
|
|
401
|
+
*
|
|
402
|
+
* @param query - Which entities (at most 64), which window, how often to read it again.
|
|
403
|
+
* @returns Each entity's changes, oldest first, and whether the read is still on its way.
|
|
404
|
+
*/
|
|
405
|
+
export declare function useStateHistory(query: HistoryQuery): History<StateHistoryPoint>;
|
|
406
|
+
/**
|
|
407
|
+
* The numeric readings of some entities over a window: what a sensor's chart is drawn from. A
|
|
408
|
+
* long window is read in buckets of a minute, an hour or a day, each with its lowest and highest.
|
|
409
|
+
*
|
|
410
|
+
* @param query - Which entities (at most 64), which window, which resolution (`auto` by default).
|
|
411
|
+
* @returns Each entity's readings, oldest first, and the resolution they were read at.
|
|
412
|
+
*/
|
|
413
|
+
export declare function useTelemetry(query: TelemetryQuery): Telemetry;
|
|
414
|
+
/**
|
|
415
|
+
* The areas of the house: the house itself (with its position, when set), its floors and its
|
|
416
|
+
* rooms, as the owner arranged them.
|
|
417
|
+
*
|
|
418
|
+
* @returns Them, in the owner's order.
|
|
419
|
+
*/
|
|
420
|
+
export declare function useAreas(): readonly AreaView[];
|
|
421
|
+
/**
|
|
422
|
+
* A camera's latest still, fetched again every so often, or an image entity's picture, fetched
|
|
423
|
+
* again when it changes: an address an `<img>` shows, let go of when a newer one replaces it.
|
|
424
|
+
*
|
|
425
|
+
* @param entityId - A `camera.*` or an `image.*` entity.
|
|
426
|
+
* @param options - How often a still is fetched again, and whether at all.
|
|
427
|
+
* @returns The address, or null before there is one.
|
|
428
|
+
*/
|
|
429
|
+
export declare function useEntityPicture(entityId: EntityId, options?: PictureOptions): EntityPicture;
|
|
309
430
|
/**
|
|
310
431
|
* The theme the interface draws in, for what draws its own colours: a canvas, a chart.
|
|
311
432
|
*
|
|
@@ -351,4 +472,4 @@ export declare function PackageLink(props: PackageLinkProps): ReactElement;
|
|
|
351
472
|
*/
|
|
352
473
|
export declare function PlatformLink(props: PlatformLinkProps): ReactElement;
|
|
353
474
|
//#endregion
|
|
354
|
-
export type { CardProps, CustomEntityState, EntitiesFilter, EntityView, EntityViewProps, Locale, Mutation, MutationOptions, PackageCall, PackageInfo, PackageLinkProps, PackageNavigate, PackageRoute, PackageSettings, PageProps, PlatformLinkProps, PlatformNavigate, PlatformTarget, PluralEnglish, RpcOptions, RpcState, SendCommand, SettingsPatch, Theme, Translate, Translation, TranslationValues, UiHost, Viewer, VisibleSettings };
|
|
475
|
+
export type { AreaKind, AreaView, CardProps, ChangeCause, CustomEntityState, EntitiesFilter, EntityPicture, EntityView, EntityViewProps, History, HistoryQuery, HistorySeries, HistoryWindow, Locale, Mutation, MutationOptions, PackageCall, PackageInfo, PackageLinkProps, PackageNavigate, PackageRoute, PackageSettings, PageProps, PictureOptions, PlatformLinkProps, PlatformNavigate, PlatformTarget, PluralEnglish, RpcOptions, RpcState, SendCommand, SettingsPatch, StateHistoryPoint, Telemetry, TelemetryPoint, TelemetryQuery, TelemetryResolution, Theme, Translate, Translation, TranslationValues, UiHost, Viewer, VisibleSettings };
|
package/dist/ui.js
CHANGED
|
@@ -173,6 +173,47 @@ function useTranslation() {
|
|
|
173
173
|
return lent === void 0 ? ENGLISH : lent();
|
|
174
174
|
}
|
|
175
175
|
/**
|
|
176
|
+
* The recorded changes of some entities over a window, live as the window moves: what a chart of
|
|
177
|
+
* an on/off thing, an activity list or a replay of a day is drawn from. Read with the viewer's
|
|
178
|
+
* permissions: an entity they may not read has no points.
|
|
179
|
+
*
|
|
180
|
+
* @param query - Which entities (at most 64), which window, how often to read it again.
|
|
181
|
+
* @returns Each entity's changes, oldest first, and whether the read is still on its way.
|
|
182
|
+
*/
|
|
183
|
+
function useStateHistory(query) {
|
|
184
|
+
return ui("useStateHistory", "1.2")(query);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* The numeric readings of some entities over a window: what a sensor's chart is drawn from. A
|
|
188
|
+
* long window is read in buckets of a minute, an hour or a day, each with its lowest and highest.
|
|
189
|
+
*
|
|
190
|
+
* @param query - Which entities (at most 64), which window, which resolution (`auto` by default).
|
|
191
|
+
* @returns Each entity's readings, oldest first, and the resolution they were read at.
|
|
192
|
+
*/
|
|
193
|
+
function useTelemetry(query) {
|
|
194
|
+
return ui("useTelemetry", "1.2")(query);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The areas of the house: the house itself (with its position, when set), its floors and its
|
|
198
|
+
* rooms, as the owner arranged them.
|
|
199
|
+
*
|
|
200
|
+
* @returns Them, in the owner's order.
|
|
201
|
+
*/
|
|
202
|
+
function useAreas() {
|
|
203
|
+
return ui("useAreas", "1.2")();
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* A camera's latest still, fetched again every so often, or an image entity's picture, fetched
|
|
207
|
+
* again when it changes: an address an `<img>` shows, let go of when a newer one replaces it.
|
|
208
|
+
*
|
|
209
|
+
* @param entityId - A `camera.*` or an `image.*` entity.
|
|
210
|
+
* @param options - How often a still is fetched again, and whether at all.
|
|
211
|
+
* @returns The address, or null before there is one.
|
|
212
|
+
*/
|
|
213
|
+
function useEntityPicture(entityId, options) {
|
|
214
|
+
return ui("useEntityPicture", "1.2")(entityId, options);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
176
217
|
* The theme the interface draws in, for what draws its own colours: a canvas, a chart.
|
|
177
218
|
*
|
|
178
219
|
* @returns Light or dark.
|
|
@@ -231,4 +272,4 @@ function PlatformLink(props) {
|
|
|
231
272
|
return createElement(ui("PlatformLink", "1.0"), props);
|
|
232
273
|
}
|
|
233
274
|
//#endregion
|
|
234
|
-
export { PackageLink, PlatformLink, useCommand, useCustomEntity, useEntities, useEntity, useLocale, usePackage, usePackageCall, usePackageMutation, usePackageNavigate, usePackageRoute, usePackageRpc, usePackageSettings, usePlatformNavigate, usePortalContainer, useTheme, useTranslation, useViewer };
|
|
275
|
+
export { PackageLink, PlatformLink, useAreas, useCommand, useCustomEntity, useEntities, useEntity, useEntityPicture, useLocale, usePackage, usePackageCall, usePackageMutation, usePackageNavigate, usePackageRoute, usePackageRpc, usePackageSettings, usePlatformNavigate, usePortalContainer, useStateHistory, useTelemetry, useTheme, useTranslation, useViewer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebulahome/package-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Write a NebulaHome package: declare it, build it, and run it on the platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"types": "./dist/ui.d.ts",
|
|
33
33
|
"default": "./dist/ui.js"
|
|
34
34
|
},
|
|
35
|
+
"./sun": {
|
|
36
|
+
"types": "./dist/sun.d.ts",
|
|
37
|
+
"default": "./dist/sun.js"
|
|
38
|
+
},
|
|
35
39
|
"./components": {
|
|
36
40
|
"types": "./dist/components.d.ts",
|
|
37
41
|
"default": "./dist/components.js"
|
|
@@ -96,10 +100,10 @@
|
|
|
96
100
|
"vitest": "^4.1.11",
|
|
97
101
|
"yaml": "^2.9.0",
|
|
98
102
|
"zod": "^4.5.4",
|
|
99
|
-
"@nebulahome/
|
|
100
|
-
"@nebulahome/tsconfig": "0.0.0",
|
|
103
|
+
"@nebulahome/eslint-config": "0.0.0",
|
|
101
104
|
"@nebulahome/ui": "0.0.0",
|
|
102
|
-
"@nebulahome/
|
|
105
|
+
"@nebulahome/tsconfig": "0.0.0",
|
|
106
|
+
"@nebulahome/contracts": "0.0.0"
|
|
103
107
|
},
|
|
104
108
|
"scripts": {
|
|
105
109
|
"build": "tsdown && node scripts/build-styles.js",
|