From bcb179e7e4c81d679a3cef524d52f7fdd0c26a08 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 6 Mar 2026 08:30:36 -0700 Subject: [PATCH] Fix TruthValue handling for different firmware versions Some Accedian firmware reports SNMP TruthValue fields as '1'/'2' (INTEGER) while others use 'true'/'false' (textual). Add isTrue() helper that accepts both formats and replace all 15+ boolean checks across the viewer (present, diagCapable, active, enabled, filter enable flags, etc). Co-Authored-By: Claude Opus 4.6 --- build_nid_viewer.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/build_nid_viewer.py b/build_nid_viewer.py index 3e00a89..7393862 100644 --- a/build_nid_viewer.py +++ b/build_nid_viewer.py @@ -734,6 +734,9 @@ function formatUptime(sec) {{ p.push(s+'s'); return p.join(' '); }} +// SNMP TruthValue: some agents return '1'/'2', others 'true'/'false' +function isTrue(v) {{ return v === '1' || v === 'true' || v === true; }} + // Derive data ports and management port from connectors dynamically function getPortLists() {{ const connectors = DATA.connectors || {{}}; @@ -990,7 +993,7 @@ function renderHeader() {{ const cfgByNum = {{}}; for (const [k,v] of Object.entries(alarmCfg)) cfgByNum[v.number] = v; for (const [k,a] of Object.entries(alarmStatus)) {{ - if (a.active === '1') {{ + if (isTrue(a.active)) {{ activeCount++; const cfg = cfgByNum[a.number]; if (cfg) sevCounts[cfg.severity] = (sevCounts[cfg.severity]||0) + 1; @@ -1137,7 +1140,7 @@ function renderPanel() {{ const iface = ifaces[connIdx]; if (connType(connIdx) === 'sfp') {{ const sfp = sfpInfo[connIdx]; - const present = sfp && sfp.present === '1'; + const present = sfp && isTrue(sfp.present); if (!present) return 'empty'; if (iface && isUp(iface.ifOperStatus)) return 'present-link'; return 'present-nolink'; @@ -1152,7 +1155,7 @@ function renderPanel() {{ function sfpLabel(connIdx) {{ const sfp = sfpInfo[connIdx]; if (!sfp) return ''; - if (sfp.present !== '1') return 'EMPTY'; + if (!isTrue(sfp.present)) return 'EMPTY'; const pn = sfp.vendorPn || ''; if (pn.length > 8) return pn.substring(0,8); return pn || sfp.vendor || ''; @@ -1214,7 +1217,7 @@ function renderPanel() {{ // Power feeds let pwrHtml = '
'; for (const [k,p] of Object.entries(pwr)) {{ - const ok = p.present === '1'; + const ok = isTrue(p.present); pwrHtml += `
${{esc(p.name)}} ${{ok?'OK':'ABSENT'}}
`; }} pwrHtml += '
'; @@ -1336,7 +1339,7 @@ function renderSfp() {{ const thresh = sfpThresh[si] || {{}}; const conn = connectors[si] || {{}}; - if (!info || info.present !== '1') {{ + if (!info || !isTrue(info.present)) {{ cards += `
@@ -1348,7 +1351,7 @@ function renderSfp() {{ continue; }} - const ddm = info.diagCapable === '1'; + const ddm = isTrue(info.diagCapable); const ddmBadge = ddm ? 'DDM Supported' : 'DDM Not Supported'; @@ -1405,8 +1408,8 @@ function renderSfp() {{
CAPABILITIES
DDM Capable: ${{ddm ? 'Yes' : 'No'}}
-
Internal Cal: ${{info.internalCal==='1' ? 'Yes' : 'No'}}
-
Alarm Capable: ${{info.alarmCapable==='1' ? 'Yes' : 'No'}}
+
Internal Cal: ${{isTrue(info.internalCal) ? 'Yes' : 'No'}}
+
Alarm Capable: ${{isTrue(info.alarmCapable) ? 'Yes' : 'No'}}
SFF-8472 Rev: ${{esc(info.rev8472)}}
ID Type: ${{esc(info.idType)}}
Ext ID: ${{esc(info.extIdType)}}
@@ -1447,7 +1450,7 @@ function renderAlarms() {{ // Collect active alarms (when status table available) const active = []; for (const [k,a] of Object.entries(alarmStatus)) {{ - if (a.active === '1') {{ + if (isTrue(a.active)) {{ const cfg = cfgByNum[a.number] || {{}}; active.push({{ ...a, ...cfg, _statusId: k }}); }} @@ -1489,7 +1492,7 @@ function renderAlarms() {{ ${{esc(c.description)}}`; if (hasSeverity) rows += ` ${{sevLabel(c.severity)}} - ${{c.enabled === '1' ? 'Yes' : 'No'}}`; + ${{isTrue(c.enabled) ? 'Yes' : 'No'}}`; if (hasCondition) rows += ` ${{esc(c.conditionType)}} ${{esc(c.amoType)}}`; @@ -1636,12 +1639,12 @@ function renderFilters() {{ let rows = ''; for (const [id, f] of Object.entries(filters)) {{ const conditions = []; - if (f.macDstEn === '1') conditions.push('MAC Dst: ' + esc(f.macDst)); - if (f.macSrcEn === '1') conditions.push('MAC Src: ' + esc(f.macSrc)); - if (f.etypeEn === '1') conditions.push('EType: ' + esc(f.etype)); - if (f.vlan1IdEn === '1') conditions.push('VLAN1: ' + esc(f.vlan1Id)); - if (f.vlan2IdEn === '1') conditions.push('VLAN2: ' + esc(f.vlan2Id)); - if (f.vlan1PriorEn === '1') conditions.push('PCP1: ' + esc(f.vlan1Prior)); + if (isTrue(f.macDstEn)) conditions.push('MAC Dst: ' + esc(f.macDst)); + if (isTrue(f.macSrcEn)) conditions.push('MAC Src: ' + esc(f.macSrc)); + if (isTrue(f.etypeEn)) conditions.push('EType: ' + esc(f.etype)); + if (isTrue(f.vlan1IdEn)) conditions.push('VLAN1: ' + esc(f.vlan1Id)); + if (isTrue(f.vlan2IdEn)) conditions.push('VLAN2: ' + esc(f.vlan2Id)); + if (isTrue(f.vlan1PriorEn)) conditions.push('PCP1: ' + esc(f.vlan1Prior)); const condStr = conditions.length ? conditions.join(', ') : 'any (catchall)'; rows += ` @@ -1802,7 +1805,7 @@ function renderLldp() {{ const iface = ifaces[portIdx]; if (isSfp) {{ const sfp = sfpInfo[portIdx]; - const present = sfp && sfp.present === '1'; + const present = sfp && isTrue(sfp.present); if (!present) return 'empty'; if (iface && isUp(iface.ifOperStatus)) return 'present-link'; return 'present-nolink'; @@ -2005,7 +2008,7 @@ function renderCoverage() {{ // Check SFP DDM const sfpInfo = DATA.sfp_info || {{}}; for (const [k,s] of Object.entries(sfpInfo)) {{ - if (s.present === '1' && s.diagCapable !== '1') {{ + if (isTrue(s.present) && !isTrue(s.diagCapable)) {{ gaps.push({{ type: 'red', text: `SFP-${{k}} DDM: Not available via SNMP (diagCapable=false). NID web UI reads SFP I2C bus directly.`