diff --git a/esphome/components/binary_sensor_map/binary_sensor_map.cpp b/esphome/components/binary_sensor_map/binary_sensor_map.cpp index d1123ddff0..b2dffaf74d 100644 --- a/esphome/components/binary_sensor_map/binary_sensor_map.cpp +++ b/esphome/components/binary_sensor_map/binary_sensor_map.cpp @@ -13,6 +13,9 @@ void BinarySensorMap::loop() { case BINARY_SENSOR_MAP_TYPE_GROUP: this->process_group_(); break; + case BINARY_SENSOR_MAP_TYPE_SUM: + this->process_sum_(); + break; } } @@ -46,6 +49,34 @@ void BinarySensorMap::process_group_() { this->last_mask_ = mask; } +void BinarySensorMap::process_sum_() { + float total_current_value = 0.0; + uint64_t mask = 0x00; + // check all binary_sensors for its state. when active add its value to total_current_value. + // create a bitmask for the binary_sensor status on all channels + for (size_t i = 0; i < this->channels_.size(); i++) { + auto bs = this->channels_[i]; + if (bs.binary_sensor->state) { + total_current_value += bs.sensor_value; + mask |= 1 << i; + } + } + // check if the sensor map was touched + if (mask != 0ULL) { + // did the bit_mask change or is it a new sensor touch + if (this->last_mask_ != mask) { + float publish_value = total_current_value; + ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value); + this->publish_state(publish_value); + } + } else if (this->last_mask_ != 0ULL) { + // is this a new sensor release + ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing 0", this->name_.c_str()); + this->publish_state(0.0); + } + this->last_mask_ = mask; +} + void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float value) { BinarySensorMapChannel sensor_channel{ .binary_sensor = sensor, diff --git a/esphome/components/binary_sensor_map/binary_sensor_map.h b/esphome/components/binary_sensor_map/binary_sensor_map.h index e99b4e18d6..a880be9623 100644 --- a/esphome/components/binary_sensor_map/binary_sensor_map.h +++ b/esphome/components/binary_sensor_map/binary_sensor_map.h @@ -9,6 +9,7 @@ namespace binary_sensor_map { enum BinarySensorMapType { BINARY_SENSOR_MAP_TYPE_GROUP, + BINARY_SENSOR_MAP_TYPE_SUM, }; struct BinarySensorMapChannel { @@ -50,8 +51,10 @@ class BinarySensorMap : public sensor::Sensor, public Component { /** * methods to process the types of binary_sensor_maps * GROUP: process_group_() just map to a value + * ADD: process_add_() adds all the values * */ void process_group_(); + void process_sum_(); }; } // namespace binary_sensor_map diff --git a/esphome/components/binary_sensor_map/sensor.py b/esphome/components/binary_sensor_map/sensor.py index 7ddf0ecf2a..025be490cd 100644 --- a/esphome/components/binary_sensor_map/sensor.py +++ b/esphome/components/binary_sensor_map/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( ICON_CHECK_CIRCLE_OUTLINE, CONF_BINARY_SENSOR, CONF_GROUP, + CONF_SUM, ) DEPENDENCIES = ["binary_sensor"] @@ -21,6 +22,7 @@ SensorMapType = binary_sensor_map_ns.enum("SensorMapType") SENSOR_MAP_TYPES = { CONF_GROUP: SensorMapType.BINARY_SENSOR_MAP_TYPE_GROUP, + CONF_SUM: SensorMapType.BINARY_SENSOR_MAP_TYPE_SUM, } entry = { @@ -41,6 +43,17 @@ CONFIG_SCHEMA = cv.typed_schema( ), } ), + CONF_SUM: sensor.sensor_schema( + BinarySensorMap, + icon=ICON_CHECK_CIRCLE_OUTLINE, + accuracy_decimals=0, + ).extend( + { + cv.Required(CONF_CHANNELS): cv.All( + cv.ensure_list(entry), cv.Length(min=1) + ), + } + ), }, lower=True, ) diff --git a/esphome/const.py b/esphome/const.py index 5d3ddcf518..8245ed26f7 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -659,6 +659,7 @@ CONF_STOP_ACTION = "stop_action" CONF_STORE_BASELINE = "store_baseline" CONF_SUBNET = "subnet" CONF_SUBSTITUTIONS = "substitutions" +CONF_SUM = "sum" CONF_SUPPLEMENTAL_COOLING_ACTION = "supplemental_cooling_action" CONF_SUPPLEMENTAL_COOLING_DELTA = "supplemental_cooling_delta" CONF_SUPPLEMENTAL_HEATING_ACTION = "supplemental_heating_action"