Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ A custom Lovelace card for Home Assistant that lets you draw 2D detection zones
- Helper overlay (device “view cone”) with configurable horizontal FOV and rotation angle
- Compact UI:
- Bottom‑left: a single ✎ “Draw” button toggles a vertical menu of modes (▭ Rect, ◯ Ellipse, ⬠ Polygon) that appears above it
- Bottom‑right: 🔒 Lock toggle prevents accidental edits (disables drawing and cancels in‑progress)
- Bottom‑right: 🔒 Lock toggle prevents accidental edits (disables drawing and cancels in‑progress). The card starts locked whenever zones already exist, and the toggle is remembered per `location` in the browser. Set `start_locked` in YAML to override both.
- Device and Entity pickers: choose a HA device and select X/Y sensor entity pairs directly from dropdowns; click Apply to persist
- The picked device and X/Y pairs are remembered per `location`, so reloading the dashboard keeps your selection
- Multi‑unit support (front‑end only): configure input/grid in mm, cm, m, in, or ft (backend remains millimetres)
Expand Down Expand Up @@ -106,7 +106,7 @@ The majority of the configuration and management of zones takes place on the act
type: custom:zone-mapper-card
location: Office # friendly name shown on card; used to build zone entity ids
dark_mode: false
start_locked: true # Start in lock mode
# start_locked: true # optional; forces the starting lock state. Leave it out to start locked whenever zones exist

# Units (front-end only, converts to mm internally)
input_units: mm # mm | cm | m | in | ft
Expand Down
38 changes: 32 additions & 6 deletions dist/zone-mapper-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,32 @@ function writeStoredSelection(location, deviceId, entities) {
}
}

const LOCK_STORAGE_PREFIX = 'zone-mapper-card.lock';

function lockStorageKey(location) {
return `${LOCK_STORAGE_PREFIX}.${slugifyLocation(location)}`;
}

// Remember the lock toggle per location so a reload keeps the grid locked
function readStoredLock(location) {
try {
const raw = window.localStorage.getItem(lockStorageKey(location));
if (raw === '1') return true;
if (raw === '0') return false;
return null;
} catch {
return null;
}
}

function writeStoredLock(location, locked) {
try {
window.localStorage.setItem(lockStorageKey(location), locked ? '1' : '0');
} catch {
// Nothing to do; the toggle still applies for the current page load
}
}

class ZoneMapperCard extends HTMLElement {
static get GRID_MIN_SPACING_PX() {
return 40;
Expand Down Expand Up @@ -229,7 +255,6 @@ class ZoneMapperCard extends HTMLElement {
return {
type: 'custom:zone-mapper-card',
dark_mode: false,
start_locked: false,
show_undo: true,
unit_display: false,
// unit_label_size: 18,
Expand Down Expand Up @@ -775,6 +800,7 @@ class ZoneMapperCard extends HTMLElement {
};
btnLock.addEventListener('click', () => {
this.isLocked = !this.isLocked;
writeStoredLock(this.location, this.isLocked);
updateLockVisual();
this._lastLockWarningTs = 0;
if (this.isLocked) {
Expand Down Expand Up @@ -1644,16 +1670,16 @@ class ZoneMapperCard extends HTMLElement {
}

_applyAutoLock() {
// When the user hasn't pinned start_locked in config, lock by default
// whenever zones already exist so accidental clicks don't overwrite them.
// Only runs once per page load.
// An explicit start_locked in config always wins. Otherwise use the last
// toggle remembered for this location, and fall back to locking whenever
// zones already exist. Only runs once per page load.
if (this._autoLockApplied) return;
if (this._lockConfigured) {
this._autoLockApplied = true;
return;
}
const hasZones = (this.zones || []).length > 0;
this.isLocked = hasZones;
const stored = readStoredLock(this.location);
this.isLocked = stored !== null ? stored : (this.zones || []).length > 0;
this._autoLockApplied = true;
if (typeof this._updateLockVisual === 'function') {
this._updateLockVisual();
Expand Down