2026-05-21 09:34:29 +00:00
|
|
|
mod at_rest;
|
2026-05-10 02:18:40 +00:00
|
|
|
mod bundle;
|
2026-05-10 20:45:56 +00:00
|
|
|
mod cec;
|
2026-05-13 18:56:42 +00:00
|
|
|
mod firmware;
|
2026-05-12 23:18:22 +00:00
|
|
|
mod gpio;
|
2026-05-11 09:47:07 +00:00
|
|
|
mod hwmon;
|
2026-05-14 05:24:21 +00:00
|
|
|
mod local_server;
|
feat(onvif-events): PullPoint subscription for all ONVIF cameras
New kiosk/src/onvif_events.rs: for each ONVIF camera in the bundle,
creates a PullPoint subscription, polls every 3s, parses
NotificationMessage XML into structured JSON (topic + source key/values
+ data key/values + timestamp), and POSTs to /api/kiosk/event with
source_type=onvif + camera_id.
Forwards ALL event topics: motion, ANPR (LicensePlateRecognition),
line crossing, intrusion, digital input, analytics, tamper — everything
the camera exposes. Node-RED sorts what matters.
Subscription lifecycle:
- CreatePullPointSubscription with 60s InitialTerminationTime
- Renew every 55s before timeout
- Unsubscribe on bundle change / shutdown
- Auto-resubscribe on pull/renew failure (30s backoff)
- Generation tracking via Weak<()> so old workers self-terminate
when start() is called with a new bundle
WSSE PasswordDigest auth for SOAP calls — same scheme the server's
onvif.ts uses. sha1 crate added.
BundleCamera extended with onvif_host/port/username/password_encrypted
fields (server already ships them; kiosk just wasn't deserializing).
Gated by BF_ENABLE_ONVIF_EVENTS=1. Enabled by default in the pi-gen
image env file.
TODO: cluster-key-based decryption of onvif_password_encrypted. For
now relies on the RTSP URI having plaintext credentials embedded (which
the ONVIF import path already ensures via rtspWithCredentials).
2026-05-21 10:03:30 +00:00
|
|
|
mod onvif_events;
|
2026-05-21 08:47:45 +00:00
|
|
|
mod os_update;
|
2026-05-10 02:18:40 +00:00
|
|
|
mod pipeline;
|
2026-05-22 18:13:39 +00:00
|
|
|
mod remote_debug;
|
2026-05-21 00:03:05 +00:00
|
|
|
mod server;
|
2026-05-10 02:18:40 +00:00
|
|
|
mod ui;
|
2026-05-10 20:15:58 +00:00
|
|
|
mod ws_client;
|
|
|
|
|
|
2026-05-19 02:25:59 +00:00
|
|
|
pub use ui::WorkerMsg;
|
|
|
|
|
|
2026-05-10 20:15:58 +00:00
|
|
|
pub enum ServerMsg {
|
|
|
|
|
ReloadBundle,
|
2026-05-21 07:10:30 +00:00
|
|
|
Standby(Option<u32>),
|
|
|
|
|
Wake(Option<u32>),
|
2026-05-11 09:47:07 +00:00
|
|
|
/// Some(0..=255) = manual PWM. None = restore auto.
|
|
|
|
|
Fan(Option<u32>),
|
2026-05-21 00:03:05 +00:00
|
|
|
/// Switch to a specific layout by ID, optionally scoped to one display.
|
|
|
|
|
SwitchLayout {
|
|
|
|
|
display_id: Option<u32>,
|
|
|
|
|
layout_id: u32,
|
|
|
|
|
},
|
2026-05-13 18:56:42 +00:00
|
|
|
/// Server-pushed "go check for a firmware update now".
|
|
|
|
|
FirmwareCheck,
|
2026-05-22 23:07:34 +00:00
|
|
|
/// Server-pushed "go check for an OS update now".
|
|
|
|
|
OsCheck,
|
2026-05-22 18:13:39 +00:00
|
|
|
/// Show terminal auth code on screen (overlay).
|
|
|
|
|
ShowTerminalCode(String),
|
|
|
|
|
/// Dismiss the terminal code overlay.
|
|
|
|
|
DismissTerminalCode,
|
2026-05-10 20:15:58 +00:00
|
|
|
}
|
2026-05-10 02:18:40 +00:00
|
|
|
|
2026-05-10 18:59:23 +00:00
|
|
|
use gstreamer::prelude::PluginFeatureExtManual;
|
2026-05-21 00:03:05 +00:00
|
|
|
use gtk4::prelude::{ApplicationExt, ApplicationExtManual};
|
2026-05-10 18:52:25 +00:00
|
|
|
use tracing::info;
|
2026-05-10 02:18:40 +00:00
|
|
|
use tracing_subscriber::EnvFilter;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
tracing_subscriber::fmt()
|
2026-05-21 00:03:05 +00:00
|
|
|
.with_env_filter(
|
|
|
|
|
EnvFilter::from_default_env().add_directive("betterframe_kiosk=info".parse().unwrap()),
|
|
|
|
|
)
|
2026-05-10 02:18:40 +00:00
|
|
|
.init();
|
|
|
|
|
|
|
|
|
|
gstreamer::init().expect("Failed to init GStreamer");
|
2026-05-10 18:52:25 +00:00
|
|
|
|
|
|
|
|
// Demote Pi5 hw H265 decoder — rejects non-standard resolutions like 960x1080
|
|
|
|
|
if let Some(factory) = gstreamer::ElementFactory::find("v4l2slh265dec") {
|
|
|
|
|
factory.set_rank(gstreamer::Rank::NONE);
|
|
|
|
|
info!("demoted v4l2slh265dec to NONE (sw fallback)");
|
|
|
|
|
}
|
2026-05-10 02:18:40 +00:00
|
|
|
let app = ui::build_app();
|
2026-05-10 18:11:31 +00:00
|
|
|
// Pass empty args to GTK — server URL handled via env or argv directly
|
2026-05-10 18:13:01 +00:00
|
|
|
app.set_flags(gtk4::gio::ApplicationFlags::NON_UNIQUE);
|
2026-05-10 18:11:31 +00:00
|
|
|
std::process::exit(app.run_with_args::<&str>(&[]).into());
|
2026-05-10 02:18:40 +00:00
|
|
|
}
|