Project journal · Version history

Building Golowyn

The story of a camera observation application, from the first successful image to multi-camera discovery and configurable observation tasks. A record of what was built, what went wrong, and what was learned along the way.

Golowyn — Cornish for “ray of light” · Camera Capture, Analysis & Publishing

How it began

The starting point was an ordinary IP camera aimed at the sky over Boscastle, Cornwall. The question was simple: could a camera feed be captured, examined and eventually analysed without depending on a proprietary monitoring application?

The first experiments used a Septekon H40i and FFmpeg. Once its RTSP stream had been identified and successfully decoded, a small Python project began to take shape. It was named Golowyn, a Cornish word meaning “ray of light”: fitting for software whose work begins when light reaches a camera sensor.

What began as a sky-camera experiment gradually developed into a broader idea: camera-independent capture, local storage, live viewing and, eventually, automated observation. The emphasis has remained on modest hardware, user control and no required cloud service.

The version history

v0.1 — First light

Working prototype

The first practical milestone was an independent snapshot: connect directly to the H40i's RTSP feed, invoke FFmpeg and save a full-resolution image. The camera supplied a 2304 × 1296 H.265/HEVC video stream. A successful PNG capture proved that Golowyn could obtain an image without routing it through the existing camera-monitoring software.

The first successful photograph was given the name First Light. The initial project structure separated camera capture from future analysis, astronomy, publishing and web-interface modules, even though most of those modules were placeholders.

v0.2 — A window into the camera

Local dashboard

A small browser-based dashboard provided a way to browse captured images and request a new snapshot. It ran locally, initially at 127.0.0.1:8062. An update script was introduced to apply future releases while preserving private camera configuration, recorded images and the Python environment.

This established an important direction: a web interface could be useful without requiring an internet service or developer-operated cloud infrastructure.

v0.3 — Live preview

Interactive viewing

A low-bandwidth live preview was added, including an Economy mode and a Preview Off setting. The interface paused its preview work when the browser tab was no longer visible, rather than continuing to generate frames that nobody was watching.

Full-resolution snapshots remained available. Testing exposed a brief interruption in the preview while a snapshot was taken: two separate FFmpeg connections were competing for work. That observation suggested the next architectural improvement.

v0.4 — Shared acquisition

Engine experiment

The preview and manual snapshot paths were brought together around a shared source of decoded frames when preview was running. With preview idle, a snapshot could still be captured independently. The initial shared-frame implementation processed approximately two frames per second — suitable for testing the approach, but not yet a full-frame-rate recording or meteor-detection system.

Real-camera testing showed that the acquisition process could become idle after Preview Off. However, taking a snapshot appeared to restart preview unexpectedly. The underlying cause turned out to be in the web page, not the new acquisition path.

v0.4.1 — Remembering the user's choice

Verified behaviour

The dashboard had reloaded after each snapshot to show the new thumbnail, resetting the preview selection to its default Economy mode. The fix preserved the chosen preview setting across that page refresh.

Subsequent testing confirmed that Preview Off remained off after a snapshot and after minimising and restoring the browser window. Switching to another Firefox tab also suspended the live preview. This became the first practical shared-acquisition baseline.

Lesson: a small interface decision can make a correctly behaving background component appear faulty. Test what the user actually experiences, not only what the engine reports.

v0.5a — Beyond the first camera

Camera Manager test build

The next experiment was to stop treating the H40i as the only camera Golowyn would ever use. A Camera Manager introduced editable RTSP connections, connection testing with FFprobe, separate saved camera configurations and camera selection in the dashboard. The original single-camera configuration was to be adopted, not overwritten.

The first real test found a migration error immediately: the old configuration had never needed a camera ID, but the new registry expected one. Golowyn responded with “No valid camera configured.” This was not a failed camera connection; it was an assumption embedded in the new code.

v0.5a.1 — Respecting the old configuration

Compatibility fix tested

The migration was corrected to derive an identifier from the existing camera name without altering the original configuration file. North Sky returned to the dashboard. The existing live preview, both snapshot paths and the image galleries were verified, and Test Connection worked against the real camera.

Lesson: upgrades must account for configurations produced by earlier versions, not just files generated by the newest code.

v0.5a.2 — A second camera, and a hidden typo

Two-camera operation tested

Adding a second RTSP camera initially appeared not to work. The explanation was refreshingly ordinary: a typo in the password field, which had been masked while typing. A Show entered password checkbox was added to the Add and Edit forms. It reveals only what the user is entering; stored credentials are not prefilled into the webpage.

With the connection details corrected, a second camera was added and previewed successfully. Snapshots worked with the preview active and idle, and its friendly display name could be changed independently of its permanent storage ID. The two-camera test demonstrated that Golowyn's configuration was no longer tied to the first Septekon installation.

There was also an interface lesson: the Camera Settings form was taking up too much space on the observation dashboard and exposing connection details unnecessarily. Moving it to a dedicated Settings page was agreed as the remaining v0.5a tidy-up, and was implemented in v0.5a.3.

v0.5a.3 — A tidier observation dashboard

Settings interface tested

Camera Settings moved to its own page, leaving the ordinary dashboard focused on selecting cameras, watching the preview and taking photographs. Existing Add/Edit Camera and Test Connection functionality remained accessible through the settings screen.

The update was installed and the user reported that the dashboard and settings tests appeared to pass. This completed the planned interface tidy-up without changing the working capture engine.

v0.5b — A camera on a USB cable

USB and RTSP tested

The next milestone asked whether Golowyn could accept a directly connected camera rather than an RTSP stream. Linux identified an RS Camera with two video-device nodes. Its capabilities included MJPEG at up to 2560 × 1440 and 30 frames per second, and a slower YUYV mode at high resolutions. The camera also exposed a persistent /dev/v4l/by-id/ path, useful for keeping track of it if Linux changes device numbers.

The first independent FFmpeg photograph was entirely black, despite a successful connection and valid image file. Rather than treating the device as incompatible, we tried discarding the first 75 frames at 15 fps. The resulting photograph worked. This led to explicit startup-frame handling for snapshots taken while preview is idle; an already-running preview can supply its latest decoded frame directly.

The v0.5b update added V4L2 camera discovery and configuration alongside RTSP. The RS Camera was added through the settings screen, and snapshots worked both with preview active and with preview off. Live preview and a return to the previously configured RTSP cameras were also reported to be working.

Lesson: a successful device connection does not necessarily mean its very first frame is a usable photograph. Real hardware tests reveal timing and warm-up behaviours that simulated sources can miss.

The result establishes one working Linux USB-camera implementation, not universal webcam compatibility. Long-term operation and additional device types remain to be tested.

v0.6a — Observing without the browser

Timed capture tested

The first independent observer ran directly from the terminal, using the saved camera configuration to capture an image every thirty seconds. Tests confirmed that it could work while Firefox and the dashboard were closed. The terminal remained responsible for stopping the process; no unattended boot service had yet been introduced.

v0.6b — Keeping the camera connection open

RTSP and USB tested

Instead of starting FFmpeg for every photograph, a persistent observer kept one connection open and read frames continuously. The North Sky camera produced twelve timed images and 732 decoded frames over a test lasting more than five minutes, without reconnections.

The USB camera also produced repeated photographs. Then came an intentional failure test: unplugging the camera interrupted the stream, but Golowyn detected the loss, retried the connection, and resumed capturing after reconnection. Its final statistics showed three reconnections, nine saved captures, and a clean exit. This was an early demonstration of recovery, not a claim of long-term reliability.

v0.6c — Observation controls in the dashboard

Multi-camera observation tested

The persistent observer acquired controls in the browser dashboard: start, stop and select an interval, without opening a separate command-line session. Capturing could continue with the Firefox tab closed as long as the Golowyn dashboard server remained running. The first practical tests showed that the photographs were saved, but the visible gallery required an F5 refresh to display them.

Testing then progressed to simultaneous observation. North Sky continued capturing when the USB camera was unplugged, reconnected and its observation stopped. A further experiment used two distinct camera configurations, north_sky and north_sky_2, pointing at the same physical RTSP source. Both operated at different snapshot intervals, but each maintained its own connection: the shared-source, multiple-task architecture was still ahead.

Lesson: a successful background worker is only part of a useful application. Its status and newly saved images must also be communicated clearly to the viewer.

v0.6c.1 — A dashboard that keeps up

Initial interface tests passed

The Recent Captures gallery was changed to refresh without reloading the entire page, following the shortest active dashboard-managed observation interval. A manual snapshot could also refresh its thumbnail without resetting Preview Off. An observation indicator now distinguishes idle, starting, capturing, waiting and reconnecting where available from worker logs and recent captures; it is not yet direct frame-level telemetry.

Camera management also gained a removal dialogue: keep the archive by default, move that camera's captures to the operating system Trash, or explicitly choose permanent deletion with extra confirmation. Unique camera IDs and display names help keep configurations distinct, while deliberate duplicate video sources remain permitted for testing. Trash failures are intended to abort rather than silently becoming permanent deletion.

The user reported that the new interface behaviours appeared to work. Destructive deletion against real archived photographs was deliberately not tested, and long-term unattended reliability remains open. The next major design challenge is supporting several observation tasks on a single physical camera source without unnecessary duplicate decoding.

v0.7a — Two jobs, one camera connection

Shared multi-task prototype tested

The earlier experiment with two configurations of North Sky demonstrated that a single physical camera could be asked to take pictures at different intervals, but it also opened two separate RTSP connections. This build took the next step: one persistent acquisition stream served two timed observation tasks, named quick (30 seconds) and slow (40 seconds).

The real-camera test recorded ten photographs in total — six from quick and four from slow — using one FFmpeg connection. Each task could be paused or resumed independently. Two captures landed within roughly half a second of one another, without an observed conflict. The dashboard was intentionally left alone while this command-line engine was proven.

Lesson: a camera source and the tasks using that source are different things. Sharing acquisition helps avoid unnecessary camera connections, but tasks still need individual identities and output records.

v0.7a.1 — Giving each task its own archive

Task storage tested

The first multi-task test uncovered a practical problem: the two tasks saved photographs into the same camera folder, making it difficult to identify which had produced each image. The solution was to store each new photograph exactly once beneath data/captures/<camera-id>/tasks/<task-name>/, retaining the existing archive untouched.

The update also writes the camera ID, task ID and UTC frame-receipt timestamp into PNG metadata; the metadata has been checked locally but not yet independently verified on the live camera files. Testing on North Sky confirmed that the new task folders and subfolders were created and that captures arrived in their corresponding locations. No duplicate full-resolution images were added to a parent “All” directory.

Lesson: archive organisation matters early. Gallery views should combine existing files virtually, rather than creating redundant copies and consuming storage unnecessarily.

v0.7b — Tasks leave the command line

Dashboard tested

After the shared observer and task folders had proved themselves, the next step was giving people graphical controls: create timed tasks, edit their intervals, pause and resume them, and browse images from each task without manually launching a terminal session. The initial live test indicated that tasks and galleries worked. The original single-observer dashboard path remained temporarily for compatibility, so the interface still had overlapping controls.

v0.7b.1 — Making the galleries manageable

Gallery tested

Multiple observation tasks quickly produced more images than a continuously growing dashboard could reasonably display. The task gallery gained a two-row scrolling viewport, while the latest/recent views learned to include photographs from task-specific directories. The user confirmed captures continued and the new gallery height felt sensible. The next question was whether two galleries were even needed on one page.

v0.7b.2 — One camera in focus, all cameras in sight

Multi-camera strip tested

The selected camera's task gallery began showing the latest fifty task photographs with an option to load older images. The large Latest Capture view stayed tied to the selected camera, while Recent Captures became a compact, horizontally scrolling strip of ten recent captures across all configured cameras. This preserved the ability to notice activity elsewhere without reproducing a second full-sized gallery. In the real dashboard, North Sky, Driveway and USB camera captures appeared together.

v0.7b.3 — One Observation Tasks interface

Consolidated; regression corrected

The original Timed Observation panel had become redundant alongside shared tasks. We removed the competing controls and kept timed snapshots as the first explicit task type, leaving room in task definitions for future recording and detection jobs. Existing captures and the command-line observer remained available; old schedules were not silently restarted or migrated.

A regression appeared immediately: after switching cameras, Recent Captures stayed stuck on “Loading recent captures”. The cause was missing dashboard JavaScript introduced during the cleanup. v0.7b.3.1 restored the initialization and rendering code, and the user confirmed the hotfix worked. This was a useful reminder that consolidation needs regression testing, not just syntax checks.

v0.7c — The detachable Camera Wall

Four live previews tested

Golowyn gained a separate browser-based Camera Wall: selected entries could display an economical live preview, the latest saved photograph, or nothing. The wall was intentionally for viewing, not configuring tasks. The real test displayed four live tiles, representing three physical cameras and a deliberate duplicate source, and also confirmed Latest Capture mode.

Measurements on the four-core OptiPlex showed that three live tiles added three FFmpeg processes. Closing the wall removed them while the background observations continued. During the sampled test, those extra processes accounted for roughly 324 MiB of resident memory and 44% of one CPU core. The machine was already very busy with other applications, so this was an encouraging functional result but also a reason to measure and improve stream efficiency.

v0.7c.1 — Arranging the views

Layout and fullscreen tested

Automatic tiling, manual row-and-column layouts, explicit camera assignments and fullscreen viewing made the wall more practical for different displays. Preferences were stored locally in the browser. The user confirmed that fullscreen configuration did work after allowing for possible latency on the heavily loaded PC.

One problem remained: moving a camera to a different tile reset its display mode to Off. v0.7c.1.1 made Live / Latest Capture / Off settings follow the camera rather than its tile. The user installed the targeted hotfix and confirmed success. No camera acquisition code changed in that repair.

v0.7c.2–v0.7c.2c.1 — Stream choices and cautious camera management

Hardware tests; targeted fixes

Golowyn's economy preview could be fed from a camera's main or secondary RTSP stream, without changing which stream supplied full-resolution manual captures. On North Sky, the main stream was observed at 2304 × 1296 H.265 and its secondary stream at 640 × 360 H.264. Benchmarks showed significantly less decoding work for the secondary stream, but the H40i's secondary video sometimes lagged or froze. The same behaviour was reproduced in a direct FFplay test outside Golowyn; it cannot simply be attributed to the dashboard.

A camera-removal bug was also found and fixed: the original removal path did not reliably remove the entry from the registry. A disposable duplicate camera was subsequently removed with captures retained. Other destructive archive-removal options remain deliberately untested against real captures. Camera Settings gained a short explanatory note about secondary-stream trade-offs.

v0.7d–v0.7d.5 — Learning what ONVIF can and cannot tell us

Read-only hardware diagnostics

Work began with LAN WS-Discovery, which returned no responses from the two network cameras on this installation. A known camera's ONVIF service was then identified at port 8899, and Golowyn gained verified direct-port probing, explicit IP inspection and an opt-in, bounded private-subnet scan. Unlike checking whether a TCP port is merely open, the scanner verifies an ONVIF SOAP response. A scan of the local 192.168.1.0/24 network found both existing IP cameras without needing their Golowyn names.

Driveway returned two H.264 Media1 profiles, 1920 × 1080 and 768 × 432, each advertising a 15 fps limit. North Sky also returned two profiles (1920 × 1080 and 640 × 360, H.264, 15 fps) when ONVIF verification was temporarily disabled. With verification enabled, Media1 GetProfiles returned Sender/FailedAuthentication, even after testing temporary credentials. A camera-clock offset of approximately −5.7 seconds did not account for the failure. The diagnostic progressively improved error reporting and fixed an exception raised after an unsuccessful retry.

That authentication edge case was deliberately parked: both cameras already worked through RTSP, and ONVIF is an optional aid to discovery, not a prerequisite for observation. These were read-only queries; no PTZ or camera configuration changes were made.

v0.7e–v0.7e.2 — Discover cameras where you add them

Graphical workflow tested

ONVIF discovery first appeared as a browser page linked from Camera Settings, and a real subnet scan correctly identified both configured network cameras. Feedback led to moving discovery into the more natural Add Camera workflow and incorporating local USB/V4L2 enumeration. The combined results identified North Sky, Driveway and the USB camera as already configured, while still permitting intentional duplicate configurations. A new device can lead into normal setup; Golowyn does not guess RTSP paths or silently register cameras.

v0.7e.2 added a scanning spinner, disabled repeated submissions while a scan was under way and improved long USB-device-path wrapping. The user confirmed the progress indicator worked. Network-wide discovery of arbitrary RTSP-only devices, authenticated ONVIF profile setup and automatic stream configuration remain outside this milestone.

v0.7f.1 — Preparing snapshot settings without changing photographs

Compatibility tested

A capture and configuration audit identified an important gap: observation tasks needed independent output settings before JPEG support, storage policies and video recording were added. This update introduced a validated task-settings model for PNG/JPEG, image dimension percentages and JPEG quality while retaining existing tasks' PNG-at-full-size behaviour. It intentionally did not yet change the image writer. The installed build passed an initial dashboard and task regression check.

v0.7f.2 — Choosing what is actually saved

Installed; testing in progress

Observation tasks gained output choices for PNG or JPEG, 100%, 75%, 50% or 25% image dimensions, and JPEG quality settings. New tasks default to JPEG at full dimensions and quality 90, while earlier tasks retain their PNG output. Task galleries were extended to recognise both image formats, including older archived PNGs. Choosing a smaller JPEG means saving that image, not keeping an undisclosed full-resolution PNG duplicate. The manual snapshot route remains on its previous PNG behaviour.

On the live North Sky camera, two existing PNG tasks and a newly created JPEG task were observed producing captures. The new task initially appeared slow to settle into its interval, then began behaving more normally; USB-camera testing was described as somewhat glitchy. Those observations require more systematic testing before the build is considered stable. Existing archives have not been deliberately rewritten or migrated.

Principles emerging from development

Local first. Golowyn is intended to run on the owner's equipment. No required cloud service, central account or telemetry is planned.

The user's choices matter. Features such as audio recording, publishing and remote access should be disabled unless deliberately configured. Turning preview off should really leave it off.

Camera independence. The H40i is the first test device, not the definition of a camera. Generic RTSP configuration and locally connected webcams are intended to broaden compatibility.

Build the foundation first. The Camera Wall, unified camera discovery and configurable snapshot formats have been implemented at different levels of testing. Meteor detection, video recording, time-lapse generation, star trails and visitor-controlled webcam views remain future work, not established capabilities.

Keep the history honest. A tested prototype, a proposed feature and a published release are three different things.

What comes next

Beyond v0.7f.2

Current focus: verification and safeguards

Multi-camera discovery, local USB enumeration and camera identification are now available through Add Camera. Independent timed observation tasks can select JPEG or PNG output and scaled image dimensions. The latest snapshot-format update is still under real-camera testing: USB stability, first-capture warm-up and sustained task intervals need checking before a stability claim is justified.

The next planned work is to verify the capture-and-gallery regression surface, then consider preview quality presets and safeguards for explicit storage destinations, low disk space and missing removable drives. Scheduled video recording, event detection, astronomy extensions, image editing and website publishing remain planned capabilities, not current features.