Sensor Calibration
Observium can automatically calculate and apply sensor alert thresholds based on observed operating data. Rather than relying on vendor defaults or manual guesswork, calibration analyses historical RRD data for each sensor and sets thresholds that reflect real-world behaviour, with a configurable safety margin.
Calibration can be scheduled automatically for eligible sensors, applied manually from the web UI, or run from the command line.
Subscription Feature
Sensor auto-calibration is included in the Subscription Edition of Observium.
How Thresholds Are Calculated
Calibration analyses the sensor's RRD data over a historical period (default: 7 days). Raw minimum, maximum, average, and standard deviation values are retained for diagnostics, but automatic threshold placement uses robust percentile baselines by default:
- Lower baseline: 1st percentile (
percentile_low) - Upper baseline: 99th percentile (
percentile_high)
Using percentiles prevents one isolated spike or corrupt sample from permanently widening the learned operating band. The configured margin is then placed outside those baselines:
| Threshold | Description |
|---|---|
| High Critical | upper_baseline + margin |
| High Warning | upper_baseline + margin/2 |
| Low Warning | lower_baseline - margin/2 |
| Low Critical | lower_baseline - margin |
Warning and critical values are rounded as an ordered pair. If rounding or a physical boundary leaves no room for both values on one side, that side is disabled instead of storing equal, reversed, or impossible thresholds.
Threshold Direction
Calibration can operate in one of three directions:
both: set both high and low thresholdshigh: set only high warning and high critical thresholdslow: set only low warning and low critical thresholds
If you do not explicitly choose a direction, Observium uses the default direction for the sensor class. For example, many classes such as temperature, current, power, load, and capacity default to high, while humidity, voltage, and fanspeed default to both, and runtime defaults to low.
This means that some sensors will not receive all four thresholds unless you explicitly override the direction in the UI or CLI.
Adaptive Margin
The margin is calculated per sensor class. For most classes it is the larger of two values:
- Range margin: a percentage of the observed operating range (
max - min) - Adaptive minimum: a percentage of the historical sensor magnitude, which prevents vanishingly small margins on very stable sensors
This ensures that a sensor with a 1 C variation over 7 days still gets a meaningful threshold gap, rather than thresholds separated by fractions of a degree.
Some sensor classes such as dbm, snr, attenuation, and sound use fixed absolute minimums instead, because percentage-of-value margins are not useful on logarithmic scales.
Thresholds are rounded before being written so that the stored values match the scale of the sensor.
Physical Bounds
Calibration will not create thresholds outside known physical ranges:
| Sensor class | Bounds |
|---|---|
temperature |
Low side cannot be below absolute zero (-273.15 C) |
fanspeed, frequency |
Low side cannot be below zero |
humidity, capacity, load |
Thresholds are limited to 0-100 |
Automatic calibration also rejects historical baselines outside these ranges. A baseline that touches a physical limit and leaves no warning/critical headroom is not applied automatically.
Automatic Calibration Scheduling
Auto-calibration scheduling is controlled by $config['sensors']['auto_calibration']['mode']:
none: disable automatic schedulingall: schedule all sensors whose classes are inauto_classesauto_only(default): schedule eligible sensors only when discovery identified their original thresholds as automatic or default
When auto-calibration scheduling is enabled, sensors are scheduled for calibration after a learning period (default: 7 days). The process is:
- Sensor is discovered and
auto_calibrate_afteris set tonow + learning_days - Each later discovery run checks whether the learning period has elapsed
- Once the date is reached, calibration runs during discovery
- On success, thresholds are applied and the sensor is marked as auto-calibrated
- Auto-calibrated thresholds are protected from later discovery updates
By default, only newly discovered sensors are enrolled. Set schedule_existing
to TRUE to enroll existing unscheduled sensors that still qualify. Jobs that
were already scheduled continue normally regardless of this setting.
When upgrading an installation with already-scheduled sensors, discovery records
whether each sensor's thresholds were automatic before auto_only permits the
pending calibration. Missing provenance fails safe until that discovery pass.
Note
Automatic calibration is skipped for ignored or deleted sensors, sensors with manual thresholds, classes not listed in auto_classes, and classes listed in skip_classes.
Each discovery process attempts at most max_per_discovery due calibrations
(default: 5), with no more than max_per_device attempts for one device
(default: 1). These bounds prevent a backlog from making discovery unbounded and
keep one device from consuming a larger process-wide budget. If calibration fails
transiently, Observium retries once per day up to max_retries times before giving
up. A log event is recorded when a sensor is abandoned.
Automatic Data-Quality Gates
Before an unattended threshold write, Observium requires:
- At least
min_coverageknown RRD data over the learning window (default: 80%) - Historical samples spanning at least
min_spanof that window (default: 80%) - A latest sample no older than
max_data_ageseconds (default: 1800) - A sensor that is enabled and currently in the
okstate - A non-zero usable baseline with valid physical values and threshold headroom
- A current value that remains inside the proposed threshold band
Failures are recorded as scheduler reasons and retried when transient. Class exclusions, manual thresholds, and auto_only ineligibility are permanent skips.
Manual Calibration via the Web UI
Single Sensor
For users with admin-level access, the current thresholds on sensor tables are clickable. Clicking the thresholds opens the calibration modal, which shows:
- Historical statistics for the selected period: minimum, maximum, average, and range
- A graph with current and proposed thresholds overlaid
- A threshold comparison table showing current, proposed, and delta values
- The calculated margin and how it was derived
You can preview the proposed thresholds before applying them. The preview displays data-quality warnings and validates threshold ordering. An invalid proposal has no Apply action; warnings that do not invalidate the thresholds remain advisory for manual calibration.
Applying calibration from the modal marks the sensor's thresholds as manual, which prevents future auto-calibration from changing them.
If the sensor already has custom or manual thresholds, the modal still opens and applying calibration replaces the current thresholds with the newly calculated values.
Bulk Calibration
The Calibration view, accessible from the sensor table navbar or the health page navbar, shows all sensors for a device or globally, with checkboxes for bulk selection.
From the calibration view you can:
- Select individual sensors using row checkboxes, use the table header checkbox for select all or none, or use Select Problems
- Choose the historical period to use: 7 days, 30 days, or 90 days
- Choose direction and margin preset for the preview and apply actions
- Click Preview Selected to open a preview modal showing proposed thresholds for all selected sensors, with per-sensor Apply buttons
- Click Apply Selected to apply calibration to all selected sensors with a progress indicator
Command Line Tool
The sensor-calibrate.php script provides preview and apply workflows suitable for scripting and scheduled tasks.
If -d is omitted, the script uses the default direction for the sensor class. Use -d both if you want to force both high and low thresholds for a class that normally calibrates only one side.
Examples:
Without -a, the script only previews proposed thresholds without modifying anything. This is safe to run at any time for review.
Applying with -a marks the thresholds as manual, just like applying from the web UI.
Configuration
All auto-calibration settings live under $config['sensors']['auto_calibration'] in config.php.
Global Settings
| Option | Default | Description |
|---|---|---|
mode |
'auto_only' |
Auto-calibration scheduler mode: none, all, auto_only |
learning_days |
7 |
Days to observe a new sensor before calibrating |
schedule_existing |
FALSE |
Enroll existing unscheduled sensors; opt in to avoid an upgrade backlog |
auto_classes |
['temperature', 'voltage', 'humidity', 'fanspeed', 'frequency', 'load'] |
Classes eligible for unattended calibration |
skip_classes |
['state'] |
Sensor classes to never auto-calibrate |
max_retries |
30 |
Maximum retry attempts before giving up on a failed calibration |
max_per_discovery |
5 |
Maximum due calibration attempts in one discovery process |
max_per_device |
1 |
Maximum due calibration attempts for one device in a discovery process |
analysis_width |
2500 |
Maximum RRD graph width used to bound analysis work |
percentile_low |
1 |
Percentile used for the robust lower baseline |
percentile_high |
99 |
Percentile used for the robust upper baseline |
min_coverage |
0.80 |
Minimum fraction of known RRD data required automatically |
min_span |
0.80 |
Minimum fraction of the learning window spanned by data |
max_data_age |
1800 |
Maximum age in seconds of the latest historical sample |
capacity is excluded from the default allowlist because the class represents
both increasing usage and remaining battery capacity, which require opposite
alarm directions. Add only definitions whose semantics you have verified.
Example: extend learning, opt existing sensors into a staged rollout, and skip humidity
Per-Class Threshold Settings
Margin behaviour is configured per sensor class. The following keys are supported:
| Key | Description |
|---|---|
margin |
Operating range multiplier for the critical threshold margin |
adaptive_min_percent |
Minimum margin as a percentage of current sensor value |
max_margin_ratio |
Cap margin at this multiple of sensor value |
fallback_min |
Absolute minimum margin |
min_high |
Fixed absolute minimum for high-threshold margins |
min_low |
Fixed absolute minimum for low-threshold margins |
Default per-class settings:
| Class | margin |
adaptive_min_percent |
Notes |
|---|---|---|---|
current |
20% | 5% | SI-range adaptive |
voltage |
20% | 5% | SI-range adaptive |
power / apower / rpower |
25% | 5% | SI-range adaptive |
frequency |
10% | 2% | Tight, mains frequency is usually very stable |
temperature |
50% | 5% | Wide range margin with 1 degree absolute fallback |
fanspeed |
30% | 3% | 100 RPM absolute fallback |
humidity / load / capacity |
15-20% | 3-5% | Percentage-based sensors |
dbm / snr / attenuation |
20% | - | Fixed absolute minimums |
wavelength |
10% | 1% | Very tight, wavelengths are stable |
default |
20% | 5% | Applied to unrecognised classes |
To override a class, add an entry to config.php:
| PHP | |
|---|---|
Threshold Protection and Recalibration
Calibration respects existing threshold state, but the protection rules are different for automatic and manual workflows:
- Auto-calibration skips sensors with manual or CLI calibration provenance, and legacy custom limits that have no automatic provenance
- Thresholds applied via the web UI modal are marked as manual and protected from future auto-calibration
- Thresholds applied via the CLI tool with
-aare also marked as manual - Thresholds applied by automatic background calibration are marked as auto-calibrated and protected from later discovery overwrites
- Each successful calibration records one audit event containing the method and old/new threshold values
- Manual recalibration from the web UI or CLI can replace existing thresholds, including thresholds that were already custom or manual
If you want a sensor to be eligible for automatic scheduling again, clear its manual protection or calibration state and let discovery schedule it again.
Troubleshooting
Sensor shows no proposed thresholds in the modal
The sensor has insufficient RRD data for the selected period, or its RRD file does not yet exist. Try a shorter period or wait for more polling data to accumulate.
Auto-calibration never fired for a new sensor
Check that $config['sensors']['auto_calibration']['mode'] is not 'none', the sensor class is present in auto_classes and absent from skip_classes, and discovery is running regularly. In auto_only mode, the sensor must also have been scheduled with discovery-provided automatic threshold provenance. Calibration is triggered during discovery, not polling.
Thresholds seem too wide or too narrow
Adjust the margin and adaptive_min_percent values for the relevant sensor class in config.php. Use a longer period such as -p 30d if you want the thresholds to reflect a broader operating history.
Auto-calibration was abandoned
The sensor failed calibration max_retries times. Common causes are a missing RRD file, insufficient coverage or span, stale data, an abnormal current state, invalid physical values, or a current reading outside the proposed band. Investigate with sensor-calibrate.php -s <id> -v.
Manual calibration from the web UI or CLI still works and applies thresholds immediately, but it does not reschedule the abandoned background job. If you want the scheduler to try again later, reset the sensor's calibration state and let discovery schedule it again after the underlying problem is fixed.