3 Commits

Author SHA1 Message Date
root
0866459b23 feat(devices): map MACs to LAN devices; identify Orbi satellite + Galaxy Tab
ARP/nmap rescan (2026-06-08) attaches real MACs to the devices band and shows
them in the UI. Reclassifies two flagged "unknowns": .13 = Orbi mesh satellite
(BC:A5:11:.. Netgear; the uhttpd UI made it look like a rogue OpenWrt box) →
Network; .171 = Galaxy Tab S4 (randomized MAC) → Personal. Remaining flags are
.15 (ASUSTek, needs ID) and .34/.35/.51 (offline).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 20:31:37 +10:00
root
d69d605108 chore(infra): drop retired ct301 from network_hosts seed
Void 1 (CT 301, .11) is retired/destroyed; remove its inventory seed row so
fresh installs don't list a dead host. Live row already deleted; the migrate
runner is filename-tracked so 023 won't re-run on existing DBs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 20:20:47 +10:00
root
9aacc58c35 chore(release): 2.0.0 — drop -alpha; Void 1 retired, CTs renamed
Void 2 reaches GA. Void 1 (CT 301) was stopped, fully backed up (vzdump +
off-CT data tarball), and destroyed; CT 310/311 renamed void-db/void-app;
the legacy void1 registry tile removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 20:09:11 +10:00
8 changed files with 32 additions and 26 deletions

View File

@@ -3,6 +3,12 @@
All notable changes to Void 2.0 are documented here. All notable changes to Void 2.0 are documented here.
Format: [Keep a Changelog](https://keepachangelog.com). Format: [Keep a Changelog](https://keepachangelog.com).
## 2.0.0 — General availability (Void 1 retired)
- **Dropped the `-alpha` tag.** Void 2 is *the* homelab dashboard; `void.hynesy.com` has served it since alpha-18.
- **Void 1 retired.** CT 301 stopped, backed up (vzdump archive + off-CT data tarball), and destroyed 2026-06-08.
- **CTs renamed**: `void2-db` / `void2-app` (CT 310 / 311) → `void-db` / `void-app`.
- **Registry**: removed the legacy `void1` service tile.
## 2.0.0-alpha.27 ## 2.0.0-alpha.27
- feat: Timelapse + AI Usage folded into the left rail as an "Apps" section, - feat: Timelapse + AI Usage folded into the left rail as an "Apps" section,
embedded as cross-origin HTTPS iframes; each stays chromeless at its own URL. embedded as cross-origin HTTPS iframes; each stays chromeless at its own URL.

View File

@@ -23,7 +23,6 @@
{ "id": "qbittorrent", "name": "qBittorrent", "category": "media", "host": "win10", "url": "http://192.168.1.230:8080", "icon": "qbittorrent" }, { "id": "qbittorrent", "name": "qBittorrent", "category": "media", "host": "win10", "url": "http://192.168.1.230:8080", "icon": "qbittorrent" },
{ "id": "chaptarr", "name": "Chaptarr", "category": "media", "host": "ct100", "url": "http://192.168.1.230:8789", "external": "https://chaptarr.hynesy.com", "icon": "readarr" }, { "id": "chaptarr", "name": "Chaptarr", "category": "media", "host": "ct100", "url": "http://192.168.1.230:8789", "external": "https://chaptarr.hynesy.com", "icon": "readarr" },
{ "id": "void1", "name": "The Void 1.x", "category": "other", "host": "ct301", "url": "http://192.168.1.11:2424", "icon": "void" },
{ "id": "farm-timelapse", "name": "Farm Timelapse", "category": "other", "host": "192.168.1.108", "url": "http://192.168.1.108:8000", "icon": "" }, { "id": "farm-timelapse", "name": "Farm Timelapse", "category": "other", "host": "192.168.1.108", "url": "http://192.168.1.108:8000", "icon": "" },
{ "id": "magicmirror", "name": "MagicMirror", "category": "other", "host": "ct111 · .224", "url": "http://192.168.1.224:8080", "icon": "magicmirror" }, { "id": "magicmirror", "name": "MagicMirror", "category": "other", "host": "ct111 · .224", "url": "http://192.168.1.224:8080", "icon": "magicmirror" },
{ "id": "claude-usage", "name": "Claude Usage", "category": "other", "host": "ct300", "url": "http://192.168.1.212:8080", "icon": "claude" } { "id": "claude-usage", "name": "Claude Usage", "category": "other", "host": "ct300", "url": "http://192.168.1.212:8080", "icon": "claude" }

View File

@@ -32,7 +32,6 @@ INSERT INTO network_hosts (id, kind, name, node, ip, mac, note) VALUES
('ct111','lxc','magicmirror','z','192.168.1.224','BC:24:11:6C:D4:E6','MagicMirror (static, was DHCP .27)'), ('ct111','lxc','magicmirror','z','192.168.1.224','BC:24:11:6C:D4:E6','MagicMirror (static, was DHCP .27)'),
('ct112','lxc','obd2','z','192.168.1.225','BC:24:11:E7:D8:BF','OBD2 telemetry (static, was DHCP .28)'), ('ct112','lxc','obd2','z','192.168.1.225','BC:24:11:E7:D8:BF','OBD2 telemetry (static, was DHCP .28)'),
('ct300','lxc','claude','z','192.168.1.212','BC:24:11:9E:AA:73','Claude Code workspace'), ('ct300','lxc','claude','z','192.168.1.212','BC:24:11:9E:AA:73','Claude Code workspace'),
('ct301','lxc','void1','z','192.168.1.11','BC:24:11:4D:B7:CC','Void 1.x legacy'),
('ct310','lxc','void2-db','z','192.168.1.215','BC:24:11:49:C6:29','Void 2.0 Postgres'), ('ct310','lxc','void2-db','z','192.168.1.215','BC:24:11:49:C6:29','Void 2.0 Postgres'),
('ct311','lxc','void2-app','z','192.168.1.216','BC:24:11:9B:B7:3A','Void 2.0 app'), ('ct311','lxc','void2-app','z','192.168.1.216','BC:24:11:9B:B7:3A','Void 2.0 app'),
('vm117','vm','Pterodactyl-Deb','z','192.168.1.247','BC:24:11:37:C1:F7','Game panel (static, in-guest)'), ('vm117','vm','Pterodactyl-Deb','z','192.168.1.247','BC:24:11:37:C1:F7','Game panel (static, in-guest)'),

View File

@@ -1,6 +1,6 @@
{ {
"name": "void-server", "name": "void-server",
"version": "2.0.0-alpha.27", "version": "2.0.0",
"type": "module", "type": "module",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@@ -1,38 +1,38 @@
{ {
"note": "Auto-scanned LAN devices (ARP/nmap 2026-06-02). Separate from Little Blue's homelab services. Vendor-guessed; identification + live discovery to come.", "note": "LAN devices ARP/nmap rescan 2026-06-08 with MACs mapped. Separate from Little Blue's homelab services (Proxmox BC:24:11:* guests, tracked in the infra inventory). Locally-administered / randomized MACs (2nd hex digit 2/6/A/E) can't be OUI-identified and are labelled by hand.",
"groups": [ "groups": [
{ "name": "Smart Home", "devices": [ { "name": "Smart Home", "devices": [
{ "name": "Amazon Echo", "ip": "192.168.1.3", "vendor": "Amazon" }, { "name": "Amazon Echo", "ip": "192.168.1.3", "mac": "48:43:DD:FC:2F:84", "vendor": "Amazon" },
{ "name": "Amazon Echo", "ip": "192.168.1.4", "vendor": "Amazon" }, { "name": "Amazon Echo", "ip": "192.168.1.4", "mac": "14:0A:C5:6D:15:6E", "vendor": "Amazon" },
{ "name": "Smart device", "ip": "192.168.1.6", "vendor": "Beken" }, { "name": "Smart device", "ip": "192.168.1.6", "mac": "C8:47:8C:01:17:70", "vendor": "Beken" },
{ "name": "Smart device", "ip": "192.168.1.23", "vendor": "Tuya" }, { "name": "Smart device", "ip": "192.168.1.23", "mac": "D4:A6:51:12:36:92", "vendor": "Tuya" },
{ "name": "Xiaomi device", "ip": "192.168.1.20", "vendor": "Xiaomi" } { "name": "Xiaomi device", "ip": "192.168.1.20", "mac": "EC:4D:3E:36:EF:E1", "vendor": "Xiaomi" }
]}, ]},
{ "name": "Entertainment", "devices": [ { "name": "Entertainment", "devices": [
{ "name": "Google / Nest", "ip": "192.168.1.12", "vendor": "Google" }, { "name": "Google / Nest", "ip": "192.168.1.12", "mac": "1C:53:F9:BB:32:24", "vendor": "Google" },
{ "name": "Google / Nest", "ip": "192.168.1.14", "vendor": "Google" }, { "name": "Google / Nest", "ip": "192.168.1.14", "mac": "D4:F5:47:95:33:93", "vendor": "Google" },
{ "name": "Google / Nest", "ip": "192.168.1.18", "vendor": "Google" }, { "name": "Google / Nest", "ip": "192.168.1.18", "mac": "EC:4D:3E:37:38:8F", "vendor": "Google", "note": "MAC OUI is Xiaomi — label may be wrong" },
{ "name": "Google / Nest", "ip": "192.168.1.21", "vendor": "Google" }, { "name": "Google / Nest", "ip": "192.168.1.21", "vendor": "Google" },
{ "name": "Google / Nest", "ip": "192.168.1.22", "vendor": "Google" }, { "name": "Google / Nest", "ip": "192.168.1.22", "vendor": "Google" },
{ "name": "Cambridge Audio", "ip": "192.168.1.29", "vendor": "StreamMagic" }, { "name": "Cambridge Audio", "ip": "192.168.1.29", "mac": "48:70:1E:01:4F:7B", "vendor": "StreamMagic" },
{ "name": "Apple TV / HomePod", "ip": "192.168.1.43", "vendor": "Apple" }, { "name": "Apple TV / HomePod", "ip": "192.168.1.43", "mac": "08:66:98:B9:CF:F2", "vendor": "Apple" },
{ "name": "Samsung TV", "ip": "192.168.1.24", "vendor": "Samsung" } { "name": "Samsung TV", "ip": "192.168.1.24", "mac": "1C:86:9A:4C:F0:EC", "vendor": "Samsung" }
]}, ]},
{ "name": "Personal", "devices": [ { "name": "Personal", "devices": [
{ "name": "Apple device", "ip": "192.168.1.133", "vendor": "Apple" }, { "name": "Galaxy Tab S4", "ip": "192.168.1.171", "mac": "5A:DA:61:7A:0F:12", "vendor": "Samsung (randomized MAC)" },
{ "name": "Samsung device", "ip": "192.168.1.61", "vendor": "Samsung" }, { "name": "Apple device", "ip": "192.168.1.133", "mac": "1C:57:DC:70:E8:2D", "vendor": "Apple" },
{ "name": "TP-Link device", "ip": "192.168.1.10", "vendor": "TP-Link" } { "name": "Samsung device", "ip": "192.168.1.61", "mac": "A0:D0:5B:04:70:96", "vendor": "Samsung" },
{ "name": "TP-Link device", "ip": "192.168.1.10", "mac": "14:EB:B6:40:7E:93", "vendor": "TP-Link" }
]}, ]},
{ "name": "Network", "devices": [ { "name": "Network", "devices": [
{ "name": "Gateway / Router", "ip": "192.168.1.1", "vendor": "Netgear" } { "name": "Gateway / Router", "ip": "192.168.1.1", "mac": "44:A5:6E:68:D0:E9", "vendor": "Netgear" },
{ "name": "Orbi Satellite", "ip": "192.168.1.13", "mac": "BC:A5:11:3E:06:88", "vendor": "Netgear (Orbi mesh)" }
]}, ]},
{ "name": "Flagged / Unknown", "devices": [ { "name": "Flagged / Unknown", "devices": [
{ "name": "Rogue OpenWrt", "ip": "192.168.1.13", "vendor": "Netgear · uhttpd", "flag": true }, { "name": "ASUS device", "ip": "192.168.1.15", "mac": "24:4B:FE:8E:09:A4", "vendor": "ASUSTek", "flag": true },
{ "name": "ASUS device", "ip": "192.168.1.15", "vendor": "ASUSTek", "flag": true }, { "name": "Unknown", "ip": "192.168.1.34", "vendor": "randomized MAC · offline", "flag": true },
{ "name": "Unknown", "ip": "192.168.1.34", "vendor": "randomized MAC", "flag": true }, { "name": "Unknown", "ip": "192.168.1.35", "vendor": "unknown · offline", "flag": true },
{ "name": "Unknown", "ip": "192.168.1.35", "vendor": "unknown", "flag": true }, { "name": "Unknown", "ip": "192.168.1.51", "vendor": "randomized MAC · offline", "flag": true }
{ "name": "Unknown", "ip": "192.168.1.51", "vendor": "randomized MAC", "flag": true },
{ "name": "Unknown", "ip": "192.168.1.171", "vendor": "randomized MAC", "flag": true }
]} ]}
] ]
} }

View File

@@ -562,6 +562,7 @@ body.drawer-open #scrim { opacity: 1; pointer-events: auto; }
} }
.dv-tile .dv-nm { font-family: var(--font-ui); font-size: 13px; color: var(--text); } .dv-tile .dv-nm { font-family: var(--font-ui); font-size: 13px; color: var(--text); }
.dv-tile .dv-ip { font-family: var(--font-mono); font-size: 12px; color: var(--muted); } .dv-tile .dv-ip { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.dv-tile .dv-mac { font-family: var(--font-mono); font-size: 10px; color: var(--muted); opacity: .6; letter-spacing: .02em; }
.dv-tile .dv-vendor { font-family: var(--font-ui); font-size: 11px; color: var(--muted); opacity: .7; } .dv-tile .dv-vendor { font-family: var(--font-ui); font-size: 11px; color: var(--muted); opacity: .7; }
.dv-tile.flag { border-color: var(--bad); background: #1a1012; } .dv-tile.flag { border-color: var(--bad); background: #1a1012; }
.dv-tile.flag .dv-nm { color: var(--bad); } .dv-tile.flag .dv-nm { color: var(--bad); }

View File

@@ -20,6 +20,7 @@ async function load() {
el('div', { class: 'dv-tile' + (d.flag ? ' flag' : '') }, el('div', { class: 'dv-tile' + (d.flag ? ' flag' : '') },
el('span', { class: 'dv-nm' }, d.name), el('span', { class: 'dv-nm' }, d.name),
el('span', { class: 'dv-ip' }, d.ip), el('span', { class: 'dv-ip' }, d.ip),
d.mac ? el('span', { class: 'dv-mac' }, d.mac) : null,
el('span', { class: 'dv-vendor' }, d.vendor || '')))))); el('span', { class: 'dv-vendor' }, d.vendor || ''))))));
mount(host, mount(host,
el('div', { class: 'dv-hd' }, el('div', { class: 'dv-hd' },

View File

@@ -13,7 +13,7 @@ import { mcpAuth } from './lib/api/middleware/mcp_auth.js';
import { handleMcp } from './lib/mcp/http.js'; import { handleMcp } from './lib/mcp/http.js';
import httpProxy from 'http-proxy'; import httpProxy from 'http-proxy';
const VERSION = '2.0.0-alpha.27'; const VERSION = '2.0.0';
// Proxy /terminal (+ its WebSocket) to ttyd on CT 300, so the embedded terminal // Proxy /terminal (+ its WebSocket) to ttyd on CT 300, so the embedded terminal
// works whether the Void is reached via Traefik (void2-app.hynesy.com) OR the // works whether the Void is reached via Traefik (void2-app.hynesy.com) OR the