<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ZhengZhiCong</title>
    <description>The latest articles on DEV Community by ZhengZhiCong (@mickey_zzc).</description>
    <link>https://dev.to/mickey_zzc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972064%2Fd8a4b5b3-f282-4858-b6f6-9f246118a9b0.png</url>
      <title>DEV Community: ZhengZhiCong</title>
      <link>https://dev.to/mickey_zzc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mickey_zzc"/>
    <language>en</language>
    <item>
      <title>Embedded Camera Module Selection Handbook — From Basics to Purchasing Reference</title>
      <dc:creator>ZhengZhiCong</dc:creator>
      <pubDate>Mon, 29 Jun 2026 23:07:58 +0000</pubDate>
      <link>https://dev.to/mickey_zzc/embedded-camera-module-selection-handbook-from-basics-to-purchasing-reference-3g1i</link>
      <guid>https://dev.to/mickey_zzc/embedded-camera-module-selection-handbook-from-basics-to-purchasing-reference-3g1i</guid>
      <description>&lt;h2&gt;
  
  
  About This Handbook
&lt;/h2&gt;

&lt;p&gt;This handbook is a revised edition of my own "Embedded Camera Module Technical Manual" that I previously compiled and shared online. The original covered eight mainstream sensors: OV2640, OV5640, OV7725, GC0309, OV7670, OV3660, GC2053, and GC4653. This revision expands coverage with 12 additional sensors (OV9281, OV5647, IMX219, IMX273, IMX296, IMX307, IMX335, IMX415, IMX477, IMX678, IMX708, IMX766), for a total of 20. The content was comprehensive, but when I sat down to use it as a purchasing reference, I felt uneasy — a single wrong voltage parameter can fry a board, and I didn't want to ship mistakes I couldn't vouch for.&lt;/p&gt;

&lt;p&gt;So I did one thing: &lt;strong&gt;verified every key parameter against official datasheets&lt;/strong&gt;. Sources include OmniVision's official product pages, GalaxyCore datasheets, SparkFun / DigiKey / Mouser datasheet mirrors, and Espressif's official esp32-camera driver source code.&lt;/p&gt;

&lt;p&gt;The result: &lt;strong&gt;most parameters were correct, but there were several critical errors&lt;/strong&gt;, especially around voltage, frame rates, and some marketing terminology. This handbook is the corrected version — every error-prone parameter is annotated with reliability status and evidence. Use it as a purchasing checklist with confidence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reliability annotation legend&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Verified: Parameter matches official datasheet exactly&lt;/li&gt;
&lt;li&gt;⚠️ Note: Original had errors or was misleading; corrected with evidence&lt;/li&gt;
&lt;li&gt;🔍 Unconfirmed: Official datasheet unclear, or varies by module manufacturer&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick Selection Guide
&lt;/h2&gt;

&lt;p&gt;Start with this table to find your use case, then read the details below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Top Pick&lt;/th&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;th&gt;Interface&lt;/th&gt;
&lt;th&gt;Key Advantage&lt;/th&gt;
&lt;th&gt;Price Tier&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Education (Arduino/STM32)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OV7670&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.3MP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;Richest ecosystem, most tutorials&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wi-Fi streaming (ESP32-CAM)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OV2640&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2MP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;Built-in JPEG compression&lt;/td&gt;
&lt;td&gt;Low-mid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-res photo + autofocus&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OV5640&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5MP&lt;/td&gt;
&lt;td&gt;DVP/MIPI&lt;/td&gt;
&lt;td&gt;Only entry-level with AF&lt;/td&gt;
&lt;td&gt;Mid-high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Night vision / machine vision&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OV7725&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.3MP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;6.0µm pixels, low-light king&lt;/td&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ultra low cost (access/POS)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;GC0309&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.3MP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;Lowest price&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3MP upgrade (ESP32)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OV3660&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3MP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;BSI tech, drop-in for OV2640&lt;/td&gt;
&lt;td&gt;Low-mid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security / surveillance&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;GC2053&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2MP&lt;/td&gt;
&lt;td&gt;DVP/MIPI&lt;/td&gt;
&lt;td&gt;1/2.9" sensor + 2.8µm pixels&lt;/td&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-end security / AI vision&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;GC4653&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4MP&lt;/td&gt;
&lt;td&gt;MIPI only&lt;/td&gt;
&lt;td&gt;4MP + BSI high sensitivity&lt;/td&gt;
&lt;td&gt;Mid-high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi / Jetson entry&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IMX219&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8MP&lt;/td&gt;
&lt;td&gt;MIPI 2L&lt;/td&gt;
&lt;td&gt;Pi V2 standard, most mature driver&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4K security / NVR&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IMX415&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8MP&lt;/td&gt;
&lt;td&gt;MIPI 2/4L&lt;/td&gt;
&lt;td&gt;4K STARVIS, rich module ecosystem&lt;/td&gt;
&lt;td&gt;Mid-high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High-end 4K security (2024)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IMX678&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8MP&lt;/td&gt;
&lt;td&gt;MIPI 2/4/8L&lt;/td&gt;
&lt;td&gt;STARVIS 2 + Clear HDR&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1080P night security&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IMX307&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2MP&lt;/td&gt;
&lt;td&gt;MIPI 2/4L&lt;/td&gt;
&lt;td&gt;2.9µm + STARVIS, strong night vision&lt;/td&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Industrial FA / global shutter&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IMX273&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.58MP&lt;/td&gt;
&lt;td&gt;MIPI 1L&lt;/td&gt;
&lt;td&gt;Pregius global shutter, 226fps&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;ESP32 users note:&lt;/strong&gt; ESP32 series only supports DVP-interface sensors. &lt;strong&gt;GC4653 is MIPI-only and cannot be used with ESP32&lt;/strong&gt;. OV3660 also only supports DVP (claims of MIPI support in the original document are wrong — see below).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  DVP Interface Basics
&lt;/h2&gt;

&lt;p&gt;DVP (Digital Video Port) transmits uncompressed raw image data via parallel data lines with a sync clock. Understanding DVP signals and timing is prerequisite for wiring and debugging all DVP modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Signal Definitions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Typical Level&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;XCLK&lt;/td&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;External master clock, typically 6–24 MHz ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCLK&lt;/td&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Pixel clock for synchronous data sampling ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VSYNC&lt;/td&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Frame sync signal ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HREF / HSYNC&lt;/td&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Line sync signal ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D[7:0]&lt;/td&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;8-bit parallel pixel data bus ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIOC / SCL&lt;/td&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;SCCB / I²C clock ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIOD / SDA&lt;/td&gt;
&lt;td&gt;Bidirectional&lt;/td&gt;
&lt;td&gt;SCCB / I²C data ✅&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PWDN&lt;/td&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Power-down control&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RESET&lt;/td&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Hardware reset (active low)&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Timing
&lt;/h3&gt;

&lt;p&gt;A complete frame is bounded by VSYNC. Within a frame, multiple HREF pulses occur, each corresponding to one line of valid pixel data. When both VSYNC and HREF are active, D[7:0] data latched on PCLK rising edge is valid pixel data.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
The red scan line sweeps left to right. When VSYNC + HREF are both HIGH, each PCLK rising edge latches one pixel byte (D0, D1, D2…).





&lt;h3&gt;
  
  
  SCCB Control Interface
&lt;/h3&gt;

&lt;p&gt;SCCB (Serial Camera Control Bus) is OmniVision's I²C-compatible 2-wire serial protocol. SCL clock frequency supports up to 400 kHz ✅ (OV2640 datasheet Table 9 confirms). If your MCU lacks internal pull-ups, add 4.7 kΩ pull-up resistors on SCL and SDA to 3.3V ✅.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;I²C addresses are sensor-specific, NOT uniform 0x30/0x60!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many online sources casually claim "OV series address is 0x30/0x60" — this is wrong. Verified 7-bit slave addresses per sensor:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sensor&lt;/th&gt;
&lt;th&gt;7-bit Address&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OV2640&lt;/td&gt;
&lt;td&gt;0x30&lt;/td&gt;
&lt;td&gt;Datasheet: 8-bit write 0x60 / read 0x61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OV5640&lt;/td&gt;
&lt;td&gt;0x3C&lt;/td&gt;
&lt;td&gt;Datasheet: 8-bit write 0x78 / read 0x79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OV7725&lt;/td&gt;
&lt;td&gt;0x21&lt;/td&gt;
&lt;td&gt;Datasheet: 8-bit write 0x42 / read 0x43&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OV7670&lt;/td&gt;
&lt;td&gt;0x21&lt;/td&gt;
&lt;td&gt;Linux kernel driver ov7670.c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GC series&lt;/td&gt;
&lt;td&gt;Vendor-defined&lt;/td&gt;
&lt;td&gt;Check specific datasheet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If SCCB configuration fails, &lt;strong&gt;verify I²C address first&lt;/strong&gt;, not just pull-ups.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  MIPI CSI-2 Interface Basics
&lt;/h2&gt;

&lt;p&gt;When resolution and frame rate go up (1080P@30fps+), DVP's 8-bit parallel bus can't keep up — too many wires, limited speed, poor noise immunity. All Sony IMX sensors below use MIPI CSI-2. Here's the foundation.&lt;/p&gt;

&lt;h3&gt;
  
  
  DVP vs MIPI CSI-2
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;DVP&lt;/th&gt;
&lt;th&gt;MIPI CSI-2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data lines&lt;/td&gt;
&lt;td&gt;8–10 parallel + sync signals&lt;/td&gt;
&lt;td&gt;1–4 differential pairs (lanes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clock&lt;/td&gt;
&lt;td&gt;Single-ended XCLK / PCLK&lt;/td&gt;
&lt;td&gt;Differential clock lane&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandwidth&lt;/td&gt;
&lt;td&gt;≤ ~200 MB/s&lt;/td&gt;
&lt;td&gt;Up to ~2.5 GB/s (4-lane)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Noise immunity&lt;/td&gt;
&lt;td&gt;Poor, long cables cause artifacts&lt;/td&gt;
&lt;td&gt;Good, differential rejects common-mode noise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Controller complexity&lt;/td&gt;
&lt;td&gt;Low (straight to FIFO)&lt;/td&gt;
&lt;td&gt;High (needs D-PHY + CSI-2 controller)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical controllers&lt;/td&gt;
&lt;td&gt;ESP32, STM32, RP2040&lt;/td&gt;
&lt;td&gt;Raspberry Pi, Jetson, Hi3516, RV1106&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical sensors&lt;/td&gt;
&lt;td&gt;OV2640, OV5640, OV7670&lt;/td&gt;
&lt;td&gt;IMX219, IMX415, IMX678&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Lane Count and Bandwidth
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lanes&lt;/th&gt;
&lt;th&gt;Total Bandwidth&lt;/th&gt;
&lt;th&gt;Suitable For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1-lane&lt;/td&gt;
&lt;td&gt;~500 MB/s&lt;/td&gt;
&lt;td&gt;1080P@30fps RAW8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2-lane&lt;/td&gt;
&lt;td&gt;~1 GB/s&lt;/td&gt;
&lt;td&gt;1080P@60fps or 4K@15fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4-lane&lt;/td&gt;
&lt;td&gt;~2 GB/s&lt;/td&gt;
&lt;td&gt;4K@30fps+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Purchasing note:&lt;/strong&gt; More lanes isn't always better — your controller's MIPI receiver must support the lane count. For example, RV1106 supports 2-lane/4-lane MIPI input; connecting a 1-lane IMX273 may not work. Check controller specs before buying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ESP32 users note:&lt;/strong&gt; ESP32 (including ESP32-S3) has &lt;strong&gt;no MIPI CSI-2 receiver&lt;/strong&gt;. None of the Sony IMX sensors below work with ESP32. You need a MIPI-capable controller like Raspberry Pi, Jetson, RV1106, Hi3516, etc.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Sensor Technology Principles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Shutter Types: Rolling vs Global
&lt;/h3&gt;

&lt;p&gt;Most sensors in this handbook use &lt;strong&gt;rolling shutter&lt;/strong&gt; — exposing rows sequentially with a time gap between rows. Fast-moving objects appear skewed/warped (&lt;strong&gt;jello effect&lt;/strong&gt;). Only IMX273, OV9281, and IMX296 use &lt;strong&gt;global shutter&lt;/strong&gt; — the entire frame is exposed simultaneously, zero motion distortion.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
A blue ball moves left to right. Rolling shutter exposes row-by-row, capturing the ball at different positions per row → diagonal skew. Global shutter exposes all rows simultaneously → clean bar.





&lt;h3&gt;
  
  
  Backside Illumination (BSI) vs Frontside Illumination (FSI)
&lt;/h3&gt;

&lt;p&gt;Traditional CMOS sensors (FSI) have metal wiring above the photodiode, blocking some light. &lt;strong&gt;BSI (Backside Illumination)&lt;/strong&gt; flips the sensor so light enters from the back, reaching the photodiode directly — &lt;strong&gt;30%–60% more light&lt;/strong&gt;. STARVIS, Exmor R, and OmniBSI all use BSI technology.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
Yellow dots are photons. FSI's wiring blocks ~50% of light. BSI flips the structure so all photons reach the sensor.





&lt;h3&gt;
  
  
  HDR Multi-Exposure Fusion
&lt;/h3&gt;

&lt;p&gt;In backlit scenes, short exposure captures highlights (sky) but shadows are black; long exposure captures shadows but highlights are blown. HDR merges multiple exposures into one image, &lt;strong&gt;preserving both highlight and shadow detail&lt;/strong&gt;. IMX307/IMX335/IMX678 all support hardware-level HDR.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
Short exposure preserves highlights, long exposure preserves shadows — merged HDR significantly expands dynamic range. Frames appear sequentially to show the fusion process.





&lt;h3&gt;
  
  
  Quad Bayer Pixel Binning
&lt;/h3&gt;

&lt;p&gt;High-resolution sensors (e.g., IMX766 50MP) have tiny pixels (1.0µm) with insufficient light per pixel. &lt;strong&gt;Quad Bayer&lt;/strong&gt; groups 4 adjacent same-color pixels, reading them as 1 larger pixel — 4× area, effective pixel size doubles (1.0µm → 2.0µm), dramatically improving low-light performance. Full resolution by day, auto-binned by night.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
4 pixels of 1.0µm merge into 1 pixel of 2.0µm. 4× area = 4× light = significantly better SNR.








&lt;h2&gt;
  
  
  OV2640 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision 1/4-inch, 2MP CMOS sensor with built-in JPEG compression engine. The standard choice for ESP32-CAM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV2640&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;2MP (1600 × 1200)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.2 µm × 2.2 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;DVP 8-bit parallel + SCCB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;YUV422, YUV420, RGB565, RGB555, RAW RGB, JPEG&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;UXGA@15fps, SVGA@30fps, CIF@60fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Master clock XCLK&lt;/td&gt;
&lt;td&gt;6 – 24 MHz (typical 24 MHz)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;Analog 2.5–3.0V, I/O 1.7–3.3V, Core 1.2/1.3V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power&lt;/td&gt;
&lt;td&gt;~125 mW (15fps UXGA YUV), ~140 mW (JPEG mode)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Official OmniVision OV2640 datasheet (uctronics.com/download/OV2640_DS.pdf)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Resolution &amp;amp; Frame Rate
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Typical fps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UXGA&lt;/td&gt;
&lt;td&gt;1600 × 1200&lt;/td&gt;
&lt;td&gt;15 fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SXGA&lt;/td&gt;
&lt;td&gt;1280 × 1024&lt;/td&gt;
&lt;td&gt;15 fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SVGA&lt;/td&gt;
&lt;td&gt;800 × 600&lt;/td&gt;
&lt;td&gt;30 fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VGA&lt;/td&gt;
&lt;td&gt;640 × 480&lt;/td&gt;
&lt;td&gt;30 fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QVGA&lt;/td&gt;
&lt;td&gt;320 × 240&lt;/td&gt;
&lt;td&gt;60 fps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Typical Pinout (24-PIN FPC)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Verified: OV2640 modules do use 24-pin 0.5mm pitch FPC (confirmed by OV2640FSL datasheet, Arducam module spec). However, &lt;strong&gt;pin order may vary by module manufacturer&lt;/strong&gt; — always check your specific board's datasheet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pin&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Pin&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;D3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;VCC (3.3V)&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;D4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;D5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;PWDN&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;D6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;RESET&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;D7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;XCLK&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;NC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;VSYNC&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;SIOC (SCL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;HREF&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;SIOD (SDA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;PCLK&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;NC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;D0&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;NC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;D1&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;NC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;D2&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;NC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Purchasing tip:&lt;/strong&gt; OV2640's built-in JPEG compression outputs compressed streams directly, significantly reducing MCU RAM and bus bandwidth requirements. Best price/performance for ESP32-CAM.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OV5640 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision 1/4-inch, 5MP CMOS sensor with integrated autofocus (AF) voice coil motor driver. The image quality ceiling for entry-level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV5640&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;5MP (2592 × 1944)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.4 µm × 1.4 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;DVP 8/10-bit OR MIPI CSI-2 (2-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;RAW RGB, RGB565/555/444, YCbCr422, JPEG&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;QSXGA@15fps, 1080P@30fps, 720P@60fps, VGA@90fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Master clock XCLK&lt;/td&gt;
&lt;td&gt;6 – 27 MHz (typical 24 MHz)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autofocus&lt;/td&gt;
&lt;td&gt;Integrated VCM driver, contrast-detect AF&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Features&lt;/td&gt;
&lt;td&gt;OmniBSI, HDR, AE/AG/AWB, 2D NR, lens correction, anti-shake&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;~140 mA (active), 20 µA (standby)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OV5640 datasheet v2.03 (cdn.sparkfun.com), OV5640 Product Brief (media.digikey.com)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interface note:&lt;/strong&gt; OV5640 supports both DVP and MIPI CSI-2. Cheap modules typically use DVP 8-bit parallel. MIPI versions are usually for phone/tablet designs. &lt;strong&gt;For AF versions, verify AF_VCC supply&lt;/strong&gt; — the VCM motor needs separate power.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OV7725 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision high-performance 1/4-inch VGA sensor using OmniPixel² technology, focused on high sensitivity, low noise, and low-light performance. At 6.0 µm pixel size, it's the strongest low-light performer in the 0.3MP class.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV7725&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;0.3MP (640 × 480)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.0 µm × 6.0 µm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;DVP 8/10-bit parallel + SCCB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;RAW RGB, RGB565/555/444, YCbCr422&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;VGA@60fps, QVGA@120fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating temp&lt;/td&gt;
&lt;td&gt;-20°C to +70°C&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensitivity&lt;/td&gt;
&lt;td&gt;3800 mV/Lux-sec (extremely high)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic range&lt;/td&gt;
&lt;td&gt;60 dB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Features&lt;/td&gt;
&lt;td&gt;OmniPixel², high sensitivity low-light, AE/AG/AWB, edge enhancement, noise suppression&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OV7725 official product page (ovt.com/products/ov7725), OV7725 datasheet&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;EOL notice:&lt;/strong&gt; OV7725 is marked End-of-Life on OmniVision's website. For new production designs, evaluate alternatives. But surplus/secondhand stock remains plentiful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is 6.0µm so big?&lt;/strong&gt; Both OV7670 and OV7725 are 0.3MP, but OV7670 pixels are only 3.6µm while OV7725 reaches 6.0µm — nearly 3x the pixel area, meaning 3x the light gathering. This is why it crushes same-resolution competitors in low light. For night vision, license plate recognition, or industrial inspection, this is the one.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  GC0309-8225N V2 Module
&lt;/h2&gt;

&lt;p&gt;Based on GalaxyCore GC0309, a 0.3MP fixed-focus module with DVP interface, focused on ultra-high cost-effectiveness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;GalaxyCore GC0309&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/9 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;0.3MP (640 × 480, actual 648×488)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.5 µm × 2.5 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel structure&lt;/td&gt;
&lt;td&gt;4-transistor (4T), low noise&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;DVP 8-bit parallel&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;YCbCr422, RGB565, RAW Bayer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;VGA@30fps (24MHz clock)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.8V typical (2.7–3.3V range)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lens&lt;/td&gt;
&lt;td&gt;Fixed focus, typical 62° FOV&lt;/td&gt;
&lt;td&gt;🔍 module-vendor defined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Features&lt;/td&gt;
&lt;td&gt;On-chip 10-bit ADC, embedded ISP, AE, AWB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: GC0309 official datasheet V1.0 (2009-12-28, GalaxyCore Inc.)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Voltage correction:&lt;/strong&gt; The original document's "3.3V single supply" is inaccurate. The official datasheet explicitly states "Single power supply requirement (2.8V)", typical 2.8V, range 2.7–3.3V. &lt;strong&gt;Recommended supply is 2.8V LDO&lt;/strong&gt; — 3.3V is within range but not the optimal operating point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; GC0309-8225N V2 is a complete module model customized by module vendors based on the GC0309 sensor. Pin definitions, lens parameters, and FPC interfaces may vary between vendors. Always refer to your specific module's datasheet.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OV7670 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision's classic 1/6-inch VGA sensor — the most historically significant and ecosystem-mature sensor in embedded vision. The de facto standard for Arduino, STM32, and FPGA education.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV7670&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/6 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;0.3MP (640 × 480)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;3.6 µm × 3.6 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;DVP 8-bit parallel + SCCB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;YUV422, RGB565, RGB555, RAW RGB, Processed Bayer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;VGA@30fps, QVGA@60fps, CIF@60fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Master clock XCLK&lt;/td&gt;
&lt;td&gt;10 – 24 MHz (typical 24 MHz)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power&lt;/td&gt;
&lt;td&gt;~60 mW (15fps VGA YUV), standby &amp;lt;20 µA&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OV7670 official datasheet (w2.electrodragon.com/Chip-dat/OmniVision-dat/OV7670-dat/OV7670-ds.pdf)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Voltage correction (important):&lt;/strong&gt; The original's "2.5–3.0V single voltage" is simplified and misleading. OV7670 actually requires &lt;strong&gt;three separate supply domains&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supply Domain&lt;/th&gt;
&lt;th&gt;Voltage Range&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DVDD (digital core)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.8V&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires dedicated LDO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AVDD (analog)&lt;/td&gt;
&lt;td&gt;2.45–3.0V&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DOVDD (I/O)&lt;/td&gt;
&lt;td&gt;1.7–3.0V&lt;/td&gt;
&lt;td&gt;Can connect to 3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Purchasing note: &lt;strong&gt;Cheap non-FIFO modules typically only expose DOVDD&lt;/strong&gt; — DVDD and AVDD are stepped down via on-board LDOs. But bare minimum boards may require external regulation. Non-FIFO versions are extremely demanding on MCU real-time performance; with STM32, pair with AL422B FIFO buffer chip.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OV3660 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision 3MP (2048×1536) sensor using OmniBSI backside-illumination technology. Natively supported by ESP32's esp32-camera library.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Multiple corrections in this section — read carefully.&lt;/strong&gt; My original version had errors in interface, frame rate, voltage, and current — all corrected against the official datasheet below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV3660&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/5 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;3MP (2048 × 1536)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.4 µm × 1.4 µm (OmniBSI)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DVP 8-bit parallel ONLY&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;RAW RGB, RGB565/555/444, YCbCr422, JPEG compression&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;QXGA@15fps, &lt;strong&gt;1080P@20fps&lt;/strong&gt;, &lt;strong&gt;720P@45fps&lt;/strong&gt;, VGA@60fps&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Core 1.5V, I/O 1.8V/2.8V, Analog 2.6–3.0V&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~98 mA (active), 20 µA (standby)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensitivity&lt;/td&gt;
&lt;td&gt;670 mV/Lux-sec&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic range&lt;/td&gt;
&lt;td&gt;70 dB @ 8x gain&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating temp&lt;/td&gt;
&lt;td&gt;-20°C to 70°C&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XCLK&lt;/td&gt;
&lt;td&gt;6 – 27 MHz&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OV3660 official datasheet (download.kamami.pl/p1196945-OV3660%20Datasheet.pdf), ESP32 Camera Driver (github.com/espressif/esp32-camera)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Correction 1 — No MIPI:&lt;/strong&gt; The original claimed OV3660 supports "DVP 8-bit OR MIPI CSI-2 (1-lane)" — this is &lt;strong&gt;wrong&lt;/strong&gt;. The official datasheet only mentions Digital Video Parallel Port with no MIPI interface description. ESP32 can use it precisely because it's DVP.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Correction 2 — Frame rate:&lt;/strong&gt; Original claimed 1080P@30fps, 720P@60fps; actual is &lt;strong&gt;1080P@20fps, 720P@45fps&lt;/strong&gt;. Original overstated by ~33%.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Correction 3 — Voltage:&lt;/strong&gt; Original "I/O 1.8–3.3V, core 1.2V, analog 2.8V" is wrong. Actual: core 1.5V, I/O 1.8V or 2.8V, analog 2.6–3.0V.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Correction 4 — Current:&lt;/strong&gt; Original "~130mA" is too high; datasheet specifies 98mA active.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purchasing tip:&lt;/strong&gt; OV3660 offers 50% higher resolution than OV2640 (3MP vs 2MP) with better low-light performance via BSI. If your project already uses OV2640 and you want to upgrade image quality while staying on ESP32, OV3660 is the best drop-in replacement (both DVP, directly supported by esp32-camera).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  GC2053 Module
&lt;/h2&gt;

&lt;p&gt;GalaxyCore 2MP (1920×1080) sensor with 1/2.9-inch large sensor and 2.8µm large pixels, supporting both MIPI and DVP interfaces. Standout low-light performance in its price tier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;GalaxyCore GC2053&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.9 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;2MP (1920 × 1080)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.8 µm × 2.8 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2-lane) or DVP&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;RAW Bayer 10-bit / 8-bit&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;1080P@30fps, 720P@60fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.8V, DVDD 1.2V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;~57 mA total (analog 17.3 + digital 37.4 + I/O 2.5)&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADC&lt;/td&gt;
&lt;td&gt;10-bit&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: GC2053 datasheet V1.1 (2018-11-29, GalaxyCore / CK Vision)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Current correction:&lt;/strong&gt; Original claimed "~95 mA"; datasheet measures approximately 57mA total (analog 17.3mA + digital 37.4mA + I/O 2.5mA). Actual power consumption is lower than original — thermal and power design can be more relaxed. MIPI 2-lane bandwidth of 1.5Gbps/lane 🔍 pending final datasheet confirmation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why choose GC2053:&lt;/strong&gt; The 1/2.9-inch sensor is larger than both OV2640 (1/4") and OV5640 (1/4"), and 2.8µm pixels are also bigger. Bigger sensor + bigger pixels = more light per pixel = better low-light performance. It has a clear advantage over same-price OV solutions for security surveillance.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  GC4653 Module
&lt;/h2&gt;

&lt;p&gt;GalaxyCore's high-performance 4MP sensor using BSI backside-illumination technology for enhanced low-light sensitivity. A high-end choice for security cameras and intelligent vision applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;"STARVIS" terminology correction.&lt;/strong&gt; The original claimed GC4653 uses "STARVIS architecture technology" — this is incorrect. STARVIS is Sony's registered trademark and exclusive technology; GalaxyCore does not use STARVIS. GC4653 actually uses in-house BSI (backside-illuminated) pixel technology for high sensitivity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;GalaxyCore GC4653&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/3 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;4MP (2560 × 1440)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.0 µm × 2.0 µm (BSI)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter&lt;/td&gt;
&lt;td&gt;Electronic rolling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MIPI CSI-2 ONLY (2-lane, RAW12/RAW10)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;RAW Bayer 12-bit / 10-bit&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;4MP@30fps, 1080P@60fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.8V, DVDD 1.2V, I/O 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;~120 mA&lt;/td&gt;
&lt;td&gt;🔍 pending datasheet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Features&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;BSI high-sensitivity low-light&lt;/strong&gt;, HDR, PDAF phase AF, 2D/3D noise reduction&lt;/td&gt;
&lt;td&gt;⚠️ see above&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: GC4653 datasheet (Camemaker), Sipeed Wiki, Sony Semiconductor official site (STARVIS trademark confirmation)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;ESP32 incompatible:&lt;/strong&gt; GC4653 is MIPI-only, incompatible with traditional DVP parallel interface. ESP32 series has no MIPI CSI-2 receiver capability and &lt;strong&gt;cannot use this sensor&lt;/strong&gt;. Requires a controller with MIPI CSI-2, such as HiSilicon Hi3516, Ingenic T31, Rockchip RV1106, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purchasing tip:&lt;/strong&gt; Confirm your controller has MIPI CSI-2 before choosing GC4653. If you're doing an ESP32 project, don't buy this sensor — you won't be able to light it up.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OV9281 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision 1/4-inch 1MP &lt;strong&gt;global shutter&lt;/strong&gt; sensor using OmniPixel®3-GS technology. Like the IMX273, it's a global shutter sensor, but much cheaper with DVP+MIPI dual interface — the most affordable global shutter option for makers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV9281&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;1MP (1280 × 800)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;3.0 µm × 3.0 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter type&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Global Shutter&lt;/strong&gt; (OmniPixel®3-GS)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2-lane) + DVP&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW8 / RAW10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;120 fps&lt;/strong&gt; (1280×800), 180fps (VGA)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.8V, DVDD 1.2V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power&lt;/td&gt;
&lt;td&gt;156 mW (active), 150 µA (standby)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S/N ratio&lt;/td&gt;
&lt;td&gt;38 dB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic range&lt;/td&gt;
&lt;td&gt;68 dB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production status&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;In production&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Machine vision, drones, barcode scanning, AR/VR, 3D depth&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OmniVision OV9281 Product Brief v1.4 (ovt.com/wp-content/uploads/2024/05/OV9281-PB-v1.4-WEB.pdf)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;ESP32 compatibility:&lt;/strong&gt; OV9281 is &lt;strong&gt;NOT&lt;/strong&gt; in the esp32-camera library (classic ESP32/S2/S3). ESP32-P4 has experimental support but unstable (esp-idf #17795). For global shutter on ESP32, there's currently no good option; use Raspberry Pi + Arducam OV9281 module instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why OV9281 over IMX273:&lt;/strong&gt; Both are global shutter, but OV9281 is much cheaper ($15-25 vs $50+) and supports both DVP and MIPI. Downsides: lower resolution (1MP vs 1.58MP) and monochrome only (no color version).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OV5647 Module
&lt;/h2&gt;

&lt;p&gt;OmniVision 1/4-inch 5MP CMOS sensor with OmniBSI technology. The original Raspberry Pi Camera Module V1 (2013) sensor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;OmniVision OV5647&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;5MP (2592 × 1944)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.4 µm × 1.4 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shutter type&lt;/td&gt;
&lt;td&gt;Rolling shutter&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;OmniBSI backside illumination&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2-lane) + DVP&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW8 / RAW10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;5MP@15fps, 1080P@30fps, 720P@60fps, VGA@90fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;Analog 2.6–3.0V (typical 2.8V), Core 1.5V, I/O 1.7–3.0V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production status&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;End-of-Life (EOL)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Raspberry Pi Camera V1, phones, notebooks&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OmniVision OV5647 datasheet (v-visiontech.com/web/userfiles/download/OV5647DS.pdf), Raspberry Pi official documentation&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Discontinued (EOL):&lt;/strong&gt; OV5647 is on OmniVision's discontinued product list. Surplus stock still available ($8-15), but &lt;strong&gt;not recommended for new designs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selection comparison:&lt;/strong&gt; OV5647 vs OV5640 — both 5MP. OV5647 is the Pi V1 sensor; OV5640 is the ESP32 ecosystem 5MP option (with AF). Pins and drivers are incompatible. For Pi projects on a budget, OV5647 surplus still works; for ESP32, use OV5640.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;NOT in esp32-camera support list.&lt;/strong&gt; ESP32 users should use OV2640 or OV5640.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  IMX219 Module
&lt;/h2&gt;

&lt;p&gt;Sony 1/4-inch 8MP CMOS sensor with Exmor R backside-illumination technology. The standard sensor for Raspberry Pi Camera Module V2, and the most ubiquitous MIPI camera in the Raspberry Pi ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX219&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;8MP (3280 × 2464)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.12 µm × 1.12 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Exmor R&lt;/strong&gt; BSI (NOT STARVIS)&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;1080P@30fps, 720P@60fps, VGA@90fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.8V, DVDD 1.2V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power&lt;/td&gt;
&lt;td&gt;~38 mA @2.8V + ~160 mA @1.2V (≈ 0.26 W)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production status&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;In production&lt;/strong&gt; (at least until Jan 2028)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX219 datasheet (dlscorp.com), Raspberry Pi official documentation&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Exmor R is NOT STARVIS:&lt;/strong&gt; Some online articles classify IMX219 as STARVIS — this is wrong. IMX219 uses Exmor R (BSI). STARVIS is Sony's later security-focused technology line with higher sensitivity and dynamic range.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purchasing tip:&lt;/strong&gt; The IMX219 module (Raspberry Pi Camera V2) is the lowest-cost entry to MIPI. Pi 4B/5 CSI connector works directly, driver is in mainline kernel, plug-and-play.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX273 Module
&lt;/h2&gt;

&lt;p&gt;Sony Pregius series global shutter sensor, 1/2.9-inch, 1.58MP. Designed for industrial FA cameras and ITS (Intelligent Traffic Systems), 226fps at full resolution — a high-performance choice for high-speed machine vision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX273&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.9 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;1.58MP (1456 × 1088)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;3.45 µm × 3.45 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Pregius Global Shutter&lt;/strong&gt; (NOT STARVIS)&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (1-lane) OR Sub LVDS (8-ch)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10 / RAW12&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;226 fps&lt;/strong&gt; (full resolution, 10-bit)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;3.3V / 1.8V / 1.2V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Industrial FA cameras, ITS, barcode scanning, defect inspection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX273 official Flyer (sony-semicon.com/files/62/flyer_industry/IMX273_287_296_297_Flyer.pdf)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Global vs Rolling Shutter:&lt;/strong&gt; Every other sensor in this handbook uses rolling shutter, which causes jello effect on fast-moving objects. IMX273 has a global shutter — the entire image is exposed simultaneously, &lt;strong&gt;zero jello effect on high-speed motion&lt;/strong&gt;. This is the core reason to choose it for industrial vision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; IMX273 comes in two variants — MIPI 1-lane and Sub LVDS 8-ch. Confirm which interface you need before buying.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX307 Module
&lt;/h2&gt;

&lt;p&gt;Sony STARVIS 2MP security sensor, 1/2.8-inch, 2.9µm large pixels. HDR support, a mainstream choice for 1080P security cameras, commonly paired with HiSilicon Hi3516 series SoCs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX307&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.8 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;2.07MP (1920 × 1080)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.9 µm × 2.9 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;STARVIS (original)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2/4-lane) + LVDS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10 / RAW12&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;60 fps (1080P)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;Multi-exposure HDR + Digital overlap HDR&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.9V, DVDD 1.2V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Security surveillance, FA cameras&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX307 official Flyer (sony-semicon.com/files/62/flyer_security/IMX307LQD_LQR_Flyer.pdf)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Highlight:&lt;/strong&gt; 2.9µm large pixels + STARVIS = excellent night vision. Paired with Hi3516C V300 is the classic security combo.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX335 Module
&lt;/h2&gt;

&lt;p&gt;Sony STARVIS 5MP security sensor, 1/2.8-inch. Steps up from IMX307's 2MP to 5MP while maintaining good day/night image quality. Commonly paired with Hi3516 / RV1106.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX335&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.8 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;5.04MP (2592 × 1944)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.0 µm × 2.0 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;STARVIS (original)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2/4-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10 / RAW12&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;60 fps (full resolution, 10-bit)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;Multi-exposure HDR + Digital overlap HDR&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.9V, DVDD 1.2V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common SoC pairing&lt;/td&gt;
&lt;td&gt;Hi3516 series, RV1106&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX335 official Flyer (sony-semicon.com/files/62/flyer_security/IMX335LQN_Flyer.pdf)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selection comparison:&lt;/strong&gt; IMX335 vs IMX307 — same 1/2.8" sensor. IMX307 is 2MP/2.9µm (better low light), IMX335 is 5MP/2.0µm (more detail). Choose IMX335 if you need to see far details, IMX307 for night surveillance.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX415 Module
&lt;/h2&gt;

&lt;p&gt;Sony STARVIS 4K (8MP) security sensor, 1/2.8-inch. The workhorse sensor for 4K security cameras, with the most mature module ecosystem — Jetson / Raspberry Pi / RV1106 all have ready drivers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX415&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.8 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;8.29MP (3840 × 2160, 4K UHD)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.45 µm × 1.45 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;STARVIS (original)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2/4-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW8 / RAW10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;4K up to 90fps (typical 30–60fps)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;Multi-exposure HDR&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.9V, DVDD 1.1V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Announced&lt;/td&gt;
&lt;td&gt;June 2019&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;4K security, NVR, industrial cameras&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX415 official Flyer (sony-semicon.com/files/62/pdf/p-12_IMX415-AAQR_AAMR_Flyer.pdf)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purchasing tip:&lt;/strong&gt; IMX415 has the best DIY/embedded module ecosystem of all Sony IMX sensors. LuckFox, Radxa, e-con Systems all offer ready-made modules with drivers for Jetson, Raspberry Pi, RV1106. The top pick for 4K MIPI projects.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX678 Module
&lt;/h2&gt;

&lt;p&gt;Sony STARVIS 2 4K (8MP) security sensor, 1/1.8-inch large sensor. A 2024 new release that comprehensively upgrades the IMX415 — bigger sensor, newer STARVIS 2 technology, faster frame rate, stronger HDR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX678&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;1/1.8 inch&lt;/strong&gt; (much larger than IMX415's 1/2.8")&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;8.29MP (3840 × 2160, 4K UHD)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.0 µm × 2.0 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;STARVIS 2&lt;/strong&gt; (next-gen)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2/4/8-lane, 4-lane×2ch)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10 / RAW12&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;72 fps&lt;/strong&gt; (4K, 10-bit) / 60fps (12-bit)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;Digital overlap HDR + &lt;strong&gt;Clear HDR&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;AVDD 3.3V&lt;/strong&gt;, DVDD 1.1V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;⚠️ see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Announced&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common SoC pairing&lt;/td&gt;
&lt;td&gt;Hi3519DV500&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX678 official Flyer (sony-semicon.com/files/62/flyer_security/IMX678-AAQR_AAQR1_Flyer.pdf, © 2024)&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Power note:&lt;/strong&gt; IMX678's AVDD is &lt;strong&gt;3.3V&lt;/strong&gt;, different from IMX335/IMX307/IMX415's 2.9V. Change the LDO output when migrating from other IMX designs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMX678 vs IMX415:&lt;/strong&gt; Both are 4K 8MP, but IMX678 has a bigger sensor (1/1.8" vs 1/2.8"), bigger pixels (2.0µm vs 1.45µm), newer tech (STARVIS 2), and stronger HDR (Clear HDR). The trade-off is more complex power/lane requirements and higher module cost as a 2024 new release.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX766 Module
&lt;/h2&gt;

&lt;p&gt;Sony 50MP smartphone sensor, 1/1.56-inch large sensor, Quad Bayer array. Used in OPPO Find X3 Pro, Reno7 Pro and other flagship phones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;NOT recommended for DIY / embedded projects.&lt;/strong&gt; The following is for reference only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX766&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/1.56 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;50MP (8192 × 6144)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.0 µm (4-in-1 binning → 2.0 µm)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel array&lt;/td&gt;
&lt;td&gt;Quad Bayer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (4-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10 / RAW8&lt;/td&gt;
&lt;td&gt;🔍&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;Full res ~24fps; binned 30fps; 1080P 60–120fps&lt;/td&gt;
&lt;td&gt;🔍&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 2.8V, DVDD 1.1V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;🔍&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phone implementations&lt;/td&gt;
&lt;td&gt;OPPO Find X3 Pro, OnePlus, Realme&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: OPPO official specs, IADIY module page, DxOMark. ⚠️ &lt;strong&gt;Sony has not published an official IMX766 datasheet&lt;/strong&gt; — some parameters are from phone manufacturers and module vendors.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Why not recommended for DIY:&lt;/strong&gt; No official datasheet (register config and power sequencing require reverse engineering), needs custom driver (no mainline Linux driver), non-standard FPC, 50MP Quad Bayer needs powerful ISP, many modules include OIS motors needing extra drivers. For high-res MIPI, choose &lt;strong&gt;IMX415&lt;/strong&gt; or &lt;strong&gt;IMX477&lt;/strong&gt; (Raspberry Pi HQ Camera) instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Sony IMX Series Key Parameters Comparison
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;All 15 sensors in one table would exceed mobile screen width. OV/GC comparison table above; Sony IMX series below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;IMX219&lt;/th&gt;
&lt;th&gt;IMX273&lt;/th&gt;
&lt;th&gt;IMX307&lt;/th&gt;
&lt;th&gt;IMX335&lt;/th&gt;
&lt;th&gt;IMX415&lt;/th&gt;
&lt;th&gt;IMX678&lt;/th&gt;
&lt;th&gt;IMX766&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;Exmor R&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pregius GS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;STARVIS&lt;/td&gt;
&lt;td&gt;STARVIS&lt;/td&gt;
&lt;td&gt;STARVIS&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;STARVIS 2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quad Bayer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolution&lt;/td&gt;
&lt;td&gt;8MP&lt;/td&gt;
&lt;td&gt;1.58MP&lt;/td&gt;
&lt;td&gt;2MP&lt;/td&gt;
&lt;td&gt;5MP&lt;/td&gt;
&lt;td&gt;8MP (4K)&lt;/td&gt;
&lt;td&gt;8MP (4K)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;50MP&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4"&lt;/td&gt;
&lt;td&gt;1/2.9"&lt;/td&gt;
&lt;td&gt;1/2.8"&lt;/td&gt;
&lt;td&gt;1/2.8"&lt;/td&gt;
&lt;td&gt;1/2.8"&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1/1.8"&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1/1.56"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.12 µm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.45 µm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.9 µm&lt;/td&gt;
&lt;td&gt;2.0 µm&lt;/td&gt;
&lt;td&gt;1.45 µm&lt;/td&gt;
&lt;td&gt;2.0 µm&lt;/td&gt;
&lt;td&gt;1.0 µm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI 2L&lt;/td&gt;
&lt;td&gt;MIPI 1L/LVDS&lt;/td&gt;
&lt;td&gt;MIPI 2/4L&lt;/td&gt;
&lt;td&gt;MIPI 2/4L&lt;/td&gt;
&lt;td&gt;MIPI 2/4L&lt;/td&gt;
&lt;td&gt;MIPI 2/4/8L&lt;/td&gt;
&lt;td&gt;MIPI 4L&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max fps&lt;/td&gt;
&lt;td&gt;1080P@30fps&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;226fps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1080P@60fps&lt;/td&gt;
&lt;td&gt;5MP@60fps&lt;/td&gt;
&lt;td&gt;4K@90fps&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4K@72fps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50MP@24fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Clear&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global shutter&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AVDD&lt;/td&gt;
&lt;td&gt;2.8V&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;td&gt;2.9V&lt;/td&gt;
&lt;td&gt;2.9V&lt;/td&gt;
&lt;td&gt;2.9V&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.3V&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.8V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best use case&lt;/td&gt;
&lt;td&gt;Raspberry Pi V2&lt;/td&gt;
&lt;td&gt;Industrial FA&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;4K Security&lt;/td&gt;
&lt;td&gt;High-end 4K&lt;/td&gt;
&lt;td&gt;⚠️ Phone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DIY recommended&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ Industrial&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ Top pick&lt;/td&gt;
&lt;td&gt;⚠️ Pricey&lt;/td&gt;
&lt;td&gt;❌ Not recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  IMX477 Module
&lt;/h2&gt;

&lt;p&gt;Sony 12.3MP sensor, 1/2.3-inch, with interchangeable C/CS-mount lens. The standard sensor for Raspberry Pi HQ Camera — ideal for projects needing high-quality imaging and interchangeable lenses: microscopy, astronomy, industrial inspection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX477&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.3 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;12.3MP (4056 × 3040)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.55 µm × 1.55 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;BSI stacked CMOS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (2/4-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW12 / RAW10 / RAW8&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;Full res@60fps (10-bit), 4K@60fps, 1080P@240fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;DOL-HDR (Digital Overlap HDR)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lens mount&lt;/td&gt;
&lt;td&gt;C-mount / CS-mount (interchangeable)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production status&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;In production&lt;/strong&gt; (at least until Jan 2030)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Announced&lt;/td&gt;
&lt;td&gt;April 2020&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Raspberry Pi HQ Camera, microscopy/astronomy, industrial&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX477 Flyer, Raspberry Pi HQ Camera product page&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purchasing tip:&lt;/strong&gt; IMX477's biggest advantage is &lt;strong&gt;interchangeable lenses&lt;/strong&gt; — C-mount and CS-mount cover wide-angle to telephoto to macro. Best image quality in the Pi ecosystem. $50-70.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX708 Module
&lt;/h2&gt;

&lt;p&gt;Sony 12MP Quad Bayer sensor, 1/2.3-inch, with PDAF phase-detection autofocus and HDR. The standard sensor for Raspberry Pi Camera Module 3 — the first Pi camera with hardware autofocus.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX708&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.3 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;12MP (4608 × 2592)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;1.4 µm × 1.4 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;BSI stacked CMOS, Quad Bayer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;1080P@50fps, 720P@100fps, 480P@120fps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autofocus&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;PDAF phase-detection autofocus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HDR&lt;/td&gt;
&lt;td&gt;Yes (up to 3MP output)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production status&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;In production&lt;/strong&gt; (at least until Jan 2030)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Announced&lt;/td&gt;
&lt;td&gt;January 2023&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Raspberry Pi Camera Module 3 (standard/wide/telephoto)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Raspberry Pi Camera Module 3 product page and product brief&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Highlight:&lt;/strong&gt; IMX708 brings hardware autofocus (PDAF) to Raspberry Pi for the first time. Available in standard, wide, and telephoto versions. $25-30 — best price/performance for Pi MIPI cameras.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  IMX296 Module
&lt;/h2&gt;

&lt;p&gt;Sony Pregius global shutter sensor, 1/2.9-inch, 1.58MP. The standard sensor for Raspberry Pi Global Shutter Camera. Like the IMX273, it's a Pregius global shutter sensor, but with official Pi ecosystem module and driver support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Specs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor&lt;/td&gt;
&lt;td&gt;Sony IMX296&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/2.9 inch&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Effective pixels&lt;/td&gt;
&lt;td&gt;1.58MP (1456 × 1088)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;3.45 µm × 3.45 µm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pregius Global Shutter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;MIPI CSI-2 (1-lane)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output format&lt;/td&gt;
&lt;td&gt;RAW10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max frame rate&lt;/td&gt;
&lt;td&gt;60.3 fps (full resolution, 10-bit)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating voltage&lt;/td&gt;
&lt;td&gt;AVDD 3.3V, DVDD 1.2V, IOVDD 1.8V&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lens mount&lt;/td&gt;
&lt;td&gt;C-mount / CS-mount (interchangeable)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production status&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;In production&lt;/strong&gt; (at least until Jan 2032)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Announced&lt;/td&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical applications&lt;/td&gt;
&lt;td&gt;Raspberry Pi Global Shutter Camera, high-speed capture, industrial&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Source: Sony IMX296 Flyer, Raspberry Pi Global Shutter Camera product page&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;IMX296 vs IMX273:&lt;/strong&gt; Both are Pregius global shutter, 3.45µm pixels. IMX296 is the official Pi Global Shutter Camera sensor with full driver/docs; IMX273 is more industrial FA focused. For Pi projects choose IMX296, for industrial FA choose IMX273.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Module Comparison Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key Parameters Comparison
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Table corrected per official datasheets. Bolded items had errors in the original or need special attention.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;OV2640&lt;/th&gt;
&lt;th&gt;OV5640&lt;/th&gt;
&lt;th&gt;OV7725&lt;/th&gt;
&lt;th&gt;GC0309&lt;/th&gt;
&lt;th&gt;OV7670&lt;/th&gt;
&lt;th&gt;OV3660&lt;/th&gt;
&lt;th&gt;GC2053&lt;/th&gt;
&lt;th&gt;GC4653&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;OmniVision&lt;/td&gt;
&lt;td&gt;OmniVision&lt;/td&gt;
&lt;td&gt;OmniVision&lt;/td&gt;
&lt;td&gt;GalaxyCore&lt;/td&gt;
&lt;td&gt;OmniVision&lt;/td&gt;
&lt;td&gt;OmniVision&lt;/td&gt;
&lt;td&gt;GalaxyCore&lt;/td&gt;
&lt;td&gt;GalaxyCore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolution&lt;/td&gt;
&lt;td&gt;2MP&lt;/td&gt;
&lt;td&gt;5MP&lt;/td&gt;
&lt;td&gt;0.3MP&lt;/td&gt;
&lt;td&gt;0.3MP&lt;/td&gt;
&lt;td&gt;0.3MP&lt;/td&gt;
&lt;td&gt;3MP&lt;/td&gt;
&lt;td&gt;2MP&lt;/td&gt;
&lt;td&gt;4MP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max size&lt;/td&gt;
&lt;td&gt;1600×1200&lt;/td&gt;
&lt;td&gt;2592×1944&lt;/td&gt;
&lt;td&gt;640×480&lt;/td&gt;
&lt;td&gt;640×480&lt;/td&gt;
&lt;td&gt;640×480&lt;/td&gt;
&lt;td&gt;2048×1536&lt;/td&gt;
&lt;td&gt;1920×1080&lt;/td&gt;
&lt;td&gt;2560×1440&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optical format&lt;/td&gt;
&lt;td&gt;1/4"&lt;/td&gt;
&lt;td&gt;1/4"&lt;/td&gt;
&lt;td&gt;1/4"&lt;/td&gt;
&lt;td&gt;1/9"&lt;/td&gt;
&lt;td&gt;1/6"&lt;/td&gt;
&lt;td&gt;1/5"&lt;/td&gt;
&lt;td&gt;1/2.9"&lt;/td&gt;
&lt;td&gt;1/3"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pixel size&lt;/td&gt;
&lt;td&gt;2.2 µm&lt;/td&gt;
&lt;td&gt;1.4 µm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.0 µm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.5 µm&lt;/td&gt;
&lt;td&gt;3.6 µm&lt;/td&gt;
&lt;td&gt;1.4 µm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.8 µm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.0 µm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;DVP/MIPI&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;DVP&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DVP only&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DVP/MIPI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MIPI only&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max fps&lt;/td&gt;
&lt;td&gt;UXGA@15fps&lt;/td&gt;
&lt;td&gt;QSXGA@15fps&lt;/td&gt;
&lt;td&gt;VGA@60fps&lt;/td&gt;
&lt;td&gt;VGA@30fps&lt;/td&gt;
&lt;td&gt;VGA@30fps&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1080P@20fps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1080P@30fps&lt;/td&gt;
&lt;td&gt;4MP@30fps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output formats&lt;/td&gt;
&lt;td&gt;YUV/RGB/RAW/JPEG&lt;/td&gt;
&lt;td&gt;YUV/RGB/RAW/JPEG&lt;/td&gt;
&lt;td&gt;YUV/RGB/RAW&lt;/td&gt;
&lt;td&gt;YUV/RGB/RAW&lt;/td&gt;
&lt;td&gt;YUV/RGB/RAW&lt;/td&gt;
&lt;td&gt;YUV/RGB/RAW/JPEG&lt;/td&gt;
&lt;td&gt;RAW Bayer&lt;/td&gt;
&lt;td&gt;RAW Bayer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autofocus&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (VCM)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;PDAF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low-light&lt;/td&gt;
&lt;td&gt;Average&lt;/td&gt;
&lt;td&gt;Average&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Excellent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Average&lt;/td&gt;
&lt;td&gt;Average&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Excellent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Excellent&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voltage&lt;/td&gt;
&lt;td&gt;1.7–3.3V (I/O)&lt;/td&gt;
&lt;td&gt;1.7–3.3V (I/O)&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.8V typical&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.8V/2.45-3V/1.7-3V&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.5V core multi-rail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.8V (I/O)&lt;/td&gt;
&lt;td&gt;1.8V (I/O)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical power&lt;/td&gt;
&lt;td&gt;~125 mW&lt;/td&gt;
&lt;td&gt;~140 mA&lt;/td&gt;
&lt;td&gt;~80 mA&lt;/td&gt;
&lt;td&gt;~60 mA&lt;/td&gt;
&lt;td&gt;~60 mW&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~98 mA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~57 mA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~120 mA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I²C address&lt;/td&gt;
&lt;td&gt;0x30&lt;/td&gt;
&lt;td&gt;0x3C&lt;/td&gt;
&lt;td&gt;0x21&lt;/td&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;0x21&lt;/td&gt;
&lt;td&gt;See DS&lt;/td&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price tier&lt;/td&gt;
&lt;td&gt;Low-mid&lt;/td&gt;
&lt;td&gt;Mid-high&lt;/td&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low-mid&lt;/td&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;td&gt;Mid-high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESP32 compatible&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ needs FIFO&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ DVP mode only&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Selection Recommendations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Education (Arduino/STM32):&lt;/strong&gt; OV7670 — Richest ecosystem, most tutorials. Note three-rail power.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wi-Fi streaming (ESP32-CAM):&lt;/strong&gt; OV2640 — Built-in JPEG, balanced power/quality, de facto standard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-res photo (ESP32/STM32):&lt;/strong&gt; OV5640 — 5MP + autofocus, best entry-level quality. Power VCM on AF versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Night vision / machine vision (low-light):&lt;/strong&gt; OV7725 — 6.0µm pixels, low-light king. ⚠️ EOL, surplus stock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ultra low cost (access/POS):&lt;/strong&gt; GC0309-8225N — Lowest price, meets basic needs. Power at 2.8V.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3MP upgrade (ESP32):&lt;/strong&gt; OV3660 — BSI, drop-in for OV2640. Note lower frame rate than OV2640.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security surveillance (indoor/outdoor):&lt;/strong&gt; GC2053 — Large sensor/pixels, MIPI high-speed, low power.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-end security / AI vision:&lt;/strong&gt; GC4653 — 4MP + BSI high sensitivity. ⚠️ MIPI only, not for ESP32.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raspberry Pi / Jetson entry (MIPI):&lt;/strong&gt; IMX219 — Pi Camera V2 standard, most mature driver, plug-and-play.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Industrial vision / high-speed capture:&lt;/strong&gt; IMX273 — Global shutter, 226fps, zero jello effect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security (1080P nighttime):&lt;/strong&gt; IMX307 — 2.9µm + STARVIS, strong night vision. Pair with Hi3516.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security (high resolution):&lt;/strong&gt; IMX335 — 5MP STARVIS, more detail. Pair with Hi3516/RV1106.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4K security / NVR:&lt;/strong&gt; IMX415 — 4K STARVIS, best module ecosystem, top pick.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-end 4K security (2024):&lt;/strong&gt; IMX678 — STARVIS 2 + Clear HDR, best image quality. ⚠️ AVDD 3.3V.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚠️ Don't buy for DIY:&lt;/strong&gt; IMX766 — 50MP phone sensor, no official datasheet, needs custom driver.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Application &amp;amp; Wiring Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ESP32 Typical Wiring
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important disclaimer:&lt;/strong&gt; The pin mapping below is based on common AI-Thinker ESP32-CAM module configurations. &lt;strong&gt;There is no official unified pin standard for ESP32-CAM&lt;/strong&gt; — the esp32-camera library examples explicitly state "pin configurations vary by board". Different vendors (AI-Thinker, Freenove, SunFounder, Espressif official EVB) may all differ. &lt;strong&gt;Always verify which board you have before wiring.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI-Thinker ESP32-CAM common mapping (applies to OV2640 / OV5640 / OV7725):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module Signal&lt;/th&gt;
&lt;th&gt;ESP32 GPIO&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;XCLK&lt;/td&gt;
&lt;td&gt;GPIO 27&lt;/td&gt;
&lt;td&gt;Master clock via LEDC PWM at 20 MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCLK&lt;/td&gt;
&lt;td&gt;GPIO 22&lt;/td&gt;
&lt;td&gt;Pixel clock input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VSYNC&lt;/td&gt;
&lt;td&gt;GPIO 25&lt;/td&gt;
&lt;td&gt;Frame sync input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HREF&lt;/td&gt;
&lt;td&gt;GPIO 23&lt;/td&gt;
&lt;td&gt;Line sync input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D0&lt;/td&gt;
&lt;td&gt;GPIO 32&lt;/td&gt;
&lt;td&gt;Data bit 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D1&lt;/td&gt;
&lt;td&gt;GPIO 35&lt;/td&gt;
&lt;td&gt;Data bit 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D2&lt;/td&gt;
&lt;td&gt;GPIO 34&lt;/td&gt;
&lt;td&gt;Data bit 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D3&lt;/td&gt;
&lt;td&gt;GPIO 5&lt;/td&gt;
&lt;td&gt;Data bit 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D4&lt;/td&gt;
&lt;td&gt;GPIO 39&lt;/td&gt;
&lt;td&gt;Data bit 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D5&lt;/td&gt;
&lt;td&gt;GPIO 18&lt;/td&gt;
&lt;td&gt;Data bit 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D6&lt;/td&gt;
&lt;td&gt;GPIO 36&lt;/td&gt;
&lt;td&gt;Data bit 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D7&lt;/td&gt;
&lt;td&gt;GPIO 19&lt;/td&gt;
&lt;td&gt;Data bit 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIOC&lt;/td&gt;
&lt;td&gt;GPIO 26&lt;/td&gt;
&lt;td&gt;SCCB clock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIOD&lt;/td&gt;
&lt;td&gt;GPIO 21&lt;/td&gt;
&lt;td&gt;SCCB data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PWDN&lt;/td&gt;
&lt;td&gt;GPIO 0&lt;/td&gt;
&lt;td&gt;Power-down control (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RESET&lt;/td&gt;
&lt;td&gt;GPIO 15&lt;/td&gt;
&lt;td&gt;Reset control (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Verification: esp32-camera repo examples/camera_example/main/camera_pinout.h (PCLK/VSYNC/HREF confirmed line-by-line against source).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  STM32 Wiring
&lt;/h3&gt;

&lt;p&gt;STM32F4/F7/H7 series feature DCMI (Digital Camera Memory Interface) peripheral for direct hardware reception of DVP data streams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect D0–D7 to DCMI_D0–DCMI_D7 corresponding GPIOs&lt;/li&gt;
&lt;li&gt;PCLK → DCMI_PIXCK&lt;/li&gt;
&lt;li&gt;HSYNC → DCMI_HSYNC&lt;/li&gt;
&lt;li&gt;VSYNC → DCMI_VSYNC&lt;/li&gt;
&lt;li&gt;I²C_SCL/SDA → any I²C peripheral&lt;/li&gt;
&lt;li&gt;Enable DCMI + DMA transfer, target buffer in SRAM or SDRAM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Power Design
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated regulation:&lt;/strong&gt; Camera modules can draw 100–150 mA 🔍 during capture (varies significantly by sensor — OV5640/GC4653 higher, GC2053/OV7670 lower). Use a dedicated LDO (e.g., AMS1117-3.3) to avoid voltage sag from sharing MCU regulator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling caps:&lt;/strong&gt; Place 10 µF + 100 nF parallel decoupling caps near the module VCC pin, as close to the FPC connector as possible. Standard practice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signal integrity:&lt;/strong&gt; Keep DVP trace length within 10 cm; for longer runs, add 22–33 Ω series termination resistors on PCLK and data lines. ⚠️ Low-speed DVP (PCLK &amp;lt; 30MHz) may not need termination — depends on actual PCB layout.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No image, no PCLK waveform&lt;/td&gt;
&lt;td&gt;XCLK missing or wrong frequency&lt;/td&gt;
&lt;td&gt;Measure XCLK with scope, confirm 6–24 MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong colors / color cast&lt;/td&gt;
&lt;td&gt;Output format mismatch with MCU decoder&lt;/td&gt;
&lt;td&gt;Check register config, confirm RGB565 or YUV422&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image banding / jitter&lt;/td&gt;
&lt;td&gt;Power ripple or PCLK interference&lt;/td&gt;
&lt;td&gt;Improve power filtering, shorten data lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCCB config failure&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Wrong I²C address&lt;/strong&gt; or no pull-ups&lt;/td&gt;
&lt;td&gt;Check address table in this doc, add 4.7kΩ pull-ups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low frame rate&lt;/td&gt;
&lt;td&gt;Low XCLK or resolution too high&lt;/td&gt;
&lt;td&gt;Raise XCLK to 24 MHz, reduce resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blurry image (OV5640 AF)&lt;/td&gt;
&lt;td&gt;VCM unpowered or AF registers unconfigured&lt;/td&gt;
&lt;td&gt;Verify AF_VCC supply, initialize AF firmware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OV7670 garbled&lt;/td&gt;
&lt;td&gt;DVDD not separately powered&lt;/td&gt;
&lt;td&gt;Confirm on-board 1.8V LDO output&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Practical Purchasing Advice
&lt;/h2&gt;

&lt;p&gt;Lessons learned from my own mistakes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Choose controller first, camera second.&lt;/strong&gt; ESP32 only does DVP — choose OV2640/OV5640/OV7725/OV3660. Only MIPI-capable controllers (RV1106, Hi3516) can use 4MP sensors like GC4653. Your controller's interface defines your options.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check if the module has FIFO.&lt;/strong&gt; OV7670 comes in versions with and without AL422B FIFO. Running non-FIFO on bare STM32 is nearly impossible for normal imaging. The cheap tier is usually non-FIFO.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AF versions need AF_VCC pin.&lt;/strong&gt; OV5640 AF modules need separate VCM motor power. Some cheap modules merge AF power with main supply, some don't expose it. Check pinout before buying.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Voltage mismatch is the most common board-frying cause.&lt;/strong&gt; Don't just connect 3.3V blindly. GC0309's optimal point is 2.8V, OV7670 core needs 1.8V. When unsure, check the voltage table in this doc or read the datasheet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EOL parts (OV7725) carry inventory risk.&lt;/strong&gt; Officially discontinued; still available on Taobao/LCSC now, but not recommended for new mass production. Fine for prototyping.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GalaxyCore datasheets are harder to find than OmniVision.&lt;/strong&gt; If Chinese channels don't have GC-series datasheets, try galaxycore.com.cn official site, or module vendor pages like MuchVision, Camemaker. Sipeed Wiki is also a good supplemental source.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Sony IMX Series Purchasing Supplement
&lt;/h2&gt;

&lt;p&gt;The purchasing advice above focuses on OV/GC series (DVP ecosystem). Here are tips specific to Sony IMX series (MIPI ecosystem):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Where to buy IMX modules:&lt;/strong&gt; IMX219 is widely available on Taobao/LCSC (Pi V2 compatibles). IMX415 modules from LuckFox, Radxa, Camemaker are recommended. IMX335/IMX307 are mostly found through security solution providers. IMX678 is a 2024 new release, modules are still scarce.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't buy phone salvage parts for embedded use.&lt;/strong&gt; Phone sensors like IMX766 are cheap on Taobao (50-300 RMB), but have no datasheet, no driver, and non-standard FPC. You'll most likely waste time trying to light them up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch the STARVIS generation.&lt;/strong&gt; Sony officially defines three generations: STARVIS (original, 2014), STARVIS 2 (2021, wider dynamic range), STARVIS 3 (latest, LOFIC structure). Confirm which generation you're getting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global shutter is only in the Pregius line.&lt;/strong&gt; If your project involves high-speed motion capture (conveyor belts, sports analysis, 3D scanning), only Pregius global shutter sensors like IMX273 can avoid jello effect. All other IMX and OV/GC sensors are rolling shutter.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;All parameters in this article verified against the following official datasheets and authoritative sources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;OmniVision official product pages — OV2640 / OV5640 / OV7725 / OV7670 / OV3660 (ovt.com)&lt;/li&gt;
&lt;li&gt;OV2640 datasheet — uctronics.com/download/OV2640_DS.pdf&lt;/li&gt;
&lt;li&gt;OV5640 datasheet v2.03 — cdn.sparkfun.com/datasheets/Sensors/LightImaging/OV5640_datasheet.pdf&lt;/li&gt;
&lt;li&gt;OV5640 Product Brief — media.digikey.com/pdf/Data%20Sheets/OmniVision%20PDFs/OV5640_PB_3-4-11.pdf&lt;/li&gt;
&lt;li&gt;OV7725 datasheet — pdf.datasheet.live/10e069da/ovt.com/OV07725-V28A.pdf&lt;/li&gt;
&lt;li&gt;OV7670 datasheet — w2.electrodragon.com/Chip-dat/OmniVision-dat/OV7670-dat/OV7670-ds.pdf&lt;/li&gt;
&lt;li&gt;OV3660 datasheet — download.kamami.pl/p1196945-OV3660%20Datasheet.pdf&lt;/li&gt;
&lt;li&gt;GC0309 datasheet V1.0 (2009-12-28) — GalaxyCore Inc.&lt;/li&gt;
&lt;li&gt;GC2053 datasheet V1.1 (2018-11-29) — GalaxyCore / CK Vision&lt;/li&gt;
&lt;li&gt;GC4653 datasheet — Camemaker; Sipeed Wiki&lt;/li&gt;
&lt;li&gt;Espressif esp32-camera driver source — github.com/espressif/esp32-camera&lt;/li&gt;
&lt;li&gt;Sony Semiconductor Solutions — STARVIS trademark confirmation (STARVIS is Sony-exclusive tech)&lt;/li&gt;
&lt;li&gt;Linux Kernel ov7670.c — I²C address definition (android.googlesource.com)&lt;/li&gt;
&lt;li&gt;SCCB Functional Specification v2.2 — protocol spec&lt;/li&gt;
&lt;li&gt;Sony IMX219 datasheet — dlscorp.com/wp-content/uploads/2018/04/Sony-IMX219-Datasheet.pdf&lt;/li&gt;
&lt;li&gt;Sony IMX273 official Flyer — sony-semicon.com/files/62/flyer_industry/IMX273_287_296_297_Flyer.pdf&lt;/li&gt;
&lt;li&gt;Sony IMX307 official Flyer — sony-semicon.com/files/62/flyer_security/IMX307LQD_LQR_Flyer.pdf&lt;/li&gt;
&lt;li&gt;Sony IMX335 official Flyer — sony-semicon.com/files/62/flyer_security/IMX335LQN_Flyer.pdf&lt;/li&gt;
&lt;li&gt;Sony IMX415 official Flyer — sony-semicon.com/files/62/pdf/p-12_IMX415-AAQR_AAMR_Flyer.pdf&lt;/li&gt;
&lt;li&gt;Sony IMX678 official Flyer — sony-semicon.com/files/62/flyer_security/IMX678-AAQR_AAQR1_Flyer.pdf (© 2024)&lt;/li&gt;
&lt;li&gt;Sony IMX766 — OPPO official specs / IADIY module page / DxOMark&lt;/li&gt;
&lt;li&gt;Sony STARVIS technology — sony-semicon.com/en/technology/security/&lt;/li&gt;
&lt;li&gt;Raspberry Pi Camera documentation — raspberrypi.com/documentation/accessories/camera.html&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>hardware</category>
      <category>iot</category>
      <category>learning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Privacy-First Open Source ESP32-S3 Camera with RTSP for MiBee NVR</title>
      <dc:creator>ZhengZhiCong</dc:creator>
      <pubDate>Sat, 13 Jun 2026 12:12:57 +0000</pubDate>
      <link>https://dev.to/mickey_zzc/building-a-privacy-first-open-source-esp32-s3-camera-with-rtsp-for-frigate-nvr-4ie4</link>
      <guid>https://dev.to/mickey_zzc/building-a-privacy-first-open-source-esp32-s3-camera-with-rtsp-for-frigate-nvr-4ie4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Like many self-hosted enthusiasts, I've been frustrated with the state of affordable IP cameras for years. Most cheap cameras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phone home to unknown servers&lt;/li&gt;
&lt;li&gt;Require cloud subscriptions for basic features&lt;/li&gt;
&lt;li&gt;Don't support standard RTSP streams&lt;/li&gt;
&lt;li&gt;Run closed-source firmware you can't audit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built &lt;strong&gt;seeed-esp32s3-cam&lt;/strong&gt; - a 100% open source, privacy-first camera firmware that works natively with &lt;strong&gt;MiBeeNvr&lt;/strong&gt;, Blue Iris, and every self-hosted NVR system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardware
&lt;/h2&gt;

&lt;p&gt;This firmware is optimized for the &lt;strong&gt;Seeed Studio ESP32-S3 Sense&lt;/strong&gt; board - an incredibly capable camera module for around &lt;strong&gt;$15 USD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ESP32-S3 dual-core processor&lt;/li&gt;
&lt;li&gt;OV2640 2MP camera sensor&lt;/li&gt;
&lt;li&gt;Built-in WiFi&lt;/li&gt;
&lt;li&gt;Microphone support&lt;/li&gt;
&lt;li&gt;SD card slot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perfect for monitoring garages, sheds, entrances, or anywhere you want an inexpensive camera without sacrificing privacy.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Key Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;📹 &lt;strong&gt;Native RTSP Server&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Works with MiBeeNvr / Blue Iris / VLC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌐 &lt;strong&gt;HTTP MJPEG Streaming&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Low latency browser preview&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔍 &lt;strong&gt;On-device Motion Detection&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Configurable sensitivity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌙 &lt;strong&gt;Night Mode&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Auto exposure adjustment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ &lt;strong&gt;Web Configuration UI&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Full settings via browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ &lt;strong&gt;Pre-built Binaries&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Flash in 2 minutes, no compiling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔒 &lt;strong&gt;100% Local Only&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ No cloud, no phone home&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📄 &lt;strong&gt;MIT Licensed&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;✅ Open source forever&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🚀 Getting Started in 5 Minutes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Flash the Firmware
&lt;/h3&gt;

&lt;p&gt;No compiling needed! Use the pre-built binaries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the latest release from &lt;a href="https://github.com/Mi-Bee-Studio/seeed-esp32s3-cam" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Flash using &lt;code&gt;esptool.py&lt;/code&gt; or your favorite flasher:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;esptool.py &lt;span class="nt"&gt;--chip&lt;/span&gt; esp32s3 write_flash 0x0 firmware.bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configure WiFi
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Connect to the WiFi hotspot &lt;code&gt;ESP32-CAM-XXXX&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;192.168.4.1&lt;/code&gt; in your browser&lt;/li&gt;
&lt;li&gt;Enter your WiFi credentials&lt;/li&gt;
&lt;li&gt;The camera will reboot and connect to your network&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Access the Web UI
&lt;/h3&gt;

&lt;p&gt;Find your camera's IP address in your router, then open it in a browser. You'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live video preview&lt;/li&gt;
&lt;li&gt;Stream quality settings&lt;/li&gt;
&lt;li&gt;Motion detection configuration&lt;/li&gt;
&lt;li&gt;Network settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎯 MiBeeNvr Integration (The Good Stuff)
&lt;/h2&gt;

&lt;p&gt;This is why I built this - &lt;strong&gt;native MiBeeNvr compatibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Add this to your MiBeeNvr configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cameras&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esp32_cam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rtsp://your-camera-ip:8554/stream&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Garage Camera&lt;/span&gt;
    &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;detect_motion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! No hacks, no custom scripts, just standard RTSP. Your camera will show up instantly in the MiBeeNvr web UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MiBeeNvr GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Mi-Bee-Studio/MiBeeNvr" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/MiBeeNvr&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Technical Details
&lt;/h2&gt;

&lt;p&gt;Built with &lt;strong&gt;ESP-IDF v5.x&lt;/strong&gt; using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardware-accelerated JPEG encoding&lt;/li&gt;
&lt;li&gt;Optimized memory management for 24/7 operation&lt;/li&gt;
&lt;li&gt;Lightweight RTSP server implementation&lt;/li&gt;
&lt;li&gt;Non-blocking WiFi handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The firmware is designed to run stable indefinitely - I've had cameras running for months without a single reboot.&lt;/p&gt;

&lt;h2&gt;
  
  
  📖 Full Documentation
&lt;/h2&gt;

&lt;p&gt;For a complete step-by-step guide including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advanced MiBeeNvr configuration&lt;/li&gt;
&lt;li&gt;Performance tuning&lt;/li&gt;
&lt;li&gt;Troubleshooting common issues&lt;/li&gt;
&lt;li&gt;Motion detection optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the &lt;strong&gt;full tutorial&lt;/strong&gt;:&lt;br&gt;
👉 &lt;a href="https://blog.mickeyzzc.tech/en/posts/iot/esp32s3-cam-monitor/" rel="noopener noreferrer"&gt;https://blog.mickeyzzc.tech/en/posts/iot/esp32s3-cam-monitor/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 Both Projects Are Open Source
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Camera Firmware:&lt;/strong&gt; &lt;a href="https://github.com/Mi-Bee-Studio/seeed-esp32s3-cam" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/seeed-esp32s3-cam&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MiBeeNvr NVR Server:&lt;/strong&gt; &lt;a href="https://github.com/Mi-Bee-Studio/MiBeeNvr" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/MiBeeNvr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PRs, feature requests, and bug reports are all welcome! This is a community project - let's build the best open source camera + NVR ecosystem together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;In an era where every IoT device seems to want your data, having fully open, local-only options is more important than ever. This camera + NVR stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Never sends data anywhere&lt;/li&gt;
&lt;li&gt;✅ You can audit every line of code&lt;/li&gt;
&lt;li&gt;✅ You control all configuration&lt;/li&gt;
&lt;li&gt;✅ Works with your existing self-hosted tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No subscriptions, no accounts, no tracking. Just a complete surveillance system that works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'm actively working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-discovery between cameras and MiBeeNvr&lt;/li&gt;
&lt;li&gt;MQTT support for Home Assistant&lt;/li&gt;
&lt;li&gt;SD card recording on cameras&lt;/li&gt;
&lt;li&gt;Two-way audio&lt;/li&gt;
&lt;li&gt;ONVIF support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know what features you'd like to see!&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>iot</category>
      <category>opensource</category>
    </item>
    <item>
      <title>VictoriaMetrics Stream Aggregation: A Three-Year Retrospective (2026)</title>
      <dc:creator>ZhengZhiCong</dc:creator>
      <pubDate>Sun, 07 Jun 2026 22:56:28 +0000</pubDate>
      <link>https://dev.to/mickey_zzc/victoriametrics-stream-aggregation-a-three-year-retrospective-2026-2ojg</link>
      <guid>https://dev.to/mickey_zzc/victoriametrics-stream-aggregation-a-three-year-retrospective-2026-2ojg</guid>
      <description>&lt;p&gt;It's been exactly three years since the &lt;a href="https://blog.mickeyzzc.tech/en/posts/telemetry/stream-metrics-one/" rel="noopener noreferrer"&gt;first article&lt;/a&gt; in this series was published in March 2023. The VictoriaMetrics ecosystem has changed dramatically since then. Let's revisit the problems we laid out, see what the official project has resolved, and assess where our custom &lt;code&gt;stream-metrics-route&lt;/code&gt; gateway stands today.&lt;/p&gt;




&lt;h2&gt;
  
  
  I. The Problems We Identified in 2023
&lt;/h2&gt;

&lt;p&gt;Here's a quick recap of the core issues from the original post:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;2023 Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;Collection gap inflation&lt;/td&gt;
&lt;td&gt;Network jitter or performance issues cause time gaps that inflate stream aggregation deltas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;Single-node compute limits&lt;/td&gt;
&lt;td&gt;Stream aggregation has no historical state, fast but single-instance bottlenecked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;td&gt;Distributed task allocation&lt;/td&gt;
&lt;td&gt;Which compute node should each sample be assigned to?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P4&lt;/td&gt;
&lt;td&gt;Out-of-order discarding for same-dimension metrics&lt;/td&gt;
&lt;td&gt;Multiple nodes computing the same dimension with different time windows causes later values to be discarded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P5&lt;/td&gt;
&lt;td&gt;Resource balancing&lt;/td&gt;
&lt;td&gt;Uneven load across distributed compute nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P6&lt;/td&gt;
&lt;td&gt;Task ID dimension explosion&lt;/td&gt;
&lt;td&gt;Stream aggregation inserts node IDs into aggregated time series — the label cardinality grows with every node you add&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To address these, we built &lt;a href="https://github.com/Mi-Bee-Studio/stream-metrics-route" rel="noopener noreferrer"&gt;&lt;code&gt;stream-metrics-route&lt;/code&gt;&lt;/a&gt;, a Go-based distributed stream aggregation gateway.&lt;/p&gt;




&lt;h2&gt;
  
  
  II. Three Years Later — What the Official Project Has Done
&lt;/h2&gt;

&lt;p&gt;I reviewed VictoriaMetrics changelogs from v1.86 through v1.138.0 and the official documentation. Here's the scorecard.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Perfectly Resolved
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Issues P3, P5: Distributed Task Allocation &amp;amp; Resource Balancing
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Official solution:&lt;/strong&gt; vmagent now natively supports &lt;code&gt;-remoteWrite.shardByURL&lt;/code&gt; with &lt;strong&gt;consistent hashing&lt;/strong&gt; sharding.&lt;/p&gt;

&lt;p&gt;Starting from v1.86, basic &lt;code&gt;shardByURL&lt;/code&gt; was introduced. &lt;strong&gt;v1.138.0 (March 2026)&lt;/strong&gt; was the real milestone — it upgraded the data distribution algorithm from round-robin to &lt;strong&gt;consistent hashing&lt;/strong&gt;, which significantly reduces data redistribution ratios during node changes.&lt;/p&gt;

&lt;p&gt;The architecture evolution looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐     ┌─────────────────┐
│ Prometheus      │     │ Prometheus      │
│ Agent 1         │     │ Agent 2         │
└────────┬────────┘     └────────┬────────┘
         │ remote write          │ remote write
         ▼                       ▼
┌─────────────────────────────────────────┐
│           vmagent Cluster               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐│
│  │vmagent-0 │  │vmagent-1 │  │vmagent-2 ││
│  └─────┬────┘  └─────┬────┘  └─────┬────┘│
│        │             │             │     │
│        └─────────────┼─────────────┘     │
│                      ▼                   │
│           ┌──────────────────┐           │
│           │ Consistent Hash │           │
│           └────────┬─────────┘           │
└────────────────────┼─────────────────────┘
                     │ shard by hash
         ┌───────────┼───────────┐
         ▼           ▼           ▼
   ┌──────────┐ ┌──────────┐ ┌──────────┐
   │vmstorage │ │vmstorage │ │vmstorage │
   │    -0    │ │    -1    │ │    -2    │
   └──────────┘ └──────────┘ └──────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The VictoriaMetrics blog provides specific algorithm recommendations. Combined with VictoriaMetrics Operator, you can manage shards via &lt;code&gt;shardCount&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Issue P2: Single-Node Compute Scaling
&lt;/h4&gt;

&lt;p&gt;vmagent now supports horizontal scaling natively with &lt;code&gt;replicas&lt;/code&gt; + &lt;code&gt;shardCount&lt;/code&gt;, including HA support — see &lt;a href="https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5573" rel="noopener noreferrer"&gt;Issue #5573&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Out-of-Order / Delayed Data Accuracy (P1 — Partial Mitigation)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;v1.112.0 (February 2025)&lt;/strong&gt; was a key release, adding &lt;strong&gt;Aggregation Windows&lt;/strong&gt; — dual-window buffering for histogram and rate calculations. Instead of flushing immediately, the output is delayed by a &lt;code&gt;samples_lag&lt;/code&gt; window, which significantly improves accuracy for late-arriving data. The tradeoff: roughly doubled memory usage (maintaining two aggregation windows simultaneously).&lt;/p&gt;

&lt;p&gt;How it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Collector          vmagent           VictoriaMetrics
   │                  │                    │
   │  sample1 @T0    │                    │
   ├─────────────────►│  Write to          │
   │                  │  Window A (current)│
   │                  │                    │
   │  sample2 @T1    │                    │
   │  (delayed)      │                    │
   ├─────────────────►│  Write to          │
   │                  │  Window B (previous)│
   │                  │                    │
   │                  │  Aggr result A @T2 │
   │                  ├────────────────────►│
   │                  │  Aggr result B @T3 │
   │                  ├────────────────────►│
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the official docs on &lt;a href="https://docs.victoriametrics.com/stream-aggregation/#aggregation-windows" rel="noopener noreferrer"&gt;streaming aggregation windows&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ Still Unresolved
&lt;/h3&gt;

&lt;h4&gt;
  
  
  True Distributed Stream Aggregation Coordination
&lt;/h4&gt;

&lt;p&gt;vmagent's stream aggregation is &lt;strong&gt;single-instance&lt;/strong&gt;. There is no coordination mechanism between instances — if two vmagent instances aggregate the same metric, you get duplicate or conflicting output. The official recommendation is to use &lt;code&gt;without&lt;/code&gt;/&lt;code&gt;by&lt;/code&gt; label clauses to divide responsibility between instances, rather than providing a cross-instance coordination protocol.&lt;/p&gt;

&lt;h4&gt;
  
  
  Task ID Dimension Explosion (P6)
&lt;/h4&gt;

&lt;p&gt;Official vmagent still inserts internal labels (such as &lt;code&gt;_aggr&lt;/code&gt;-related labels) into aggregated time series, but lacks a &lt;code&gt;stream_task_id&lt;/code&gt; pre-marking plus dimension control design.&lt;/p&gt;




&lt;h2&gt;
  
  
  III. stream-metrics-route: Current Status and Value
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Code Architecture
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;router.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Routing core — filters metrics based on relabel rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remotecluster.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Dual hashmod scheduling core&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remotewrite.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remote write HTTP client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kafka.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kafka producer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Core Algorithm (from &lt;code&gt;remotecluster.go&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Dual hashmod scheduling&lt;/span&gt;
&lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sortLabelsHashKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dime&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hashMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dimension&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// First hashmod → task partition ID&lt;/span&gt;

&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"stream_task_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dime&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c"&gt;// Insert stream_task_id label&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;hashnode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sortLabelsHashKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filterLabels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Second hashmod → node selection&lt;/span&gt;
&lt;span class="n"&gt;tmpch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hashMod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uplen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashnode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c"&gt;// Which backend writer to send to&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Is It Still Needed in 2026?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Yes — but with an adjusted role.&lt;/strong&gt; The positioning should shift from "full stream aggregation gateway" to &lt;strong&gt;"metric distribution routing gateway + Kafka integration layer."&lt;/strong&gt; The core differentiated value:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dual hashmod scheduling + &lt;code&gt;stream_task_id&lt;/code&gt; pre-injection&lt;/strong&gt; — tags metrics at the gateway layer, so all downstream nodes route consistently by this ID. This solves dimension control earlier in the pipeline than the official approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-backend async distribution&lt;/strong&gt; — supports async distribution to both Kafka and remote write, solving the "synchronous forwarding blocks the time window" problem from the original post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Native Prometheus relabeling integration&lt;/strong&gt; — works with standard Prometheus relabel configs, no custom syntax to learn.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  IV. Recommended 2026 Hybrid Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐   ┌──────────────────┐
│  Prometheus     │   │  Business System │
│  Agent Cluster  │   │  Metrics (Kafka) │
└────────┬────────┘   └────────┬─────────┘
         │                     │
         ▼                     ▼
    ┌──────────────────────────────┐
    │   stream-metrics-route       │
    │   (Routing Layer)            │
    │   - Dual hashmod scheduling  │
    │   - stream_task_id injection │
    │   - Relabeling               │
    └──────┬──────┬──────┬─────────┘
           │      │      │
    task=0 │ task=1│task=2│
           ▼      ▼      ▼
    ┌─────────────────────────┐
    │   vmagent Cluster       │
    │  (v1.112.0+ with        │
    │   aggregation windows)  │
    └──────────┬──────────────┘
               │
               ▼
    ┌──────────────────┐      ┌────────────┐
    │  VictoriaMetrics │      │   Kafka    │
    │  (Storage)       │      │   (Topic)  │
    └──────────┬───────┘      └────────────┘
               │
               ▼
    ┌──────────────────┐
    │  vmalert         │
    │  Grafana         │
    └──────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;vmagent version requirement:&lt;/strong&gt; &amp;gt;= v1.112.0, with aggregation windows enabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# stream aggregation config&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http_request_duration_seconds_bucket'&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
  &lt;span class="na"&gt;without&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;enable_windows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;   &lt;span class="c1"&gt;# Critical! Enables dual-window buffering&lt;/span&gt;
  &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rate_sum&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  V. Evolution Recommendations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Short-term
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Upgrade vmagent to &amp;gt;= v1.112.0&lt;/td&gt;
&lt;td&gt;Enable &lt;code&gt;enable_windows: true&lt;/code&gt; to improve histogram aggregation accuracy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluate stream-metrics-route necessity&lt;/td&gt;
&lt;td&gt;If you have no Kafka requirement or high-cardinality &lt;code&gt;stream_task_id&lt;/code&gt; control need, consider migrating away&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Medium-term
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Retain stream-metrics-route as front-end routing only&lt;/td&gt;
&lt;td&gt;Keep hashmod task allocation + Kafka distribution; remove aggregation responsibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disable raw metric persistence&lt;/td&gt;
&lt;td&gt;Write only stream-aggregated results to storage to reduce volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add metadata management module&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;ruler-handle-process&lt;/code&gt; from the original post (dynamic Record Rule by dimension) is worth building or contributing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Long-term
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Contribute &lt;code&gt;stream_task_id&lt;/code&gt; dimension control upstream&lt;/td&gt;
&lt;td&gt;If the dual hashmod design proves out in production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Improve monitoring metrics&lt;/td&gt;
&lt;td&gt;Add business-level metrics — queue depth per routing rule, distribution latency, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Assessment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Problem resolution rate&lt;/td&gt;
&lt;td&gt;~50% — 2 of 4 core problems resolved via official upgrades; 2 still need custom solutions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is stream-metrics-route still needed?&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — repositioned as "metric distribution routing gateway + Kafka integration layer"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recommended architecture&lt;/td&gt;
&lt;td&gt;Prometheus → stream-metrics-route → vmagent v1.112.0+ → VictoriaMetrics Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three years is a long time in the observability space. The VictoriaMetrics ecosystem has matured significantly — consistent hashing, aggregation windows, and native sharding all address problems that required custom tooling in 2023. But the hard problems around true &lt;em&gt;distributed&lt;/em&gt; stream aggregation coordination and dimension control at the gateway layer remain open.&lt;/p&gt;

&lt;p&gt;If you're running a similar stack, the hybrid approach — letting the official project handle what it's good at (single-node aggregation, storage) while keeping custom routing for what it isn't (distributed coordination, dimension pre-injection, Kafka bridging) — has proven to be the right call for us.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.mickeyzzc.tech/en/posts/telemetry/stream-metrics-two/" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>performance</category>
    </item>
    <item>
      <title>Scaling VictoriaMetrics Stream Aggregation: A Deep Dive into Distributed Design（2023）</title>
      <dc:creator>ZhengZhiCong</dc:creator>
      <pubDate>Sun, 07 Jun 2026 22:50:31 +0000</pubDate>
      <link>https://dev.to/mickey_zzc/scaling-victoriametrics-stream-aggregation-a-deep-dive-into-distributed-design-629</link>
      <guid>https://dev.to/mickey_zzc/scaling-victoriametrics-stream-aggregation-a-deep-dive-into-distributed-design-629</guid>
      <description>&lt;p&gt;VictoriaMetrics' stream aggregation is a powerful feature for reducing metric cardinality in real time. But when you push it to millions of time series across a distributed fleet, the native implementation starts to show cracks.&lt;/p&gt;

&lt;p&gt;This post walks through what I found analyzing the stream aggregation source code, the real-world problems that emerged at scale, and the distributed gateway we built to solve them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Community VM Stream Aggregation — Capability Analysis
&lt;/h2&gt;

&lt;p&gt;Stream aggregation was integrated into &lt;code&gt;vmagent&lt;/code&gt; starting from version 1.86 (&lt;a href="https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3460" rel="noopener noreferrer"&gt;GitHub issue #3460&lt;/a&gt;). Let's look at what it actually does under the hood.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Computation: The &lt;code&gt;pushSample&lt;/code&gt; Function
&lt;/h3&gt;

&lt;p&gt;The heart of stream aggregation lives in the &lt;code&gt;pushSample&lt;/code&gt; function. Here's the simplified logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;totalAggrState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pushSample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputKey&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fasttime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixTimestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;deleteDeadline&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalSecs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalSecs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;again&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;totalStateValue&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;lastValues&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lastValueState&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;vNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loaded&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadOrStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;loaded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vNew&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;sv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;totalStateValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;deleted&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;inputKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;lv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lastValueState&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;inputKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ignoreInputDeadline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteDeadline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deleteDeadline&lt;/span&gt;
        &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteDeadline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deleteDeadline&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;deleted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="n"&gt;again&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core idea: each incoming sample's value is compared against the last seen value for that time series. The &lt;em&gt;delta&lt;/em&gt; is accumulated into a running total. This works well for counters that monotonically increase, but there's a critical detail — the time window logic is simple periodic checking with no sophisticated handling for delayed or out-of-order arrivals.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Stream Aggregation Looks Like in Practice
&lt;/h3&gt;

&lt;p&gt;In theory, stream aggregation should cleanly reduce high-cardinality metrics down to manageable summaries. In practice, the picture is messier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ideal model&lt;/strong&gt;: every sample arrives on time, windows align perfectly, aggregation is lossless&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reality&lt;/strong&gt;: samples arrive late, retries flood old data, gaps appear from network or service issues&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Issues with Native Stream Aggregation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Collection Gap Problem
&lt;/h3&gt;

&lt;p&gt;Collection gaps are inevitable. Network blips, service restarts, GC pauses — any of these can cause a gap in metric collection. For high-precision stream aggregation, gaps create a specific failure mode:&lt;/p&gt;

&lt;p&gt;When a counter's last tracked value is &lt;code&gt;1000&lt;/code&gt;, and a gap causes the next received value to be &lt;code&gt;5000&lt;/code&gt;, the delta is &lt;code&gt;4000&lt;/code&gt; — which may span an unknown number of actual increments. If the gap occurred &lt;em&gt;within&lt;/em&gt; a single aggregation window, the inflated value corrupts that window's result. If the gap crosses window boundaries, you get compounding errors in downstream calculations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed Computing Challenges
&lt;/h3&gt;

&lt;p&gt;Stream aggregation doesn't persist historical data, so it's fast — but even the fastest service has single-node limits. When you need to scale horizontally, a cascade of new problems appears:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is vmagent's built-in collection viable at scale?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In testing, enabling vmagent shard + replica collection with real-time stream aggregation caused significant resource spikes. At very large scales, collection gaps became more frequent, which &lt;em&gt;amplified&lt;/em&gt; the calculation errors from gaps rather than mitigating them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which compute node should each sample be assigned to?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without a consistent routing strategy, the same metric dimension gets split across nodes, producing partial results that can't be safely combined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you handle the same dimension set being computed by multiple nodes with different values?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When multiple nodes produce results for the same dimension within the same time window, VictoriaMetrics triggers its out-of-order handling logic — which discards later values. You lose data silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you balance resources in distributed computation?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uneven distribution means some nodes are overloaded while others sit idle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about the new dimensions introduced by routing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you insert a task ID to differentiate compute nodes, you've just added a new dimension that grows with every node you add — defeating part of the purpose of aggregation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design and Implementation: A Distributed Stream Aggregation Gateway
&lt;/h2&gt;

&lt;p&gt;After analyzing these problems, it became clear that a frontend module was needed to address them at the entry point. Since &lt;code&gt;vmgateway&lt;/code&gt; is an enterprise component, we built our own: &lt;strong&gt;&lt;code&gt;vm-receive-route&lt;/code&gt;&lt;/strong&gt;, a distributed stream aggregation gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Insight from Source Code
&lt;/h3&gt;

&lt;p&gt;Two aspects of the native implementation are particularly relevant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time window range:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fasttime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixTimestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;deleteDeadline&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalSecs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intervalSecs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The window has a 50% grace period (&lt;code&gt;intervalSecs &amp;gt;&amp;gt; 1&lt;/code&gt;) beyond the configured interval. This is the only protection against late-arriving data — and it's quite generous, which means stale data can still influence results within that extended window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calculation logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;inputKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lastValueState&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;inputKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ignoreInputDeadline&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The aggregation only checks if a previous value exists and is smaller — it doesn't handle the case where a late-arriving sample with a lower value (after a restart, for example) creates a negative delta that's simply ignored. There's no deduplication, no gap detection, no intelligent merging.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the Gateway Solves
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Asynchronous Processing
&lt;/h4&gt;

&lt;p&gt;Most &lt;code&gt;remote write&lt;/code&gt; adapters (like &lt;code&gt;prometheus-kafka-adapter&lt;/code&gt;) do synchronous forwarding — they wait for the downstream (Kafka, etc.) to acknowledge before accepting the next batch. Stream aggregation has &lt;em&gt;window constraints&lt;/em&gt;: if the write pipeline blocks and samples arrive late, they miss their window and calculations drift.&lt;/p&gt;

&lt;p&gt;The gateway decouples ingestion from forwarding using an internal buffer. The &lt;code&gt;remote write&lt;/code&gt; endpoint returns immediately, and samples are forwarded asynchronously to the stream aggregation backend. This prevents back-pressure from creating cascading delays.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Time Window Filtering
&lt;/h4&gt;

&lt;p&gt;Since stream aggregation already computes deltas between successive values, there's no need for complex out-of-order handling at this layer. The gateway simply cooperates with the aggregation window:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Samples arriving within the window → forward normally&lt;/li&gt;
&lt;li&gt;Samples arriving outside the window → discard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solves two problems at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus retries that send large backlogs of old samples no longer corrupt real-time results&lt;/li&gt;
&lt;li&gt;The resource overhead of processing those retries is eliminated at the gateway level — the aggregation backend never sees them&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Dimension Control
&lt;/h4&gt;

&lt;p&gt;The stream aggregation component inserts a node ID into each aggregated time series to distinguish labels across compute nodes. But as nodes scale horizontally, the cardinality of &lt;em&gt;that label&lt;/em&gt; scales too. You need a way to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Control dimension growth from node identities&lt;/li&gt;
&lt;li&gt;Route time series by dimension to the correct node&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We designed a &lt;strong&gt;dual hashmod scheduling algorithm&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The gateway assigns a hash-based task ID to each time series based on its stable dimensions (not the node identity)&lt;/li&gt;
&lt;li&gt;The same series always routes to the same compute node, regardless of which gateway instance processed it&lt;/li&gt;
&lt;li&gt;The task ID dimension is bounded by the number of unique dimension combinations, not the number of gateway nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By moving the task ID labeling to the gateway layer, we eliminated the unbounded dimension growth that horizontal scaling would otherwise cause.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Backend Service Migration for Failures
&lt;/h4&gt;

&lt;p&gt;When a compute node fails, its in-memory aggregation state is lost. The gateway detects failures via health checks and reroutes traffic to healthy nodes. Since the dual hashmod ensures consistent routing, the remaining nodes can immediately pick up the work, though there will be a brief period of incomplete aggregation until the state rebuilds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Record Rule Dimension Task Generator
&lt;/h2&gt;

&lt;p&gt;Stream aggregation is great for reducing cardinality of &lt;em&gt;single metrics&lt;/em&gt;. But real-world monitoring scenarios require combining multiple metrics with functions — which is where Prometheus &lt;code&gt;Record Rule&lt;/code&gt; comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Record Rules at Scale
&lt;/h3&gt;

&lt;p&gt;Consider an HTTP request metric with a &lt;code&gt;req_path&lt;/code&gt; dimension:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before stream aggregation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;a_http_req_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"30021"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dis_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"202"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;req_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/api/foo?abc=xyz"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;a_http_req_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"30023"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dis_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"202"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;req_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/api/bar?abc=def"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;a_http_req_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"10021"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dis_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"202"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;req_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/api/baz?abc=ghi"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After stream aggregation (dropping &lt;code&gt;req_path&lt;/code&gt; and &lt;code&gt;src_port&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;agg_a_http_req_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dis_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"202"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;agg_a_http_req_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dis_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"500"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;agg_a_http_req_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"bj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dis_svr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"192.168.2.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"400"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what you &lt;em&gt;actually&lt;/em&gt; want to display is the success rate per target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum by (dis_svr) (
    rate(a_http_req_total{code=~"2.*"}[5m])
)
/
sum by (dis_svr) (
    rate(a_http_req_total{}[5m])
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use &lt;code&gt;Record Rule&lt;/code&gt; to precompute this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;a_http_req_total:sum:rate:5m&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum by (src_svr, dis_svr, code) (rate(a_http_req_total{}[5m]))&lt;/span&gt;
        &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;a_http_req_total:sum:rate:5m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem? &lt;code&gt;Record Rule&lt;/code&gt; loads &lt;em&gt;all&lt;/em&gt; dimensions of the metric into memory. When dimension counts reach critical thresholds, it triggers OOM. Even below that threshold, higher cardinality means slower computation.&lt;/p&gt;

&lt;p&gt;In production, &lt;code&gt;istio_requests_total&lt;/code&gt; QPS could be delayed by &lt;strong&gt;20 minutes&lt;/strong&gt; at high dimension counts. After applying stream aggregation to reduce from tens of millions of time series down to tens of thousands, the delay dropped to 1-2 minutes — better, but still far from real-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Dimension-Split Record Rules
&lt;/h3&gt;

&lt;p&gt;The issue is that &lt;code&gt;Record Rule&lt;/code&gt; evaluates one query per group, loading everything into memory. But if you split the query by specific dimension values, you can process them concurrently.&lt;/p&gt;

&lt;p&gt;The static approach after stream aggregation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agg_a_http_req_total:sum:rate:5m-2xx&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum by (src_svr, dis_svr, code) (rate(agg_a_http_req_total{code=~"2.*"}[5m]))&lt;/span&gt;
        &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agg_a_http_req_total:sum:rate:5m&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agg_a_http_req_total:sum:rate:5m-4xx&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum by (src_svr, dis_svr, code) (rate(agg_a_http_req_total{code=~"4.*"}[5m]))&lt;/span&gt;
        &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agg_a_http_req_total:sum:rate:5m&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agg_a_http_req_total:sum:rate:5m-5xx&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum by (src_svr, dis_svr, code) (rate(agg_a_http_req_total{code=~"5.*"}[5m]))&lt;/span&gt;
        &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agg_a_http_req_total:sum:rate:5m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the problem is that in production, dimension labels are dynamic. You can't hardcode splits for every dimension value. You need a &lt;strong&gt;label metadata management system&lt;/strong&gt; that watches dimension combinations and dynamically generates split queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;ruler-handle-process&lt;/code&gt; Component
&lt;/h3&gt;

&lt;p&gt;We built a small metadata watch and rule builder that automates this. Its configuration looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;recode_rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
    &lt;span class="na"&gt;recode_to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio_requests_total:sum:rate:5m&lt;/span&gt;
    &lt;span class="na"&gt;metric_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio_requests_total&lt;/span&gt;
    &lt;span class="na"&gt;aggr_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum&lt;/span&gt;
    &lt;span class="na"&gt;vector_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rate&lt;/span&gt;
    &lt;span class="na"&gt;vector_range&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
    &lt;span class="na"&gt;group_by_and_filter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;source_workload&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;destination_workload&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cluster&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;namespace&lt;/span&gt;
    &lt;span class="na"&gt;group_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;response_code&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;namespace&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;source_workload_namespace&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;destination_workload_namespace&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;destination_service_name&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cluster&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;reporter&lt;/span&gt;
    &lt;span class="na"&gt;filter_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k8s-hw-bj-xxxxxx"&lt;/span&gt;
    &lt;span class="na"&gt;with_out&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;source_workload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ingressgateway-workflows"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component watches the actual dimension combinations under the metric name &lt;code&gt;istio_requests_total&lt;/code&gt; and generates a set of &lt;code&gt;Record Rule&lt;/code&gt; configurations — one per unique dimension combination. Combined with Prometheus's Rule component for concurrent evaluation, this reduced computation latency from minutes to &lt;strong&gt;seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The generated rules look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio_requests_total:sum:rate:5m-7218756fe8a0bc327e818812cefb02f7&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum by (...) (rate(istio_requests_total{cluster="k8s-hw-bj-1-prod", destination_workload="skyaxe-778-flink", ...}[5m]))&lt;/span&gt;
        &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio_requests_total:sum:rate:5m&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio_requests_total:sum:rate:5m-8e30244048f8d5519a6332f309578ed4&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum by (...) (rate(istio_requests_total{cluster="k8s-hw-bj-1-prod", destination_workload="t-bean-portal", ...}[5m]))&lt;/span&gt;
        &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio_requests_total:sum:rate:5m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each unique dimension combination gets its own rule group, enabling true concurrent computation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Combinations for Different Scales
&lt;/h2&gt;

&lt;p&gt;Using community open-source components alongside our custom gateway and rule builder, we assembled a tiered architecture that handles everything from small deployments to massive fleets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Small Scale: Tens of Thousands of Single Metrics
&lt;/h3&gt;

&lt;p&gt;Minimal setup — vmagent with built-in stream aggregation. No gateway needed. The single-node limits aren't reached yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Medium Scale: Tens of Thousands of Multi-Metrics
&lt;/h3&gt;

&lt;p&gt;Add Record Rules for computed metrics. Use the dimension-split approach to keep computation fast. Stream aggregation reduces cardinality before Record Rule evaluation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Large Scale: Millions+ of Single Metrics
&lt;/h3&gt;

&lt;p&gt;This is where the distributed gateway comes in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple vmagent instances behind the gateway for horizontal ingestion&lt;/li&gt;
&lt;li&gt;Dual hashmod scheduling ensures consistent routing&lt;/li&gt;
&lt;li&gt;Time window filtering at the gateway prevents retries from polluting results&lt;/li&gt;
&lt;li&gt;Asynchronous forwarding prevents back-pressure from creating cascading delays&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Large Scale: Scenario-Based Computational Aggregation for Millions of Metrics
&lt;/h3&gt;

&lt;p&gt;The full stack:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stream aggregation&lt;/strong&gt; — first pass cardinality reduction at ingestion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed gateway&lt;/strong&gt; — routing, filtering, and load distribution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic rule builder&lt;/strong&gt; — watches dimension metadata and generates concurrent Record Rule groups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule engine&lt;/strong&gt; — evaluates split queries in parallel&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;VictoriaMetrics' stream aggregation is a solid foundation, but it was designed for single-node operation. When you need to scale horizontally, you encounter a series of interconnected problems — collection gaps, dimension explosion, record rule performance bottlenecks — that the native implementation doesn't address.&lt;/p&gt;

&lt;p&gt;The solutions aren't particularly complex individually (async processing, time window filtering, hash-based routing, dimension-aware rule generation), but they need to work together as a coherent system. The gateway pattern — intercepting the &lt;code&gt;remote write&lt;/code&gt; path before it reaches the aggregation layer — proved to be the right abstraction point for injecting these capabilities without modifying upstream code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ruler-handle-process&lt;/code&gt; component was the second key insight: rather than fighting Prometheus Record Rule's single-query-per-group limitation, we embraced it by dynamically splitting queries by dimension and running them concurrently. This turned a 20-minute computation into a seconds-level operation.&lt;/p&gt;

&lt;p&gt;If you're running VictoriaMetrics at scale and hitting these issues, the patterns described here should be applicable regardless of your specific stack. The gateway approach is generic enough to work with any Prometheus-compatible &lt;code&gt;remote write&lt;/code&gt; backend.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.mickeyzzc.tech/en/posts/telemetry/stream-metrics-one/" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>monitoring</category>
      <category>performance</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>MiBeeNvr: A Lightweight Home NVR System I Built</title>
      <dc:creator>ZhengZhiCong</dc:creator>
      <pubDate>Sun, 07 Jun 2026 09:27:47 +0000</pubDate>
      <link>https://dev.to/mickey_zzc/mibeenvr-a-lightweight-home-nvr-system-i-built-41b</link>
      <guid>https://dev.to/mickey_zzc/mibeenvr-a-lightweight-home-nvr-system-i-built-41b</guid>
      <description>&lt;p&gt;I have several cameras at home — a few Xiaomi cameras, some DIY ESP32 cameras, and multiple Raspberry Pi CSI cameras. I'd been using cloud storage solutions, but I was never comfortable with them: vendor lock-in, network dependency, and the costs add up. So I decided to build my own NVR system, called MiBeeNvr.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Build MiBeeNvr
&lt;/h2&gt;

&lt;p&gt;To be honest, I was never satisfied with existing cloud storage solutions. Take Xiaomi cameras, for example. By default, you can only view them through the Mi Home app. Recordings are either stored on an SD card (limited capacity, frequent plugging/unplugging) or in the cloud. Cloud storage costs tens of dollars per month, and there's the privacy concern — you never know when the manufacturer might use your video data for AI training or sell it to third parties. Not to mention vendor lock-in — switching platforms is nearly impossible.&lt;/p&gt;

&lt;p&gt;ESP32 cameras have a similar problem. I built several ESP32 cameras, storing recordings on SD cards, but viewing and playback were inconvenient. I needed a unified management platform.&lt;/p&gt;

&lt;p&gt;I also tried other open-source solutions: ZoneMinder requires a LAMP stack — installing and deploying it is more complex than my entire project; Shinobi's configuration is a nightmare; and some smaller projects are basically unmaintained. Frigate is nice but primarily focused on AI detection and depends on Docker — too heavy.&lt;/p&gt;

&lt;p&gt;In short, I wanted something that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A single binary file — download and run&lt;/li&gt;
&lt;li&gt;Lightweight enough to run on a Raspberry Pi&lt;/li&gt;
&lt;li&gt;Supports multiple camera types, especially Xiaomi's proprietary protocol&lt;/li&gt;
&lt;li&gt;Clean Web interface without frontend complexity&lt;/li&gt;
&lt;li&gt;Auto-cleanup of old recordings, won't fill up the disk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After searching around, none of the existing solutions fit. So I wrote my own.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is MiBeeNvr
&lt;/h2&gt;

&lt;p&gt;MiBeeNvr is a lightweight NVR system written in Go, designed to solve local storage for home cameras.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall Architecture
&lt;/h3&gt;

&lt;p&gt;The system has three layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Camera End&lt;/strong&gt; — multiple camera types connect through different protocols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Xiaomi cameras use the proprietary "miss" protocol (encrypted, multi-layer)&lt;/li&gt;
&lt;li&gt;ESP32 cameras send HTTP JPEG/MJPEG streams directly&lt;/li&gt;
&lt;li&gt;Raspberry Pi CSI cameras output standard RTSP H.264 via MediaMTX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Protocol Bridge Layer&lt;/strong&gt; — proprietary protocols get converted to standard RTSP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;go2rtc&lt;/code&gt; handles Xiaomi's miss protocol decryption and transcodes it to RTSP&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MediaMTX&lt;/code&gt; converts Raspberry Pi CSI interface video to RTSP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MiBeeNvr Core&lt;/strong&gt; — handles the recording logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST API receives all video streams&lt;/li&gt;
&lt;li&gt;Recording engine segments incoming video into MP4 files&lt;/li&gt;
&lt;li&gt;SQLite stores metadata (pure Go, no CGO, no separate DB installation)&lt;/li&gt;
&lt;li&gt;Auto-cleanup daemon removes old recordings per retention policy&lt;/li&gt;
&lt;li&gt;HLS live streaming for real-time viewing (up to 4 concurrent)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Access Methods&lt;/strong&gt; — users interact through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built-in Web UI (Svelte 5 SPA, embedded in the single binary)&lt;/li&gt;
&lt;li&gt;WebDAV (read-write) and FTP for file-level access&lt;/li&gt;
&lt;li&gt;Prometheus metrics for system monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: cameras → protocol bridge → MiBeeNvr core → user access, all in a single binary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recording Pipeline
&lt;/h3&gt;

&lt;p&gt;Video processing follows a straightforward pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Input&lt;/strong&gt; — RTSP streams are handled via &lt;code&gt;gortsplib&lt;/code&gt;, HTTP JPEG streams are periodically grabbed as frames&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decode &amp;amp; Mux&lt;/strong&gt; — RTP packets are depacketized via &lt;code&gt;pion/rtp&lt;/code&gt;, then muxed into MP4 via &lt;code&gt;go-mp4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt; — video is segmented into files (configurable: 30s or 10m intervals), SQLite tracks metadata, files go to disk&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The frontend uses Svelte 5 — the entire SPA is compiled to static assets and embedded into the Go binary. Deployment is a single file, no separate Web server needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend tech stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go 1.26 + modernc.org/sqlite (pure Go, no CGO dependency)&lt;/li&gt;
&lt;li&gt;chi routing library, clean and efficient&lt;/li&gt;
&lt;li&gt;gortsplib for RTSP/RTP protocol&lt;/li&gt;
&lt;li&gt;pion/rtp for real-time streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SQLite was chosen because it's single-file, pure Go, performs well enough for home use, supports concurrent access, and most importantly, doesn't require a separate database installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Philosophy
&lt;/h3&gt;

&lt;p&gt;The entire project's design philosophy is &lt;strong&gt;"simple and straightforward:"&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single binary file, no external dependencies&lt;/li&gt;
&lt;li&gt;Supports cross-compilation, runs on AMD64/ARM64&lt;/li&gt;
&lt;li&gt;YAML configuration, intuitive&lt;/li&gt;
&lt;li&gt;Built-in Web interface, open browser to use&lt;/li&gt;
&lt;li&gt;Minimal resource usage, runs smoothly on Raspberry Pi 4&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Supports multiple camera protocols: RTSP (H.264/H.265), HTTP JPEG&lt;/li&gt;
&lt;li&gt;Built-in Web interface with dark/light theme switching&lt;/li&gt;
&lt;li&gt;Chinese/English bilingual support&lt;/li&gt;
&lt;li&gt;WebDAV (read-write), FTP, REST API&lt;/li&gt;
&lt;li&gt;MQTT-triggered recording, ideal for smart home integration&lt;/li&gt;
&lt;li&gt;Prometheus monitoring metrics&lt;/li&gt;
&lt;li&gt;Per-camera independent retention policies&lt;/li&gt;
&lt;li&gt;MP4 segmented recording, auto-cleanup of old files&lt;/li&gt;
&lt;li&gt;Supports HLS live streaming (up to 4 concurrent)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  My Actual Deployment
&lt;/h2&gt;

&lt;p&gt;I run it on an ARM64 mini host with 512MB RAM and 2GB storage. The system runs very stably — basically set it and forget it.&lt;/p&gt;

&lt;p&gt;Connected 4 cameras, each with its own characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Raspberry Pi CSI Camera&lt;/strong&gt; — RTSP bridge via MediaMTX, converting CSI interface video to standard RTSP. Configured as &lt;code&gt;rtsp_h264&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESP32-S3 Camera&lt;/strong&gt; — DIY, running MJPEG stream via HTTP protocol. Configured as &lt;code&gt;http_jpeg&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Xiaomi Camera (Balcony)&lt;/strong&gt; — Protocol conversion via go2rtc (Xiaomi proprietary → RTSP), 2K resolution, configured as &lt;code&gt;rtsp_h265&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Xiaomi Camera (Living Room)&lt;/strong&gt; — Same as above, 1080P.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Configuration is 30-second segment recording with 1-day retention. This interval is a trade-off: too short creates too many files, too long makes it inconvenient to look up incidents. WebDAV (read-write) and FTP are enabled for convenient phone viewing and backup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6ezz6dqetie2wev5hqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6ezz6dqetie2wev5hqs.png" alt="Camera management page" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Web interface is clean — camera management and recording lists are straightforward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqppfsih7x2m5bczottro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqppfsih7x2m5bczottro.png" alt="Recording list (dark)" width="800" height="957"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Settings page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4795f8lnr5rtl9hsaris.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4795f8lnr5rtl9hsaris.png" alt="Settings page" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration File
&lt;/h3&gt;

&lt;p&gt;The complete configuration file looks like this — YAML format, clear at a glance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:9090"&lt;/span&gt;

&lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;root_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/mnt/data/nvr"&lt;/span&gt;
  &lt;span class="na"&gt;segment_duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;30s"&lt;/span&gt;

&lt;span class="na"&gt;cameras&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rpi-csi-cam"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RPi&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CSI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Camera"&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtsp_h264"&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtsp://10.0.1.100:8554/stream"&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;esp32-cam"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ESP32-S3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Camera"&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http_jpeg"&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://10.0.1.101/capture"&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xiaomi-balcony"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Xiaomi&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Camera"&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtsp_h265"&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtsp://10.0.1.102:8554/xiaomi_stream"&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;cleanup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;retention_days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
  &lt;span class="na"&gt;disk_threshold_percent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;95&lt;/span&gt;

&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin"&lt;/span&gt;
  &lt;span class="na"&gt;password_hash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mibee-nvr&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hash-password&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;command&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;generate"&lt;/span&gt;

&lt;span class="na"&gt;webdav&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;path_prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dav"&lt;/span&gt;
  &lt;span class="na"&gt;read_write&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;ftp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2121&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Xiaomi Camera Integration
&lt;/h2&gt;

&lt;p&gt;Xiaomi camera protocol is a major headache. It uses its proprietary "miss" (Mi Secure Streaming) protocol with multi-layer encryption, without a standard RTSP interface. Even if you know the camera's IP, you can't pull a stream with VLC.&lt;/p&gt;

&lt;p&gt;Fortunately, there's &lt;a href="https://github.com/AlexxIT/go2rtc" rel="noopener noreferrer"&gt;go2rtc&lt;/a&gt;, a lifesaver. The integration works in four steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Account auth &amp;amp; key exchange&lt;/strong&gt; — go2rtc logs into your Xiaomi account, retrieves device lists and encryption keys from Xiaomi Cloud&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Establish P2P connection&lt;/strong&gt; — go2rtc initiates a miss protocol handshake with the camera, establishing a peer-to-peer link&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video stream relay&lt;/strong&gt; — the camera sends its encrypted miss stream to go2rtc continuously; go2rtc decrypts and transcodes it into a standard RTSP stream (H.265); MiBeeNvr receives this as a normal RTSP camera and records segmented MP4 files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent access&lt;/strong&gt; — once set up, you no longer need the Mi Home app or Xiaomi cloud subscription; all recordings are accessible via MiBeeNvr's Web UI, WebDAV, or FTP&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The entire process requires no firmware flashing, no camera disassembly, and no Xiaomi cloud storage subscription. go2rtc handles all the protocol conversion.&lt;/p&gt;

&lt;h3&gt;
  
  
  go2rtc Deployment
&lt;/h3&gt;

&lt;p&gt;The easiest way to deploy go2rtc is with Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create configuration file&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; go2rtc.yaml &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
streams:
  xiaomi_balcony:
    - xiaomi://your_account:cn@10.0.1.100?did=your_camera_did&amp;amp;model=isa.camera.hlc7
  xiaomi_living_room:
    - xiaomi://your_account:cn@10.0.1.101?did=your_camera_did&amp;amp;model=isa.camera.mj200

rtsp:
  listen: ":8554"
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Run container&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; go2rtc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 8554:8554 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 1984:1984 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/go2rtc.yaml:/config.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  alexxit/go2rtc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;xiaomi://&lt;/code&gt; protocol requires Xiaomi account and password authentication&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;did&lt;/code&gt; is the device's unique identifier, &lt;code&gt;model&lt;/code&gt; is the device model (can be found in the Mi Home app)&lt;/li&gt;
&lt;li&gt;go2rtc automatically handles P2P connection and miss protocol decryption&lt;/li&gt;
&lt;li&gt;The final standard RTSP stream is exposed on port 8554, and MiBeeNvr connects to it like any normal camera&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then point to go2rtc in MiBeeNvr's config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cameras&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xiaomi-balcony"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Xiaomi&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Camera"&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtsp_h265"&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rtsp://localhost:8554/xiaomi_balcony"&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pitfalls Encountered
&lt;/h3&gt;

&lt;p&gt;Xiaomi camera integration has several pitfalls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First-time network connection&lt;/strong&gt;: Xiaomi cameras must be able to reach the internet for key exchange with Xiaomi servers. After connection is established, subsequent transmission is over LAN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device ID acquisition&lt;/strong&gt;: Each camera's &lt;code&gt;did&lt;/code&gt; is unique. Use go2rtc's WebUI (port 1984) for auto-discovery, or dig through the Mi Home app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not all models are supported&lt;/strong&gt;: go2rtc maintains a compatibility list — check before buying a camera.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H.265 vs H.264&lt;/strong&gt;: Newer Xiaomi cameras mostly use H.265. MiBeeNvr supports both codecs, but H.265 saves storage space.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ESP32 Camera Projects
&lt;/h2&gt;

&lt;p&gt;While working on MiBeeNvr, I also built several ESP32 camera firmware projects. ESP32 cameras had their share of pitfalls, but were also quite interesting.&lt;/p&gt;

&lt;p&gt;I built three firmware projects with different positioning, all designed as upstream capture endpoints for MiBeeNvr — cameras handle video capture, MiBeeNvr handles unified storage and management.&lt;/p&gt;

&lt;h3&gt;
  
  
  MiBeeCam — ESP32-S3-A10 Solution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Mi-Bee-Studio/luatos-esp32s3-a10-camera" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; · MIT License&lt;/p&gt;

&lt;p&gt;This is the most successful solution. ESP32-S3-A10 dev board + OV2640 camera (8225N module), 16MB Flash, ESP-IDF v5.4.3 development. Features include MJPEG stream, frame-differencing motion detection, Web config interface, Prometheus metrics. Having an LCD screen makes debugging much easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Thinker ESP32-CAM — Classic Solution
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Mi-Bee-Studio/ai-thinker-esp32-cam" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; · MIT License&lt;/p&gt;

&lt;p&gt;Entry-level choice, AI Thinker ESP32-CAM dev boards are widely available for around $10-15. 4MB Flash + 4MB PSRAM, runs MJPEG stream without issues. Highlights include SD card storage and NAS upload (WebDAV/HTTP), plus adaptive dark scene detection — automatically switches to infrared mode at night. Downside: no screen, 4MB Flash is limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  MiBeeHomeCam — XIAO ESP32-S3 Sense
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Mi-Bee-Studio/seeed-esp32s3-cam" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; · GPL v3.0&lt;/p&gt;

&lt;p&gt;The most advanced solution. XIAO ESP32-S3 Sense board is compact and refined, with dual camera support (OV2640/OV3660), 8MB Octal PSRAM. Highlights include AVI segmented recording (real video recording, not just snapshots), FTP/WebDAV dual-protocol upload, watchdog anti-freeze, chip temperature monitoring, batch file management. Suitable for long-term stable operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selection Guide
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Beginners&lt;/strong&gt;: Choose AI Thinker ESP32-CAM — cheap with plenty of resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily use&lt;/strong&gt;: Choose MiBeeCam — LCD screen makes debugging convenient&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maximum features&lt;/strong&gt;: Choose XIAO ESP32-S3 Sense — most powerful&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  System Service Configuration
&lt;/h2&gt;

&lt;p&gt;For stable operation, I use systemd to manage MiBeeNvr:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;MiBee NVR&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;
&lt;span class="py"&gt;Wants&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;nvr&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/mnt/data/nvr/bin/mibee-nvr -config /mnt/data/nvr/mibee-nvr.yaml&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/mnt/data/nvr&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;

&lt;span class="c"&gt;# Security hardening
&lt;/span&gt;&lt;span class="py"&gt;NoNewPrivileges&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;ProtectSystem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;strict&lt;/span&gt;
&lt;span class="py"&gt;ReadWritePaths&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/mnt/data/nvr&lt;/span&gt;
&lt;span class="py"&gt;PrivateTmp&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save to &lt;code&gt;/etc/systemd/system/mibee-nvr.service&lt;/code&gt;, then &lt;code&gt;systemctl enable --now mibee-nvr&lt;/code&gt;. Auto-start on boot, auto-restart on failure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open Source
&lt;/h2&gt;

&lt;p&gt;MiBeeNvr is open source, stars and contributions welcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MiBeeNvr&lt;/strong&gt;: &lt;a href="https://github.com/Mi-Bee-Studio/MiBeeNvr" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/MiBeeNvr&lt;/a&gt; (MIT License)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MiBeeCam&lt;/strong&gt;: &lt;a href="https://github.com/Mi-Bee-Studio/luatos-esp32s3-a10-camera" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/luatos-esp32s3-a10-camera&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Thinker ESP32-CAM&lt;/strong&gt;: &lt;a href="https://github.com/Mi-Bee-Studio/ai-thinker-esp32-cam" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/ai-thinker-esp32-cam&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MiBeeHomeCam&lt;/strong&gt;: &lt;a href="https://github.com/Mi-Bee-Studio/seeed-esp32s3-cam" rel="noopener noreferrer"&gt;https://github.com/Mi-Bee-Studio/seeed-esp32s3-cam&lt;/a&gt; (GPL v3.0)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Documentation is comprehensive, with detailed deployment and configuration instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing Thoughts
&lt;/h3&gt;

&lt;p&gt;To be honest, I built this project mainly because I was dissatisfied with all the existing solutions. Cloud storage is too expensive, open-source solutions are too heavy, and commercial products are too closed. Building my own was just right: lightweight, free, and fully under my control.&lt;/p&gt;

&lt;p&gt;Oh, about the name MiBeeNvr — "Mi" stands for me (Mickey), "Bee" stands for... let's keep that a secret, and "Nvr" is naturally Network Video Recorder. Simple, memorable, and a bit meaningful.&lt;/p&gt;

&lt;p&gt;If you also have home camera needs or ideas about NVR systems, feel free to reach out. Issues are welcome on GitHub.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://blog.mickeyzzc.tech/en/" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>github</category>
      <category>nvr</category>
      <category>camera</category>
    </item>
  </channel>
</rss>
