DEV Community

Cover image for MiBeeBell: one quiet alert feed for a self-hosted camera-and-network stack, with optional AI triage
ZhengZhiCong
ZhengZhiCong

Posted on Edited on AI-assisted

MiBeeBell: one quiet alert feed for a self-hosted camera-and-network stack, with optional AI triage

I maintain a small set of self-hosted tools under the MiBeeStudio name. The newest is MiBeeBell (蜂铃), a closed-source alert hub. This post is about it, but I am writing it as the middle of a stack rather than a standalone product: MiBeeNvr v0.14.1 records my cameras, MiBeeSteward v0.8.0 keeps an inventory of every device on the network, and Bell is the layer that decides what actually reaches my phone.

If you self-host more than one thing, you already know the problem Bell solves. The rest of this post covers what Bell does, why I built the compatibility the way I did, the AI part, how the two other projects feed it, and where it sits next to Alertmanager, PagerDuty, and friends.

The problem Bell sits in the middle of

A camera drops off the network and reconnects. Your NVR sees it go offline, come back, go offline again. A switch reboots and eight cameras blink out at once. Meanwhile your network scanner notices a certificate on the router is fifteen days from expiry, a new device joined the LAN, and an external probe to an upstream DNS started failing.

Each of those is a real event. In raw form they arrive as a flood: dozens of near-identical pings, no recovery notice when things settle, and no hint that the eight offline cameras share one cause. Bell does not monitor anything itself. It receives alerts that other systems already produced, converges them, and sends one useful message per situation to the channels you actually read.

What Bell is

Bell is a single binary with an embedded web UI and a local SQLite database. Credentials are encrypted at rest with AES-256-GCM. There is no cloud account and no operational dependency on me or any service. On my box it sits at roughly 15 to 21 MB of resident memory and runs on hardware with 512 MB to spare.

The core job is convergence:

  • Deduplication and aggregation: events sharing a key within a 60-second window collapse into one, with a count.
  • Similarity aggregation: thirty messages in thirty seconds from one source become one.
  • Cooldown: repeated recurrences are throttled (default five minutes), and the state survives restarts.
  • Silence: absolute and daily-period windows, including cross-midnight schedules; recovery events still get through.
  • Escalation: an error unresolved for fifteen minutes is promoted to critical and pushed to an extra channel.
  • Common-cause merging and dependency suppression: the eight-cameras-at-once case collapses to one story.

Two to five nodes can run as a full mesh; if one fails the others take over dispatch. That matters more for an always-on notification path than it first sounds.

Compatibility is the point

I did not want Bell to care who produced an alert. So the ingest side speaks the dialects that existing tooling already emits. Seven ingest types:

  • Generic webhook
  • Alertmanager-compatible
  • PagerDuty Events v2-compatible
  • Grafana native
  • Simple JSON (the ntfy / Gotify shape)
  • Bark-compatible
  • MQTT

That list is the real product. It means Bell drops in front of Prometheus, Grafana, Home Assistant, a DIY script, an IoT broker, or any app that can POST a webhook, without an adapter per source. On the way out it supports around seventeen channels, including the three Chinese IM platforms (Feishu, WeCom, DingTalk) as native first-class targets, plus Telegram, Slack, Discord, email, ntfy, Bark, Pushover, SMS, and more. Retries, rate limiting, delivery auditing, and a degraded state are built in.

The honest framing: Apprise and shoutrrr are delivery libraries. Bell is the orchestration layer in front of them. It is not a channel; it is what decides whether a channel gets bothered.

The AI part, and why it is small on purpose

Alerting has one rule I refuse to break: the model must never decide whether you get woken up. A wrong "don't bother" silently drops a real incident. So in Bell, AI only annotates. The event still flows through the rule layer and out to your channels exactly as before. If the AI stack dies entirely, you lose the enhancement, not the alert.

The analyzer has two tiers, each independently switchable:

  • Local tier: a small distilled model compiled into the binary. No network, no cost, microsecond-level latency, and it does not count against the cloud budget. It covers the repetitive, obviously-classifiable events.
  • Cloud tier: an OpenAI-compatible endpoint you configure yourself (I run OpenRouter with a DeepSeek model; any compatible endpoint works). Stronger reasoning for the cases the local model is unsure about.

One thing to state plainly: the cloud tier sends alert content to the model provider. If that bothers you, run local-only or turn both off. The system was designed so either choice is fine.

When enabled, the model adds four kinds of annotation:

  1. Triage against criteria you write, gated by a confidence threshold (below about 70 percent it stays quiet).
  2. Severity downgrade suggestions, and only downgrade, never up. A wrong call can soften a label but can never invent an urgent page.
  3. A human-readable summary of the raw fields, shown in the notification ahead of the template text.
  4. Tags and grouping hints that help the dedup layer do its job.

Resilience around the AI is deliberate. There is a circuit breaker: when the cloud endpoint fails repeatedly (I have watched an OpenRouter DNS timeout flip the analyzer red, then heal itself), it stops calling the cloud and the local tier keeps running. A daily budget caps cloud calls (about a hundred per day by default); past that, only the local tier is used. Repeated events within ten minutes reuse the prior result instead of calling again. And when the analyzer itself degrades or the budget is spent, Bell emits its own alert through the normal path. Status is visible in the UI: the AI node on the data-flow diagram turns red on degradation.

By default all of this is off.

How the rest of the stack feeds it

Bell is useful alone, but the reason I built it is that my other two projects each produce alerts and neither was a good place to manage them.

MiBeeNvr v0.14.1, the cameras

NVR records RTSP, ONVIF (with LAN auto-discovery and plug-and-play enrollment), HTTP-JPEG, Xiaomi cameras, GB/T 28181, and push-in streams (WHIP, RTMP, SRT), plus SIP doorbells. It does live view over WebRTC, HLS, and HTTP-FLV; thermal cameras render as a heat-map with temperature readouts; recording covers MP4 segments, per-camera retention, timelapse (including dynamic capture as footage arrives), multiple storage partitions, and network audio pickups. Object detection runs entirely in the browser via ONNX Runtime Web and WebGPU, so the inference decision never leaves the tab.

v0.14.1 is a compatibility and fix release on top of that: it unblocks old-firmware ONVIF cameras that choked on the auth handshake or reported stale endpoints, fixes GB/T 28181-2011 legacy devices, adds native and Docker fnOS packages, and brings Opus audio on RTSP plus AAC audio on HTTP-FLV. The bit that matters for Bell is the external alert webhook (HMAC-signed, off by default) that forwards NVR events to any HTTP endpoint. A camera going offline, a recording failure, disk pressure, a doorbell call, these now have a destination. NVR can also run with Prometheus and Alertmanager, which Bell ingests natively.

MiBeeSteward v0.8.0, the network and devices

Steward discovers and fingerprints everything on the network (active scans plus router-resident passive sources), builds an inventory with change history, draws L2 topology, tracks TLS certificate chains, and runs synthetic probes. v0.8.0 extended the probe subsystem, added public-egress quality assessment, shipped a Rust agent, and produced native deb/rpm packages.

For alerting, Steward already exposes /metrics for Prometheus and ships a sample Alertmanager configuration and alert rules, plus its own notifier (webhook, email, Feishu, WeCom, Telegram, Discord). The catch: that notifier has no silencing, no routing tree, no dedup. It is fine for "tell me something changed," weak for "tell me the right thing once." Bell is the layer that adds the discipline. Steward's metrics and alert rules point at Bell's Alertmanager-compatible ingest, and its webhook goes to Bell's generic ingest.

What you actually get by combining them

Picture a small outage. A switch loses power. MiBeeNvr sees eight cameras drop; MiBeeSteward sees the same eight devices vanish from the network and a probe to an upstream fail. Raw, that is a wall of notifications.

Through Bell: the eight camera-offline events share one switch and merge into a single message; the device-lost events from Steward align with the same incident; the local or cloud analyzer can label it "common cause: upstream power or network," and the recovery, when it comes, is one line instead of eight. You get woken once, with context, not eight times with noise.

That is the combined capability: cameras, network, and devices all funnel into one local-first, Chinese-IM-native, optionally-AI-triaged feed that knows when to stay quiet. No cloud, no per-seat fee, no spinning up a separate on-call product for a home or small-office setup.

Where Bell sits next to the rest

I mapped Bell against roughly forty tools across five layers: pure delivery, routing and aggregation, on-call and incident, full-stack monitoring, and the homelab and domestic ecosystem. A compact view:

Dimension MiBeeBell Alertmanager PagerDuty Apprise
Self-hosted and free yes yes no yes
Open source no (closed) yes no yes
Native Chinese IM (Feishu, WeCom, DingTalk) yes partial (WeCom only) no yes
Dedup, cooldown, silence, escalate yes yes yes no
On-call scheduling no no yes no
AI annotation (off by default) yes no yes no
Data stays local yes yes no yes
Multi-node HA (mesh) yes yes (gossip) cloud no

The honest placement:

  • Versus Alertmanager: the real overlap. Alertmanager is the standard, free, open source. Its Chinese-channel support is thin (WeCom native, the others need hand-built webhooks). Bell's edge is the out-of-the-box three IM platforms, the optional AI annotation, and mesh HA. If you already run a polished Alertmanager with webhooks wired, Bell is a convenience, not a replacement.
  • Versus PagerDuty and Opsgenie: self-hosted, free, Chinese-native, data-local. Those are SaaS with per-seat pricing and data off your hardware. Bell does not try to replace their on-call scheduling and incident timelines; it is a complement for teams that do not need that whole machinery.
  • Versus Apprise and shoutrrr: those are delivery channels. Bell sits in front and decides what they carry.
  • Versus monitoring stacks (Uptime Kuma, Zabbix, Grafana, Prometheus): upstream. They produce the alerts; Bell converges and dispatches them. Several already reach Chinese IM through webhooks; Bell's value is unifying many sources locally with one convergence and annotation layer.

The gap Bell occupies: self-hosted, local-first, Chinese three-piece out of the box, optional AI off by default, single-file with zero external dependencies. Within that intersection I found no directly equivalent tool. On raw feature depth it is behind Alertmanager for routing sophistication and behind PagerDuty for full incident management.

Honest limits

  • Closed source. I currently have no plan to compete with the alerting industry, so Bell ships as a binary, not a repo. The trade is the usual one: you cannot audit the code, though your data stays on your hardware and there is no cloud dependency. Binaries and docs live in a public release repo; checksums and clear licensing are things I am tightening up.
  • First release is fnOS only. v0.1.0 ships as a FlyNAS (fnOS) package (ARM64 and amd64). Linux, Windows, and Docker forms are described but not yet published as artifacts. Do not expect a one-line install elsewhere yet.
  • Bell produces no metrics of its own. It depends on upstreams like NVR and Steward. Stand it up alone and there is nothing to alert on.
  • No on-call scheduling or incident timelines. If you need rotation, escalation chains with people, and post-mortems, look at Grafana OnCall or PagerDuty; Bell is the quieter front end, not the whole pager.
  • Cloud AI sends content out. Stated above; local-only or off is a first-class option.

Where to look

If you run a similar stack and Bell's convergence logic misses a case, that is exactly the kind of report I want. The whole point is fewer, better notifications.

Top comments (0)