gabe /presentato-mf
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
acme-camera: agenda, requirements, summary, Q&A; broker topics, cameractl/configctl/infctl types
3b61cfd · Gabriel Morell · 2026-10-13 19:35
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 | − | |
| 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