@khalido/home 0.0.0-stage → 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/.env.example +25 -0
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +77 -2
- package/dist/clock.d.ts +17 -0
- package/dist/clock.js +43 -0
- package/dist/config.d.ts +273 -0
- package/dist/config.js +392 -0
- package/dist/connector.d.ts +34 -0
- package/dist/connector.js +47 -0
- package/dist/connectors/amber/client.d.ts +61 -0
- package/dist/connectors/amber/client.js +106 -0
- package/dist/connectors/amber/index.d.ts +30 -0
- package/dist/connectors/amber/index.js +94 -0
- package/dist/connectors/cast/codec.d.ts +38 -0
- package/dist/connectors/cast/codec.js +102 -0
- package/dist/connectors/cast/index.d.ts +60 -0
- package/dist/connectors/cast/index.js +426 -0
- package/dist/connectors/cast/schemas.d.ts +167 -0
- package/dist/connectors/cast/schemas.js +87 -0
- package/dist/connectors/cast/serve.d.ts +11 -0
- package/dist/connectors/cast/serve.js +57 -0
- package/dist/connectors/cast/state.d.ts +62 -0
- package/dist/connectors/cast/state.js +133 -0
- package/dist/connectors/cast/tls.d.ts +3 -0
- package/dist/connectors/cast/tls.js +67 -0
- package/dist/connectors/cast/writes.d.ts +80 -0
- package/dist/connectors/cast/writes.js +390 -0
- package/dist/connectors/daikin/client.d.ts +65 -0
- package/dist/connectors/daikin/client.js +221 -0
- package/dist/connectors/daikin/index.d.ts +41 -0
- package/dist/connectors/daikin/index.js +108 -0
- package/dist/connectors/enphase/client.d.ts +65 -0
- package/dist/connectors/enphase/client.js +173 -0
- package/dist/connectors/enphase/index.d.ts +43 -0
- package/dist/connectors/enphase/index.js +174 -0
- package/dist/connectors/enphase/schemas.d.ts +51 -0
- package/dist/connectors/enphase/schemas.js +34 -0
- package/dist/connectors/hue/client.d.ts +48 -0
- package/dist/connectors/hue/client.js +95 -0
- package/dist/connectors/hue/events.d.ts +41 -0
- package/dist/connectors/hue/events.js +156 -0
- package/dist/connectors/hue/index.d.ts +42 -0
- package/dist/connectors/hue/index.js +205 -0
- package/dist/connectors/hue/schemas.d.ts +65 -0
- package/dist/connectors/hue/schemas.js +48 -0
- package/dist/connectors/hue/state.d.ts +43 -0
- package/dist/connectors/hue/state.js +84 -0
- package/dist/connectors/printers/client.d.ts +28 -0
- package/dist/connectors/printers/client.js +74 -0
- package/dist/connectors/printers/codec.d.ts +76 -0
- package/dist/connectors/printers/codec.js +246 -0
- package/dist/connectors/printers/found.d.ts +15 -0
- package/dist/connectors/printers/found.js +35 -0
- package/dist/connectors/printers/index.d.ts +52 -0
- package/dist/connectors/printers/index.js +282 -0
- package/dist/connectors/printers/state.d.ts +60 -0
- package/dist/connectors/printers/state.js +99 -0
- package/dist/connectors/spotify/changes.d.ts +32 -0
- package/dist/connectors/spotify/changes.js +84 -0
- package/dist/connectors/spotify/client.d.ts +199 -0
- package/dist/connectors/spotify/client.js +270 -0
- package/dist/connectors/spotify/index.d.ts +92 -0
- package/dist/connectors/spotify/index.js +745 -0
- package/dist/connectors/up/client.d.ts +183 -0
- package/dist/connectors/up/client.js +308 -0
- package/dist/connectors/up/index.d.ts +91 -0
- package/dist/connectors/up/index.js +213 -0
- package/dist/connectors/up/spend.d.ts +78 -0
- package/dist/connectors/up/spend.js +213 -0
- package/dist/connectors/up/webhook.d.ts +13 -0
- package/dist/connectors/up/webhook.js +32 -0
- package/dist/connectors/weather/blocks.d.ts +51 -0
- package/dist/connectors/weather/blocks.js +106 -0
- package/dist/connectors/weather/bom.d.ts +37 -0
- package/dist/connectors/weather/bom.js +237 -0
- package/dist/connectors/weather/ftp.d.ts +5 -0
- package/dist/connectors/weather/ftp.js +46 -0
- package/dist/connectors/weather/google.d.ts +31 -0
- package/dist/connectors/weather/google.js +364 -0
- package/dist/connectors/weather/index.d.ts +53 -0
- package/dist/connectors/weather/index.js +267 -0
- package/dist/connectors/weather/open-meteo.d.ts +15 -0
- package/dist/connectors/weather/open-meteo.js +285 -0
- package/dist/connectors/weather/rain.d.ts +19 -0
- package/dist/connectors/weather/rain.js +51 -0
- package/dist/connectors/weather/source.d.ts +149 -0
- package/dist/connectors/weather/source.js +77 -0
- package/dist/connectors/weather/sun.d.ts +48 -0
- package/dist/connectors/weather/sun.js +65 -0
- package/dist/discover.d.ts +195 -0
- package/dist/discover.js +446 -0
- package/dist/energy.d.ts +61 -0
- package/dist/energy.js +162 -0
- package/dist/finders-entry.d.ts +1 -0
- package/dist/finders-entry.js +2 -0
- package/dist/finders.d.ts +45 -0
- package/dist/finders.js +173 -0
- package/dist/health.d.ts +28 -0
- package/dist/health.js +35 -0
- package/dist/home.d.ts +81 -0
- package/dist/home.js +114 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/lane.d.ts +17 -0
- package/dist/lane.js +74 -0
- package/dist/locate.d.ts +27 -0
- package/dist/locate.js +59 -0
- package/dist/manifest.d.ts +31 -0
- package/dist/manifest.js +4 -0
- package/dist/manifests.d.ts +5 -0
- package/dist/manifests.js +23 -0
- package/dist/node-fetch.d.ts +9 -0
- package/dist/node-fetch.js +25 -0
- package/dist/poll.d.ts +10 -0
- package/dist/poll.js +33 -0
- package/docs/cast.md +133 -0
- package/docs/cli.md +39 -0
- package/docs/config.md +36 -0
- package/docs/decisions.md +150 -0
- package/docs/devices.md +128 -0
- package/docs/enphase-notes.md +24 -0
- package/docs/google.md +92 -0
- package/docs/ideas.md +69 -0
- package/docs/matter.md +55 -0
- package/docs/performance.md +12 -0
- package/docs/philosophy.md +23 -0
- package/docs/up.md +84 -0
- package/docs/using.md +65 -0
- package/docs/weather-probe.md +63 -0
- package/examples/home.jsonc +74 -0
- package/examples/home.svg +76 -0
- package/home.schema.json +474 -0
- package/llms.txt +32 -0
- package/package.json +143 -4
- package/skills/draw-home/README.md +26 -0
- package/skills/draw-home/SKILL.md +82 -0
- package/skills/use-home/SKILL.md +86 -0
- package/src/cli/cache.ts +29 -0
- package/src/cli/cast.ts +172 -0
- package/src/cli/config.ts +52 -0
- package/src/cli/context.ts +118 -0
- package/src/cli/discover.ts +175 -0
- package/src/cli/enphase.ts +62 -0
- package/src/cli/hue.ts +124 -0
- package/src/cli/locate.ts +47 -0
- package/src/cli/main.ts +182 -0
- package/src/cli/printers.ts +21 -0
- package/src/cli/probe.ts +274 -0
- package/src/cli/spotify.ts +76 -0
- package/src/cli/status.ts +228 -0
- package/src/cli/up.ts +350 -0
- package/src/clock.ts +62 -0
- package/src/config.ts +578 -0
- package/src/connector.ts +77 -0
- package/src/connectors/amber/README.md +40 -0
- package/src/connectors/amber/client.ts +157 -0
- package/src/connectors/amber/index.ts +118 -0
- package/src/connectors/cast/README.md +43 -0
- package/src/connectors/cast/codec.ts +126 -0
- package/src/connectors/cast/index.ts +551 -0
- package/src/connectors/cast/schemas.ts +101 -0
- package/src/connectors/cast/serve.ts +72 -0
- package/src/connectors/cast/state.ts +203 -0
- package/src/connectors/cast/tls.ts +100 -0
- package/src/connectors/cast/writes.ts +572 -0
- package/src/connectors/daikin/README.md +78 -0
- package/src/connectors/daikin/client.ts +295 -0
- package/src/connectors/daikin/index.ts +145 -0
- package/src/connectors/enphase/README.md +64 -0
- package/src/connectors/enphase/client.ts +244 -0
- package/src/connectors/enphase/index.ts +241 -0
- package/src/connectors/enphase/schemas.ts +45 -0
- package/src/connectors/hue/README.md +50 -0
- package/src/connectors/hue/client.ts +157 -0
- package/src/connectors/hue/events.ts +182 -0
- package/src/connectors/hue/index.ts +261 -0
- package/src/connectors/hue/schemas.ts +60 -0
- package/src/connectors/hue/state.ts +124 -0
- package/src/connectors/printers/README.md +46 -0
- package/src/connectors/printers/client.ts +114 -0
- package/src/connectors/printers/codec.ts +292 -0
- package/src/connectors/printers/found.ts +46 -0
- package/src/connectors/printers/index.ts +385 -0
- package/src/connectors/printers/state.ts +182 -0
- package/src/connectors/spotify/README.md +80 -0
- package/src/connectors/spotify/changes.ts +127 -0
- package/src/connectors/spotify/client.ts +387 -0
- package/src/connectors/spotify/index.ts +929 -0
- package/src/connectors/up/README.md +35 -0
- package/src/connectors/up/client.ts +518 -0
- package/src/connectors/up/index.ts +370 -0
- package/src/connectors/up/spend.ts +280 -0
- package/src/connectors/up/webhook.ts +62 -0
- package/src/connectors/weather/README.md +84 -0
- package/src/connectors/weather/blocks.ts +173 -0
- package/src/connectors/weather/bom.ts +344 -0
- package/src/connectors/weather/ftp.ts +48 -0
- package/src/connectors/weather/google.ts +425 -0
- package/src/connectors/weather/index.ts +380 -0
- package/src/connectors/weather/open-meteo.ts +309 -0
- package/src/connectors/weather/rain.ts +73 -0
- package/src/connectors/weather/source.ts +236 -0
- package/src/connectors/weather/sun.ts +114 -0
- package/src/discover.ts +634 -0
- package/src/energy.ts +221 -0
- package/src/finders-entry.ts +2 -0
- package/src/finders.ts +247 -0
- package/src/health.ts +74 -0
- package/src/home.ts +205 -0
- package/src/index.ts +62 -0
- package/src/lane.ts +110 -0
- package/src/locate.ts +85 -0
- package/src/manifest.ts +43 -0
- package/src/manifests.ts +27 -0
- package/src/node-fetch.ts +41 -0
- package/src/poll.ts +33 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Weather probe, 2026-10-13
|
|
2
|
+
|
|
3
|
+
Build BOM from the anonymous FTP products, not the app API and not the website's HTTP paths. Open-Meteo owns `sky` and backs everything else; its BOM model is dead. Live probes from Sydney on 2026-10-13 around 20:00 AEDT, against Sydney CBD (-33.8688, 151.2093), curl 8.7.1 and Bun 1.4.2.
|
|
4
|
+
|
|
5
|
+
Two premises of the brief did not hold:
|
|
6
|
+
|
|
7
|
+
- **The app API has stated terms now.** Every response carries `"copyright": "This application programming interface (API) is owned by the Bureau of Meteorology. You must not use, copy or share it."`
|
|
8
|
+
- **The official feeds are not CC BY.** The catalogue says they "are free to access and are not for commercial use". The copyright page grants CC BY only where a page says so, and otherwise allows "personal use, or use within your organisation. You must not supply it to any other person". The product files point to that page. KO's home is personal use, so it is fine to read them. Committing real BOM files as test fixtures in a public repo is supplying them, so BOM fixtures should be invented values in the real shape.
|
|
9
|
+
|
|
10
|
+
## What answered
|
|
11
|
+
|
|
12
|
+
| Path | Result | User agent |
|
|
13
|
+
| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
14
|
+
| App API `api.weather.bom.gov.au/v1/locations/r3gx2f/observations`, `/forecasts/daily`, `/forecasts/hourly`, `?search=` | 200, 25–80 ms, `cache-control: max-age≈100` | Bun's default `Bun/1.4.2` gets no answer at all (10 s timeout, not a 403). `Bun`, `curl/8.7.1`, `home/0.1`, empty and browser UAs all get 200. |
|
|
15
|
+
| `www.bom.gov.au/fwo/IDN60901/IDN60901.94768.json` (station JSON) and `/fwo/IDN11060.xml` (NSW precis) | 403 for curl, `home/0.1` and Bun; 200 for empty or browser UA | The 403 body: "The Bureau of Meteorology website does not support web scraping: if you are trying to access Bureau data through automated means, you should stop." It names anonymous FTP as the channel. |
|
|
16
|
+
| `reg.bom.gov.au/fwo/...` (same files) | 200 for every UA, no auth | This is the Registered User host: the block page links it for paid services ($1,282/yr FTP registration). Serving unauthenticated looks like a gap, not permission. Ignores `If-None-Match` (200, not 304). |
|
|
17
|
+
| FTP `ftp://ftp.bom.gov.au/anon/gen/fwo/` | 226, 0.8–1.0 s per file | Any UA. Station JSON is **not** on FTP (550). |
|
|
18
|
+
| Open-Meteo `api.open-meteo.com/v1/forecast` | 200, 1.3 s every time (TLS to a German origin: 0.32 s connect, 0.95 s TLS) | Bun default UA fine. |
|
|
19
|
+
| Open-Meteo `models=bom_access_global` | 200 but every value `null`; `/v1/bom` the same | Its metadata says `data_end_time` 2025-06-30. The docs page: "BOM is currently upgrading its key platforms and services. During this process, open-data delivery has been temporarily suspended." Do not pass `models`; the default `best_match` answered. |
|
|
20
|
+
|
|
21
|
+
Bun's `fetch` refuses FTP (measured: `TypeError: protocol must be http:, https: or s3:`).
|
|
22
|
+
|
|
23
|
+
## The FTP products
|
|
24
|
+
|
|
25
|
+
- **Observations: `IDN60920.xml`** (562 KB, all NSW stations). Observatory Hill (WMO 94768) has air and apparent temperature, humidity, wind direction, speed and degrees, gust when present, rain since 9am (`rainfall`, with its own start and end time), running max and min. Every station has `lat`/`lon` to 4 decimals and a `forecast-district-id`, so the nearest station comes from the file itself, with distance, from latitude and longitude alone. Other states: `IDV60920`, `IDQ60920`, and so on.
|
|
26
|
+
- **Forecast: `IDN10064.xml`** (19 KB, Sydney metro: Sydney, Penrith, Parramatta, Bondi and 4 more) or `IDN11060.xml` (736 KB, all NSW precis). Per location and day: icon code, precis text, rain chance, rain range, min, max. Locations carry an `aac` and a name but **no coordinates**, so mapping a home to its forecast location needs either an option (`forecastLocation: "Sydney"`) or a heuristic (the nearest station's `forecast-district-id` matches the location's parent area). I recommend the option; a wrong guess at a forecast town is worse than asking once.
|
|
27
|
+
- **Cadence.** `IDN60920` is 10-minutely: at 20:23 most stations, Observatory Hill included, had a 20:10 observation, issued at 20:11 and sent at 20:13. The build reads at `:05` and `:35` anyway (see `src/connectors/weather/README.md`). (The station JSON lists only `:00` and `:30` rows, which is what an earlier draft of this note read as half-hourly.) Some stations in the file are days old (daily manual reports). The precis is issued twice a day plus amendments; each file names its `next-routine-issue-time` (04:15 and 04:35 next morning here), so poll hourly and parse the issue time.
|
|
28
|
+
- **After the afternoon issue, today has no min, max or rain range** in both the precis and the app API's daily. `forecast.today` must accept missing fields.
|
|
29
|
+
|
|
30
|
+
## Rain since 9am disagreed, and it is not rounding
|
|
31
|
+
|
|
32
|
+
At the same minute the app API said 15 mm, the station JSON `rain_trace` said "14.2" (at 20:00) and the FTP XML said 15.0 mm (09:00 to 20:03). Same station, different cut-off times. The slice carries the time it is for, so this shows up as two honest values rather than an error.
|
|
33
|
+
|
|
34
|
+
## Which slices each source can own
|
|
35
|
+
|
|
36
|
+
- **BOM (FTP)**: `now` (observed), `forecast` (official precis). No cloud, UV or radiation.
|
|
37
|
+
- **BOM app API**: `now`, `forecast` with UV max and sunrise, hourly UV. No cloud % or radiation. Prohibited by its own terms.
|
|
38
|
+
- **Open-Meteo**: `sky` (cloud, UV, shortwave radiation: the only source with radiation), plus `now` and `forecast` as modelled fallbacks. `current` is 15-minute interpolated (`"interval": 900`), so it is `modelled: true`. Limits: 600/min, 5,000/h, 10,000/day, 300,000/month; data CC BY 4.0, attribution link required where shown.
|
|
39
|
+
- **Google Weather**: `now` (`currentConditions`, not stated as observed, so modelled until shown otherwise), `forecast` (10 days), `sky` minus radiation (cloud, UV). Australia is covered for current, hourly and daily. Its `currentConditionsHistory.qpf` is a rolling 24 h, not since 9am; I will not map one onto the other.
|
|
40
|
+
- **`sun`**: local, `suncalc`, no source.
|
|
41
|
+
|
|
42
|
+
That gives the default `[bom(), openMeteo()]`: observed beats modelled for `now`, the forecaster's precis beats a model for `forecast`, and `sky` falls through to Open-Meteo whatever the order. Google slots in after BOM when KO has a key.
|
|
43
|
+
|
|
44
|
+
## Decision for KO: how `bom()` reaches FTP
|
|
45
|
+
|
|
46
|
+
Recommended: `bom({ fetch })` stays a fetch-only client, parsing XML, and a small FTP transport turns `ftp://` URLs into a `Response`. It uses `basic-ftp` (6.2.3, MIT, no dependencies, Node `net`; measured in Bun 1.4.2: `IDN10064.xml` in 267 ms, `IDN60920.xml` in 765 ms) and lives outside the runtime-neutral build, the way `bunPinnedFetch` and `bunGatewayFetch` are runtime transports passed in today. Cost: one dependency, under 1 s per poll, 562 KB per read, about 27 MB a day at two reads an hour, for observations. If FTP dies, `now` and `forecast` fall back to Open-Meteo, marked modelled.
|
|
47
|
+
|
|
48
|
+
Alternatives, not recommended:
|
|
49
|
+
|
|
50
|
+
1. App API: one JSON shape, nearest station and distance for free, 30 ms. Against it: "You must not use, copy or share it", undocumented, and it silently drops Bun's default UA. Home Assistant's bremor integration still uses it, sending `User-Agent: MakeThisAPIOpenSource/1.0.0`, 6-character geohash (its `geohash7` variable is 6 characters too), polling every 5 minutes.
|
|
51
|
+
2. `reg.bom.gov.au` over HTTPS: works with plain `fetch` today, but it is the paid host and unannounced access could be cut or billed.
|
|
52
|
+
3. `www.bom.gov.au` with a browser UA: evades a block whose message says to stop. No.
|
|
53
|
+
|
|
54
|
+
## The `openmeteo` npm SDK: not using it
|
|
55
|
+
|
|
56
|
+
Read from the installed `openmeteo@1.2.3` (`lib/index.d.ts`, `lib/index.js`) and `@openmeteo/sdk@1.28.0`. `fetchWeatherApi(url, params: any, retries?, backoffFactor?, backoffMax?, fetchOptions?)` forces `format=flatbuffers` and returns `WeatherApiResponse[]`. Values are read by position (`hourly().variables(0).valuesArray()` as a `Float32Array`) in the order you asked for them, not by name. It calls the global `fetch` with only `fetchOptions`, so a test cannot inject a `fetch` the way every other client here does. Fixtures would be binary. It adds `flatbuffers` and the SDK, about 700 KB, for one point and a dozen variables. Plain `fetch` of the JSON API gives named fields, a readable fixture and zod, so the SDK buys nothing here.
|
|
57
|
+
|
|
58
|
+
## Sources
|
|
59
|
+
|
|
60
|
+
- BOM catalogue: https://www.bom.gov.au/catalogue/data-feeds.shtml, FTP guide: https://www.bom.gov.au/catalogue/anon-ftp.shtml, copyright: https://www.bom.gov.au/other/copyright.shtml (all 403 to non-browser clients)
|
|
61
|
+
- bremor/bureau_of_meteorology at `e9cd8da` (2026-10-07): `PyBoM/const.py`, `PyBoM/collector.py`, `PyBoM/helpers.py`
|
|
62
|
+
- Open-Meteo: https://open-meteo.com/en/docs, https://open-meteo.com/en/docs/bom-api, https://open-meteo.com/en/licence, https://open-meteo.com/en/terms
|
|
63
|
+
- Google Weather: https://developers.google.com/maps/documentation/weather/current-conditions, https://developers.google.com/maps/documentation/weather/coverage
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// An invented home: the example house in home.svg, addresses from 192.0.2.0/24 (reserved for documentation).
|
|
2
|
+
// Copy it beside your private files, not into a repo. Secrets are env names; paths are relative to this file.
|
|
3
|
+
{
|
|
4
|
+
"$schema": "../home.schema.json",
|
|
5
|
+
"name": "Example house",
|
|
6
|
+
|
|
7
|
+
// `home locate "<street address>" --write` fills latitude and longitude (and timezone, when absent); the address is not kept.
|
|
8
|
+
"location": {
|
|
9
|
+
"latitude": -33.8688,
|
|
10
|
+
"longitude": 151.2093,
|
|
11
|
+
"bomForecast": "Sydney",
|
|
12
|
+
"timezone": "Australia/Sydney",
|
|
13
|
+
},
|
|
14
|
+
"weather": { "sources": ["bom", "open-meteo"], "pollMinutes": 15 },
|
|
15
|
+
|
|
16
|
+
"plan": { "svg": "home.svg" },
|
|
17
|
+
|
|
18
|
+
// Each room's id matches <g class="room" id="…"> in home.svg. `hueRoom` is the Hue room whose lights its marker shows.
|
|
19
|
+
"rooms": [
|
|
20
|
+
{
|
|
21
|
+
"id": "room-living",
|
|
22
|
+
"name": "Living",
|
|
23
|
+
"floor": "ground",
|
|
24
|
+
"hueRoom": "11111111-1111-4111-8111-111111111111",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "room-kitchen",
|
|
28
|
+
"name": "Kitchen",
|
|
29
|
+
"floor": "ground",
|
|
30
|
+
"hueRoom": "22222222-2222-4222-8222-222222222222",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "room-bed-1",
|
|
34
|
+
"name": "Bedroom",
|
|
35
|
+
"floor": "ground",
|
|
36
|
+
"hueRoom": "33333333-3333-4333-8333-333333333333",
|
|
37
|
+
},
|
|
38
|
+
{ "id": "room-bath", "name": "Bathroom", "floor": "ground" },
|
|
39
|
+
{ "id": "room-hall", "name": "Hall", "floor": "ground" },
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
// Only what it takes to reach each device, and where it is: its identity (bridgeId, mac, serial) and last known host.
|
|
43
|
+
// Model, firmware and the like come live.
|
|
44
|
+
"devices": [
|
|
45
|
+
{
|
|
46
|
+
"id": "bridge",
|
|
47
|
+
"connector": "hue",
|
|
48
|
+
"room": "room-hall",
|
|
49
|
+
"host": "192.0.2.2",
|
|
50
|
+
"bridgeId": "0017880000000000",
|
|
51
|
+
"key": "HUE_APPLICATION_KEY",
|
|
52
|
+
"ca": "hue-root-ca.pem",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": "ac",
|
|
56
|
+
"connector": "daikin",
|
|
57
|
+
"room": "room-living",
|
|
58
|
+
"name": "Living AC",
|
|
59
|
+
"host": "192.0.2.10",
|
|
60
|
+
"mac": "00005E005301",
|
|
61
|
+
},
|
|
62
|
+
// The array is drawn on the roof at marker-solar; capacityW is its rated size from the installer's paperwork.
|
|
63
|
+
{
|
|
64
|
+
"id": "solar",
|
|
65
|
+
"connector": "enphase",
|
|
66
|
+
"host": "192.0.2.21",
|
|
67
|
+
"serial": "000000000000",
|
|
68
|
+
"token": "enphase-token.json",
|
|
69
|
+
"marker": "marker-solar",
|
|
70
|
+
"capacityW": 6600,
|
|
71
|
+
},
|
|
72
|
+
{ "id": "prices", "connector": "amber", "key": "AMBER_KEY" },
|
|
73
|
+
],
|
|
74
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -90 640 510" role="img" aria-label="Plan of an example single-storey house, rooms labelled, solar array on the roof" font-family="-apple-system, 'SF Pro Text', 'Helvetica Neue', sans-serif">
|
|
2
|
+
<!--
|
|
3
|
+
Example home for @khalido/home, drawn by hand to show the contract. Not a real house.
|
|
4
|
+
|
|
5
|
+
Contract for anything that draws on this file (skills/draw-home/SKILL.md):
|
|
6
|
+
- Each room is <g class="room" id="room-…" data-floor data-name>. Ids are stable and
|
|
7
|
+
match "rooms" in home.json; devices refer to rooms by these ids.
|
|
8
|
+
- Each room holds an empty <g class="marker" id="marker-…" transform="translate(x,y)">
|
|
9
|
+
at its top-right inner corner. Draw a device's state inside it at the origin; never
|
|
10
|
+
move the anchor.
|
|
11
|
+
- A device drawn outside any room (the solar array on the roof) has its own marker,
|
|
12
|
+
named by that device's "marker" in home.jsonc.
|
|
13
|
+
- Strokes and text use currentColor, so a page that inlines the file themes it.
|
|
14
|
+
-->
|
|
15
|
+
<style>
|
|
16
|
+
svg:root { color: #1d1d1f; }
|
|
17
|
+
svg:root .bg { fill: #ffffff; }
|
|
18
|
+
.bg { fill: none; }
|
|
19
|
+
.room rect { fill: #8e8e9314; stroke: currentColor; stroke-width: 2; }
|
|
20
|
+
.array rect { fill: #8e8e9314; stroke: currentColor; stroke-width: 1.5; }
|
|
21
|
+
.label { font-size: 13px; fill: currentColor; }
|
|
22
|
+
.muted { opacity: 0.6; }
|
|
23
|
+
@media (prefers-color-scheme: dark) {
|
|
24
|
+
svg:root { color: #ececf0; }
|
|
25
|
+
svg:root .bg { fill: #1c1c1e; }
|
|
26
|
+
.room rect { fill: #ffffff10; }
|
|
27
|
+
}
|
|
28
|
+
</style>
|
|
29
|
+
<rect class="bg" y="-90" width="640" height="510"/>
|
|
30
|
+
|
|
31
|
+
<!-- Outer wall -->
|
|
32
|
+
<rect x="20" y="20" width="600" height="380" fill="none" stroke="currentColor" stroke-width="4"/>
|
|
33
|
+
|
|
34
|
+
<!-- Solar array on the roof, outside any room: the Enphase device's marker -->
|
|
35
|
+
<g class="array" id="array-solar" data-name="Solar">
|
|
36
|
+
<text class="label muted" x="36" y="-44">Roof</text>
|
|
37
|
+
<rect x="220" y="-74" width="60" height="44"/>
|
|
38
|
+
<rect x="290" y="-74" width="60" height="44"/>
|
|
39
|
+
<rect x="360" y="-74" width="60" height="44"/>
|
|
40
|
+
<rect x="430" y="-74" width="60" height="44"/>
|
|
41
|
+
<g class="marker" id="marker-solar" transform="translate(504,-70)"/>
|
|
42
|
+
</g>
|
|
43
|
+
|
|
44
|
+
<g class="room" id="room-living" data-floor="ground" data-name="Living">
|
|
45
|
+
<rect x="20" y="20" width="320" height="220"/>
|
|
46
|
+
<text class="label" x="36" y="44">Living</text>
|
|
47
|
+
<g class="marker" id="marker-living" transform="translate(324,36)"/>
|
|
48
|
+
</g>
|
|
49
|
+
|
|
50
|
+
<g class="room" id="room-kitchen" data-floor="ground" data-name="Kitchen">
|
|
51
|
+
<rect x="340" y="20" width="280" height="160"/>
|
|
52
|
+
<text class="label" x="356" y="44">Kitchen</text>
|
|
53
|
+
<g class="marker" id="marker-kitchen" transform="translate(604,36)"/>
|
|
54
|
+
</g>
|
|
55
|
+
|
|
56
|
+
<g class="room" id="room-hall" data-floor="ground" data-name="Hall">
|
|
57
|
+
<rect x="340" y="180" width="280" height="60"/>
|
|
58
|
+
<text class="label muted" x="356" y="214">Hall</text>
|
|
59
|
+
<g class="marker" id="marker-hall" transform="translate(604,196)"/>
|
|
60
|
+
</g>
|
|
61
|
+
|
|
62
|
+
<g class="room" id="room-bed-1" data-floor="ground" data-name="Bedroom">
|
|
63
|
+
<rect x="20" y="240" width="360" height="160"/>
|
|
64
|
+
<text class="label" x="36" y="264">Bedroom</text>
|
|
65
|
+
<g class="marker" id="marker-bed-1" transform="translate(364,256)"/>
|
|
66
|
+
</g>
|
|
67
|
+
|
|
68
|
+
<g class="room" id="room-bath" data-floor="ground" data-name="Bathroom">
|
|
69
|
+
<rect x="380" y="240" width="240" height="160"/>
|
|
70
|
+
<text class="label" x="396" y="264">Bathroom</text>
|
|
71
|
+
<g class="marker" id="marker-bath" transform="translate(604,256)"/>
|
|
72
|
+
</g>
|
|
73
|
+
|
|
74
|
+
<!-- Front door, on the hall's right wall -->
|
|
75
|
+
<path d="M620 196 v28" stroke="currentColor" stroke-width="6" class="muted"/>
|
|
76
|
+
</svg>
|