Skip to content

Commit 413964c

Browse files
jpettittclaude
andcommitted
v0.2.0: location markers, configurable main clock, theme-friendly colors
Markers - new `markers:` config: pin any number of HA entities (zone / person / device_tracker) on the map. Each shows a colored dot, the entity's friendly_name (or a per-marker override), and the current local time at that location, DST-aware via IANA polygon hit-test. - per-marker `color`, card-wide `markerColor`, or — when neither is set — the new `--geo-marker-color` CSS variable lets themes restyle without touching card config. - `markerLabelMode: always | hover` controls whether the label + time render under the dot or only on hover/tap. - `markerShowDay` (default true) appends the weekday after the time so a marker on the far side of the planet whose date has rolled over reads obviously. - markers are HTML overlays, not SVG, so the dot, halo, and label text stay at fixed CSS pixel size regardless of card width (previous SVG version was illegible on anything but full screen). Home marker - new `showHomeMarkerLabel` toggle adds the home name + current local time under the existing home dot, using the HA-configured `time_zone` (or polygon hit-test as fallback). Main clock — BREAKING - new `mainTimeSource: home | device | entity` (default `home`). Pre-0.2.0 cards always read the viewing browser's zone; that's now `mainTimeSource: device`. To preserve old behavior, set `mainTimeSource: device` explicitly. - `mainTimeEntity` companion field for `entity` mode. Editor - markers panel: per-row entity selector + label + color picker, add/remove buttons, label-visibility + show-day toggles. - entity selection now uses HA's `<ha-selector>` (the official high-level wrapper). Editor awaits `loadCardHelpers()` before rendering, which is what registers the selector internals — without this gate the picker tags stayed inert and invisible. - color pickers now fire on `change` (commit) instead of `input` (every drag step), eliminating the redraw thrash that made the picker feel laggy. - numeric textfields likewise commit on `change` so typing a number doesn't trigger a map redraw per keystroke. Internals - HassLike type unified in src/types.ts; drops the divergent copies in card and editor. - `sunElevation` documented as a public test-ground-truth export. - console.debug noise from earlier debugging dropped. Docs - README updated for the breaking change, the new config keys, the Greenwich (not sun) fallback for non-sun centering modes when their data is missing, and the editor's actual component list. - TODO.md groomed: monthly Blue Marble, HACS release, and the in-HA-test items ticked off. - dev/index.html gained controls for the new toggles + colors. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 504827c commit 413964c

11 files changed

Lines changed: 1597 additions & 198 deletions

README.md

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,27 @@ the planet.
4141
hemisphere stays in the middle and the map slowly drifts),
4242
`home` (your HA-configured longitude), `longitude` (any numeric
4343
value), or `entity` (follow a zone / person / device-tracker entity).
44+
All non-`sun` modes fall back to **Greenwich (lon=0°)** with a
45+
console warning when their data isn't available — so a misconfigured
46+
mode looks visibly different from `sun` instead of silently behaving
47+
the same.
4448
- **Home marker** — optional dot at your HA-configured location that
45-
tracks the map's drift.
49+
tracks the map's drift, with an opt-in label + current local time
50+
beneath it.
51+
- **Location markers** — pin any list of HA entities (zones, persons,
52+
device-trackers) on the map; each shows the entity's label and the
53+
current local time at that zone (DST-aware, looked up from its
54+
longitude/latitude). Labels are always-visible by default; flip to
55+
hover-only if you'd rather keep the map tidy. The weekday is
56+
appended to the time so a marker on the far side of the planet
57+
whose date has rolled over is obvious at a glance — toggle off if
58+
you want time-only. Per-marker color, or a card-wide default that
59+
themes can override via `--geo-marker-color`.
60+
- **Main-clock time source** — the wall-clock readout can read from
61+
your HA location (default), the viewing device, or any HA entity
62+
with a longitude/latitude. *(Breaking change in v0.2.0: pre-0.2.0
63+
cards behaved as if the source was the viewing device. Set
64+
`mainTimeSource: device` to keep the old behavior.)*
4665
- **Time scrubbing** — freeze the clock at any UTC moment via `now: …`
4766
for screenshots or to preview the look at, say, the December solstice.
4867
- **Visual editor** — opens automatically when adding the card; advanced
@@ -116,6 +135,7 @@ center: sun
116135
centerLongitude: -119 # required when center: longitude. -180..180.
117136
centerEntity: zone.home # required when center: entity. Must expose a longitude attribute.
118137
showHomeMarker: false # render a dot at hass.config.latitude/longitude
138+
showHomeMarkerLabel: false # also show home name + current local time under the dot
119139

120140
# Imagery + atmosphere (under "Advanced visual settings" in the editor)
121141
dayBrightness: 1.15 # CSS brightness() on the day layer (0.5..2.0)
@@ -131,6 +151,25 @@ updateInterval: 1 # seconds between clock-readout ticks (1..600).
131151
# both drop to 30 minutes when the card is off-screen.
132152
now: "2024-12-21T09:21:00Z" # freeze the clock at this moment (omit for live)
133153

154+
# Main-clock time source — home (default) | device | entity
155+
# - 'home' reads hass.config.time_zone (the HA-configured zone)
156+
# - 'device' uses the viewing browser's zone (pre-0.2.0 behavior)
157+
# - 'entity' picks the IANA zone of an HA entity's lat/lon
158+
mainTimeSource: home
159+
mainTimeEntity: zone.work # required when mainTimeSource: entity
160+
161+
# Location markers — list of HA entities to pin on the map.
162+
# Each entity must expose numeric `latitude` and `longitude` attributes.
163+
markers:
164+
- entity: zone.work
165+
label: Office # optional — defaults to the entity's friendly_name
166+
color: "#3da9fc" # optional — defaults to markerColor
167+
- entity: person.alice
168+
markerLabelMode: always # always | hover
169+
markerColor: "#3da9fc" # default fill for markers without their own color
170+
# — omit (or unset) to let `--geo-marker-color` win
171+
markerShowDay: true # append weekday after the time (e.g. "12:22 PM Friday")
172+
134173
# Overlays
135174
showTimezoneBand: true # hour-of-day numbers across the top
136175
showTimezoneBoundaries: true # 15° offset rectangle bands + IANA polygons
@@ -145,12 +184,17 @@ imageryBase: "" # override the assets URL (e.g. host on a CDN)
145184
146185
- **`sun`** (default) — centered on the current subsolar longitude. The map
147186
drifts westward as the sun moves; the daylit hemisphere stays in the middle.
148-
- **`home`** — centered on `hass.config.longitude`. Falls back to `sun` if HA
149-
hasn't reported a location.
150-
- **`longitude`** — centered on a numeric `centerLongitude` value.
187+
- **`home`** — centered on `hass.config.longitude`. Falls back to **Greenwich
188+
(0°)** with a `console.warn` if HA hasn't reported a longitude.
189+
- **`longitude`** — centered on a numeric `centerLongitude` value. Falls back
190+
to **Greenwich (0°)** if the value is missing or non-numeric.
151191
- **`entity`** — centered on the longitude attribute of an HA entity. Works
152192
with `zone.*`, `person.*`, and most `device_tracker.*` entities. Falls back
153-
to `sun` if the entity is missing or has no longitude.
193+
to **Greenwich (0°)** if the entity is missing or has no numeric longitude.
194+
195+
The Greenwich fallback is deliberate — it's visually distinct from `sun`
196+
mode so a misconfiguration doesn't silently look right. Watch the browser
197+
console for a one-off warn line that names the broken field.
154198

155199
### Theme via CSS variables
156200

@@ -169,6 +213,7 @@ geo-clock-card:
169213
--geo-tz-mid: "#6ab0ff"
170214
--geo-tz-line: rgba(255, 255, 255, 0.18)
171215
--geo-home-marker: var(--accent-color, "#ff7a3d")
216+
--geo-marker-color: "#3da9fc"
172217
```
173218

174219
Most of these have a matching named config option (e.g. `dayBrightness`
@@ -210,7 +255,7 @@ center mode, time-scrubbing with solstice/equinox presets, etc.
210255
- [`src/timezone-band.ts`](src/timezone-band.ts) — top-of-map hour band + tick lines.
211256
- [`src/day-image.ts`](src/day-image.ts) — picks the right monthly daylight image for a given date.
212257
- [`src/geo-clock-card.ts`](src/geo-clock-card.ts) — the Lit element that wires it all together.
213-
- [`src/geo-clock-card-editor.ts`](src/geo-clock-card-editor.ts) — visual config editor (HA `ha-textfield` / `ha-select` / `ha-formfield` / `ha-switch` / `ha-entity-picker` / `ha-expansion-panel`); lazy-loaded by the card via `getConfigElement()` and bundled inline.
258+
- [`src/geo-clock-card-editor.ts`](src/geo-clock-card-editor.ts) — visual config editor (HA `ha-textfield` / `ha-switch` / `ha-formfield` / `ha-selector` / `ha-expansion-panel`, plus native `<select>` for the centering / time-source / marker-mode dropdowns where `ha-select` was unreliable). Awaits `loadCardHelpers()` before rendering so the entity selectors register correctly. Lazy-loaded by the card via `getConfigElement()` and bundled inline.
214259

215260
The original design notes are in [`DESIGN.md`](DESIGN.md).
216261

TODO.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
- [x] Lit element with SVG mask + feathered terminator
1010
- [x] Local time + UTC + date readout
1111
- [x] NASA Blue/Black Marble fetch script
12-
- [ ] First in-Home-Assistant test (pending user verification)
13-
- [ ] HACS metadata polish + first tagged release
12+
- [x] First in-Home-Assistant test
13+
- [x] HACS metadata polish + first tagged release (v0.1.x shipped, v0.2.0 in flight)
1414

1515
## Stage 2 — time-zone affordances
1616

@@ -24,12 +24,13 @@
2424

2525
## Stage 3 — decisions deferred to here
2626

27-
- [ ] Monthly Blue Marble variant (auto-pick by current month)
27+
- [x] Monthly Blue Marble variant (auto-pick by current month) — 24 frames (start + mid each month) shipped via day-image.ts
2828
- [ ] Better terminator: WebGL/canvas with sun-elevation alpha + tinted twilight
29-
- [ ] Bundling strategy: ship imagery in HACS package vs. fetch on first load vs. CDN
30-
- [ ] Optional: location pins (config + HA zones)
29+
- [x] Bundling strategy: imagery ships alongside the JS bundle in dist/, copied by HACS / manual install
30+
- [x] Location pins (config + HA zones) — `markers:` array with per-marker label + color, always-visible or hover label modes
31+
- [x] Configurable main-clock time source (home/device/entity, default `home`) — **breaking change** in 0.2.0: pre-0.2.0 cards behaved like `device`
3132
- [ ] Optional: alternate projection (Mercator)
32-
- [ ] Optional: Lovelace visual config editor
33+
- [x] Lovelace visual config editor
3334

3435
## Quality / housekeeping (ongoing)
3536

dev/index.html

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,28 @@ <h1>geo-clock-card — local preview</h1>
6464
<label><input id="band" type="checkbox" checked> show hour band</label>
6565
<label><input id="boundaries" type="checkbox" checked> show TZ boundaries</label>
6666
<label><input id="homemarker" type="checkbox"> home marker</label>
67+
<label><input id="homemarkerlabel" type="checkbox"> home marker label + time</label>
68+
<label><input id="markers" type="checkbox"> sample markers (London, Tokyo)</label>
69+
<label>marker labels:
70+
<select id="markerLabelMode">
71+
<option value="always" selected>always</option>
72+
<option value="hover">hover only</option>
73+
</select>
74+
</label>
75+
<label><input id="markerShowDay" type="checkbox" checked> show weekday on markers</label>
76+
<label>marker default color:
77+
<input id="markerColor" type="color" value="#3da9fc">
78+
</label>
79+
<label>tz line color:
80+
<input id="tzLineColor" type="color" value="#ffffff">
81+
</label>
82+
<label>main time source:
83+
<select id="mainTimeSource">
84+
<option value="home" selected>home (HA tz)</option>
85+
<option value="device">device</option>
86+
<option value="entity">entity</option>
87+
</select>
88+
</label>
6789
<label>center:
6890
<select id="center">
6991
<option value="sun" selected>sun (subsolar)</option>
@@ -101,6 +123,13 @@ <h1>geo-clock-card — local preview</h1>
101123
const center = document.getElementById('center');
102124
const centerLongitude = document.getElementById('centerLongitude');
103125
const homemarker = document.getElementById('homemarker');
126+
const homemarkerlabel = document.getElementById('homemarkerlabel');
127+
const markersEl = document.getElementById('markers');
128+
const markerLabelMode = document.getElementById('markerLabelMode');
129+
const markerShowDayEl = document.getElementById('markerShowDay');
130+
const markerColor = document.getElementById('markerColor');
131+
const tzLineColor = document.getElementById('tzLineColor');
132+
const mainTimeSource = document.getElementById('mainTimeSource');
104133
const live = document.getElementById('live');
105134
const datetime = document.getElementById('datetime');
106135
const brightness = document.getElementById('brightness');
@@ -147,8 +176,23 @@ <h1>geo-clock-card — local preview</h1>
147176
center: center.value,
148177
centerLongitude: Number(centerLongitude.value),
149178
showHomeMarker: homemarker.checked,
179+
showHomeMarkerLabel: homemarkerlabel.checked,
180+
markerLabelMode: markerLabelMode.value,
181+
markerShowDay: markerShowDayEl.checked,
182+
markerColor: markerColor.value,
183+
timezoneLineColor: tzLineColor.value,
184+
mainTimeSource: mainTimeSource.value,
150185
imageryBase: '../dist/',
151186
};
187+
if (markersEl.checked) {
188+
cfg.markers = [
189+
{ entity: 'zone.london', label: 'London', color: '#3da9fc' },
190+
{ entity: 'zone.tokyo', label: 'Tokyo', color: '#ff7a3d' },
191+
];
192+
}
193+
if (mainTimeSource.value === 'entity') {
194+
cfg.mainTimeEntity = 'zone.london';
195+
}
152196
if (!live.checked && datetime.value) {
153197
cfg.now = inputUtcToIso(datetime.value);
154198
}
@@ -157,8 +201,27 @@ <h1>geo-clock-card — local preview</h1>
157201
// on the first render. (HA itself sets hass after construction
158202
// too, but the preview is single-shot per rebuild.)
159203
card.hass = {
160-
config: { latitude: 36.5, longitude: -119 },
161-
states: {},
204+
config: {
205+
latitude: 36.5,
206+
longitude: -119,
207+
time_zone: 'America/Los_Angeles',
208+
},
209+
states: {
210+
'zone.london': {
211+
attributes: {
212+
latitude: 51.5074,
213+
longitude: -0.1278,
214+
friendly_name: 'London',
215+
},
216+
},
217+
'zone.tokyo': {
218+
attributes: {
219+
latitude: 35.6762,
220+
longitude: 139.6503,
221+
friendly_name: 'Tokyo',
222+
},
223+
},
224+
},
162225
};
163226
stage.appendChild(card);
164227
twilightVal.textContent = `${twilight.value}°`;
@@ -187,6 +250,13 @@ <h1>geo-clock-card — local preview</h1>
187250
center.addEventListener('change', rebuild);
188251
centerLongitude.addEventListener('input', rebuild);
189252
homemarker.addEventListener('change', rebuild);
253+
homemarkerlabel.addEventListener('change', rebuild);
254+
markersEl.addEventListener('change', rebuild);
255+
markerLabelMode.addEventListener('change', rebuild);
256+
markerShowDayEl.addEventListener('change', rebuild);
257+
markerColor.addEventListener('change', rebuild);
258+
tzLineColor.addEventListener('change', rebuild);
259+
mainTimeSource.addEventListener('change', rebuild);
190260
live.addEventListener('change', rebuild);
191261
datetime.addEventListener('input', () => {
192262
if (datetime.value) live.checked = false;

0 commit comments

Comments
 (0)