Accumulated uncommitted infra changes: - Caddyfile: repoint HA/Zabbix to 192.168.1.4/.3, add ~20 new site routes - Immich: move media to /mnt/smsg, enable CUDA ML, mem limits, rewrite backup.sh - Add service stacks: agap-mcp, anki, family, freshrss, iperf3, kanboard, linkwarden, qbittorrent, radicale, syncthing, vikunja, windows - openwebui: enable API keys; ollama: drop CPU fallback - seafile/zabbix: extra_hosts entries; matrix: add user juris - Remove pihole stack and stale wiki/migrate.py - Ignore marketplace-mcp (standalone repo) and linkwarden runtime data Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
46 lines
1.5 KiB
JavaScript
46 lines
1.5 KiB
JavaScript
const BASE = () => process.env.HA_URL || 'http://192.168.1.4:8123';
|
|
let _token = null;
|
|
|
|
export function initHA(token) {
|
|
_token = token;
|
|
console.log('Home Assistant: ready');
|
|
}
|
|
|
|
function token() {
|
|
if (!_token) throw new Error('HA not initialized');
|
|
return _token;
|
|
}
|
|
|
|
async function api(path, opts = {}) {
|
|
const res = await fetch(`${BASE()}/api${path}`, {
|
|
...opts,
|
|
headers: { Authorization: `Bearer ${token()}`, 'Content-Type': 'application/json', ...opts.headers },
|
|
});
|
|
if (!res.ok) throw new Error(`HA API ${path}: ${res.status}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function haGetState(entityId) {
|
|
const s = await api(`/states/${entityId}`);
|
|
return { entity_id: s.entity_id, state: s.state, attributes: s.attributes, last_changed: s.last_changed };
|
|
}
|
|
|
|
export async function haListEntities(domain) {
|
|
const states = await api('/states');
|
|
const filtered = domain ? states.filter(s => s.entity_id.startsWith(`${domain}.`)) : states;
|
|
return filtered.map(s => ({ entity_id: s.entity_id, state: s.state, friendly_name: s.attributes.friendly_name }));
|
|
}
|
|
|
|
export async function haCallService(domain, service, data = {}) {
|
|
return api(`/services/${domain}/${service}`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
export async function haGetHistory(entityId, hours = 24) {
|
|
const start = new Date(Date.now() - hours * 3600 * 1000).toISOString();
|
|
const data = await api(`/history/period/${start}?filter_entity_id=${entityId}&minimal_response=true`);
|
|
return data[0] || [];
|
|
}
|