Configuration Guide

OWL uses two configuration files to separate detection settings from infrastructure settings. Both are standard INI files that can be edited with any text editor or adjusted through the web dashboard.

Config File Overview

File

Location

Purpose

GENERAL_CONFIG.ini

~/owl/config/

Detection parameters, camera, sensitivity presets, tracking, relay mapping

CONTROLLER.ini

~/owl/config/

MQTT, network mode, GPS, web dashboard, actuation timing

An active_config.txt file in the same directory points to the current detection config (defaults to config/GENERAL_CONFIG.ini).

Copy-on-write protection

GENERAL_CONFIG.ini and CONTROLLER.ini are protected defaults. When changes are made through the dashboard, a timestamped copy is created automatically (e.g. GENERAL_CONFIG_20260318_1430.ini) so the originals are never corrupted.

Sensitivity Presets

Instead of separate config files for each sensitivity level, OWL embeds sensitivity presets directly in GENERAL_CONFIG.ini:

[Sensitivity]
active = medium

[Sensitivity_Low]
exg_min = 25
exg_max = 200
hue_min = 41
hue_max = 80
...

[Sensitivity_Medium]
exg_min = 25
exg_max = 200
hue_min = 39
hue_max = 83
...

[Sensitivity_High]
exg_min = 22
exg_max = 210
hue_min = 35
hue_max = 85
...

Each preset stores the 9 GreenOnBrown threshold values. The [Sensitivity] active key determines which preset is loaded at startup. You can switch presets from the dashboard, the wired controller sensitivity switch, or the AI assistant.

Custom presets can be saved from the dashboard and are stored as additional [Sensitivity_YourName] sections in the config file.

Changing Settings

There are several ways to adjust OWL settings:

Dashboard sliders (recommended)

The web dashboard provides range sliders for all detection parameters. Changes take effect immediately and are persisted to the config file.

AI assistant

Open the Agent tab in the dashboard and describe what you want in plain language — e.g. “make detection more sensitive” or “switch to the exg algorithm”. See the AI Assistant guide.

Direct INI editing

Edit the config file directly with a text editor:

nano ~/owl/config/GENERAL_CONFIG.ini

Save the file and restart OWL for changes to take effect.

Command line flags

Override the config file or enable display mode at startup:

# Use a specific config file
python owl.py --config config/my_custom.ini

# Show display for threshold adjustment
python owl.py --show-display

# Camera focus mode
python owl.py --focus

# Process a video or image directory
python owl.py --input path/to/media

Complete GENERAL_CONFIG.ini Template

[System]
algorithm = exhsv
input_file_or_directory =
relay_num = 4
actuation_duration = 0.15
delay = 0
actuation_top = 0.0
actuation_bottom = 1.0
actuation_zone = 100
on_error = off

[Controller]
controller_type = none
status_led_pin = 40
gps_led_pin = 38
switch_purpose = recording
switch_pin = 36
detection_mode_pin_up = 36
detection_mode_pin_down = 35
recording_pin = 33
sensitivity_pin = 32

[Visualisation]
image_loop_time = 5

[Camera]
resolution_width = 1456
resolution_height = 1088
exp_compensation = -2
awb_mode = auto
awb_red_gain = 2.0
awb_blue_gain = 2.0
rotation = auto
crop_left = 0.02
crop_right = 0.02
crop_top = 0.02
crop_bottom = 0.02
crop_factor_horizontal = 0.02
crop_factor_vertical = 0.02
camera_type = auto

[GreenOnGreen]
model_path = models
confidence = 0.5
detect_classes =
actuation_mode = centre
min_detection_pixels = 50
inference_resolution = 320
crop_buffer_px = 20

[GreenOnBrown]
exg_min = 25
exg_max = 200
hue_min = 39
hue_max = 83
saturation_min = 50
saturation_max = 220
brightness_min = 60
brightness_max = 190
min_detection_area_percent = 0.0075
invert_hue = False

[DataCollection]
image_sample_enable = False
detection_enable = True
sample_method = whole
sample_frequency = 30
sample_mode = frames
sample_distance_m = 1.0
sample_interval_s = 2.0
jpeg_quality = 95
record_mode = images
video_max_s = 60
shutter_cap = False
smear_limit_mm = 2.0
min_speed_kmh = 1.0
save_directory = /media/owl/SanDisk
log_fps = False
camera_name = cam1
storage_location = auto
internal_save_directory = /home/owl/owl_images
min_free_gb = 4
image_quota_gb = 12

[Relays]
0 = 13
1 = 15
2 = 16
3 = 18

[Tracking]
tracking_enabled = False
track_class_window = 5
track_crop_persist = 3

[Sensitivity]
active = medium

[Sensitivity_Low]
exg_min = 25
exg_max = 200
hue_min = 41
hue_max = 80
saturation_min = 52
saturation_max = 218
brightness_min = 62
brightness_max = 188
min_detection_area_percent = 0.015

[Sensitivity_Medium]
exg_min = 25
exg_max = 200
hue_min = 39
hue_max = 83
saturation_min = 50
saturation_max = 220
brightness_min = 60
brightness_max = 190
min_detection_area_percent = 0.0075

[Sensitivity_High]
exg_min = 22
exg_max = 210
hue_min = 35
hue_max = 85
saturation_min = 40
saturation_max = 225
brightness_min = 50
brightness_max = 200
min_detection_area_percent = 0.004

Complete CONTROLLER.ini Reference

[MQTT]
enable = True
broker_ip = localhost
broker_port = 1883
device_id = auto

[WebDashboard]
port = 8000

[Network]
mode = networked
static_ip = localhost
controller_ip = localhost

[GPS]
# GPS data source (none / serial / tcp / gpsd)
source = none
# Serial device path and baud (only used when source = serial)
port = /dev/ttyACM0
baudrate = 9600
# TCP listener (only when source = tcp). `enable = True` is a deprecated
# back-compat alias for `source = tcp`.
enable = False
nmea_port = 8500
# Session / coverage tracking (applies to every non-none source)
boom_width = 12.0
track_save_directory = tracks

[Actuation]
# Relay timing — used as fallback when no GPS speed data
actuation_duration = 0.15
delay = 0.0
# Speed-adaptive actuation geometry (networked controller, or an OWL with its own GPS)
actuation_length_cm = 10
offset_cm = 30
speed_avg_window = 2.0

[Security]
# Per-device API token, minted automatically when the OWL is provisioned
# through the phone app (v3.11+). Guards mutating dashboard routes
# (network changes, passwords, shutdown/reboot, session delete) via the
# X-Device-Token header. Absent on units set up before v3.11 - those
# accept requests without the header (legacy behaviour). Deleting the
# section restores legacy behaviour; re-running first-boot setup mints
# a fresh token.
device_token = <minted-at-provisioning>

Parameter Reference — GENERAL_CONFIG.ini

System

Parameter

Default

Description

algorithm

exhsv

Detection algorithm: exg, exhsv, hsv, lut, gog, gog-hybrid

input_file_or_directory

(empty)

Path to image, video, or directory for offline processing. Leave empty for live camera.

relay_num

4

Number of relay lanes (1-4).

actuation_duration

0.15

Relay activation time in seconds.

delay

0

Delay between detection and actuation in seconds.

actuation_top

0.0

Top of the actuation band as a fraction of the cropped height (0.0 = top of crop). A weed fires its relay only while its centre is inside the band. Raise this to ignore weeds too far ahead.

actuation_bottom

1.0

Bottom of the actuation band as a fraction of the cropped height (1.0 = bottom of crop). Lower this to ignore weeds too close (where the solenoid can’t react in time).

actuation_zone

100

Legacy bottom-anchored zone (% from bottom). Used only if actuation_top/actuation_bottom are absent (then actuation_top = 1 - actuation_zone/100, actuation_bottom = 1.0). Prefer the band keys above.

on_error

off

What the nozzles do on a spraying fault: the camera stops sending frames, dashboard and switch control stops updating, or a relay is stuck on. off turns detection off and all nozzles off. on blanket sprays while spraying is switched on, if detection can no longer run (camera lost); otherwise spot spraying continues. Either way the fault shows on the dashboard, the phone app and the status LED.

Status LED fault codes. The status LED flashes a code, repeated, while a fault or error is active:

Flashes

Meaning

1

Camera or software dependency failed at start

2

Camera not found at start

3

Camera lost while running (spraying fault)

4

Dashboard and switch control stopped updating (spraying fault)

5

Storage full or storage error

6

No USB drive for recording, or the drive was removed

7

A relay is stuck on (spraying fault)

Controller

Parameter

Default

Description

controller_type

none

Wired controller type: none, ute, or advanced.

status_led_pin

40

BOARD pin for status indicator LED (shared by Ute and Advanced).

gps_led_pin

38

BOARD pin for GPS status LED (shared by Ute and Advanced).

switch_purpose

recording

Ute controller switch function: recording or detection.

switch_pin

36

BOARD pin for Ute controller toggle switch. Avoid BOARD 37 if using a Sixfab HAT. Pins used by on-device GPS hardware are refused (see below).

detection_mode_pin_up

36

BOARD pin for detection mode up (Advanced controller).

detection_mode_pin_down

35

BOARD pin for detection mode down (Advanced controller).

recording_pin

33

BOARD pin for recording toggle (Advanced controller).

sensitivity_pin

32

BOARD pin for sensitivity switch (Advanced controller).

Camera

Parameter

Default

Description

resolution_width

1456

Camera capture width in pixels.

resolution_height

1088

Camera capture height in pixels.

exp_compensation

-2

Exposure compensation (-8 to 8). Negative values give faster shutter speed. Applied live (no restart) on picamera2.

awb_mode

auto

White balance: auto, daylight, cloudy, tungsten, fluorescent, indoor or manual. auto lets libcamera balance the scene, the same as rpicam-hello. The presets pin the colour temperature to a narrow window of the Pi sensor tuning file (daylight = 5500-6500 K) and render Arducam IMX296 modules strongly red. manual disables auto white balance and applies the gains below. Applied live from the dashboard’s Advanced Settings editor or the phone app.

max_gain

auto

Gain limit while the shutter limit is active: auto, or a number such as 8. Lower means less noise but darker images in poor light. Set from the collect screen’s Camera settings.

awb_red_gain

2.0

Red colour gain (0.1-8.0), used only when awb_mode = manual. Higher = redder. Filled in by Calibrate white balance (dashboard Config tab or phone app): point the camera at bare soil or a grey card, tap once, and OWL samples the auto gains and locks them as manual so colours stay fixed for detection. The dashboard also shows the live gains and estimated colour temperature the camera is using.

awb_blue_gain

2.0

Blue colour gain (0.1-8.0), used only when awb_mode = manual. Set by the same calibration.

rotation

auto

Image rotation: auto, 0 or 180. auto is upright for the Global Shutter camera (IMX296, OWL 3.0 mount) and 180 for the classic enclosure, where the HQ/Camera Module 3 sensors mount upside down. Set 0 or 180 explicitly if your mount differs. Applied at startup - restart detection after changing it.

crop_left

0.02

Fraction of width cropped from the left edge (0.0-0.49).

crop_right

0.02

Fraction of width cropped from the right edge (0.0-0.49).

crop_top

0.02

Fraction of height cropped from the top edge (0.0-0.49).

crop_bottom

0.02

Fraction of height cropped from the bottom edge (0.0-0.49). Detection runs only inside the remaining rectangle; relay lanes are spread across the cropped width and recenter automatically.

crop_factor_horizontal

0.02

Legacy symmetric horizontal crop. Used only if crop_left/crop_right are absent (then both fall back to this value).

crop_factor_vertical

0.02

Legacy symmetric vertical crop. Used only if crop_top/crop_bottom are absent.

camera_type

auto

Camera selection: auto (auto-detect), rpi (force Pi camera), usb (force USB webcam).

allow_high_resolution

False

Bypass the Pi 3/4 832x640 safety clamp. Leave False unless you’ve verified your hardware handles the target resolution.

Geometry lives in GEOMETRY.ini

The crop edges (crop_left/right/top/bottom) and the actuation band (actuation_top/bottom) are mount geometry — physical to how a unit is bolted on. They live in their own config/GEOMETRY.ini, which OWL reads last so it always wins over any values in the active config. This means switching or saving a named detection config (sensitivity, algorithm, thresholds) never changes a unit’s geometry, and geometry is never copied into named configs. Set it with the dashboard’s Adjust geometry editor (which writes GEOMETRY.ini) or by editing GEOMETRY.ini by hand. The keys are documented in the [Camera] and [System] tables for reference.

Setting the resolution

Resolution can be changed two ways — pick whichever fits your workflow.

Dashboard Config tab. Open the dashboard → CONFIG tab → Camera section → Resolution dropdown. The dropdown offers the supported presets (1456x1088, 1280x960, 1280x720, 1024x768, 800x600, 640x480, 416x320, 320x240) and writes both resolution_width and resolution_height to the active config in a single step. Changes are persisted via the copy-on-write mechanism described above.

Direct INI editing. Set resolution_width and resolution_height independently under [Camera], then restart OWL for the change to take effect. This route is fine when you’re already editing the file for other reasons, or when you need a resolution outside the dashboard preset list.

Pi 3 / Pi 4 safety clamp

On the Raspberry Pi 3 and Pi 4, requests above 832x640 are silently clamped to 640x480. Older Pi models are known to lock up at higher resolutions, and the clamp prevents bricked devices in the field.

To override the clamp, set [Camera] allow_high_resolution = True — but only after verifying that the specific Pi hardware in front of you actually copes with the resolution you’re requesting. The dashboard surfaces an active clamp via a banner in the Camera section.

The Pi 5 is not affected by the clamp.

Visualisation

Parameter

Default

Description

image_loop_time

5

Seconds between display frame updates when using --show-display.

GreenOnGreen

Parameter

Default

Description

model_path

models

Directory containing YOLO model files (NCNN or PyTorch).

confidence

0.5

Minimum confidence threshold for detections (0.0-1.0).

detect_classes

(empty)

Comma-separated class IDs to detect. Empty means all classes.

actuation_mode

centre

How detections map to relays: centre (bounding box centre) or zone (segmentation mask pixel count, requires seg model).

min_detection_pixels

50

Minimum pixel count for valid segmentation detections (zone mode).

inference_resolution

320

Input image size for YOLO inference. Smaller is faster, larger is more accurate.

crop_buffer_px

20

Pixel buffer added around crop mask regions (gog-hybrid mode).

GreenOnBrown

Parameter

Default

Description

exg_min

25

Minimum Excess Green threshold (0-255). Lower = more sensitive.

exg_max

200

Maximum Excess Green threshold (0-255). Keep above 180.

hue_min

39

Minimum hue threshold (0-179). Green vegetation is typically 39-83.

hue_max

83

Maximum hue threshold (0-179).

saturation_min

50

Minimum saturation threshold (0-255).

saturation_max

220

Maximum saturation threshold (0-255).

brightness_min

60

Minimum brightness threshold (0-255).

brightness_max

190

Maximum brightness threshold (0-255).

min_detection_area_percent

0.0075

Minimum weed size as a percentage of the detection frame area (0.0005-5). Increase to ignore small noise. Resolution-independent.

invert_hue

False

When True, detects colours outside the hue range instead of inside. Useful for detecting non-green targets.

!!! note “Legacy min_detection_area” Older configs used min_detection_area (contour area in pixels). It is still accepted: OWL converts it to min_detection_area_percent at startup and removes the px key the next time the config is saved. New configs should use the percent key only.

DataCollection

Parameter

Default

Description

image_sample_enable

False

Enable image data collection to USB drive.

detection_enable

True

Enable weed detection and relay actuation. Set False for data collection only.

sample_method

whole

Image sampling method: bbox (bounding boxes only), square (square crops), whole (full frame).

sample_frequency

30

Save an image every N frames (when sample_mode = frames).

sample_mode

frames

Which frames are saved: frames (every sample_frequency frames), distance (every sample_distance_m of GPS travel; every sample_interval_s without a fresh GPS speed; nothing while parked) or time (every sample_interval_s). The data-collection screen sets this live.

sample_distance_m

1.0

Distance mode: metres travelled between images.

sample_interval_s

2.0

Time mode, and distance mode without GPS: seconds between images.

jpeg_quality

95

JPEG quality of saved images (50-100).

record_mode

images

images, or video: one .mp4 clip per recording in the session folder, stopped at video_max_s.

video_max_s

60

Video clip length limit in seconds (5-60).

shutter_cap

False

Limit the shutter time so ground movement during one exposure (GPS speed x shutter time) stays under smear_limit_mm; the gain rises instead. Released whenever GPS speed is missing. Check it on your camera first with tools/shutter_cap_probe.py.

smear_limit_mm

2.0

Blur limit for shutter_cap and the collect screen’s blur warning, in mm of ground movement per image.

min_speed_kmh

1.0

No still images while a fresh GPS speed is below this, for example parked or turning at a headland. 0 never pauses. Without a GPS speed, images keep coming. Video clips are not paused.

save_directory

/media/owl/SanDisk

Directory for saved images. Typically a USB drive mount point.

log_fps

False

Log frame processing times to file.

camera_name

cam1

Camera identifier used in saved file names.

storage_location

auto

Where recordings go: auto (default - USB when a drive is mounted, otherwise the Pi’s internal storage with the min_free_gb floor protecting the system disk), usb (recording requires a drive mounted under /media), or internal (always the Pi’s own eMMC/SD storage - sealed OWL 3.0 units).

internal_save_directory

/home/owl/owl_images

Recording path used in internal storage mode.

min_free_gb

4

Internal mode only: recording is refused, and stops within seconds, when free disk space falls below this floor. Recording becomes available again once sessions are deleted or downloaded.

image_quota_gb

12

Image allowance shown on the app/dashboard storage bar. Display only — the enforced limit is min_free_gb.

Tracking

Parameter

Default

Description

tracking_enabled

False

Enable ByteTrack multi-object tracking for persistent weed IDs across frames.

track_class_window

5

Number of frames to smooth class predictions over. Reduces class flickering.

track_crop_persist

3

Number of frames a crop mask region persists after the crop leaves frame (gog-hybrid mode).

Relays

Parameter

Description

0 = 13

Relay 0 maps to GPIO board pin 13

1 = 15

Relay 1 maps to GPIO board pin 15

2 = 16

Relay 2 maps to GPIO board pin 16

3 = 18

Relay 3 maps to GPIO board pin 18

Sensitivity

Parameter

Default

Description

active

medium

Active sensitivity preset name. Built-in presets: low, medium, high. Custom presets can be saved from the dashboard.

Parameter Reference — CONTROLLER.ini

MQTT

Parameter

Default

Description

enable

True

Enable MQTT communication with the dashboard.

broker_ip

localhost

MQTT broker IP address. localhost for standalone, controller IP for networked.

broker_port

1883

MQTT broker port.

device_id

auto

Unique device identifier. auto generates from hostname.

WebDashboard

Parameter

Default

Description

port

8000

Gunicorn listening port (behind Nginx reverse proxy).

ui

full

In-cab controller only: the screen the kiosk opens. full is the full dashboard; collect is the data-collection screen, which holds detection off on every OWL. Both stay reachable at /full and /collect. Restart owl-controller after changing.

Collect

Read by the in-cab controller’s data-collection screen and, since v3.23, by the standalone dashboard (on the OWL’s own CONTROLLER.ini). Written by the record form and the collect screen’s Settings tab. Every key is optional and can be edited by hand.

Parameter

Default

Description

language

en

Language of the record form and capture settings: en or da.

crops, seasonal_crops, weather, lighting, purposes

built-in lists

Comma-separated preset slugs for the record form. Values go into image EXIF and session_metadata.json and are what Noktura maps onto dataset fields, so keep the slugs (for example wheat, natural_sun, herbicide).

last_crop, last_crop_season, last_weather, last_lighting, last_purpose

empty

The choices from the last Start recording, pre-selected next time. Written automatically; notes are never saved here.

sample_mode, sample_distance_m, sample_interval_s, jpeg_quality, record_mode, video_max_s, shutter_cap, smear_limit_mm, max_gain, min_speed_kmh

distance, 1.0, 2.0, 95, images, 60, false, 2.0, auto, 1.0

In-cab controller only: capture settings pushed to every OWL (see DataCollection above). A standalone OWL keeps these in its own active config ([DataCollection], and [Camera] max_gain) instead.

soft_ratio, dark_brightness, dark_percent, clipped_percent, not_saving_s, storage_low_mb

0.6, 40, 30, 5, 10, 2048

Warning thresholds for the collect screen.

Network

Parameter

Default

Description

mode

networked

Network mode: standalone (creates WiFi hotspot) or networked (joins existing network).

static_ip

localhost

Static IP for the OWL on the network.

controller_ip

localhost

IP address of the networked controller (networked mode only).

Pins used by on-device GPS. When [GPS] source = nrf91, BOARD 37 (GPIO 26, modem power) and BOARD 21 and 24 (the modem UART) belong to the modem. When source = serial with port = /dev/ttyAMA0 or /dev/serial0, BOARD 8 and 10 belong to the GPS. A relay, LED or switch configured on one of these pins is disabled at startup with an error in the journal (the OWL keeps running), and the dashboards, phone app and networked controller refuse the change. Without that hardware configured, nothing is reserved.

GPS

The networked controller supports four GPS input modes, selected via the source key. Pick whichever matches your hardware — only the keys relevant to your chosen source are read.

Parameter

Default

Description

source

none

GPS data source. One of: none (disabled), serial (USB/UART device on this Pi), nrf91 (the nRF9151 modem on the production CM5 carrier, read by the OWL itself; set up by bash owl_setup.sh --factory), tcp (NMEA pushed over TCP, e.g. from a Teltonika router), or gpsd (read from the local gpsd daemon on localhost:2947).

port

/dev/ttyACM0

Serial device path (used when source = serial, also passed to gpsd as its DEVICES hint). Ublox USB dongles enumerate as /dev/ttyACM0; CP2102/CH340 adapters as /dev/ttyUSB0; Pi primary UART is /dev/ttyAMA0 (or /dev/serial0 on Raspberry Pi OS). To find yours: ls /dev/ttyACM* /dev/ttyUSB* after plugging in the GPS. The production carrier’s nRF9151 modem is /dev/ttyAMA3.

baudrate

9600

Serial link speed (used when source = serial). Ublox factory default is 9600; Sixfab GNSS HAT and some marine modules use 115200. Wrong baud = silent failure (garbled unicode in the log). The carrier’s nRF9151 modem runs at 460800.

enable

False

DEPRECATED. Kept as a back-compat alias: if source = none and enable = True, the controller behaves as if source = tcp. New configs should set source directly.

nmea_port

8500

TCP port the controller listens on when source = tcp. Configure your router to forward NMEA to <controller-ip>:<nmea_port>. Port 8500 is pre-opened in the UFW firewall rules.

boom_width

12.0

Spray boom width in metres. Used to convert distance into hectares: area_ha = distance_km × boom_width_m / 10.

track_save_directory

tracks

Directory (relative to project root) where session GeoJSON track files are written as track_YYYY-MM-DD_HHMMSS.geojson. Files are never auto-deleted — monitor disk on long-running kiosks.

The GPS tab in the dashboard renders these breadcrumbs on a Leaflet map (OpenStreetMap tiles when online, dark grid fallback when offline) with a HDOP-coloured current-position marker and Centre/Fit-all controls.

Actuation

Parameter

Default

Description

actuation_duration

0.15

Relay activation time in seconds (fallback when no GPS speed data).

delay

0.0

Travel time from the camera’s view to the nozzle, in seconds, counted from frame capture. The OWL subtracts the frame’s processing time before scheduling the relay, so 0 opens the nozzle as soon as the weed is detected.

actuation_length_cm

10

Physical spray patch length in cm (speed-adaptive calculation).

offset_cm

30

Distance from camera to nozzle in cm (speed-adaptive calculation).

speed_avg_window

2.0

Time window in seconds for GPS speed averaging.

With GPS speed, spray duration is actuation_length_cm / speed, stretched to cover the ground travelled between frames (at most 3 patch lengths), and the delay is offset_cm / speed. An OWL with its own GPS ([GPS] source = serial or nrf91) computes this itself while it has a fresh fix, and that wins over the networked controller’s broadcast; when the fix is lost it uses the controller’s timing, or the fixed values above if there is no controller. Phone GPS never drives timing. When forward speed makes sprays land late or leaves gaps between frames, the dashboards and phone app show a warning with a speed to slow to.

Security

Parameter

Default

Description

device_token

(minted at setup)

Per-device API token (v3.11+, contract 2). controller/shared/setup.sh creates one on every standalone install if the key is missing, and the phone app’s first-boot setup mints one too. Mutating dashboard routes (network reconfiguration, password changes, shutdown/reboot, recording-session delete) require it in the X-Device-Token header. Units without the key accept requests without the header (legacy behaviour). There is deliberately no localhost bypass: nginx proxies every request from 127.0.0.1, so a bypass would disable the check entirely. Note this means a plain browser cannot call these routes on a token-minted unit - use the phone app, or remove the [Security] section to revert to legacy behaviour.

Cloud

Written by owl_cloud_provision.sh (run by hand, or by the phone app after the unit is claimed in Noktura). See the OWL app claim flow for how a shipped unit gets these values.

Parameter

Default

Description

enable

False

Master switch for the cloud bridge. False = fully local unit.

broker_host / broker_port

mqtt.noktura.tech / 8883

Cloud MQTT broker (TLS).

device_id

(issued at claim)

Site slug on the cloud side, e.g. owl-2026-000001. Must be lowercase and equal to username.

username / password_file

(issued at claim)

Bridge login. The password lives only in password_file (mode 600).

ca_cert

/home/owl/.owl/cloud/ca.crt

CA used to verify the cloud broker certificate. The template default is the file owl_cloud_provision.sh --ca-file installs. When the script runs with --system-ca (or without --ca-file), it writes the system CA path /etc/ssl/certs instead, which is what Noktura uses.

portal_url

(blank)

When set, the dashboard and app show an “Open in Noktura” link to <portal_url>/d/<device_id>.

storage_host

(blank)

v3.18+. Every upload or download a cloud command asks for must be HTTPS on this host. The phone app sets it when it connects the OWL to Noktura. Blank (manual provisioning) accepts any HTTPS host.

Cloud-origin commands arrive on a separate local topic and pass an allowlist: list, upload, preview and delete recorded sessions, update the software to a release tag (vX.Y.Z, never a branch), download and select a detection model, restart the OWL service and reboot. Nothing else from the cloud runs: no detection toggles, no configuration edits, no branch installs. The local broker itself listens on loopback only (v3.18+): the phone app and kiosk reach the OWL through HTTPS, never MQTT.


Next Steps