A lightweight smart home dashboard for the Barnes & Noble Nook Simple Touch (BNRV300) — an e-ink Android 2.1 device repurposed as a wall-mounted home control panel. Controls WiZ smart bulbs over local UDP, shows live weather, and runs entirely on a Raspberry Pi Zero 2W with no cloud dependency.
Home screen — clock, device tiles, weather summary and scenes at a glance
Fullscreen clock — tap the clock on the home screen to expand; hours and minutes fill the panel with date on the right
Weather detail — tap the weather panel for a split view: left panel shows current conditions (date, icon, big temperature, rain/humidity/UV, daily L/H range) on a grey background; right panel shows a 7-day forecast with day, icon, condition and temperature range
Fullscreen weather — tap temperature or rain % to expand a single stat edge-to-edge
Device drawer — tap any device tile to slide up per-bulb controls: power, brightness and colour temperature presets
This project requires a rooted Nook. The easiest way is NookManager — a graphical one-click rooter created by @jeff_kz on XDA Developers.
-
NookManager (original thread, fw 1.2.x and beyond) by jeff_kz: https://xdaforums.com/t/root-nookmanager-graphical-rooter-for-1-2-x-and-beyond.2040351/
-
Updated image for fw 1.2.2 by @nmyshkin (same instructions, replace the image): https://xdaforums.com/t/nst-g-updating-nookmanager-for-fw-1-2-2.3873048/#post-78286686
Full credit to both for keeping this ancient hardware alive and useful.
Do these steps once, right after rooting and connecting ADB. They remove B&N's home app, prevent the screen from ever sleeping, and auto-launch the browser on every boot.
The B&N launcher runs its own sleep timer that overrides Android's screen timeout and shows a screensaver. Remove it permanently:
adb shell "su -c 'mount -o rw,remount /dev/block/mmcblk0p5 /system \
&& rm /system/app/Home.apk \
&& mount -o ro,remount /dev/block/mmcblk0p5 /system'"Android's stock launcher (com.android.launcher) or ADW Launcher take over as fallback — neither interferes with always-on browser use.
Android 2.1 has no sqlite3 or content command to raise the screen timeout beyond 1 hour. The fix is a userinit.sh that Android executes on every boot:
svc power stayon true— keeps screen on while charging- Kernel wake lock — prevents CPU suspend
- Periodic touch event every 50 min — resets the screen-off timer before the 1-hour limit fires (handles the battery/unplugged case)
am start— opens the dashboard in NakedBrowser automatically
cat > /tmp/userinit.sh << 'EOF'
#!/system/bin/sh
svc power stayon true
echo "nook-dashboard" > /sys/power/wake_lock
am start -n com.fevdev.nakedbrowser/.NakedBrowserActivity -d "http://<your-pi-ip>:<port>"
(while true; do
sleep 3000
sendevent /dev/input/event2 3 0 10
sendevent /dev/input/event2 3 1 790
sendevent /dev/input/event2 1 330 1
sendevent /dev/input/event2 0 0 0
sendevent /dev/input/event2 1 330 0
sendevent /dev/input/event2 0 0 0
done) &
EOF
adb push /tmp/userinit.sh /data/local/userinit.sh
adb shell "su -c 'chmod 755 /data/local/userinit.sh'"Replace
<your-pi-ip>:<port>with your actual server address before pushing.
Once rooted, the Nook makes a surprisingly good always-on home dashboard. E-ink draws near-zero power when the image is static, the screen is large enough to read across a room, and the hardware is nearly free second-hand.
This project gives you:
- Clock & date — tap to expand fullscreen
- Live weather — current conditions + 7-day forecast via Open-Meteo (no API key needed), tap panels to expand; weather detail shows a split layout with big current conditions on the left and the 7-day forecast on the right
- Device controls — per-bulb on/off, brightness, colour temperature, RGB colour via a slide-up drawer; ON state renders in dark grey (not black) to prevent e-ink ghosting
- Scenes — one-tap lighting presets
- Fully local — Pi sends UDP commands directly to WiZ bulbs and Xiaomi/Mi devices; no cloud required for light control
- Offline resilience — if the server goes down, the dashboard automatically switches to the clock view (which keeps ticking client-side) and shows a SERVER OFFLINE badge until it reconnects
| Part | Notes |
|---|---|
| Nook Simple Touch BNRV300 | Android 2.1, 800×600 e-ink, rooted via NookManager |
| Raspberry Pi Zero 2W | Runs the Node.js server; any Pi or always-on machine works |
| WiZ smart bulbs | Any WiZ bulb reachable by local IP |
| Xiaomi / Mi / Yeelight bulbs | Optional; requires python-miio on the Pi (see below) |
git clone https://github.com/paras-pathak/nook-dashboard.git
cd nook-dashboard
cp config.example.json config.jsonEdit config.json:
port— port for the server (default3001)location— your latitude/longitude and city name (used for weather only)devices— your bulbs with local IPs and MAC addresses (WiZ and/or Xiaomi)scenes— lighting presets (see Scene commands below)
Finding bulb IPs: WiZ app → bulb → Device Info, or check your router's DHCP table. Set static DHCP leases by MAC address in your router so IPs never change.
Xiaomi devices use the miio protocol instead of WiZ UDP. Add "type": "miio" plus deviceId and token to their config entry:
{ "ip": "192.168.1.103", "mac": "AA:BB:CC:DD:EE:03", "name": "Bedside Lamp", "room": "Bedroom",
"type": "miio", "deviceId": 123456789, "token": "your32charhextoken0000000000000000" }The server uses python-miio to talk to these devices. Install it on your Pi:
pip3 install python-miio --break-system-packagesFinding your token: The easiest way is Xiaomi Cloud Tokens Extractor by @PiotrMachowski — run it on any machine, log in with your Mi Home credentials, and it prints tokens for all your devices. Full credit to PiotrMachowski for maintaining this tool.
git clone https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor.git
cd Xiaomi-cloud-tokens-extractor && pip3 install -r requirements.txt
python3 token_extractor.pyOption A — systemd (recommended, auto-starts on boot):
# Copy and edit the service file
cp nook-dashboard.service /etc/systemd/system/nook-dashboard.service
nano /etc/systemd/system/nook-dashboard.service # set User, WorkingDirectory, ExecStartFind your node path first:
which node || which nodejs
# If installed via Homebridge: find /opt -name node -type fThen enable and start:
sudo systemctl daemon-reload
sudo systemctl enable nook-dashboard
sudo systemctl start nook-dashboard
sudo systemctl status nook-dashboardOption B — manual:
nohup node server.js > server.log 2>&1 &Open http://<your-pi-ip>:<port> in a browser to confirm it works.
If you set up userinit.sh above, the browser opens automatically on every boot. Otherwise navigate manually to http://<your-pi-ip>:<port> in the Nook's browser.
Add
?v=1to the URL (increment each time) if you need to force a cache refresh — the old WebKit caches aggressively.
Each scene is a list of commands. Each command targets all devices, a room, or a specific bulb by MAC:
{ "all": true, "state": false }
{ "room": "Living Room", "state": true, "dimming": 50, "temp": 3000 }
{ "mac": "AA:BB:CC:DD:EE:01", "state": true, "r": 180, "g": 0, "b": 180 }| Field | Type | Description |
|---|---|---|
state |
boolean | on / off |
dimming |
10–100 | brightness % |
temp |
2200–6500 | colour temperature in Kelvin |
r g b |
0–255 | RGB colour (overrides temp) |
| Endpoint | Method | Description |
|---|---|---|
/api/state |
GET | Full state: weather, device states, config |
/api/device/:mac |
POST | Set bulb params (state, dimming, temp, r, g, b) |
/api/scene/:index |
POST | Trigger scene by index |
/api/admin/config |
POST | Save updated device/scene config |
If you want to modify the frontend, these will save you hours:
- No
display:flex— use-webkit-boxwith-webkit-box-orient,-webkit-box-direction,-webkit-box-align,-webkit-box-pack - No CSS Grid, no
gap, noinset— use floats and margins - Scroll drift —
overflow:hiddenalone isn't enough; addposition:fixedtohtml,body onclickon large divs is unreliable — always add a visible tappable back button; don't rely solely on tap-anywhere handlers- Aggressive caching — the browser caches JS and HTML even with
Cache-Control: no-cache; use versioned URLs (?v=N) on the Nook to force fresh loads - Timezone — old Android reports UTC regardless of system timezone; correct it server-side by sending the Pi's UTC offset and recalculating in JS
- Portrait on wake — after sleep the browser sometimes resets to portrait; CSS
@media (orientation:portrait)withrotate(90deg)and swappedwidth/heightforces landscape back @font-facewith TTF files fails silently — even with a correct MIME type, old WebKit may refuse to load font files over HTTP; embed the font as a base64 data URI in thesrc:of@font-faceto bypass this entirely- E-ink ghosting — avoid large pure-black (
#000) filled areas that stay on screen for extended periods; use dark grey (#444or similar) for persistent ON states - Matter devices — WiZ Matter bulbs still respond to direct UDP on local IP; no hub needed for basic on/off/dim/colour control
MIT




