Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
hardware:baby-mirror [2026/07/20 18:17] – created diamondhardware:baby-mirror [2026/08/25 19:17] (current) Sparky
Line 1: Line 1:
 # Baby Mirror # Baby Mirror
  
-Donated to us by [/dev/hack](https://devhack.net), thanks to the folks over there!+The Baby Mirror is a [MagicMirror²](https://magicmirror.builders/smart mirror: 
 +a Raspberry Pi driving a monitor mounted behind one-way glass. It was donated to 
 +DMA by /dev/hack, thanks to the folks over there! We use it to display info to 
 +the space, including a feed of community quotes.
  
-It sits on top of the tool chest. There's currently plans to mount it just above the tool chest and on the wall.+## Where it is
  
-The mirror is a Raspberry Pi with a display driver boardThe mirror itself is basically just a big monitor.+Currently sitting on top of the tool chestPlanned to be wall-mounted above the 
 +chest.
  
-## Accessing the Mirror+## Hardware and software 
 + 
 +- **Board:** Raspberry Pi 3B+ (1 GB RAM) 
 +- **Display:** monitor + display driver board behind one-way glass 
 +- **OS:** Debian 13 (Trixie), 64-bit 
 +- **MagicMirror:** v2.37.0, running under Electron 42.5.2 on Node 24 
 +- **Networking:** managed by NetworkManager 
 + 
 +Note that the Pi has been updated since it was donated. It is no longer running 
 +the original /dev/hack image, so do not assume the stock /dev/hack layout or 
 +tooling. Paths and service setup are documented below and were confirmed on the 
 +device on 2026-08-25. 
 + 
 +## Finding the mirror on the network 
 + 
 +The mirror is on the DMA **user VLAN** (the `dma.space/hello` network), so you 
 +must be on that network to reach it. Its address comes from DHCP and changes. 
 + 
 +**The hostname does not resolve.** `smartmirror.user.dma.computer` will not 
 +resolve even when you are on the user VLAN, because every VLAN's DHCP hands out 
 +public DNS (1.1.1.1 and 1.0.0.1) and the router does not run an internal 
 +resolver. Do not rely on the hostname. mDNS (`smartmirror.local`) did not answer 
 +either when this was last checked. 
 + 
 +To find its current address, use one of: 
 + 
 +1. The router's DHCP lease table. 
 +2. A sweep of the user VLAN, then look for a host answering SSH with a Debian 
 +   banner. It was at `10.20.110.92` on 2026-08-25. 
 +3. A keyboard on the Pi itself and `hostname -I`. 
 + 
 +## Access 
 + 
 +- **SSH user:** `localadmin` 
 +- **Password:** stored in the **infra Vaultwarden** (vault.dma.space) under the 
 +  `smartmirror` item. That item lived in a personal vault until 2026-08-24 and 
 +  is now shared to the org, so if you cannot find it, check that you are looking 
 +  at the org vault. *(Do not paste credentials on this page, the wiki is 
 +  public.)* 
 + 
 +``` 
 +ssh localadmin@<ip> 
 +``` 
 + 
 +SSH host key fingerprints (verify on first connect): 
 + 
 +``` 
 +256  SHA256:3KxeMLQ0FjtB0n0XmRc0ugtDom14vmPNLxVWl/idsEA (ED25519) 
 +256  SHA256:QubQF144eoTKvpVRUvECWkBkMP5zG7dTFgEVft/hJaU (ECDSA) 
 +3072 SHA256:TfAb3KQ5LukzQ/dXTOH2esfB9q4QgeBNKeidXbsNLJs (RSA) 
 +``` 
 + 
 +All three were confirmed correct on 2026-08-25. 
 + 
 +## Console access 
 + 
 +If the mirror is off the network, you can get a local console with a USB 
 +keyboard: 
 + 
 +- **Ctrl+Alt+F2** switches to a text console. 
 +- **Ctrl+Alt+F7** switches back to the MagicMirror display. 
 + 
 +Two things to know before you rely on this. The console keymap is not US and has 
 +dead keys, so quotes and symbols are hard to type correctly, and `loadkeys` 
 +cannot help because `/usr/share/keymaps` is not installed. Anything involving 
 +quotes or a password is much easier over SSH. Also remember to log out of the 
 +console when you are done, since the space is shared. 
 + 
 +## If the mirror is on but shows no data 
 + 
 +A module reporting "no internet connection" usually means the Pi is up but has 
 +dropped off wifi. This happened on 2026-08-25 and the device had been offline 
 +long enough that nobody noticed. 
 + 
 +Wifi is managed by **NetworkManager**, not by a `wpa_supplicant.conf` file. 
 +There is no `/etc/wpa_supplicant/wpa_supplicant.conf` on this box, and editing 
 +`wpa_cli` network blocks will not work, because NetworkManager owns the 
 +supplicant. 
 + 
 +From a console on the Pi, the fix that worked was simply restarting the service: 
 + 
 +```bash 
 +sudo systemctl restart NetworkManager 
 +``` 
 + 
 +It reconnected and picked up a DHCP lease immediately. If that is not enough: 
 + 
 +```bash 
 +nmcli device status 
 +sudo nmcli device wifi rescan 
 +nmcli device wifi list 
 +sudo nmcli --ask device wifi connect dma.space/hello 
 +``` 
 + 
 +`nmcli device wifi connect` can report that the network cannot be found when the 
 +scan cache is stale, so always rescan first. Using `--ask` prompts for the 
 +password instead of taking it on the command line, which avoids both shell 
 +quoting and the console keymap problem. 
 + 
 +## How MagicMirror is managed 
 + 
 +MagicMirror runs as a **systemd user service** under the `localadmin` account. 
 +The unit lives at `~/.config/systemd/user/magicmirror.service`, is enabled at 
 +boot, and starts `/home/localadmin/scripts/start_mm.sh`. The systemd unit and 
 +the `/dev/hack` start script are not alternatives to each other; the unit runs 
 +the script. 
 + 
 +```bash 
 +systemctl --user status magicmirror.service 
 +systemctl --user restart magicmirror.service 
 +``` 
 + 
 +**Logs.** `journalctl --user` does not work on this device and reports "No 
 +journal files were found", because the per-user journal is not persisted. Use 
 +either of these instead: 
 + 
 +```bash 
 +systemctl --user status magicmirror.service --no-pager 
 +sudo journalctl _UID=1000 -n 40 --no-pager 
 +``` 
 + 
 +## Configuration 
 + 
 +MagicMirror config lives at: 
 + 
 +``` 
 +/home/localadmin/MagicMirror/config/config.js 
 +``` 
 + 
 +Modules are configured in the `modules: [ ... ]` array in that file. Installed 
 +modules live under `/home/localadmin/MagicMirror/modules/`. 
 + 
 +**Always back up and validate before restarting.** A malformed `config.js` stops 
 +MagicMirror from starting and leaves the mirror blank. 
 + 
 +```bash 
 +cd /home/localadmin/MagicMirror/config 
 +cp config.js config.js.bak-$(date +%F) 
 +# edit, then check that it parses before restarting: 
 +node -e 'require("/home/localadmin/MagicMirror/config/config.js"); console.log("OK")' 
 +systemctl --user restart magicmirror.service 
 +``` 
 + 
 +To roll back: 
 + 
 +```bash 
 +cp config.js.bak-<date> config.js 
 +systemctl --user restart magicmirror.service 
 +``` 
 + 
 +## Displaying the community quotes feed 
 + 
 +Quotes come from `#.offtopic > quotes` in Zulip, published as an Atom feed: 
 + 
 +``` 
 +https://portal.dma.space/api/feeds/quotes.atom 
 +``` 
 + 
 +The feed is public and needs no token. Confirm the mirror can reach it before 
 +relying on it, and **test with GET, not HEAD**. The endpoint is GET-only and 
 +`curl -I` returns 405 even when the feed is perfectly healthy: 
 + 
 +```bash 
 +curl -sS -o /dev/null -w '%{http_code}\n' https://portal.dma.space/api/feeds/quotes.atom 
 +``` 
 + 
 +The display uses MagicMirror's built-in 
 +[`newsfeed`](https://docs.magicmirror.builders/modules/newsfeed.html) module. 
 +This is the block currently in `config.js`: 
 + 
 +```js 
 +
 +    module: "newsfeed", 
 +    position: "bottom_bar", 
 +    config: { 
 +        feeds: [ 
 +            { 
 +                title: "DMA Quotes", 
 +                url: "https://portal.dma.space/api/feeds/quotes.atom" 
 +            } 
 +        ], 
 +        showSourceTitle: false, 
 +        showPublishDate: false, 
 +        showDescription: false 
 +    } 
 +}, 
 +``` 
 + 
 +`showDescription` is deliberately `false`. Each entry carries the whole quote in 
 +its `<title>` and has no `<summary>` or `<content>`, so there is no description 
 +to show. For the same reason, do not add `ignoreOldItems`: quotes are posted 
 +infrequently and the newest entry is often weeks old, so filtering by age would 
 +empty the bar. 
 + 
 +The large centred text on the mirror is the separate `compliments` module, not 
 +the quotes feed. 
 + 
 +## Editing safely 
 + 
 +This is a **production device** on the space's network. Coordinate before making 
 +changes, back up `config.js` first, validate that it parses, and restart the 
 +service to apply. If the mirror comes up blank after a change, restore the 
 +backup and restart. 
 + 
 +## Known issues 
 + 
 +- The wifi dropout described above has not been tested across a reboot. The 
 +  NetworkManager profile should persist, but a silent recurrence is possible. 
 +  If the mirror goes dark again, check wifi first.
  
-TODO