<?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: Suraj Raj Bhandari</title>
    <description>The latest articles on DEV Community by Suraj Raj Bhandari (@surajrb).</description>
    <link>https://dev.to/surajrb</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%2F4144114%2F4ea585c7-eec1-4496-84bc-9104b507d0fd.png</url>
      <title>DEV Community: Suraj Raj Bhandari</title>
      <link>https://dev.to/surajrb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/surajrb"/>
    <language>en</language>
    <item>
      <title>Okay, I've been sitting on this post for a while and I'm finally writing it. 😄</title>
      <dc:creator>Suraj Raj Bhandari</dc:creator>
      <pubDate>Sat, 26 Sep 2026 10:23:17 +0000</pubDate>
      <link>https://dev.to/surajrb/okay-ive-been-sitting-on-this-post-for-a-while-and-im-finally-writing-it-437f</link>
      <guid>https://dev.to/surajrb/okay-ive-been-sitting-on-this-post-for-a-while-and-im-finally-writing-it-437f</guid>
      <description>&lt;p&gt;For months now I've been working on &lt;strong&gt;OpenNVR&lt;/strong&gt;, an open-source NVR (network video recorder) for IP cameras. And the part I'm most excited about: you can literally ask your cameras questions, and the AI answering you runs on your own machine. Not some vendor's cloud. Yours.&lt;/p&gt;

&lt;p&gt;This is what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fatqdigu4tj8a9j9fhqfo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fatqdigu4tj8a9j9fhqfo.gif" alt="Asking the OpenNVR camera agent a question. It runs YOLOv8 on a live frame and answers locally" width="640" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time I see that work I still smile a little.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I care about this so much
&lt;/h2&gt;

&lt;p&gt;Think about how most cameras work today. You buy one, it connects to the manufacturer's cloud, and your footage goes... somewhere. They hold the keys. They run the AI. If they get breached, you get breached.&lt;/p&gt;

&lt;p&gt;And this isn't hypothetical. In 2016 the Mirai botnet took over hundreds of thousands of IP cameras and used them for one of the biggest DDoS attacks ever. In 2021 someone got into a camera vendor's cloud and could watch around 150,000 cameras, in hospitals, schools, prisons.&lt;/p&gt;

&lt;p&gt;That always bothered me. A camera in your house should work for you. So OpenNVR is built the other way round: your cameras, your hardware, your AI, and nothing leaves the box unless you decide it should.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it running
&lt;/h2&gt;

&lt;p&gt;I really wanted this to be easy, so it's two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/open-nvr/open-nvr.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;open-nvr
./start.sh          &lt;span class="c"&gt;# Windows: .\start.ps1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a small setup wizard. Every question already has a default, so honestly you can just keep pressing Enter. At the end it gives you a URL and a one-time token. Open it, set a password, add a camera, and in about 30 seconds you'll see detection boxes on your live feed.&lt;/p&gt;

&lt;p&gt;I'll be honest though: the first run takes 8 to 15 minutes because it's downloading Docker images. Go get a chai. ☕ After that it starts in seconds.&lt;/p&gt;

&lt;p&gt;Don't have an IP camera? No problem. The camera agent can use your laptop webcam, or you can install the OpenNVR Cam app on an old Android phone and it becomes a real ONVIF camera.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can talk to your cameras (my favourite part)
&lt;/h2&gt;

&lt;p&gt;This is the thing I show everyone first. There's a camera agent: a small local LLM (Ollama, &lt;code&gt;qwen2.5:1.5b&lt;/code&gt; by default) that can call vision tools on your live cameras. So you can ask things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Is anyone in the kitchen?" and it runs YOLOv8 on the current frame&lt;/li&gt;
&lt;li&gt;"What's at the back gate?" and it describes the scene&lt;/li&gt;
&lt;li&gt;"Did anyone walk past in the last ten minutes?" and it checks recent events&lt;/li&gt;
&lt;li&gt;"Did a red truck come by earlier?" and it searches the history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use it by voice (Whisper listens, Piper talks back) or just type with &lt;code&gt;--chat&lt;/code&gt;. Both run on a normal CPU. No API keys, no account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;examples/camera-agent/quickstart.sh &lt;span class="nt"&gt;--chat&lt;/span&gt;
&lt;span class="c"&gt;# then open http://localhost:9100/demo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;Some design decisions I'm really happy with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recording never depends on the AI.&lt;/strong&gt; Video gets recorded in one-minute chunks no matter what. If every model crashes, your footage is still there. This part has to be boring, and it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A cheap detector decides when the expensive stuff runs.&lt;/strong&gt; A small model watches a low frame rate copy of each stream. Only when it sees something interesting does it wake up the heavy models like face recognition or plate reading. That's how the whole thing fits on a mini PC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Models and rules are separate.&lt;/strong&gt; Models answer "what is this?". Apps answer "should I care?" (this zone, these hours, this plate list). So you can swap a model without rewriting your rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One place for history.&lt;/strong&gt; Everything worth remembering goes into one event store, so "was a red van here on Tuesday?" gives the same answer from the search page, the agent, or an app you install next month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plug in your own model
&lt;/h2&gt;

&lt;p&gt;This is the developer part I love. If your model sits behind a REST or WebSocket endpoint, it can plug into OpenNVR. A trimmed down version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opennvr_adapter_sdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AdapterApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AdapterService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BodyShape&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BODY_BYTES_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InferResponse&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDetector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AdapterService&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;  &lt;span class="c1"&gt;# load your weights
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;infer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;InferResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;frame_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BODY_BYTES_KEY&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# ... run your model ...
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;InferResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;detections&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]})&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AdapterApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;MyDetector&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-detector&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;me&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;license&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MIT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tasks_advertised&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object_detection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;body_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BodyShape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IMAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;fastapi_app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with &lt;code&gt;uvicorn&lt;/code&gt;, register the URL, done. The SDK is Apache-2.0, so your adapter can use whatever license you want. Full version is in the &lt;a href="https://github.com/open-nvr/ai-adapter/blob/main/opennvr_adapter_sdk/README.md" rel="noopener noreferrer"&gt;SDK README&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  An app store instead of YAML files
&lt;/h2&gt;

&lt;p&gt;Once it's running there's an App Catalog with thirteen one-click apps: number plate recognition, a doorbell that recognises faces, intrusion zones, loitering, people counting, line crossing, abandoned objects, package delivery, gate control, "find the red truck" footage search, alert routing, a Home Assistant bridge, and more.&lt;/p&gt;

&lt;p&gt;Each app has to say up front which cameras and network hosts it needs, and an admin approves that before install. No app can quietly get access it never asked for.&lt;/p&gt;

&lt;p&gt;Want to write your own? &lt;code&gt;pip install opennvr-app-sdk &amp;amp;&amp;amp; opennvr-app new my-app&lt;/code&gt; gives you a starter where you fill in one method: your rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Private by default
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloud access and AI calls to the internet are blocked (HTTP 403) until you explicitly turn them on.&lt;/li&gt;
&lt;li&gt;Camera passwords are encrypted at rest.&lt;/li&gt;
&lt;li&gt;Every AI decision is logged with an ID that traces the alert back to the exact model that made it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you like reading architecture papers, we wrote one: &lt;a href="https://doi.org/10.5281/zenodo.22804254" rel="noopener noreferrer"&gt;here it is&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hardware do you need?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Raspberry Pi 4/5 (4 GB):&lt;/strong&gt; recording, streaming, detection, zone and line apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mini PC / NUC (8 to 16 GB):&lt;/strong&gt; all of that plus plate and face recognition and the text agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Something with an NVIDIA GPU:&lt;/strong&gt; everything, including scene descriptions and the voice agent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I'd love your help
&lt;/h2&gt;

&lt;p&gt;We're still early, and honestly every bit of feedback helps a lot right now. If this sounds interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ &lt;a href="https://github.com/open-nvr/open-nvr" rel="noopener noreferrer"&gt;Star the repo on GitHub&lt;/a&gt;. It really helps other self-hosters find it.&lt;/li&gt;
&lt;li&gt;Try it on your own machine and &lt;a href="https://github.com/open-nvr/open-nvr/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; for anything that breaks or confuses you. I read all of them.&lt;/li&gt;
&lt;li&gt;Tell me in the comments: &lt;strong&gt;what would you ask your cameras?&lt;/strong&gt; I'm genuinely curious.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! 🙏&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/open-nvr/open-nvr" rel="noopener noreferrer"&gt;https://github.com/open-nvr/open-nvr&lt;/a&gt;&lt;br&gt;
Website: &lt;a href="https://opennvr.org" rel="noopener noreferrer"&gt;https://opennvr.org&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>security</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
