I had a spare 1920 by 1080 monitor and a small PC doing nothing. Together they became a heads-up display: four camera feeds across the top and a weather panel underneath. It runs in Rainmeter, it has no browser and no cloud dashboard, and it has survived a year of daily use. Here is how it is put together and what I would do differently.

Layout

The screen is split into a 2 by 2 grid of camera tiles, each 960 by 540, with the weather strip overlaid along the bottom. Each tile is its own Rainmeter skin so I can move or disable one without touching the rest.

Cameras: snapshot polling

The first version used WebParser with Download=1 against my local snapshot proxy, refreshing each tile once a second. It is simple and it is enough to see who is on the drive. The downside is that one frame a second is not video, and four tiles polling at once is a surprising amount of HTTP traffic.

Weather: event-driven, not polled

The weather panel is a PNG rendered by a PowerShell script from Apple’s WeatherKit API. The script draws a five-day strip, a temperature graph and a wind arrow with System.Drawing and writes the image to disk every fifteen minutes.

Rainmeter does not poll it. The skin uses a FileView measure watching the folder, and OnChangeAction redraws the meter when the file changes.

[MeasureWeatherFile]
Measure=Plugin
Plugin=FileView
Path=C:\hud\weather
OnChangeAction=[!UpdateMeter MeterWeather][!Redraw]

[MeterWeather]
Meter=Image
ImageName=C:\hud\weather\weather.png

This means the display is idle until something changes. It also means the script that makes the image is the only thing that knows about WeatherKit, so I can replace the data source without touching the skin.

Two small gotchas from the PowerShell side. Use [char]176 for the degree sign rather than typing it, otherwise it depends on the file encoding. And if you schedule the render with Task Scheduler, tick Run task as soon as possible after a scheduled start is missed. Without it, a daily trigger that fires while the PC is off never catches up, and the panel quietly shows yesterday’s forecast.

The upgrade: real video with mpv

Snapshot polling eventually annoyed me, so the cameras now play their RTSP substreams in mpv. Each camera gets a borderless mpv window positioned over its tile.

mpv --profile=low-latency --no-border --ontop `
    --geometry=960x540+0+0 --no-osc --no-input-default-bindings `
    rtsp://viewer:[email protected]/s1

Use the substream (s1 on UniFi cameras) rather than the full-resolution main stream. The tile is only 960 wide, and four main streams will max out a small CPU.

A pair of PowerShell scripts, Start-CCTV and Stop-CCTV, launch and kill the four windows, and a shortcut on the desktop toggles between the live view and the lighter snapshot skins.

What I would change

Start with mpv. The snapshot proxy was a good first step, but once you have seen real video on the wall you will not go back. Keep the weather event-driven, keep the camera credentials on a read-only account, and keep every element in its own skin so you can rebuild one without rebuilding all of them.