()
| 1759 | const rssi = (v.rssi == null) ? '—' : `${v.rssi}`; |
| 1760 | const rcol = (v.rssi == null) ? '#64748b' : _wifiSignalColor(v.rssi); |
| 1761 | const sel = _wifiState.btSelected === v.mac; |
| 1762 | return `<tr class="border-b border-slate-800/60 cursor-pointer hover:bg-slate-800/40${sel ? ' bg-sky-500/15' : ''}" onclick="wifiBtSelect('${v.mac}')" title="Click to highlight this device on the spectrum"> |
| 1763 | <td class="py-1 pr-3">${sel ? '<span class="text-sky-400">▸</span> ' : ''}${name}<div class="text-[10px] text-gray-600 font-mono">${v.mac}</div></td> |
| 1764 | <td class="py-1 pr-3"><span style="color:${k.c}">${k.t}</span>${v.randomized ? ' <span class="text-[9px] text-gray-500">rnd</span>' : ''}</td> |
| 1765 | <td class="py-1 pr-3">${v.vendor || '—'}</td> |
| 1766 | <td class="py-1 pr-3">${cls}</td> |
| 1767 | <td class="py-1 pr-3 text-right font-mono" style="color:${rcol}">${rssi}</td> |
| 1768 | </tr>`; |
| 1769 | }).join(''); |
| 1770 | } |
| 1771 | |
| 1772 | // Click a BT device row → highlight it on the 2.4 GHz spectrum (toggle off if |
| 1773 | // the same row is clicked again). Mirrors the Wi-Fi AP select behaviour. |
| 1774 | function wifiBtSelect(mac) { |
| 1775 | _wifiState.btSelected = (_wifiState.btSelected === mac) ? null : mac; |
| 1776 | _wifiFsRenderSide(); |
| 1777 | _wifiBtRender(); |
| 1778 | if (_wifiState.data) _wifiDrawSpectrum(); |
| 1779 | } |
| 1780 | |
| 1781 | // ---- Zigbee / 802.15.4 overlay (via an on-demand Huginn sniff) ------------- |
| 1782 | // The Zigbee toggle stays greyed until a HuginnESP companion is on USB. |
| 1783 | function _wifiZbCheck() { |
| 1784 | fetch('/api/net/zigbee/status').then(r => r.json()).then(st => { |
| 1785 | const ok = !!(st && st.available); |
| 1786 | _wifiState.zbAvailable = ok; |
| 1787 | const chk = document.getElementById('wifi-zb'), lab = document.getElementById('wifi-zb-label'); |
| 1788 | if (chk) chk.disabled = !ok; |
| 1789 | if (lab) { |
| 1790 | lab.classList.toggle('opacity-40', !ok); |
| 1791 | lab.classList.toggle('cursor-not-allowed', !ok); |
| 1792 | lab.classList.toggle('cursor-pointer', ok); |
| 1793 | lab.classList.toggle('text-gray-400', ok); |
| 1794 | lab.title = ok ? 'Sniff Zigbee / 802.15.4 with the connected HuginnESP' |
| 1795 | : (st && st.error ? st.error : 'Connect a HuginnESP (ESP32-C5) companion to sniff Zigbee'); |
| 1796 | } |
| 1797 | _wifiFsSyncGates(); |
| 1798 | }).catch(() => {}); |
| 1799 | } |
| 1800 | |
| 1801 | function wifiZbScan() { |
| 1802 | if (_wifiState.zbBusy) return; |
nothing calls this directly
no test coverage detected