01 · Ingest
Talk to every PLC you already own.
Five native protocol drivers run in their own worker processes — a misbehaving driver can never bring the others down. Per-device poll rates, an in-app Test Connection button, and an OPC UA browser that bulk-imports the address space.
- Modbus TCP — host, port, unit ID, custom byte order, address offset.
int16/uint16/int32/uint32/float/bool plus per-tag bit extraction from packed registers. Optional keep-alive heartbeat reaches 100% reliability against Siemens S7-1200 at 1 s polling.
- OPC UA — polling and Subscriptions (push value-changes only, sub-second latency). Browse the namespace from the configuration UI, see the live current value alongside each node, bulk-add the ones you want. Namespaces 0 and 1 visible for diagnostics. Tested against S7-1200: 352 variables imported in 30 s.
- IEC 60870-5-104 — for RTU and electrical-substation gear. CP56Time2a timestamps preserved end-to-end. Buffered-event replay on reconnect. Per-device IANA timezone configurable for RTUs that send naive timestamps.
- MQTT with Sparkplug B — hand-rolled decoder, longest-prefix topic routing, alias-state tracking. New MQTT Brokers tab in System Configurations. Production deployments can use the bundled Mosquitto broker or point at an existing one.
- CSV folder watching — still the simplest path. Drop a file in
raw_data/<device>/ (or a per-device custom path), the watchdog ingests it idempotently. CSV-file retention policy auto-deletes old source files while keeping the audit-trail row.
- Self-healing workers — the OPC UA and Modbus pollers cleanly drop a stale TCP session if a poll is cancelled mid-call, then reconnect on the next cycle. Exponential backoff per device (5 s → 5 min cap) on persistent errors, with quarantine logging after 10 failures. Cable-yank end-to-end recovery in 14 s on OPC UA.
- One worker per protocol — Windows services
SyncTideModbus, SyncTideOPCUA, SyncTideIEC104, SyncTideMQTT plus the CSV ingester. Independent logs, independent restarts.
- Seconds-resolution comm timeout — devices.comm_timeout_seconds is configurable down to 5 s, based on the most recent measurement timestamp the device reported (not on polling attempts). Suitable for sub-second OPC UA subscriptions.
02 · Alarm
Catch the bad shift before it ends.
A single tag can carry up to four simultaneous rules with hysteresis and severity. Cross-device site KPIs alarm just like device tags. Operating curves catch process drift the obvious thresholds miss.
- Multiple rules per tag — up to 4 simultaneous (HiHi / Hi / Lo / LoLo). Each has its own threshold, hysteresis band, severity (info / warning / critical) and friendly name. Hysteresis stops chatter on noisy signals: once raised, an alarm stays raised until the value crosses the threshold ± hysteresis in the clear direction.
- Alarm types — threshold (any of
> < ≥ ≤ = ≠), digital (bit transitions), totalizer (over a sliding window), virtual-tag derived, and communication-loss. All organised in a hierarchical category tree.
- Operating curves — X-vs-Y alarm rules with a tolerance band. Reusable curve templates propagate edits across many devices; the Dashboard Curves view colours measured points by whether they fall inside or outside the envelope. Either axis can be a device tag or a cross-device site KPI.
- Site KPIs (cross-device virtual tags) — formulas that aggregate or compare measurements across multiple devices using
${DeviceCode:TagName} references. Three alarm modes: Value, Δ Deviation %, Out of Band. Optional target value + tolerance band drives 🟢/🟡/🔴 status colouring.
- Real-time evaluator — the alarm watchdog runs on a 5-second tick. Streak detection flips device status to Error after 3 consecutive failed polls, regardless of the rolling 20-poll success rate. Detect-to-enqueue latency in production is single-digit seconds.
- Acknowledgement attribution — alarm history records who closed each event and how:
Platform: Administrator, Telegram: Tiago G., SMS: +351 912 345 678, or Token: <contact> (email magic-link ack).
03 · Notify
Four channels, one escalation engine.
Operators acknowledge alarms by replying on the same chat — no token typing, no separate app, no portal to log into. Escalation chains cascade through parent groups with cooldowns and exponential backoff.
- SMS — over a local Teltonika RUT241 4G router (no monthly per-SMS fees) or via Twilio. Inbound replies handled by webhook. The on-prem path keeps SMS working when the corporate internet is down.
- WhatsApp — via Twilio, or directly through Meta WhatsApp Cloud (Meta's free tier covers the first 1 000 service conversations a month).
- Telegram — outbound from a bot you create in BotFather; inbound replies handled by a dedicated long-polling worker. Operators reply with "ack", "ok", "sim", "confirmo", ✅ or 👍 — or just swipe-reply on the original message — and the alarm closes.
- Email — any SMTP server (Gmail, Outlook, on-prem). Operators ack via a one-click magic-link.
- Escalation chains — contact lists cascade through parent groups. Retries on no-reply with exponential backoff. Per-rule cooldown (default 30 min, configurable down to zero for every-alarm-sends-fresh).
- Test send — every gateway has a per-channel validation that catches the "typed a phone number in the chat-ID field" mistake before submission. Inline tooltips with concrete setup steps for BotFather, Twilio Console, Meta Developer, and common SMTP providers.
- Hand-it-to-operators docs — separate Telegram setup guides for administrators and end users.
04 · Visualise
Dashboards that match the team you have.
Per-user Home layouts, geo-aware maps, trend explorer, live site-flow diagrams. Operators on phones and laptops open http://<host>.local on the LAN — no IT setup, no per-device hosts files.
- Customisable Home page — each user picks which widgets show, where, and at what refresh rate. Catalogue: KPI cards, site alarm panel, asset tree, geo map, fleet health banner, ranking chart, recent events feed, trend chart, calendar heatmap, alarm summary, and the site flow diagram. Admins can save an org-wide default.
- Site flow diagram — Graphviz topology of the device-relationships you configure, status-coloured nodes (green / gray / red) and edges with live tag values (e.g.
120 m³/h instead of Flow (m³/h)).
- Trend explorer — per-device, per-tag, per-time-bucket. Pick the metric (Avg / Min / Max / Last / Difference) per tag type. Real-time refreshing fragments at 5 s / 10 s.
- Geo dashboards — interactive Folium maps with per-device status, clustering, category filtering. CARTO tiles by default; Mapbox satellite via your own key.
- Operating-curve view — scatter of measured points overlaid on the configured envelope, colour-coded for in/out-of-band.
- Real-time tag view per device — latest value per tag with freshness badge and 5 s auto-refresh.
- Local-time UI — every operator-visible timestamp renders in the operator's local zone (driven by
TZ on Linux, system zone on Windows). The database still stores UTC.
- LAN access without setup — bundled Caddy reverse proxy serves the platform at
http://<hostname>.local on port 80 (or 8080 if 80 is taken). Firewall rule auto-added at install, removed cleanly on uninstall.
05 · Report
The Monday-morning printouts, on autopilot.
Template-driven PDF and Excel generation, scheduled or one-shot. Per-customer branding. Per-user device scoping ensures contractors see only their own equipment.
- PDF + Excel — LibreOffice-backed template engine. Drop your
.xlsx or .docx template, define placeholders, the engine fills them in.
- Schedules — hourly, daily, weekly, monthly. Per-template recipient list with email delivery.
- Configurable metrics — pick Avg / Min / Max / Last / Difference per tag type, with bucket selector. Totalizer tags get a bar chart by default.
- Per-user scoping — every report endpoint and download is filtered through the requesting user's allowed device list.
- Report history with full audit trail — who scheduled, who downloaded, what time window.
- CSV export — for the spreadsheet-first team. Configurable column layout and date format.
06 · Store
Time-series at industrial scale.
PostgreSQL 17 plus TimescaleDB — both bundled in the installer, both already configured. The measurements table becomes a hypertable on first migration, chunks older than 7 days auto-compress, retention runs nightly.
- TimescaleDB hypertable on
measurements — 1-day chunks. Compression policy kicks in at 7 days, typically 90–95% disk reduction on industrial signals.
- BRIN index on
time_stamp — ~1000× smaller than B-tree on append-only data, equivalent range-scan performance.
- Per-table autovacuum tuning on the hot tables (
measurements, alarm_events, messaging_history).
- Data Retention engine — three sliders in System Configurations (raw measurements / alarm history / messaging history) plus an opt-in CSV-file sweep. Nightly run at 03:00 local. Uses
drop_chunks on TimescaleDB, plain DELETE without.
- Backups — Windows: scheduled task. Linux/Docker:
backup_cloud.sh with off-host upload hooks. Both produce one self-contained file per night.
- Report-by-exception universal toggle (per protocol) — skip DB writes for unchanged values, with optional periodic heartbeat for flat-line tags. Cuts redundant writes by 50–95% on stable sites.
07 · Deploy
Your hardware. Your rules.
No outbound calls. No telemetry. No licence phone-home. Air-gapped deployments are the default, not a configuration option you have to discover.
- Single signed Windows installer — bundles PostgreSQL 17, TimescaleDB 2.26.4, all five protocol workers, FastAPI backend, Streamlit UI, alarm watchdog, messaging scheduler, the Caddy reverse proxy, and a Windows Firewall rule. Nine NSSM-managed services. Fresh install on a clean Windows 10 VM is end-to-end automatic.
- Linux Docker stack — same source tree, multi-stage Dockerfile, full
docker-compose.yml plus a production override with TLS and auth, bundled Mosquitto broker, off-host backup script, runbook in OPERATIONS.md.
- In-place upgrades — Inno Setup detects existing installs by stable AppId and skips PostgreSQL, LibreOffice, admin account and licence wizards. Customer credentials never stomped. Services stopped before file copy; integrity manifest and DB preserved. Delta packages produced from every prior shipped version.
- Ed25519-signed everything — release packages, update packages, licence files. Split signing keys for licences vs updates. Integrity manifest per release.
- Hardening defaults — default-password detection forces rotate on first login, rate limiting on
/auth/login and webhook endpoints, per-user device scoping on every data endpoint, installer-level ACLs lock down .env + license.lic + integrity_manifest.json, webhook HMAC verification, interactive API docs disabled in production.
- Self-validating extension install — the installer probes Postgres after the preload-conf change. If the TimescaleDB DLL doesn't load (some Windows ABI edge cases), it auto-reverts and continues on plain Postgres. The customer never ends up with a stuck install.
- Service-registration recovery — handles the flaky EnterpriseDB exit-1-on-success quirk by registering the postgresql-17 service via
pg_ctl if the installer skipped it.
08 · Licence
Buy it the way you buy CapEx.
Two commercial models — annual subscription that includes updates, or perpetual licence you own outright with optional maintenance. Six tiers priced by tag count, plus optional Messaging and Reports modules. Full pricing on the pricing page.
- Subscription — annual fee, all updates + technical support included. Ingestion and messaging stop if the subscription lapses; the UI stays readable.
- Perpetual — one-time fee, runs forever on your hardware regardless of maintenance status. Add annual maintenance to keep receiving updates.
- Tiers — Starter (50 tags) → Standard (250) → Professional (500) → Enterprise (1 000) → Industrial (2 500) → Unlimited.
- Optional modules — Messaging (the 4-channel engine) and Reports (PDF/Excel) bolt onto any tier. Base licence always covers dashboards + alarms + equipment configuration.
- 30-day trial keys — signed
.lic files issued on request. No credit card.