🦉 ViewOwl
Turn any API data source into a live ESP32 display — without writing firmware

Part of the OWLOS open-source IoT family (ESP32 / ESP8266 firmware & tools) — ViewOwl is its next step, not a from-scratch experiment.
Try it live → view.owlos.sk — explore the dashboard and the template gallery right in your browser. (Public demo — beta, not for production; see the on-site notice.)
In one sentence
You write a regular HTML page that pulls data from any API. ViewOwl takes a screenshot of it and streams the image to a cheap ESP32 display over Wi-Fi. That’s it.
What problem does this solve?
Without ViewOwl
Say you want to show your weather station temperature on a small screen in the hallway. Here’s what you’d have to do:
- Write C/C++ firmware for ESP32 that talks to your specific API
- Handle JSON parsing on a microcontroller
- Draw the UI pixel-by-pixel using a graphics library
- Re-flash the device every time you change the design
- Repeat all of this for each new data source or display type
This is hard, slow, and requires deep embedded development knowledge.
With ViewOwl
- Take any data available over HTTP/API (weather, stock prices, smart home, telemetry — anything)
- Build an HTML page as you normally would — with CSS, animations, whatever design you like
- Host it on a server (or locally)
- ViewOwl automatically takes screenshots and streams them to the ESP32
The ESP32 just receives the image and shows it. No custom firmware per use case.
Who is this for?
| You are… |
ViewOwl helps you… |
| Building a home weather station |
Display a beautiful dashboard from Open-Meteo API without any ESP32 code |
| Monitoring servers or equipment |
Put Grafana / Prometheus status on a physical screen |
| Running a café or office |
Hang an info board with a menu, schedule, or announcements |
| Working with smart home systems |
Visualize Home Assistant data on a wall-mounted display |
| Trading crypto |
Show live prices on a bedside screen |
| A maker / hobbyist |
Build something cool without learning embedded GUI frameworks |
Real-world examples
Weather station
API: open-meteo.com (free, no key required)
Shows: temperature, humidity, pressure, forecast
Updates: every 5 minutes automatically
Write an HTML page that does a fetch() to Open-Meteo on load — and you get a beautiful live widget. ViewOwl renders it and sends it to the screen. A ready-made template is already included in the repo.
Server monitoring
API: your Prometheus, Grafana, Zabbix, or any monitoring tool
Shows: CPU, RAM, uptime, alerts
Updates: in real time
Already have a dashboard in your browser? Just give ViewOwl its URL — and it will appear on a physical screen in your server room.
Stock & crypto prices
API: CoinGecko, Yahoo Finance, any broker API
Shows: prices, charts, daily changes
Updates: every minute
Smart home
API: Home Assistant REST API, MQTT-to-HTTP bridge
Shows: room temperatures, device states, energy usage
Updates: on state change
Info board / announcements
Source: Google Sheets, Notion API, or plain static HTML
Shows: café menu, class schedule, office announcements
Updates: you edit the spreadsheet — the screen updates itself
How it works
flowchart TD
A["Your HTML page<br/>CSS · JavaScript · fetch() any API"]
B["Grabber — server<br/>renders the page in a real browser,<br/>screenshots it, converts to the display's format"]
C["UDP Server<br/>sends the frame to each device,<br/>and skips it when nothing has changed"]
D["ESP32 + display<br/>receives the frame and draws it"]
A --> B --> C -->|UDP / Wi-Fi| D
As a user, only the first and last parts matter:
- You write HTML → take an ESP32 with a display → connect to the network → done.
Smarter than it sounds — not just screenshots
ViewOwl doesn’t blast raw images over the air. Each frame is compressed before it’s sent, and a frame that hasn’t changed isn’t sent at all — the device tells the server what it already has, and the server skips it. Animations are pre-rendered once on the server, stored in the device’s flash, and play back locally even with no network. That’s how a wall of screens stays light on a small server and an ordinary Wi-Fi connection.
Why a custom protocol — and what it taught us
ViewOwl streams full-screen frames to microcontrollers with only a few hundred kilobytes of RAM. That workload breaks the usual IoT answers:
- MQTT is built for small pub/sub telemetry, not bulk binary frames — a broker hop, payload and buffering limits, and ESP32 MQTT clients that get flaky over multi-day uptimes.
- WebSocket / TCP carry connection state and socket buffers the device can’t spare; head-of-line blocking costs RAM a frame-pusher doesn’t have.
So the transport is small and purpose-built: a stop-and-wait flow over UDP (HELLO / AUTH / DATA / ACK / DONE) with retransmit and session recovery. Stop-and-wait is the point — the device never holds more than one packet, so memory stays bounded. It’s closer to “reliable file copy, one packet at a time” than to a TCP reimplementation. Devices run for weeks without watchdog reboots.
The non-obvious details are scar tissue from real failures, not preference:
- The frame checksum must match byte-for-byte across server and firmware. One mismatched CRC variant silently disables “skip unchanged frames” and makes every device re-download its identical frame forever — a freeze every few minutes until it’s found.
- Every frame is rendered at the device’s exact resolution. A 480×320 frame on a 320×240 panel crops; it doesn’t scale.
- Animated templates must be deterministic — frame N must always produce identical pixels (no
Math.random() / clock), or the dedup checksum never matches and the device re-downloads endlessly.
In practice the transport is the stable part; the hard, evolving engineering is the rendering side.
ViewOwl is more than a renderer for one screen. User accounts and roles already work today, alongside a real-time management dashboard, guest devices, and built-in security (rate limiting, IP auto-blocking). That’s why the server does more than a lone weather clock strictly needs — it’s designed to host many people’s devices, not one.
We deliberately run the live instance on modest hardware. It’s a standing stress test: pushing a small box on purpose surfaces limits early and keeps the system honest about what it can take. The heavier stack pays off the moment you run a fleet, let several people manage their own screens, or change content as often as you edit a web page. For a single static screen it’s more than you need — but it still runs on a small VPS or single-board computer.
Quick start
What you need
Hardware:
- ESP32 with an LCD display (ST7796 or ILI9341, 480×320 or 320×240), or a 240×240 round GC9A01 panel (integrated ESP32-C3)
- 5V power supply
- Wi-Fi network
Software:
- .NET 8 SDK
- ESP-IDF (to flash the ESP32)
Step 1 — Prepare your HTML page
Create a regular HTML page that fetches data from your API.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
width: 480px; height: 320px;
background: #0a0a1a;
color: #00ff88;
font-family: monospace;
display: flex; align-items: center; justify-content: center;
}
.temp { font-size: 72px; font-weight: bold; }
</style>
</head>
<body>
<div class="temp" id="temp">--°C</div>
<script>
async function update() {
const r = await fetch('https://api.open-meteo.com/v1/forecast?latitude=50.45&longitude=30.52¤t=temperature_2m');
const d = await r.json();
document.getElementById('temp').textContent = d.current.temperature_2m + '°C';
}
update();
setInterval(update, 60000);
</script>
</body>
</html>
The page dimensions must match your display resolution. The standard is 480×320 px.
Step 2 — Start the server
# Clone the repository
git clone https://github.com/KirinDenis/ViewOwl.git
cd ViewOwl
# Start the Grabber (renders your HTML to PNG)
dotnet run --project ViewOwl.Grabber.WebAPI
# In another terminal, start the UDP Server
dotnet run --project ViewOwl.UDP.Server
UDP Server listens on port 11000 by default.
Open ViewOwl.ESP32.Client/main/config.h and fill in your settings:
#define WIFI_SSID "YourWiFi"
#define WIFI_PASS "YourPassword"
#define SERVER_IP "192.168.1.100" // IP of the machine running UDP Server
#define SERVER_PORT 11000
Flash the firmware via ESP-IDF:
cd ViewOwl.ESP32.Client
idf.py build flash monitor
Step 4 — Done!
Power on the ESP32. It will connect to Wi-Fi, receive the first frame from the server, and show your HTML page on the display.
Project structure
ViewOwl/
├── ViewOwl.UDP.Server/ # UDP server — receives PNG, broadcasts frames
├── ViewOwl.UDP.Client.WPF/ # WPF client for Windows (debug / simulation)
├── ViewOwl.Grabber.WebAPI/ # Grabber — renders HTML to PNG via headless browser
├── ViewOwl.Grabber.Engine/ # Rendering engine (PuppeteerSharp / Chromium)
├── ViewOwl.ESP32.Client/ # ESP32 firmware — rectangular SPI panels (ESP-IDF, C)
├── ViewOwl.ESP32_C3.Client/ # ESP32-C3 firmware — 240×240 round GC9A01 display
├── ViewOwl.Config/ # Shared configuration
├── ViewOwl.UDP.Utils/ # UDP protocol utilities
└── ExchangeFolder/
└── SitesTemplates/ # Ready-made HTML templates (weather, dashboards)
Ready-made templates
The ExchangeFolder/SitesTemplates/ folder includes templates you can use right away:
| Template |
Description |
API |
scifi_weather.html |
Sci-fi weather widget |
Open-Meteo (free) |
scifi_weather_dashboard.html |
3-city weather dashboard |
Open-Meteo (free) |
scifi_weather_dashboard2.html |
Extended weather dashboard |
Open-Meteo (free) |
scifi_weather_3.html |
Full sensor dashboard: pressure, air quality, forecast |
Open-Meteo (free) |
All templates work without API keys and are ready to use out of the box.
Technical specs
| Parameter |
Value |
| Transport protocol |
UDP |
| Pixel format |
BGR565 (16-bit color) |
| Recommended resolution |
480×320 px |
| Supported displays |
ST7796, ILI9341, ILI9486 (rectangular) · GC9A01 240×240 round (ESP32-C3) |
| Server platform |
.NET 8, Linux ARM64 / x64 |
| Client platform |
ESP32 (ESP-IDF) |
| UDP Server port |
11000 |
| Grabber API port |
80 |
Limitations & things to know
- JavaScript is fully supported — the page is rendered by a real browser (Chromium)
- Page size must match the display resolution
- Refresh rate is controlled by the server configuration
- Network — ESP32 and server must be on the same network, or the server must be publicly accessible
- Colors may look slightly different from a monitor due to the BGR565 color depth of TFT displays
Part of OWLOS
ViewOwl is the latest project in the OWLOS open-source IoT line, developed with its maker community — not a one-off experiment.
ViewOwl carries those lessons forward into a server-rendered display platform.
Contributing
Templates, display drivers, bug fixes — all contributions are welcome!
- Fork the repository
- Create a branch:
git checkout -b feature/my-template
- Commit:
git commit -m 'Add: my weather template'
- Push:
git push origin feature/my-template
- Open a Pull Request
License
MIT — see License.md
Made with by humans and AI · ViewOwl — your data deserves a beautiful screen
评论