ESPHome 2025.5.2
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
binary_sensor_map.cpp
Go to the documentation of this file.
1#include "binary_sensor_map.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace binary_sensor_map {
6
7static const char *const TAG = "binary_sensor_map";
8
9void BinarySensorMap::dump_config() { LOG_SENSOR(" ", "binary_sensor_map", this); }
10
12 switch (this->sensor_type_) {
14 this->process_group_();
15 break;
17 this->process_sum_();
18 break;
20 this->process_bayesian_();
21 break;
22 }
23}
24
26 float total_current_value = 0.0;
27 uint8_t num_active_sensors = 0;
28 uint64_t mask = 0x00;
29
30 // - check all binary_sensors for its state
31 // - if active, add its value to total_current_value.
32 // - creates a bitmask for the binary_sensor states on all channels
33 for (size_t i = 0; i < this->channels_.size(); i++) {
34 auto bs = this->channels_[i];
35 if (bs.binary_sensor->state) {
36 num_active_sensors++;
37 total_current_value += bs.parameters.sensor_value;
38 mask |= 1ULL << i;
39 }
40 }
41
42 // potentially update state only if a binary_sensor is active
43 if (mask != 0ULL) {
44 // publish the average if the bitmask has changed
45 if (this->last_mask_ != mask) {
46 float publish_value = total_current_value / num_active_sensors;
47 this->publish_state(publish_value);
48 }
49 } else if (this->last_mask_ != 0ULL) {
50 // no buttons are pressed and the states have changed since last run, so publish NAN
51 ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
52 this->publish_state(NAN);
53 }
54
55 this->last_mask_ = mask;
56}
57
59 float total_current_value = 0.0;
60 uint64_t mask = 0x00;
61
62 // - check all binary_sensor states
63 // - if active, add its value to total_current_value
64 // - creates a bitmask for the binary_sensor states on all channels
65 for (size_t i = 0; i < this->channels_.size(); i++) {
66 auto bs = this->channels_[i];
67 if (bs.binary_sensor->state) {
68 total_current_value += bs.parameters.sensor_value;
69 mask |= 1ULL << i;
70 }
71 }
72
73 // update state only if any binary_sensor states have changed or if no state has ever been sent on boot
74 if ((this->last_mask_ != mask) || (!this->has_state())) {
75 this->publish_state(total_current_value);
76 }
77
78 this->last_mask_ = mask;
79}
80
82 float posterior_probability = this->bayesian_prior_;
83 uint64_t mask = 0x00;
84
85 // - compute the posterior probability by taking the product of the predicate probablities for each observation
86 // - create a bitmask for the binary_sensor states on all channels/observations
87 for (size_t i = 0; i < this->channels_.size(); i++) {
88 auto bs = this->channels_[i];
89
90 posterior_probability *=
91 this->bayesian_predicate_(bs.binary_sensor->state, posterior_probability,
92 bs.parameters.probabilities.given_true, bs.parameters.probabilities.given_false);
93
94 mask |= ((uint64_t) (bs.binary_sensor->state)) << i;
95 }
96
97 // update state only if any binary_sensor states have changed or if no state has ever been sent on boot
98 if ((this->last_mask_ != mask) || (!this->has_state())) {
99 this->publish_state(posterior_probability);
100 }
101
102 this->last_mask_ = mask;
103}
104
105float BinarySensorMap::bayesian_predicate_(bool sensor_state, float prior, float prob_given_true,
106 float prob_given_false) {
107 float prob_state_source_true = prob_given_true;
108 float prob_state_source_false = prob_given_false;
109
110 // if sensor is off, then we use the probabilities for the observation's complement
111 if (!sensor_state) {
112 prob_state_source_true = 1 - prob_given_true;
113 prob_state_source_false = 1 - prob_given_false;
114 }
115
116 return prob_state_source_true / (prior * prob_state_source_true + (1.0 - prior) * prob_state_source_false);
117}
118
120 BinarySensorMapChannel sensor_channel{
121 .binary_sensor = sensor,
122 .parameters{
123 .sensor_value = value,
124 },
125 };
126 this->channels_.push_back(sensor_channel);
127}
128
129void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float prob_given_true, float prob_given_false) {
130 BinarySensorMapChannel sensor_channel{
131 .binary_sensor = sensor,
132 .parameters{
133 .probabilities{
134 .given_true = prob_given_true,
135 .given_false = prob_given_false,
136 },
137 },
138 };
139 this->channels_.push_back(sensor_channel);
140}
141} // namespace binary_sensor_map
142} // namespace esphome
constexpr const char * c_str() const
Definition string_ref.h:69
Base class for all binary_sensor-type classes.
void add_channel(binary_sensor::BinarySensor *sensor, float value)
Add binary_sensors to the group when only one parameter is needed for the configured mapping type.
float bayesian_predicate_(bool sensor_state, float prior, float prob_given_true, float prob_given_false)
Computes the Bayesian predicate for a specific observation If the sensor state is false,...
void loop() override
The loop calls the configured type processing method.
std::vector< BinarySensorMapChannel > channels_
void process_group_()
Methods to process the binary_sensor_maps types.
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
bool has_state() const
Return whether this sensor has gotten a full state (that passed through all filters) yet.
Definition sensor.cpp:97
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7