acme-camera: agenda, requirements, summary, Q&A; broker topics, cameractl/configctl/infctl types

3b61cfd · Gabriel Morell · 2026-10-13 19:35

3 files +215 -5

Files changed

modified content/presentations/acme-camera.md
+215 −5
@@ -14,6 +14,19 @@ reveal_transition = "slide"
14 14
15 15 ---
16 16
17 +# Agenda
18 +
19 +1. Architecture: hardware and software
20 +2. Performance metrics and targets
21 +3. Instrumentation and fleet data
22 +4. Risks, plan and questions
23 +
24 +Note:
25 +Roughly 15 minutes each, questions welcome throughout
26 +Detail for every software component is in the appendix if we want to dig in
27 +
28 +---
29 +
17 30 # Product Overview
18 31
19 32 A wireless security system architecture supporting long operational life
@@ -21,6 +34,21 @@ A wireless security system architecture supporting long operational life
21 34 Note:
22 35 The pitch: months on a charge, a person-confirmed alert in seconds, and fleet data that proves both
23 36
37 +--
38 +
39 +## Requirements
40 +
41 +- Battery powered, months per charge
42 +- Outdoor: weatherproof, −20 to 50 °C
43 +- Person-confirmed alerts in seconds
44 +- Night vision and a spotlight
45 +- Setup from a phone, Wi-Fi to the home
46 +- Optional solar
47 +
48 +Note:
49 +Matches the example products: a standalone battery camera and a solar-topped variant
50 +Temperature range matters for the battery more than anything else, cold eats usable capacity
51 +
24 52 ---
25 53
26 54 # Assumptions
@@ -47,7 +75,9 @@ No continuous recording, a battery camera can't afford it
47 75 width="900" height="500" style="border:0" loading="lazy"
48 76 ></iframe>
49 77
50 −&nbsp;
78 +Note:
79 +Two domains: an always-on MCU with the sensors, lights, PMIC and BLE / Thread radio, and a mostly-asleep SOC with the camera, storage and Wi-Fi
80 +The MCU decides when the SOC is worth waking
51 81
52 82 ---
53 83
@@ -185,6 +215,7 @@ Read-only rootfs means an update is a whole-slot swap, nothing drifts between de
185 215 | cameractl | sensor, ISP, clip buffer |
186 216 | portalctl | BLE via mcuctl, HTTP |
187 217 | configctl | `/data/config` |
218 +| telemetryctl | `/data/telemetry`, uplink |
188 219
189 220 Note:
190 221 Each unit runs as its own user with ProtectSystem=strict and DeviceAllow for only its hardware
@@ -243,6 +274,7 @@ Factory reset wipes /data and revokes the device cert server side
243 274 | <a href="#/cameractl">cameractl</a> | frames to storage and cloud |
244 275 | <a href="#/configctl">configctl</a> | source of truth for settings |
245 276 | <a href="#/infctl">infctl</a> | on-device inference (bonus) |
277 +| telemetryctl | buffers and uploads metrics |
246 278
247 279 Note:
248 280 Details and types for each are in the appendix, the links jump there
@@ -367,7 +399,7 @@ Energy per wake comes from the fuel gauge before and after, which ties every eve
367 399 ## Collection
368 400
369 401 - Components publish metrics to the broker
370 −- A telemetry agent aggregates and buffers to flash
402 +- telemetryctl aggregates and buffers to flash
371 403 - MCU logs hourly samples while the SOC sleeps
372 404 - Uploads ride along when Wi-Fi is already up
373 405
@@ -457,6 +489,23 @@ Telemetry ships in EVT firmware, the pilot fleet is where the targets get valida
457 489
458 490 ---
459 491
492 +# Summary
493 +
494 +- The MCU decides when the SOC wakes
495 +- PIR + radar: wake for people only
496 +- Yocto, signed A/B, sandboxed daemons
497 +- ≥ 3 months, < 5 s to alert
498 +- Telemetry from day one gates every OTA
499 +
500 +Note:
501 +If Acme remembers one thing: battery life is designed in, measured on every build, and proven across the fleet
502 +
503 +---
504 +
505 +# Questions?
506 +
507 +---
508 +
460 509 # Appendix
461 510
462 511 Component details and types
@@ -467,11 +516,29 @@ Component details and types
467 516
468 517 # Component : Broker
469 518
470 −- MQTT
519 +- MQTT (mosquitto) on a Unix socket
471 520
472 521 Note: on unix socket for the ability to have granular security
473 −TODO: why a unix socket over TCP (file permissions / peer credentials per component)
474 −TODO: topic layout and which components publish/subscribe
522 +No TCP listener at all, so nothing on the network can reach it
523 +The socket's file permissions decide who can connect, and the peer uid (SO_PEERCRED) maps each connection to a component without passwords or certs
524 +A small auth plugin applies per-topic ACLs to that identity
525 +
526 +--
527 +
528 +## Topics
529 +
530 +| Topic | Publisher | Subscribers |
531 +|---|---|---|
532 +| `motion/event` | mcuctl | cameractl, powerctl |
533 +| `power/reading` | powerctl | portalctl, telemetryctl |
534 +| `config/request` | portalctl | configctl |
535 +| `config/<area>` | configctl | everyone |
536 +| `camera/clip` | cameractl | telemetryctl |
537 +| `metrics/<unit>` | everyone | telemetryctl |
538 +
539 +Note:
540 +config/<area> is retained, so a restarted component gets the current config the moment it subscribes
541 +Only configctl can publish config, only portalctl can request changes, the ACLs enforce the arrows in this table
475 542
476 543 ---
477 544
@@ -686,15 +753,61 @@ Read-only view assembled from the other components via the broker
686 753
687 754 # Component: Cameractl
688 755
756 +Frames to the clip buffer, the cloud and inference
757 +
689 758 Note:
690 759 Reads frames from the camera and decides to do further processing depending on config
691 760
761 +--
762 +
763 +## Capture
764 +
765 +What starts a recording, and how much
766 +
767 +```rust
768 +enum CaptureTrigger { Motion, LiveView, Timer }
769 +
770 +enum Resolution { P720, P1080, P1440 }
771 +
772 +struct ClipPolicy {
773 + resolution: Resolution,
774 + max_len_s: u16,
775 + extend_on_motion: bool,
776 +}
777 +```
778 +
779 +Note:
780 +extend_on_motion keeps recording while the radar still sees someone, up to max_len_s
781 +
782 +--
783 +
784 +## Clips
785 +
786 +Where frames go
787 +
788 +```rust
789 +enum Sink { ClipBuffer, Cloud, Inference }
790 +
791 +struct Clip {
792 + id: u64,
793 + trigger: CaptureTrigger,
794 + started_at: u64,
795 + len_ms: u32,
796 + uploaded: bool,
797 +}
798 +```
799 +
800 +Note:
801 +Every clip lands in the local buffer first, then uploads, so a weak or missing network never loses one
802 +
692 803 ---
693 804
694 805 <!-- .slide: id="configctl" -->
695 806
696 807 # Component: Configctl
697 808
809 +Source of truth for settings
810 +
698 811 Note:
699 812 Source of truth for various configurations set from the portal
700 813 - Network configuration
@@ -704,10 +817,107 @@ Source of truth for various configurations set from the portal
704 817
705 818 --
706 819
820 +## Device Config
821 +
822 +One versioned document
823 +
824 +```rust
825 +struct DeviceConfig {
826 + version: u32,
827 + display_name: String,
828 + network: WifiCredentials,
829 + cloud: CloudConfig,
830 + motion: MotionDetectionMode,
831 + light: LightControlMode,
832 + power: PowerCtlMode,
833 + processing: ProcessingConfig,
834 +}
835 +```
836 +
837 +Note:
838 +Written atomically to /data/config, then published retained on config/<area>
839 +The cloud can push changes too, they go through the same validation as the portal's
840 +
841 +--
842 +
843 +## Cloud & Processing
844 +
845 +```rust
846 +struct CloudConfig {
847 + endpoint: String,
848 + device_id: String,
849 +}
850 +
851 +enum ProcessingConfig {
852 + Off,
853 + Detect {
854 + targets: Vec<InferenceTarget>,
855 + threshold: f32,
856 + },
857 +}
858 +```
859 +
860 +Note:
861 +ProcessingConfig is what infctl reads to decide which models to run
862 +
863 +--
864 +
865 +## Applying Changes
866 +
867 +Every request gets an answer
868 +
869 +```rust
870 +enum ConfigResult {
871 + Applied { version: u32 },
872 + Rejected { reason: String },
873 +}
874 +```
875 +
876 +Note:
877 +Every ConfigRequest gets a ConfigResult back, so the portal can show why a change was refused
878 +
879 +--
880 +
707 881 <!-- .slide: id="infctl" -->
708 882
709 883 # Component: Infctl
710 884
885 +On-device inference on the SOC's NPU
886 +
711 887 Note:
712 888 This one is -- because it's a bonus one that we may not get into
713 889 Configures on-device inference using NPU hardware available in modern camera SOCs
890 +
891 +--
892 +
893 +## Models
894 +
895 +```rust
896 +struct Model {
897 + name: String,
898 + version: String,
899 + input: (u16, u16),
900 +}
901 +
902 +enum InferenceTarget {
903 + Person, Vehicle, Package, Animal,
904 +}
905 +```
906 +
907 +Note:
908 +Models ship with the OS image so they're signed and A/B like everything else
909 +
910 +--
911 +
912 +## Detections
913 +
914 +```rust
915 +struct Detection {
916 + target: InferenceTarget,
917 + confidence: f32,
918 + bbox: (u16, u16, u16, u16),
919 +}
920 +```
921 +
922 +Note:
923 +A detection above the threshold upgrades a motion event into a person / vehicle / package alert

Parents: 8acc3b5