Design Pattern(?): Sensor Fusion Proxy Pattern

Note: First of all, when I put “Design Pattern(?):” at the beginning of a post, I’m putting it up for discussion. I’m only making suggestions here, not offering a complete solution.

Sensor Fusion Proxy Pattern

Background

There are officially no dedicated design patterns for sensor fusion or Kalman filters in openHAB. The existing design patterns in the openHAB community tend to focus on topics such as proxy items, group behaviors, expiration timers, and rule organization, but not on mathematical signal processing.

Why doesn’t this exist (yet)?

openHAB itself is primarily an integration and orchestration platform. It brings together numerous protocols/technologies (KNX, Zigbee, Z-Wave, MQTT, etc.) and enables automation.
Complex filtering or fusion algorithms are rarely built directly into it, as they typically run better in a dedicated computing environment (e.g., Python, Node-RED, InfluxDB with capacity queries, edge devices such as ESP32).

But: You can invent a design pattern for it

One could propose a “Sensor Fusion Proxy Pattern” for openHAB. Idea:

  1. Raw Sensors → Items with raw values ​​(e.g., temperature from multiple sensors).
  2. Pre-Processing → Small scripts/rules in openHAB or externally (Jython/JS scripting, Node-RED, MQTT broker, Python script with Kalman).
  3. Fusion Item (Proxy) → The result of the fusion (e.g., “Filtered_Temperature”) is written to a new item.
  4. Automations only use the proxy item, never the raw data.

This would be analogous to other patterns (such as the Proxy Item Pattern), except that the “proxy” here is a fusion/filter output.

Example of an implementation idea

  • Items: Temp_Sensor1, Temp_Sensor2, Temp_Fused
  • Rule (pseudocode in JS scripting):
var s1 = items.getNumber("Temp_Sensor1");
var s2 = items.getNumber("Temp_Sensor2");
var fused = (s1 + s2) / 2; // simple fusion
events.postUpdate("Temp_Fused", fused);
  • For more complex things (Kalman, Extended Kalman, Particle Filter):

  • Either a binding to an external process (Python script via MQTT or REST).

  • Or a rule script in GraalJS/Jython with a Kalman library.

Proposal for a new design pattern

“Sensor Fusion Proxy Pattern”

  • Motivation: Use of multiple uncertain sensors, smoothing/filtering of measured values.
  • Structure: Raw items → fusion rule → proxy item → automations.
  • Variant: Simple fusion (mean, median) vs. complex (Kalman, ML approaches).
  • Best practice: Outsource computationally intensive tasks, use a proxy only for integration.

Design Pattern: Sensor Fusion Proxy Pattern

Motivation / Problem

Many smart home sensors provide measurements that are noisy, inaccurate, or vary. To create reliable automations, this raw data must be filtered or merged. openHAB doesn’t offer special filters like Kalman out of the box, but sensor fusion can be implemented using rules or external services.

Goal:

  • Combine multiple raw sensors into a single, reliable value.
  • Automations only work with the filtered values.
  • Computationally intensive filters (e.g., Kalman) can be outsourced.

Solution / Pattern

“Sensor Fusion Proxy Pattern”

Structure:

  1. Raw Items: Represent the unprocessed sensor values.
Temp_Sensor1
Temp_Sensor2
Temp_Sensor3
  1. Fusion Rule / Script / Process: Calculates the filtered value from the raw sensors.
  2. Proxy Item: Stores the result of the fusion. Automations access this item exclusively.
Temp_Fused
  1. Automations / Visualization: Uses Temp_Fused instead of the raw sensors.

Implementation options

1. Internal openHAB DSL Rule

Simple mean approach:

rule "Fuse temperature sensors"
when
    Member of gTemperatureSensors changed
then
    var sum = 0.0
    var count = 0
    gTemperatureSensors.members.forEach[ sensor |
        val value = sensor.state as Number
        if(value != null) {
            sum += value.doubleValue
            count += 1
        }
    ]
    if(count > 0) {
        val fused = sum / count
        Temp_Fused.postUpdate(fused)
    }
end
  • gTemperatureSensors is a group of all raw sensor items.
  • Advantage: No external dependencies.
  • Disadvantage: No complex filters (Kalman).

2. Jython Scripting (Rule Engine)

For more flexible logic, e.g. E.g. moving average or Kalman filter integration:

from core.rules import rule
from core.triggers import when
from core.actions import ScriptExecution

last_value = None
alpha = 0.5  # einfacher Low-Pass Filter

@rule("Fuse temperature sensors Jython")
@when("Member of gTemperatureSensors changed")
def fuse_temperature(event):
    global last_value
    values = [item.state for item in gTemperatureSensors.members if item.state is not None]
    if values:
        avg = sum(values)/len(values)
        if last_value is None:
            filtered = avg
        else:
            filtered = alpha * avg + (1-alpha) * last_value
        last_value = filtered
        Temp_Fused.postUpdate(filtered)

3. JavaScript Scripting (GraalJS)

var members = gTemperatureSensors.members;
var sum = 0;
var count = 0;

for (var i = 0; i < members.length; i++) {
    var value = members[i].state;
    if (value != null) {
        sum += value;
        count += 1;
    }
}

if (count > 0) {
    var fused = sum / count;
    Temp_Fused.postUpdate(fused);
}

4. Node-RED

  • Node-RED can act as an external rule engine system.

  • openHAB Nodes:

    • events: state → Triggers when a sensor changes.
    • Function Node → Fusion/Filter:
    let values = [msg.payload.Temp_Sensor1, msg.payload.Temp_Sensor2];
    let fused = values.reduce((a,b) => a+b,0) / values.length;
    msg.payload = {Temp_Fused: fused};
    return msg;
    
    • openHAB out → Update Temp_Fused.
  • Advantage: Visual, external logic, easy use of complex filters.

5. MQTT + External Python Script with Kalman Filter

Setup:

  • Sensors publish their values ​​via MQTT:
    home/sensor/temperature1
    home/sensor/temperature2
    
  • openHAB subscribes to the filtered value:
    Temp_Fused -> MQTT Topic: home/sensor/temperature/fused
    
  • Python Kalman Script:
import paho.mqtt.client as mqtt
from filterpy.kalman import KalmanFilter
import numpy as np

kf = KalmanFilter(dim_x=1, dim_z=1)
kf.x = np.array([[20]])  # Initial
kf.P *= 1000
kf.F = np.array([[1]])
kf.H = np.array([[1]])
kf.R = 2
kf.Q = 0.1

def fuse(values):
    for v in values:
        kf.predict()
        kf.update(v)
    return kf.x[0,0]

def on_message(client, userdata, msg):
    payload = [float(x) for x in msg.payload.decode().split(',')]
    fused = fuse(payload)
    client.publish("home/sensor/temperature/fused", fused)

client = mqtt.Client()
client.on_message = on_message
client.connect("localhost",1883,60)
client.subscribe("home/sensor/temperature")
client.loop_forever()
  • openHAB receives the already filtered value via MQTT-Thing:
    Number Temp_Fused "Fused Temperature [%.1f °C]" {channel="mqtt:topic:broker:temp_fused"}
    

Best Practices

  1. Use proxy items: Automations never access raw sensors directly.
  2. Outsource computationally intensive filters: Node-RED or Python for Kalman/ML filters.
  3. Logging / Monitoring: Write fused values ​​to a persistent database (InfluxDB) to check filter quality.
  4. Fallbacks: If sensors fail, fusion should remain robust (e.g., median instead of mean).
  5. Documentation: Clearly name raw sensors, fusion algorithm, and proxy items, e.g., Temp_Sensor1Temp_Fused.

How does the Sensor Fusion Proxy Pattern differ from the Sensor Aggregation Pattern and Bayesian Sensor Aggregation?

My proposed “Sensor Fusion Proxy Pattern” with the two existing openHAB patterns:

Sensor Fusion Proxy Pattern vs. Sensor Aggregation

Feature Sensor Fusion Proxy Pattern Sensor Aggregation Pattern
Goal Merge multiple sensors into a filtered, stable value (e.g., mean, Kalman) Combine multiple sensors logically, e.g., OR, AND for presence or switch states
Type of processing Mathematical filters, statistical fusion, external algorithms if necessary Logical combination of sensor states
Complexity Medium to high, depending on filter/algorithm Low
Handling of uncertainty Considers sensor uncertainties, noise, and outliers No uncertainty handling, only binary or group-based
Examples Temperature fusion with Kalman, combined humidity or brightness values ​​ Motion detector: “If anyone reports → presence”

Conclusion:
My pattern extends the classic Sensor Aggregation pattern with filtering, smoothing, and uncertainty handling. While Sensor Aggregation simply aggregates, Sensor Fusion goes a step further: “How ​​can I intelligently merge the data, not just combine it?

Sensor Fusion Proxy Pattern vs. Bayesian Sensor Aggregation

Feature Sensor Fusion Proxy Pattern Bayesian Sensor Aggregation
Goal General sensor fusion: stabilization, smoothing, combined values ​​ Probabilistic evaluation of sensors to calculate probabilities for states
Type of processing Filter-based: mean, median, low-pass, Kalman, etc. Bayesian calculations, weighting of sensor probabilities
Complexity Medium to high (with Kalman) High (Bayesian logic, probability theory)
Handling of uncertainty Yes, via filters/statistics, but not probabilistic Yes, probabilistic; sensor reliability explicitly modeled
External processing Optional (Python, Node-RED, MQTT) Optional, usually Jython or external calculations required
Examples Filtered temperature or humidity Presence detection with probabilities from multiple sensors

Conclusion:
Bayesian Sensor Aggregation is more specific: It concerns the probability of a state based on uncertain sensors.
Sensor Fusion Proxy Pattern is more general: The goal is smoothing, filtering, and merging measured values. Bayesian Aggregation could even be considered a special variant of Sensor Fusion.

:light_bulb: Summary

  • Sensor Aggregation: Simple logical combination → no uncertainty handling.
  • Sensor Fusion Proxy Pattern (new): Mathematical fusion/filtering → stabilized values, outlier handling, smoothing.
  • Bayesian Sensor Aggregation: Probabilistic fusion → evaluates the probability of states, explicitly for uncertain sensors.

So: My pattern is a flexible “all-rounder” that can accommodate simple averages, Kalman filters, or even Bayesian logic. It’s less about the probability of a state and more about reliable, fused measurements that can be used by automation.

Comparison diagram

The diagram shows the Sensor Fusion Proxy Pattern, the Sensor Aggregation Pattern, and the Bayesian Aggregation Pattern side by side and visualizes the data flows – making the difference immediately visible.

Here’s the diagram showing the differences:

  • Left: Sensor Aggregation → simple logical connection.
  • Middle: Sensor Fusion Proxy Pattern → mathematical filtering/fusion, including Kalman.
  • Right: Bayesian Sensor Aggregation → probabilistic evaluation.
  • Bottom: All lead to a common proxy item that is used in automations.

Are you using this in practice? What sort of home automations are you solving with this pattern?

How do I know when it would be appropriate to use this over something simpler like a simple average over time?

A good design pattern provides now only what to do but how to identify when you have a problem that the design pattern is suited for. Most openHAB users don’t really even know what Baesian means, let alone have heard of a Kalhman filter. In a home auotmation context, often (but not always) simply rounding the number or taking a moving average is more than sufficient to smooth out the readings from a noisy sensor. So how do I know when I need something more?

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.