preact-homeassistant 0.1.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/LICENSE +21 -0
- package/README.md +250 -0
- package/dist/index.d.ts +276 -0
- package/dist/index.js +459 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
- package/src/HAContext.tsx +407 -0
- package/src/__tests__/cacheUtils.test.ts +61 -0
- package/src/__tests__/registerPreactCard.test.tsx +213 -0
- package/src/__tests__/setup.ts +27 -0
- package/src/__tests__/testHelpers.tsx +73 -0
- package/src/__tests__/useCachedFetch.test.tsx +147 -0
- package/src/__tests__/useEntity.test.tsx +140 -0
- package/src/__tests__/useMultiCalendarEvents.test.tsx +217 -0
- package/src/__tests__/useWeatherForecast.test.tsx +197 -0
- package/src/cacheUtils.ts +32 -0
- package/src/index.ts +27 -0
- package/src/registerPreactCard.tsx +191 -0
- package/src/styleRegistry.ts +31 -0
- package/src/types/calendar.ts +40 -0
- package/src/types/common.ts +23 -0
- package/src/types/index.ts +38 -0
- package/src/types/sun.ts +20 -0
- package/src/types/weather.ts +42 -0
- package/src/useCallbackStable.ts +24 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stu Kabakoff
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# preact-homeassistant
|
|
2
|
+
|
|
3
|
+
Preact hooks and helpers for building Home Assistant custom cards. Handles the
|
|
4
|
+
web-component lifecycle, Shadow DOM, entity subscriptions, and data fetching so
|
|
5
|
+
you can focus on your card's UI.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add preact preact-homeassistant
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`preact` is a peer dependency.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { registerPreactCard, useEntity, css } from 'preact-homeassistant';
|
|
19
|
+
|
|
20
|
+
css`
|
|
21
|
+
.my-card { padding: 16px; }
|
|
22
|
+
.my-card .temperature { font-size: 2em; }
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
function MyCardContent({ config }: { config: { entity: string } }) {
|
|
26
|
+
const weather = useEntity(config.entity);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<ha-card>
|
|
30
|
+
<div class="card-content my-card">
|
|
31
|
+
<span class="temperature">{weather?.state ?? '...'}</span>
|
|
32
|
+
</div>
|
|
33
|
+
</ha-card>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function MyCardEditor({ hass, config, onConfigChanged }) {
|
|
38
|
+
const entities = Object.keys(hass.states).filter((e) => e.startsWith('weather.'));
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div style={{ padding: '16px' }}>
|
|
42
|
+
<ha-select
|
|
43
|
+
label="Weather entity"
|
|
44
|
+
value={config.entity}
|
|
45
|
+
naturalMenuWidth
|
|
46
|
+
fixedMenuPosition
|
|
47
|
+
onChange={(e) => onConfigChanged({ ...config, entity: (e.target as HTMLSelectElement).value })}
|
|
48
|
+
onclosed={(e) => e.stopPropagation()}
|
|
49
|
+
>
|
|
50
|
+
{entities.map((id) => (
|
|
51
|
+
<ha-list-item key={id} value={id}>
|
|
52
|
+
{hass.states[id]?.attributes?.friendly_name ?? id}
|
|
53
|
+
</ha-list-item>
|
|
54
|
+
))}
|
|
55
|
+
</ha-select>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
registerPreactCard({
|
|
61
|
+
type: 'my-weather-card',
|
|
62
|
+
name: 'My Weather Card',
|
|
63
|
+
description: 'A simple weather card',
|
|
64
|
+
Component: MyCardContent,
|
|
65
|
+
ConfigComponent: MyCardEditor,
|
|
66
|
+
getStubConfig: () => ({ entity: '' }),
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
That's it. `registerPreactCard` creates the web component, registers the custom
|
|
71
|
+
element with Home Assistant, sets up Shadow DOM, injects registered styles, and
|
|
72
|
+
wraps your component in the data provider. Your component receives `config` as a
|
|
73
|
+
prop and uses hooks for everything else.
|
|
74
|
+
|
|
75
|
+
## `registerPreactCard(options)`
|
|
76
|
+
|
|
77
|
+
| Option | Type | Required | Description |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| `type` | `string` | Yes | Custom element tag name (e.g. `'my-weather-card'`) |
|
|
80
|
+
| `name` | `string` | Yes | Display name in the HA card picker |
|
|
81
|
+
| `description` | `string` | Yes | Description in the HA card picker |
|
|
82
|
+
| `Component` | `ComponentType<{ config: T }>` | Yes | Main card Preact component |
|
|
83
|
+
| `ConfigComponent` | `ComponentType<{ hass, config, onConfigChanged }>` | No | Visual editor. Receives `hass`, the current `config`, and an `onConfigChanged` callback. Registered as `${type}-editor`. |
|
|
84
|
+
| `UnconfiguredComponent` | `ComponentType<{}>` | No | Shown before config/hass are available |
|
|
85
|
+
| `getStubConfig` | `() => Partial<T>` | No | Default config for the card picker |
|
|
86
|
+
|
|
87
|
+
The card renders into a Shadow DOM root. The editor renders into the light DOM
|
|
88
|
+
(required for HA's own custom elements like `<ha-select>` to work).
|
|
89
|
+
|
|
90
|
+
## Hooks
|
|
91
|
+
|
|
92
|
+
### `useEntity(entityId)`
|
|
93
|
+
|
|
94
|
+
Subscribe to a specific entity. Only re-renders when that entity's state changes.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
const sensor = useEntity('sensor.temperature');
|
|
98
|
+
// sensor?.state === '72'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Returns a strict type based on the domain prefix:
|
|
102
|
+
- `'calendar.*'` → `CalendarEntity`
|
|
103
|
+
- `'weather.*'` → `WeatherEntity`
|
|
104
|
+
- `'sun.sun'` → `SunEntity`
|
|
105
|
+
- Other domains → `HassEntity` (the loose type from `home-assistant-js-websocket`)
|
|
106
|
+
|
|
107
|
+
The mapping comes from the `DomainEntityMap` interface. To add a new domain,
|
|
108
|
+
see the *Contributing types* section below.
|
|
109
|
+
|
|
110
|
+
### `useHass()`
|
|
111
|
+
|
|
112
|
+
Access the full `hass` object for calling services or reading config. Does not
|
|
113
|
+
re-render on entity changes.
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
const { getHass } = useHass();
|
|
117
|
+
await getHass()?.callService('light', 'turn_on', { entity_id: 'light.bedroom' });
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `useCalendarEvents(entityId, { start, end })`
|
|
121
|
+
|
|
122
|
+
Fetch calendar events for a date range from a single calendar.
|
|
123
|
+
|
|
124
|
+
### `useMultiCalendarEvents(entityIds, { start, end })`
|
|
125
|
+
|
|
126
|
+
Fetch events from multiple calendars. Events are returned with `calendarId`
|
|
127
|
+
attached. Caches to localStorage and debounce-refetches when entities change.
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
const { events, status, error, refetch } = useMultiCalendarEvents(
|
|
131
|
+
['calendar.family', 'calendar.work'],
|
|
132
|
+
{ start, end },
|
|
133
|
+
);
|
|
134
|
+
// status: 'loading' | 'cached' | 'ready' | 'refreshing'
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `useWeatherForecast(entityId, type)`
|
|
138
|
+
|
|
139
|
+
Fetch weather forecast data. Caches to localStorage, debounce-refetches on
|
|
140
|
+
entity changes, and auto-refetches at the top of each hour.
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
const { forecast, status, error, refetch } = useWeatherForecast('weather.home', 'hourly');
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `useCachedFetch(cacheKey, fetcher, deps)`
|
|
147
|
+
|
|
148
|
+
Generic hook for fetching data with localStorage caching. The domain-specific
|
|
149
|
+
hooks above are built on this.
|
|
150
|
+
|
|
151
|
+
## Styles
|
|
152
|
+
|
|
153
|
+
Styles are registered globally via the `css\`\`` tagged template and
|
|
154
|
+
auto-injected into each card's Shadow DOM by `registerPreactCard`. Use
|
|
155
|
+
`.styles.ts` files imported as side effects.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
// MyCard.styles.ts
|
|
159
|
+
import { css } from 'preact-homeassistant';
|
|
160
|
+
|
|
161
|
+
css`
|
|
162
|
+
.my-card { padding: 16px; }
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
// MyCard.tsx
|
|
166
|
+
import './MyCard.styles'; // registers styles on import
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `registerRawStyles(cssString)`
|
|
170
|
+
|
|
171
|
+
Register a raw CSS string, e.g. from a Vite `?inline` import.
|
|
172
|
+
|
|
173
|
+
## Cache utilities
|
|
174
|
+
|
|
175
|
+
`loadFromCache(key)` / `saveToCache(key, data)` — localStorage wrapper with
|
|
176
|
+
24-hour expiry. Used internally by the data hooks.
|
|
177
|
+
|
|
178
|
+
## Other utilities
|
|
179
|
+
|
|
180
|
+
### `useCallbackStable(fn)`
|
|
181
|
+
|
|
182
|
+
Returns a stable callback ref that always calls the latest `fn`. Avoids effect
|
|
183
|
+
re-runs while keeping the closure current.
|
|
184
|
+
|
|
185
|
+
## Types
|
|
186
|
+
|
|
187
|
+
All HA domain types live in [`src/types/`](src/types/):
|
|
188
|
+
|
|
189
|
+
- [`calendar.ts`](src/types/calendar.ts) — `CalendarEntity`, `CalendarEvent`, `CalendarEventWithSource`
|
|
190
|
+
- [`weather.ts`](src/types/weather.ts) — `WeatherEntity`, `WeatherForecast`, `ForecastType`
|
|
191
|
+
- [`sun.ts`](src/types/sun.ts) — `SunEntity`
|
|
192
|
+
- [`common.ts`](src/types/common.ts) — `HomeAssistant`, `FetchStatus`
|
|
193
|
+
- [`index.ts`](src/types/index.ts) — `DomainEntityMap`, `EntityForId<T>`
|
|
194
|
+
|
|
195
|
+
Re-exported from the package root:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import type {
|
|
199
|
+
HomeAssistant,
|
|
200
|
+
CalendarEntity,
|
|
201
|
+
WeatherEntity,
|
|
202
|
+
SunEntity,
|
|
203
|
+
WeatherForecast,
|
|
204
|
+
EntityForId,
|
|
205
|
+
/* ... */
|
|
206
|
+
} from 'preact-homeassistant';
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Contributing types
|
|
210
|
+
|
|
211
|
+
The HA domain types in this package are intentionally minimal — only the
|
|
212
|
+
domains the maintainers have actually needed. If your card needs strict types
|
|
213
|
+
for another domain (light, climate, media_player, cover, etc.), PRs are very
|
|
214
|
+
welcome.
|
|
215
|
+
|
|
216
|
+
1. Look up the domain in the [Home Assistant frontend repo](https://github.com/home-assistant/frontend/tree/dev/src/data) — most domains have a `data/<domain>.ts` file with TypeScript types.
|
|
217
|
+
2. Add `src/types/<domain>.ts` mirroring the fields your card needs. Extend `HassEntityBase` and `HassEntityAttributeBase` from `home-assistant-js-websocket`.
|
|
218
|
+
3. Add the entity to `DomainEntityMap` in [`src/types/index.ts`](src/types/index.ts) and re-export the types.
|
|
219
|
+
4. Add a quick test under `src/__tests__/` if you're feeling thorough.
|
|
220
|
+
5. PR.
|
|
221
|
+
|
|
222
|
+
We err toward including only fields that are well-documented; speculative
|
|
223
|
+
attributes can land later.
|
|
224
|
+
|
|
225
|
+
## Development
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
pnpm install
|
|
229
|
+
pnpm test # vitest run
|
|
230
|
+
pnpm build # tsc --noEmit && vite build
|
|
231
|
+
pnpm lint # biome check
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Publishing
|
|
235
|
+
|
|
236
|
+
Releases are published to npm manually from a local machine (no CI publish):
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
pnpm test && pnpm build && pnpm typecheck
|
|
240
|
+
git tag v0.X.Y && git push origin v0.X.Y
|
|
241
|
+
pnpm publish --access public --provenance
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
The `--provenance` flag attaches SLSA build attestation. A GitHub release with
|
|
245
|
+
release notes + the packaged tarball is created automatically when the tag is
|
|
246
|
+
pushed (see [`.github/workflows/release.yml`](.github/workflows/release.yml)).
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { ComponentChildren } from 'preact';
|
|
2
|
+
import { ComponentType } from 'preact';
|
|
3
|
+
import { Connection } from 'home-assistant-js-websocket';
|
|
4
|
+
import { HassConfig } from 'home-assistant-js-websocket';
|
|
5
|
+
import { HassEntities } from 'home-assistant-js-websocket';
|
|
6
|
+
import { HassEntity } from 'home-assistant-js-websocket';
|
|
7
|
+
import { HassEntityAttributeBase } from 'home-assistant-js-websocket';
|
|
8
|
+
import { HassEntityBase } from 'home-assistant-js-websocket';
|
|
9
|
+
import { HassServices } from 'home-assistant-js-websocket';
|
|
10
|
+
import { JSX } from 'preact';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Calendar entity - only exposes the current/next event.
|
|
14
|
+
* Use useCalendarEvents() to fetch a list of events.
|
|
15
|
+
*/
|
|
16
|
+
export declare interface CalendarEntity extends HassEntityBase {
|
|
17
|
+
entity_id: `calendar.${string}`;
|
|
18
|
+
state: 'on' | 'off' | 'unavailable' | 'unknown';
|
|
19
|
+
attributes: HassEntityAttributeBase & {
|
|
20
|
+
message?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
start_time?: string;
|
|
23
|
+
end_time?: string;
|
|
24
|
+
location?: string;
|
|
25
|
+
all_day?: boolean;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Calendar event returned by the calendar/get_events websocket call.
|
|
31
|
+
*/
|
|
32
|
+
export declare interface CalendarEvent {
|
|
33
|
+
start: string;
|
|
34
|
+
end: string;
|
|
35
|
+
summary: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
location?: string;
|
|
38
|
+
uid?: string;
|
|
39
|
+
recurrence_id?: string;
|
|
40
|
+
rrule?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Calendar event with its source calendar entity ID attached. Used by
|
|
45
|
+
* useMultiCalendarEvents() to disambiguate events from multiple calendars.
|
|
46
|
+
*/
|
|
47
|
+
export declare interface CalendarEventWithSource extends CalendarEvent {
|
|
48
|
+
calendarId: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* CSS tagged template literal for syntax highlighting.
|
|
53
|
+
* Automatically registers the styles with the global registry.
|
|
54
|
+
*/
|
|
55
|
+
export declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Map of known HA domains to their strict entity types. Contributors adding
|
|
59
|
+
* new domain types should add a new file under `src/types/` and extend this map.
|
|
60
|
+
*/
|
|
61
|
+
export declare interface DomainEntityMap {
|
|
62
|
+
calendar: CalendarEntity;
|
|
63
|
+
weather: WeatherEntity;
|
|
64
|
+
sun: SunEntity;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Infers the strict entity type from an entity ID literal type.
|
|
69
|
+
*
|
|
70
|
+
* EntityForId<'calendar.family'> -> CalendarEntity
|
|
71
|
+
* EntityForId<'weather.home'> -> WeatherEntity
|
|
72
|
+
* EntityForId<'sensor.foo'> -> HassEntity (fallback)
|
|
73
|
+
*/
|
|
74
|
+
export declare type EntityForId<T extends string> = T extends `${infer D}.${string}` ? D extends KnownDomain ? DomainEntityMap[D] : HassEntity : HassEntity;
|
|
75
|
+
|
|
76
|
+
export declare type FetchStatus = 'loading' | 'cached' | 'ready' | 'refreshing';
|
|
77
|
+
|
|
78
|
+
export declare type ForecastType = 'daily' | 'hourly' | 'twice_daily';
|
|
79
|
+
|
|
80
|
+
export declare function HAProvider({ hass, subscribeToEntity, children }: HAProviderProps): JSX.Element;
|
|
81
|
+
|
|
82
|
+
declare interface HAProviderProps {
|
|
83
|
+
hass: HomeAssistant | undefined;
|
|
84
|
+
subscribeToEntity: (entityId: string, callback: (entity: any) => void) => () => void;
|
|
85
|
+
children: ComponentChildren;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Subset of the Home Assistant `hass` object passed to custom cards.
|
|
90
|
+
*/
|
|
91
|
+
export declare interface HomeAssistant {
|
|
92
|
+
states: HassEntities;
|
|
93
|
+
config: HassConfig;
|
|
94
|
+
services: HassServices;
|
|
95
|
+
connection: Connection;
|
|
96
|
+
callService: (domain: string, service: string, data?: object) => Promise<void>;
|
|
97
|
+
themes?: {
|
|
98
|
+
darkMode?: boolean;
|
|
99
|
+
theme?: string;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
declare type KnownDomain = keyof DomainEntityMap;
|
|
104
|
+
|
|
105
|
+
export declare function loadFromCache<T>(key: string): T | undefined;
|
|
106
|
+
|
|
107
|
+
export declare function registerPreactCard<TConfig>(options: RegisterPreactCardOptions<TConfig>): void;
|
|
108
|
+
|
|
109
|
+
declare interface RegisterPreactCardOptions<TConfig> {
|
|
110
|
+
type: string;
|
|
111
|
+
name: string;
|
|
112
|
+
description: string;
|
|
113
|
+
Component: ComponentType<{
|
|
114
|
+
config: TConfig;
|
|
115
|
+
}>;
|
|
116
|
+
ConfigComponent?: ComponentType<{
|
|
117
|
+
hass: HomeAssistant;
|
|
118
|
+
config: TConfig;
|
|
119
|
+
onConfigChanged: (config: TConfig) => void;
|
|
120
|
+
}>;
|
|
121
|
+
UnconfiguredComponent?: ComponentType<{}>;
|
|
122
|
+
getStubConfig?: () => Partial<TConfig>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Register raw CSS string (e.g., from ?inline imports).
|
|
127
|
+
* Only registers if not already present.
|
|
128
|
+
*/
|
|
129
|
+
export declare function registerRawStyles(styles: string): void;
|
|
130
|
+
|
|
131
|
+
export declare function saveToCache<T>(key: string, data: T): void;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Sun entity - provides sunrise/sunset and elevation information.
|
|
135
|
+
*/
|
|
136
|
+
export declare interface SunEntity extends HassEntityBase {
|
|
137
|
+
entity_id: 'sun.sun';
|
|
138
|
+
state: 'above_horizon' | 'below_horizon';
|
|
139
|
+
attributes: HassEntityAttributeBase & {
|
|
140
|
+
next_dawn?: string;
|
|
141
|
+
next_dusk?: string;
|
|
142
|
+
next_midnight?: string;
|
|
143
|
+
next_noon?: string;
|
|
144
|
+
next_rising?: string;
|
|
145
|
+
next_setting?: string;
|
|
146
|
+
elevation?: number;
|
|
147
|
+
azimuth?: number;
|
|
148
|
+
rising?: boolean;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Generic hook for fetching data with localStorage caching. Returns a cache-aware
|
|
154
|
+
* status string to distinguish cached vs fresh data.
|
|
155
|
+
*/
|
|
156
|
+
export declare function useCachedFetch<T>(cacheKey: string, fetcher: () => Promise<T>, deps: unknown[]): UseCachedFetchResult<T>;
|
|
157
|
+
|
|
158
|
+
declare interface UseCachedFetchResult<T> {
|
|
159
|
+
data: T | undefined;
|
|
160
|
+
status: FetchStatus;
|
|
161
|
+
error: Error | undefined;
|
|
162
|
+
refetch: () => void;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Fetch calendar events for a date range from a single calendar.
|
|
167
|
+
*/
|
|
168
|
+
export declare function useCalendarEvents(entityId: `calendar.${string}`, options: {
|
|
169
|
+
start: Date;
|
|
170
|
+
end: Date;
|
|
171
|
+
}): UseCalendarEventsResult;
|
|
172
|
+
|
|
173
|
+
declare interface UseCalendarEventsResult {
|
|
174
|
+
events: CalendarEvent[] | undefined;
|
|
175
|
+
loading: boolean;
|
|
176
|
+
error: Error | undefined;
|
|
177
|
+
refetch: () => void;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creates a stable callback reference that always calls the latest version of the callback.
|
|
182
|
+
* Unlike useCallback, this never changes identity, so it won't cause re-renders in children.
|
|
183
|
+
*
|
|
184
|
+
* @param callback The callback function to stabilize
|
|
185
|
+
* @returns A stable function reference that always calls the latest callback
|
|
186
|
+
*/
|
|
187
|
+
export declare function useCallbackStable<T extends (...args: never[]) => unknown>(callback: T): T;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Subscribe to a specific entity by ID. Re-renders only when that entity changes.
|
|
191
|
+
*
|
|
192
|
+
* Returns a typed entity based on the domain prefix:
|
|
193
|
+
* - 'calendar.xyz' -> CalendarEntity
|
|
194
|
+
* - 'weather.xyz' -> WeatherEntity
|
|
195
|
+
* - 'sun.sun' -> SunEntity
|
|
196
|
+
* - other domains -> HassEntity (fallback)
|
|
197
|
+
*/
|
|
198
|
+
export declare function useEntity<T extends string>(entityId: T): EntityForId<T> | undefined;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get access to the full hass object for calling services / accessing config.
|
|
202
|
+
* Does NOT re-render on entity changes. Use useEntity for that.
|
|
203
|
+
*/
|
|
204
|
+
export declare function useHass(): {
|
|
205
|
+
getHass: () => HomeAssistant | undefined;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Fetch events from multiple calendars for a date range, with localStorage
|
|
210
|
+
* caching. Events are tagged with their source calendar ID.
|
|
211
|
+
*/
|
|
212
|
+
export declare function useMultiCalendarEvents(entityIds: `calendar.${string}`[], options: {
|
|
213
|
+
start: Date;
|
|
214
|
+
end: Date;
|
|
215
|
+
}): UseMultiCalendarEventsResult;
|
|
216
|
+
|
|
217
|
+
declare interface UseMultiCalendarEventsResult {
|
|
218
|
+
events: CalendarEventWithSource[] | undefined;
|
|
219
|
+
status: FetchStatus;
|
|
220
|
+
error: Error | undefined;
|
|
221
|
+
refetch: () => void;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Fetch weather forecast data with localStorage caching. Auto-refetches at the
|
|
226
|
+
* top of each hour and when the underlying entity changes (debounced).
|
|
227
|
+
*/
|
|
228
|
+
export declare function useWeatherForecast(entityId: `weather.${string}`, type: ForecastType): UseWeatherForecastResult;
|
|
229
|
+
|
|
230
|
+
declare interface UseWeatherForecastResult {
|
|
231
|
+
forecast: WeatherForecast[] | undefined;
|
|
232
|
+
status: FetchStatus;
|
|
233
|
+
error: Error | undefined;
|
|
234
|
+
refetch: () => void;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Weather entity - current conditions only.
|
|
239
|
+
* Use useWeatherForecast() to fetch forecast data.
|
|
240
|
+
*/
|
|
241
|
+
export declare interface WeatherEntity extends HassEntityBase {
|
|
242
|
+
entity_id: `weather.${string}`;
|
|
243
|
+
state: string;
|
|
244
|
+
attributes: HassEntityAttributeBase & {
|
|
245
|
+
temperature?: number;
|
|
246
|
+
apparent_temperature?: number;
|
|
247
|
+
dew_point?: number;
|
|
248
|
+
humidity?: number;
|
|
249
|
+
pressure?: number;
|
|
250
|
+
wind_speed?: number;
|
|
251
|
+
wind_gust_speed?: number;
|
|
252
|
+
wind_bearing?: number;
|
|
253
|
+
visibility?: number;
|
|
254
|
+
supported_features?: number;
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Weather forecast item returned by the weather/get_forecasts websocket call.
|
|
260
|
+
*/
|
|
261
|
+
export declare interface WeatherForecast {
|
|
262
|
+
datetime: string;
|
|
263
|
+
condition?: string;
|
|
264
|
+
temperature?: number;
|
|
265
|
+
templow?: number;
|
|
266
|
+
precipitation_probability?: number;
|
|
267
|
+
precipitation?: number;
|
|
268
|
+
humidity?: number;
|
|
269
|
+
wind_speed?: number;
|
|
270
|
+
wind_bearing?: number;
|
|
271
|
+
cloud_coverage?: number;
|
|
272
|
+
uv_index?: number;
|
|
273
|
+
is_daytime?: boolean;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export { }
|