Bayesian Sensors in OH4

In this tutorial, I’m going to update for OH4 the system I introduced in OH3 for managing items which use Bayesian probabilities for determining a particular binary status.

You can find the components of the OH3 version here:

WARNING:

These rules and widget are no longer actively maintained. They will work for many OH3 versions and in some cases, the forum threads include suggestions for manually updating the individual components for later OH3 versions.


Credit:

This is an implementation of @cweitkamp’s awesome Bayesian aggregation design pattern. So, much of the credit goes to him and you will want to read through his post for a more detailed explanation of the underlying concepts and very clear description and example of probability selection.

WARNING:

There are breaking changes in the configuration from OH3 versions of this system. However, OH3 sensors will be automatically updated to the newer configuration the first time they are audited (see Auditing the sensor configuration below) or the first time the sensor is activated, so no action is required on the users part.

Introduction

Bayesian probability is a method of determining the likelihood of an event based on a prior understanding of how likely it is that different factors contribute to that event. This is useful in home automation because this enables the user to capture as an event or state more complex situations than basic binary sensors or probabilities.

As a basic example, consider an automation that changes the home from day mode to night mode. A basic home automation might just set night mode at 10PM. But sometimes I go to bed early and sometimes I stay up late, so that’s not very useful. I need the decision tree to include my behavior as well. So now the automation could look like:

when bedroom light is turned on then set night mode

It should be clear immediately why this is insufficient. If I get up early in the morning and it is still dark out, I will turn the bedroom light on, but it is not night time. That automation has to increase in complexity:

when bedroom light is turned on and after 6PM then set night mode

But, I often go into my bedroom to get something during the evening which requires me to turn on the light even if I am not getting ready for bed yet. This simple idea of the system in night mode or not can depend on an very large number of factors that may or may not come into play each night: time, status of motion, lights, and room presence in the house, weekend or weekday, guests in the house, is a movie playing on one of the TVs, is the front door locked, is the car in the garage…etc.

One solution is certainly to just continue to build out the automation decision tree to accommodate all the different possible combinations of inputs, but this grows roughly exponentially depending on the inputs. A Bayesian sensor provides a second possible solution to this where each of the possible inputs can be assigned a probability that it coincides with the desired event and the likelihood of the event is determined by the combination of each of those input states and their probabilities. When each of the contributing factors have been aggregated into a final probability, that probability can be compared to a threshold value to determine whether an event or state has been achieved. If it’s 10:15 PM on a weekday, and the kitchen light is off, even if I forgot to lock the front door, when I turn on the bedroom light there’s a 96% probability that it is night time and that’s higher than a 95% threshold so the automation system gets the event that nighttime has arrived.

Basic setup

This system requires two items for each Bayesian sensor, with the option for a third.

  • Group item (required) - sensor settings and group for all items to be included in probabilities
  • Proxy item (required) - (usually a Switch) Item to hold the final state of the decision (“Is the final probability greater than the threshold?”)
  • Posterior item (optional) - Number item to hold the most recently calculated probability (only included if you want to know the most recent calculated probability or persist and track the probability over time)

One rule is required to process the probabilities when item states change. Optionally, creating and configuring these items can be achieved through two UI interfaces that interact with an second rule. Each of these components can be installed directly from the marketplace, but there is a little additional configuration required:

Marketplace threads for the rules and widgets can be found here:

UI install and setup

Use the Add-on Store on your openHAB Administration to access the marketplace and install the requirements.

  • These rules require that the JSScripting add-on is installed. This add-on is found under AutomationLanguages & Technologies
  • The rules are found under AutomationRule Templates
  • The widgets are found under User InterfacesWidgets for the Main UI.

Rules

You will only need 1 copy of each rule.

  1. Bayesian sensor activation - Create a new rule using SettingsRules+ and select Bayesian sensor activation from the list under the Create from Template heading.
    • Give the rule any ID that you like.
    • Give the rule any Name that you like.
    • You can save the rule without a trigger for now. You will configure a trigger for this rule after you have created your first sensor.
  2. Bayesian sensor management - Create a new rule using SettingsRules+ and select Bayesian sensor management from the list under the Create from Template heading.
    • Give the rule an ID. It may be any ID that you like, but if you use the ID bayesian_widget_management then it will be automatically detected by the widgets. If you use a custom ID you will have to configure the widgets to use that custom ID.
    • Give the rule any Name that you like.
    • You do not have to configure anything else for this rule. It does not have a trigger it will only ever be called directly from the widgets.

The first time this rule runs it will create an item named Widget_Settings_Bayesian_Sensor_Details. This item allows the details widget to refresh when this rule is run. You do not ever have to interact with this item, and if it gets deleted it will just get recreated the next time this rule runs.

Widgets

Bayesian sensor details

This widget is designed to emulate the appearance of the standard OH MainUI configuration details pages. This means that it works best when added to a page by itself. For example:

config:
  label: Settings - Bayesian Sensor Details
blocks:
  - component: oh-block
    config: {}
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config: {}
                slots:
                  default:
                    - component: widget:jag_bayesian_sensor_details
                      config:
                        manageRule: custom_rule_name_here
                        sensor: =vars.bayesianItem || 'some_sensor_name'
grid: []
canvas: []

You may give this page any Page ID that you like, however the recommended ID is settings_bayesian_details. If you use this ID then then the sensor list widget will find it automatically and you do not need to configure that widget’s detailPage property.

Widget Configuration On Page
Parameter Required Explanation
sensor Yes This must be set to =vars.bayesianItem for the page to load the correct sensor item when opened. It will not show anything on the page if this is not set. The rest of the expression in the example above adds some_sensor_name if you want a default sensor to be shown (for example, on this page test viewer)
manageRule No Only set this configuration if you have given the bayesian sensor management rule an ID that is NOT bayesian_widget_management
useLabel No By default, the observatin list shows the labels of the observations item. Set this to false to display the item names instead

Bayesian sensor list

This widget is designed to emulate the appearance of the standard OH MainUI configuration list pages. This means that it works best when added to a page by itself. For example:

config:
  label: Settings - Bayesian Sensors
blocks:
  - component: oh-block
    config: {}
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config: {}
                slots:
                  default:
                    - component: widget:jag_bayesian_sensor_list
                      config:
                        manageRule: custom_rule_name_here
                        detailPage: custom_detail_page_id_here
grid: []
canvas: []

You may give this page any Page ID that you like.

Widget Configuration On Page
Parameter Required Explanation
detailPage No Only set this configuration if you have given the bayesian detail page an ID that is NOT bayesian_widget_management
manageRule No Only set this configuration if you have given the bayesian sensor management rule an ID that is NOT settings_bayesian_details

Each item in the list shows you the label and name of the sensor item. On the right side, the chip includes an icon indicating the result of the most recent configuration audit (see Auditing the sensor configuration below) the current calculated probability and the set threshold for that sensor. If the details widget has been configured and added to a page properly, then clicking on any item will open the details page for that particular sensor item.

Manual install and setup

If you do not wish to use the UI widgets for management of you bayesian sensors then you only need to install the activation rule as described above. You can create the sensor items manually either in the UI or .items files following the Configuration settings described below.

Creating Bayesian Sensors

Creation of bayesian sensors with basic settings and adding pre-existing items as simple observations can be handled entirely though the UI widgets. More advanced features can be set using the full metadata after initial creation.

Create a sensor

Open the sensors list page and click on the blue + icon in the lower right corner. This will give you two options:

  • Create New Group - Creates a group to be a bayesian sensor and initializes the basic metadata. Can also create associated items.
  • Create From Existing - Initializes the basic metadata for a group item that already exists. Does not create any other items.

For this tutorial, select Create New Group and a dialog will come up:

Field Required Default Explanation
Name Yes none This will be the name of the Group Item that holds the bayseian sensor configuration. There is no default for this value, you must provide a valid OH Item name.
Label No New Bayesian Group This will be the label of the group item itself
New Proxy Item No checked A proxy item is also required for the bayesian function so if the New Proxy Item option is selected this will create a Switch Item with the name {NameField}_Proxy at the same time the group is created.
New Posterior Item No unchecked A posterior item is not required for the bayesian function, but if you want to know the probability or track it over time select this to create a Number Item with the name {NameField}_Posterior at the same time the group is created.

When a new sensor is created in this manner, then in the sensor list you will see a new item that looks like:
new_sensor_list

Note that this indicates that no audit has been run on the new configuration (that must be done manually) and it currently has no calculated value (there’s nothing to calculate yet). But we can click on the item to open up its details page:

For this tutorial, proxy and posterior items were automatically generated and associated with the sensor. You can also see the default values that are assigned to various important configuration parameters. There are also no observation items included in this sensor yet, so before this sensor can work we must add some.

Add an observation

In order for an item to contribute as a valid observation for a sensor there must be information about that observation in the sensor’s metadata, and that item must be a member of the sensor group. You can, of course, do this manually but the widget also gives you a short cut for this.

Click on the Add Observation Item and it will turn into a simple input that allows you to type in the name of the item you wish to include in the sensor. This does not create a new item, you must supply the name of an item that already exists. Cancel the new observation with the X button or accept it with the check.

Accepting the new observation will update the metadata and add the item to the sensor group. This means that the new observation will now appear in the list of the sensor’s observations with some basic information available: The item label, the operation that tests whether the observation is true (e.g., eq for equality), the state that will result in a true observation, and what the item’s current value is.

To manage the observation, swipe to the right on the list item and you will see three buttons:

  • Delete - Removes this observation from the sensor (does not delete the item)
  • Edit - Opens a small observation editing form
  • Link - Opens the standard OH details page for the item

You can edit the test and true state settings, as well as the observation’s true and false probabilities. There are more advanced options for the observations as well, but these you will need to set by editing the metadata directly.

Auditing the sensor configuration

Due to the amount and complexity of possible configuration, the system offers a method to verify the accuracy of a sensor’s configuration by running a configuration audit. Press the Audit Configuration button at the bottom of the details page and many common errors with be checked for. The results of the Audit will display in the OH logs and on the sensor details page itself. For example, the proxy item must be configured using the proxy sensor propery and if it is not this results in an error, whereas the sensor’s state when true (the sensor’s probability has exceeded the threshhold) has a possible default value of ON and will only result in a warning if it is missing:

We can use the Edit Metadata to fix these two issues and the sensor will fully pass when the audit is run again:

Enabling a sensor

At this point, the sensor will still never calculate a probability and change it’s proxy item. For this final step we have to add the sensor as a trigger to the Bayesian sensor activation rule. The effect we want is for the sensor to be recalculated any time one of the observation items changes it’s state. Because all the observation items are members of the sensor group, this is easy to do.

Edit the rule and add an item trigger, selecting the sensor item itself and had a memeber change

At this point, your sensor should be fully functional. When one of the observation items changes the sensor’s probability will be recalculated, and the proxy item will change (or not) accordingly.

Configuration Reference

Main group configuration options

Each of the following options is set in the metadata config:

Config option Required Explanation
proxy yes The name of the item that will receive commands based on the result of the probability calculation
threshold yes Numerical value between 0 and 1 that defines the boundary between the sensor being probably true and probably false
trueState no The command to be sent to the proxy item when the calculated probability is greater than or equal to the threshold (default = ON)
falseState no The command to be sent to the proxy item when the calculated probability is less than the threshold (default = OFF)
prior no The initial likelihood that the sensor is in a true state (default = 0.5 )
posterior no The name of a item (type: Number:dimensionless) in which to store the calculated posterior probability of the sensor
obs yes Map of the individual items to be checked to compute the probability with the name of each item as a key (see Observation item configuration options below)

Audit

If you have used the widget and widget rule to check the metadata configuration then an audit property will also be found in the config metadata. You never have to add this property yourself it will be automatically generated. If the configuration contains no errors or warnings then the property will indicate that the configuration passed, otherwise it will show the errors and warnings. You can delete this key and its values if you wish without impacting the function of the Bayesian group, but the widget will not be able to show the results of the most recent audit if you do.

Observation item configuration options

For each item in the obs map the following options are available:

Sensors option Required Explanation
testState yes The state relevant for the check of whether the item represents a true or false observation: value type depends on testType
pTrue yes Numerical value from 0 to 1 representing the probability that the main condition is true if this observation is true
pFalse yes Numerical value from 0 to 1 representing the probability that the main condition is true if this observation is false
testType no Short code specifying the kind of test performed on the item state (default test is basic equality) see table below for full list of options
decay no Map of options detailing time-based decrease in pTrue value, see table below for full list of map values

If testType is not specified then a basic test of equality between the item state and testState is performed and the observation is true if the equality is true. Other tests are defined using the testType as follows:

testType value testState value Test performed
gt numerical value true if item state is greater than testState
lt numerical value true if item state is less then testState
bt two-element array of numerical values true if item state is greater than first array element and less than second array element
neq any valid state true if item state is not equal to testState
list array of any length and element type true if item state is equal to any element in testState

The decay property causes the probability if true value (pTrue) of an observation to decrease over time from some reference time. Usually this will be the last time the item was changed but could be from some absolute time of day or other time point. This requires that there be an additional Type:DateTime Item that holds the timestamp of interest (the timestamp profile being the most obvious way of creating this).

Decay configuration Required Explanation
decayStep yes Numerical value between 0 and 1 to reduce the pTrue value with each timeStep
timestamp no Item name of the DateTime item that holds timestamp value (default is sensor item name with ‘_TS’ appended to the end)
timeStep no Number of minutes between each decrement of the pTrue value (default = 5 minutes)
decayMin no Numerical value between 0 and 1 representing the minimum value that pTrue can be decreased to (default = 0.6)

Examples

Here is an example of a properly configured BayesianSensor metadata with some annotations to help understand.

value: " "
config:
  proxy: Occupancy_Kitchen
  trueState: ON
  falseState: OFF
  obs:
    Occupancy_Kitchen_Detection: #Item that indicates if the camera that sees kitchen area has detected a person
      pFalse: 0.2 #The camera also sees a few other areas such as the backyard through the back door
      pTrue: 0.9  #If a person has been detected by the camera it is very likely that there is a person in the kitchen
      testState: ON
    Speaker_Kitchen_Playing: #Switch indicating if sonos speaker is playing
      pFalse: 0.3 #Sometimes kitchen speaker is linked to other speakers in the house
      pTrue: 0.75 #Usually if the speaker in the kitchen is playing, someone is in the kitchen
      testState: ON
    Switch_BreakfastLight_OnOff: #Light over the table in the adjoining breakfast space
      pFalse: 0.4
      pTrue: 0.9
      testState: ON
      decay: #Kids have the tendency to leave the light on so over time this decreases the probability that this light correlates with someone in the kitchen area
        timestamp: Switch_BreakfastLight_OnOff_TS #Name of the DateTime item that holds the last changed timestamp for the light switch
        timeStep: 5 #Decrease every five minutes
        decayStep: 0.05 #Decrease probability by 5%
        decayMin: 0.4 #If the light has been on long enough it hits a minimum equal to `pFalse` which means this observation has no impact on the final probability
    Switch_KitchenLight_OnOff:
      pFalse: 0.3
      pTrue: 0.9
      testState: ON
      decay:
        timestamp: Switch_KitchenLight_OnOff_TS
        timeStep: 5
        decayStep: 0.05
        decayMin: 0.4
    AutomationTime: #My system's time of day item
      testType: list #Check if the item state is equal to any of the elements in the given array
      pFalse: 0.1
      pTrue: 0.5
      testState: #Array of times of day we are likely to be in the kitchen (rarely is someone in the kitchen after bedtime or before the start of the morning
        - MORNING
        - AFTERNOON
        - EVENING
  prior: 0.3 #Baseline probability that someone is in the kitchen at any one time (my wife likes to cook a lot so someone is in the kitchen often)
  audit: #This metadata has been checked by the widget rule
    passed: true #The metadata is properly formatted
  posterior: Occupancy_Kitchen_Posterior #Each time a new probability is calculated it is stored in this item
  threshold: 0.95 #A high level of certainty (95% certain) is required to set the kitchen occupancy to ON

This next example is for a switch that triggers my time of day item to change over from WAKE_UP to MORNING. Over the years this has proven to be a very difficult task for the system to work out because of so many different possibilities between me, my wife, kids, weekdays and weekends, but this Bayesian group sensor is exceptionally accurate, even with only simple equality tests for all the different sensor observations.

value: " "
config:
  proxy: AutomationTime_Morning_Start
  obs:
    AutomationTime:
      pFalse: 0.3
      pTrue: 0.99
      testState: WAKE_UP
    Phone_JustinsCell_ChargingState:
      pFalse: 0.5
      pTrue: 0.75
      testState: OFF
    Sensor_MasterBath_Motion:
      pFalse: 0.5
      pTrue: 0.9
      testState: ON
    Sensor_MasterCloset_Motion:
      pFalse: 0.5
      pTrue: 0.8
      testState: ON
    Switch_MasterBedroomFan_OnOff:
      pFalse: 0.5
      pTrue: 0.9
      testState: OFF
  prior: 0.5
  audit:  #This metadata has been checked by the widget rule
    warnings: #Two warnings have cropped up with this configuration for values that I have not specified and so are falling back to the default values instead.
      number: 2
      list:
        "0": trueState not set - default ON will be used
        "1": falseState not set - default OFF will be used
  posterior: AutomationTime_Morning_Start_Posterior
  threshold: 0.9
7 Likes