Fix empty display after save (lastSaveTime guard) + OPNsense JSON payload fix
This commit is contained in:
@@ -133,8 +133,9 @@ input[type=time]::-webkit-calendar-picker-indicator{filter:invert(.5)}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Uses sensor.home_dhcp_leases_lan — the OPNsense integration DHCP sensor
|
||||
// Leases attribute has capital L, fields: address, hostname, mac, expires
|
||||
// DHCP source: sensor.home_dhcp_leases_lan
|
||||
// attributes.Leases (capital L): [{address, hostname, mac, expires, type}]
|
||||
// Online = expires is in the future
|
||||
const DHCP='sensor.home_dhcp_leases_lan';
|
||||
const CHUNKS=12, CHUNK_SIZE=250;
|
||||
const chunkId=i=>`input_text.parental_config_${i}`;
|
||||
@@ -142,7 +143,7 @@ const COLORS=['#ef5350','#ff7043','#ffa726','#66bb6a','#26c6da','#42a5f5','#7e57
|
||||
const MAC_RE=/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i;
|
||||
let ws,wsId=1,pending={},retryTimer;
|
||||
let states={},cfg={users:[]},prefs={url:'',token:''};
|
||||
let devTargetUser=null,schedOpen={},renderTimer=null;
|
||||
let devTargetUser=null,schedOpen={},renderTimer=null,lastSaveTime=0;
|
||||
|
||||
function loadPrefs(){try{const p=localStorage.getItem('pc2_prefs');if(p){prefs=JSON.parse(p);return true;}}catch(e){}return false;}
|
||||
function savePrefs(){localStorage.setItem('pc2_prefs',JSON.stringify(prefs));}
|
||||
@@ -162,7 +163,6 @@ function saveSettings(){
|
||||
prefs={url,token:tok};savePrefs();
|
||||
closeModal('settings-modal');if(ws)ws.close();connect();
|
||||
}
|
||||
|
||||
function connect(){
|
||||
setHA('conn');clearTimeout(retryTimer);
|
||||
const wsUrl=prefs.url.replace(/^https?/,m=>m==='https'?'wss':'ws')+'/api/websocket';
|
||||
@@ -207,7 +207,8 @@ async function onAuth(){
|
||||
}
|
||||
function onStateChange({entity_id,new_state}){
|
||||
states[entity_id]=new_state;
|
||||
if(entity_id===chunkId(0)){parseCfg();schedRender();return;}
|
||||
// Only re-parse config if the change didn't come from our own save (5s grace period)
|
||||
if(entity_id===chunkId(0)){if(Date.now()-lastSaveTime>5000)parseCfg();schedRender();return;}
|
||||
if(entity_id===DHCP){updateDHCP();schedRender();return;}
|
||||
if(entity_id.startsWith('device_tracker.')){schedRender();}
|
||||
}
|
||||
@@ -229,6 +230,7 @@ function parseCfg(){
|
||||
}
|
||||
}
|
||||
async function saveCfg(){
|
||||
lastSaveTime=Date.now();
|
||||
const json=JSON.stringify(cfg);
|
||||
try{localStorage.setItem('pc2_backup',json);}catch(e){}
|
||||
const saves=[];
|
||||
@@ -241,14 +243,8 @@ async function saveCfg(){
|
||||
catch(e){toast('Save failed','e');console.error('saveCfg',e);}
|
||||
}
|
||||
|
||||
// ── DHCP: sensor.home_dhcp_leases_lan ──
|
||||
// attributes.Leases (capital L) = array of {address, hostname, mac, expires, type}
|
||||
// Online = expires timestamp is in the future
|
||||
function getLeases(){return states[DHCP]?.attributes?.Leases||[];}
|
||||
function isOnline(lease){
|
||||
if(!lease.expires)return true;
|
||||
return new Date(lease.expires)>new Date();
|
||||
}
|
||||
function isOnline(lease){if(!lease.expires)return true;return new Date(lease.expires)>new Date();}
|
||||
function updateDHCP(){
|
||||
const s=states[DHCP];
|
||||
const dot=document.getElementById('dhcp-dot');const lbl=document.getElementById('dhcp-lbl');
|
||||
@@ -263,7 +259,6 @@ function getLease(mac){
|
||||
function deviceInfo(mac){
|
||||
const lease=getLease(mac);
|
||||
if(lease)return{online:isOnline(lease),ip:lease.address||'',label:lease.hostname||mac};
|
||||
// fallback: GPS device_tracker entities
|
||||
const m=normMac(mac);
|
||||
for(const[eid,s]of Object.entries(states)){
|
||||
if(!eid.startsWith('device_tracker.'))continue;
|
||||
@@ -281,7 +276,6 @@ function discoveredDevices(){
|
||||
if(!mac||assigned.has(mac))continue;
|
||||
out.push({mac,name:r.hostname||mac,ip:r.address||'',online:isOnline(r)});
|
||||
}
|
||||
// also include any GPS trackers with MACs not already in leases
|
||||
for(const[eid,s]of Object.entries(states)){
|
||||
if(!eid.startsWith('device_tracker.'))continue;
|
||||
const a=s.attributes||{};const mac=normMac(a.mac||a.mac_address||a.macaddress||'');
|
||||
@@ -363,7 +357,7 @@ function openAddDeviceModal(userId){
|
||||
const disc=discoveredDevices();const list=document.getElementById('disc-list');
|
||||
const note=document.getElementById('dhcp-note');
|
||||
const hasDHCP=!!states[DHCP]&&states[DHCP].state!=='unavailable'&&states[DHCP].state!=='unknown';
|
||||
note.innerHTML=hasDHCP?'':`<div class="ibox">DHCP sensor not found. Check that <code>sensor.home_dhcp_leases_lan</code> exists in HA. You can still enter a MAC manually.</div>`;
|
||||
note.innerHTML=hasDHCP?'':`<div class="ibox">DHCP sensor not found. Check <code>sensor.home_dhcp_leases_lan</code> exists in HA. You can still enter a MAC manually.</div>`;
|
||||
if(!disc.length){list.innerHTML=`<div style="padding:10px;text-align:center;font-size:.8rem;color:var(--muted)">${hasDHCP?'All devices already assigned':'No DHCP data available'}</div>`;}
|
||||
else{list.innerHTML=disc.map(d=>`<div class="dlist-item" data-mac="${d.mac}" data-name="${esc(d.name)}" onclick="pickDisc(this)"><span style="width:7px;height:7px;border-radius:50%;background:${d.online?'var(--ok)':'var(--muted)'};flex-shrink:0"></span><div><div class="dl-name">${esc(d.name)}</div><div class="dl-sub">${d.mac}${d.ip?' · '+d.ip:''}</div></div></div>`).join('');}
|
||||
openModal('add-dev-modal');
|
||||
|
||||
Reference in New Issue
Block a user