mirror of
https://github.com/esphome/esphome.git
synced 2024-12-01 13:13:54 +01:00
Merge branch 'dev' into optolink
This commit is contained in:
commit
6431bd552e
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -23,6 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 5
|
||||
matrix:
|
||||
include:
|
||||
- id: ci-custom
|
||||
|
@ -16,6 +16,9 @@ void BinarySensorMap::loop() {
|
||||
case BINARY_SENSOR_MAP_TYPE_SUM:
|
||||
this->process_sum_();
|
||||
break;
|
||||
case BINARY_SENSOR_MAP_TYPE_BAYESIAN:
|
||||
this->process_bayesian_();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,46 +26,51 @@ void BinarySensorMap::process_group_() {
|
||||
float total_current_value = 0.0;
|
||||
uint8_t num_active_sensors = 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
|
||||
|
||||
// - check all binary_sensors for its state
|
||||
// - if active, add its value to total_current_value.
|
||||
// - creates a bitmask for the binary_sensor states on all channels
|
||||
for (size_t i = 0; i < this->channels_.size(); i++) {
|
||||
auto bs = this->channels_[i];
|
||||
if (bs.binary_sensor->state) {
|
||||
num_active_sensors++;
|
||||
total_current_value += bs.sensor_value;
|
||||
total_current_value += bs.parameters.sensor_value;
|
||||
mask |= 1ULL << i;
|
||||
}
|
||||
}
|
||||
// check if the sensor map was touched
|
||||
|
||||
// potentially update state only if a binary_sensor is active
|
||||
if (mask != 0ULL) {
|
||||
// did the bit_mask change or is it a new sensor touch
|
||||
// publish the average if the bitmask has changed
|
||||
if (this->last_mask_ != mask) {
|
||||
float publish_value = total_current_value / num_active_sensors;
|
||||
this->publish_state(publish_value);
|
||||
}
|
||||
} else if (this->last_mask_ != 0ULL) {
|
||||
// is this a new sensor release
|
||||
// no buttons are pressed and the states have changed since last run, so publish NAN
|
||||
ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
|
||||
this->publish_state(NAN);
|
||||
}
|
||||
|
||||
this->last_mask_ = mask;
|
||||
}
|
||||
|
||||
void BinarySensorMap::process_sum_() {
|
||||
float total_current_value = 0.0;
|
||||
uint64_t mask = 0x00;
|
||||
|
||||
// - check all binary_sensor states
|
||||
// - if active, add its value to total_current_value
|
||||
// - creates a bitmask for the binary_sensor status on all channels
|
||||
// - creates a bitmask for the binary_sensor states 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;
|
||||
total_current_value += bs.parameters.sensor_value;
|
||||
mask |= 1ULL << i;
|
||||
}
|
||||
}
|
||||
|
||||
// update state only if the binary sensor states have changed or if no state has ever been sent on boot
|
||||
// update state only if any binary_sensor states have changed or if no state has ever been sent on boot
|
||||
if ((this->last_mask_ != mask) || (!this->has_state())) {
|
||||
this->publish_state(total_current_value);
|
||||
}
|
||||
@ -70,15 +78,65 @@ void BinarySensorMap::process_sum_() {
|
||||
this->last_mask_ = mask;
|
||||
}
|
||||
|
||||
void BinarySensorMap::process_bayesian_() {
|
||||
float posterior_probability = this->bayesian_prior_;
|
||||
uint64_t mask = 0x00;
|
||||
|
||||
// - compute the posterior probability by taking the product of the predicate probablities for each observation
|
||||
// - create a bitmask for the binary_sensor states on all channels/observations
|
||||
for (size_t i = 0; i < this->channels_.size(); i++) {
|
||||
auto bs = this->channels_[i];
|
||||
|
||||
posterior_probability *=
|
||||
this->bayesian_predicate_(bs.binary_sensor->state, posterior_probability,
|
||||
bs.parameters.probabilities.given_true, bs.parameters.probabilities.given_false);
|
||||
|
||||
mask |= ((uint64_t) (bs.binary_sensor->state)) << i;
|
||||
}
|
||||
|
||||
// update state only if any binary_sensor states have changed or if no state has ever been sent on boot
|
||||
if ((this->last_mask_ != mask) || (!this->has_state())) {
|
||||
this->publish_state(posterior_probability);
|
||||
}
|
||||
|
||||
this->last_mask_ = mask;
|
||||
}
|
||||
|
||||
float BinarySensorMap::bayesian_predicate_(bool sensor_state, float prior, float prob_given_true,
|
||||
float prob_given_false) {
|
||||
float prob_state_source_true = prob_given_true;
|
||||
float prob_state_source_false = prob_given_false;
|
||||
|
||||
// if sensor is off, then we use the probabilities for the observation's complement
|
||||
if (!sensor_state) {
|
||||
prob_state_source_true = 1 - prob_given_true;
|
||||
prob_state_source_false = 1 - prob_given_false;
|
||||
}
|
||||
|
||||
return prob_state_source_true / (prior * prob_state_source_true + (1.0 - prior) * prob_state_source_false);
|
||||
}
|
||||
|
||||
void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float value) {
|
||||
BinarySensorMapChannel sensor_channel{
|
||||
.binary_sensor = sensor,
|
||||
.sensor_value = value,
|
||||
.parameters{
|
||||
.sensor_value = value,
|
||||
},
|
||||
};
|
||||
this->channels_.push_back(sensor_channel);
|
||||
}
|
||||
|
||||
void BinarySensorMap::set_sensor_type(BinarySensorMapType sensor_type) { this->sensor_type_ = sensor_type; }
|
||||
|
||||
void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float prob_given_true, float prob_given_false) {
|
||||
BinarySensorMapChannel sensor_channel{
|
||||
.binary_sensor = sensor,
|
||||
.parameters{
|
||||
.probabilities{
|
||||
.given_true = prob_given_true,
|
||||
.given_false = prob_given_false,
|
||||
},
|
||||
},
|
||||
};
|
||||
this->channels_.push_back(sensor_channel);
|
||||
}
|
||||
} // namespace binary_sensor_map
|
||||
} // namespace esphome
|
||||
|
@ -12,51 +12,88 @@ namespace binary_sensor_map {
|
||||
enum BinarySensorMapType {
|
||||
BINARY_SENSOR_MAP_TYPE_GROUP,
|
||||
BINARY_SENSOR_MAP_TYPE_SUM,
|
||||
BINARY_SENSOR_MAP_TYPE_BAYESIAN,
|
||||
};
|
||||
|
||||
struct BinarySensorMapChannel {
|
||||
binary_sensor::BinarySensor *binary_sensor;
|
||||
float sensor_value;
|
||||
union {
|
||||
float sensor_value;
|
||||
struct {
|
||||
float given_true;
|
||||
float given_false;
|
||||
} probabilities;
|
||||
} parameters;
|
||||
};
|
||||
|
||||
/** Class to group binary_sensors to one Sensor.
|
||||
/** Class to map one or more binary_sensors to one Sensor.
|
||||
*
|
||||
* Each binary sensor represents a float value in the group.
|
||||
* Each binary sensor has configured parameters that each mapping type uses to compute the single numerical result
|
||||
*/
|
||||
class BinarySensorMap : public sensor::Sensor, public Component {
|
||||
public:
|
||||
void dump_config() override;
|
||||
|
||||
/**
|
||||
* The loop checks all binary_sensor states
|
||||
* When the binary_sensor reports a true value for its state, then the float value it represents is added to the
|
||||
* total_current_value
|
||||
* The loop calls the configured type processing method
|
||||
*
|
||||
* Only when the total_current_value changed and at least one sensor reports an active state we publish the sensors
|
||||
* average value. When the value changed and no sensors ar active we publish NAN.
|
||||
* */
|
||||
* The processing method loops through all sensors and calculates the numerical result
|
||||
* The result is only published if a binary sensor state has changed or, for some types, on initial boot
|
||||
*/
|
||||
void loop() override;
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
/** Add binary_sensors to the group.
|
||||
* Each binary_sensor represents a float value when its state is true
|
||||
|
||||
/**
|
||||
* Add binary_sensors to the group when only one parameter is needed for the configured mapping type.
|
||||
*
|
||||
* @param *sensor The binary sensor.
|
||||
* @param value The value this binary_sensor represents
|
||||
*/
|
||||
void add_channel(binary_sensor::BinarySensor *sensor, float value);
|
||||
void set_sensor_type(BinarySensorMapType sensor_type);
|
||||
|
||||
/**
|
||||
* Add binary_sensors to the group when two parameters are needed for the Bayesian mapping type.
|
||||
*
|
||||
* @param *sensor The binary sensor.
|
||||
* @param prob_given_true Probability this observation is on when the Bayesian event is true
|
||||
* @param prob_given_false Probability this observation is on when the Bayesian event is false
|
||||
*/
|
||||
void add_channel(binary_sensor::BinarySensor *sensor, float prob_given_true, float prob_given_false);
|
||||
|
||||
void set_sensor_type(BinarySensorMapType sensor_type) { this->sensor_type_ = sensor_type; }
|
||||
|
||||
void set_bayesian_prior(float prior) { this->bayesian_prior_ = prior; };
|
||||
|
||||
protected:
|
||||
std::vector<BinarySensorMapChannel> channels_{};
|
||||
BinarySensorMapType sensor_type_{BINARY_SENSOR_MAP_TYPE_GROUP};
|
||||
// this gives max 64 channels per binary_sensor_map
|
||||
|
||||
// this allows a max of 64 channels/observations in order to keep track of binary_sensor states
|
||||
uint64_t last_mask_{0x00};
|
||||
|
||||
// Bayesian event prior probability before taking into account any observations
|
||||
float bayesian_prior_{};
|
||||
|
||||
/**
|
||||
* methods to process the types of binary_sensor_maps
|
||||
* GROUP: process_group_() just map to a value
|
||||
* Methods to process the binary_sensor_maps types
|
||||
*
|
||||
* GROUP: process_group_() averages all the values
|
||||
* ADD: process_add_() adds all the values
|
||||
* BAYESIAN: process_bayesian_() computes the predicate probability
|
||||
* */
|
||||
void process_group_();
|
||||
void process_sum_();
|
||||
void process_bayesian_();
|
||||
|
||||
/**
|
||||
* Computes the Bayesian predicate for a specific observation
|
||||
* If the sensor state is false, then we use the parameters' probabilities for the observatiosn complement
|
||||
*
|
||||
* @param sensor_state State of observation
|
||||
* @param prior Prior probability before accounting for this observation
|
||||
* @param prob_given_true Probability this observation is on when the Bayesian event is true
|
||||
* @param prob_given_false Probability this observation is on when the Bayesian event is false
|
||||
* */
|
||||
float bayesian_predicate_(bool sensor_state, float prior, float prob_given_true, float prob_given_false);
|
||||
};
|
||||
|
||||
} // namespace binary_sensor_map
|
||||
|
@ -20,16 +20,29 @@ BinarySensorMap = binary_sensor_map_ns.class_(
|
||||
)
|
||||
SensorMapType = binary_sensor_map_ns.enum("SensorMapType")
|
||||
|
||||
CONF_BAYESIAN = "bayesian"
|
||||
CONF_PRIOR = "prior"
|
||||
CONF_PROB_GIVEN_TRUE = "prob_given_true"
|
||||
CONF_PROB_GIVEN_FALSE = "prob_given_false"
|
||||
CONF_OBSERVATIONS = "observations"
|
||||
|
||||
SENSOR_MAP_TYPES = {
|
||||
CONF_GROUP: SensorMapType.BINARY_SENSOR_MAP_TYPE_GROUP,
|
||||
CONF_SUM: SensorMapType.BINARY_SENSOR_MAP_TYPE_SUM,
|
||||
CONF_BAYESIAN: SensorMapType.BINARY_SENSOR_MAP_TYPE_BAYESIAN,
|
||||
}
|
||||
|
||||
entry = {
|
||||
entry_one_parameter = {
|
||||
cv.Required(CONF_BINARY_SENSOR): cv.use_id(binary_sensor.BinarySensor),
|
||||
cv.Required(CONF_VALUE): cv.float_,
|
||||
}
|
||||
|
||||
entry_bayesian_parameters = {
|
||||
cv.Required(CONF_BINARY_SENSOR): cv.use_id(binary_sensor.BinarySensor),
|
||||
cv.Required(CONF_PROB_GIVEN_TRUE): cv.float_range(min=0, max=1),
|
||||
cv.Required(CONF_PROB_GIVEN_FALSE): cv.float_range(min=0, max=1),
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = cv.typed_schema(
|
||||
{
|
||||
CONF_GROUP: sensor.sensor_schema(
|
||||
@ -39,7 +52,7 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_CHANNELS): cv.All(
|
||||
cv.ensure_list(entry), cv.Length(min=1, max=64)
|
||||
cv.ensure_list(entry_one_parameter), cv.Length(min=1, max=64)
|
||||
),
|
||||
}
|
||||
),
|
||||
@ -50,7 +63,18 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_CHANNELS): cv.All(
|
||||
cv.ensure_list(entry), cv.Length(min=1, max=64)
|
||||
cv.ensure_list(entry_one_parameter), cv.Length(min=1, max=64)
|
||||
),
|
||||
}
|
||||
),
|
||||
CONF_BAYESIAN: sensor.sensor_schema(
|
||||
BinarySensorMap,
|
||||
accuracy_decimals=2,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_PRIOR): cv.float_range(min=0, max=1),
|
||||
cv.Required(CONF_OBSERVATIONS): cv.All(
|
||||
cv.ensure_list(entry_bayesian_parameters), cv.Length(min=1, max=64)
|
||||
),
|
||||
}
|
||||
),
|
||||
@ -66,6 +90,17 @@ async def to_code(config):
|
||||
constant = SENSOR_MAP_TYPES[config[CONF_TYPE]]
|
||||
cg.add(var.set_sensor_type(constant))
|
||||
|
||||
for ch in config[CONF_CHANNELS]:
|
||||
input_var = await cg.get_variable(ch[CONF_BINARY_SENSOR])
|
||||
cg.add(var.add_channel(input_var, ch[CONF_VALUE]))
|
||||
if config[CONF_TYPE] == CONF_BAYESIAN:
|
||||
cg.add(var.set_bayesian_prior(config[CONF_PRIOR]))
|
||||
|
||||
for obs in config[CONF_OBSERVATIONS]:
|
||||
input_var = await cg.get_variable(obs[CONF_BINARY_SENSOR])
|
||||
cg.add(
|
||||
var.add_channel(
|
||||
input_var, obs[CONF_PROB_GIVEN_TRUE], obs[CONF_PROB_GIVEN_FALSE]
|
||||
)
|
||||
)
|
||||
else:
|
||||
for ch in config[CONF_CHANNELS]:
|
||||
input_var = await cg.get_variable(ch[CONF_BINARY_SENSOR])
|
||||
cg.add(var.add_channel(input_var, ch[CONF_VALUE]))
|
||||
|
@ -34,6 +34,7 @@ ETHERNET_TYPES = {
|
||||
"DP83848": EthernetType.ETHERNET_TYPE_DP83848,
|
||||
"IP101": EthernetType.ETHERNET_TYPE_IP101,
|
||||
"JL1101": EthernetType.ETHERNET_TYPE_JL1101,
|
||||
"KSZ8081": EthernetType.ETHERNET_TYPE_KSZ8081,
|
||||
}
|
||||
|
||||
emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t")
|
||||
|
@ -74,6 +74,10 @@ void EthernetComponent::setup() {
|
||||
phy = esp_eth_phy_new_jl1101(&phy_config);
|
||||
break;
|
||||
}
|
||||
case ETHERNET_TYPE_KSZ8081: {
|
||||
phy = esp_eth_phy_new_ksz8081(&phy_config);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this->mark_failed();
|
||||
return;
|
||||
@ -140,7 +144,7 @@ void EthernetComponent::loop() {
|
||||
}
|
||||
|
||||
void EthernetComponent::dump_config() {
|
||||
std::string eth_type;
|
||||
const char *eth_type;
|
||||
switch (this->type_) {
|
||||
case ETHERNET_TYPE_LAN8720:
|
||||
eth_type = "LAN8720";
|
||||
@ -158,6 +162,14 @@ void EthernetComponent::dump_config() {
|
||||
eth_type = "IP101";
|
||||
break;
|
||||
|
||||
case ETHERNET_TYPE_JL1101:
|
||||
eth_type = "JL1101";
|
||||
break;
|
||||
|
||||
case ETHERNET_TYPE_KSZ8081:
|
||||
eth_type = "KSZ8081";
|
||||
break;
|
||||
|
||||
default:
|
||||
eth_type = "Unknown";
|
||||
break;
|
||||
@ -170,7 +182,8 @@ void EthernetComponent::dump_config() {
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " MDC Pin: %u", this->mdc_pin_);
|
||||
ESP_LOGCONFIG(TAG, " MDIO Pin: %u", this->mdio_pin_);
|
||||
ESP_LOGCONFIG(TAG, " Type: %s", eth_type.c_str());
|
||||
ESP_LOGCONFIG(TAG, " Type: %s", eth_type);
|
||||
ESP_LOGCONFIG(TAG, " PHY addr: %u", this->phy_addr_);
|
||||
}
|
||||
|
||||
float EthernetComponent::get_setup_priority() const { return setup_priority::WIFI; }
|
||||
|
@ -14,11 +14,13 @@ namespace esphome {
|
||||
namespace ethernet {
|
||||
|
||||
enum EthernetType {
|
||||
ETHERNET_TYPE_LAN8720 = 0,
|
||||
ETHERNET_TYPE_UNKNOWN = 0,
|
||||
ETHERNET_TYPE_LAN8720,
|
||||
ETHERNET_TYPE_RTL8201,
|
||||
ETHERNET_TYPE_DP83848,
|
||||
ETHERNET_TYPE_IP101,
|
||||
ETHERNET_TYPE_JL1101,
|
||||
ETHERNET_TYPE_KSZ8081,
|
||||
};
|
||||
|
||||
struct ManualIP {
|
||||
@ -69,7 +71,7 @@ class EthernetComponent : public Component {
|
||||
int power_pin_{-1};
|
||||
uint8_t mdc_pin_{23};
|
||||
uint8_t mdio_pin_{18};
|
||||
EthernetType type_{ETHERNET_TYPE_LAN8720};
|
||||
EthernetType type_{ETHERNET_TYPE_UNKNOWN};
|
||||
emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
|
||||
emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
|
||||
optional<ManualIP> manual_ip_{};
|
||||
|
@ -63,7 +63,7 @@ FanIsOffCondition = fan_ns.class_("FanIsOffCondition", automation.Condition.temp
|
||||
FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(Fan),
|
||||
cv.Optional(CONF_RESTORE_MODE, default="RESTORE_DEFAULT_OFF"): cv.enum(
|
||||
cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum(
|
||||
RESTORE_MODES, upper=True, space="_"
|
||||
),
|
||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent),
|
||||
|
@ -122,11 +122,18 @@ void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Colo
|
||||
}
|
||||
|
||||
// Adjust limits to nice y_per_div boundaries
|
||||
int yn = int(ymin / y_per_div);
|
||||
int ym = int(ymax / y_per_div) + int(1 * (fmodf(ymax, y_per_div) != 0));
|
||||
ymin = yn * y_per_div;
|
||||
ymax = ym * y_per_div;
|
||||
yrange = ymax - ymin;
|
||||
int yn = 0;
|
||||
int ym = 1;
|
||||
if (!std::isnan(ymin) && !std::isnan(ymax)) {
|
||||
yn = (int) floorf(ymin / y_per_div);
|
||||
ym = (int) ceilf(ymax / y_per_div);
|
||||
if (yn == ym) {
|
||||
ym++;
|
||||
}
|
||||
ymin = yn * y_per_div;
|
||||
ymax = ym * y_per_div;
|
||||
yrange = ymax - ymin;
|
||||
}
|
||||
|
||||
/// Draw grid
|
||||
if (!std::isnan(this->gridspacing_y_)) {
|
||||
|
@ -60,7 +60,7 @@ LIGHT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ex
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(LightState),
|
||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTJSONLightComponent),
|
||||
cv.Optional(CONF_RESTORE_MODE, default="restore_default_off"): cv.enum(
|
||||
cv.Optional(CONF_RESTORE_MODE, default="ALWAYS_OFF"): cv.enum(
|
||||
RESTORE_MODES, upper=True, space="_"
|
||||
),
|
||||
cv.Optional(CONF_ON_TURN_ON): auto.validate_automation(
|
||||
|
@ -92,7 +92,7 @@ def switch_schema(
|
||||
device_class: str = _UNDEF,
|
||||
icon: str = _UNDEF,
|
||||
block_inverted: bool = False,
|
||||
default_restore_mode: str = "RESTORE_DEFAULT_OFF",
|
||||
default_restore_mode: str = "ALWAYS_OFF",
|
||||
):
|
||||
schema = _SWITCH_SCHEMA.extend(
|
||||
{
|
||||
|
@ -16,6 +16,7 @@ time_based_ns = cg.esphome_ns.namespace("time_based")
|
||||
TimeBasedCover = time_based_ns.class_("TimeBasedCover", cover.Cover, cg.Component)
|
||||
|
||||
CONF_HAS_BUILT_IN_ENDSTOP = "has_built_in_endstop"
|
||||
CONF_MANUAL_CONTROL = "manual_control"
|
||||
|
||||
CONFIG_SCHEMA = cover.COVER_SCHEMA.extend(
|
||||
{
|
||||
@ -26,6 +27,7 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend(
|
||||
cv.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
|
||||
cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_HAS_BUILT_IN_ENDSTOP, default=False): cv.boolean,
|
||||
cv.Optional(CONF_MANUAL_CONTROL, default=False): cv.boolean,
|
||||
cv.Optional(CONF_ASSUMED_STATE, default=True): cv.boolean,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
@ -51,4 +53,5 @@ async def to_code(config):
|
||||
)
|
||||
|
||||
cg.add(var.set_has_built_in_endstop(config[CONF_HAS_BUILT_IN_ENDSTOP]))
|
||||
cg.add(var.set_manual_control(config[CONF_MANUAL_CONTROL]))
|
||||
cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
|
||||
|
@ -79,6 +79,14 @@ void TimeBasedCover::control(const CoverCall &call) {
|
||||
auto pos = *call.get_position();
|
||||
if (pos == this->position) {
|
||||
// already at target
|
||||
if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
|
||||
// for covers with manual control switch, we can't rely on the computed position, so if
|
||||
// the command triggered again, we'll assume it's in the opposite direction anyway.
|
||||
auto op = pos == COVER_CLOSED ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
|
||||
this->position = pos == COVER_CLOSED ? COVER_OPEN : COVER_CLOSED;
|
||||
this->target_position_ = pos;
|
||||
this->start_direction_(op);
|
||||
}
|
||||
// for covers with built in end stop, we should send the command again
|
||||
if (this->has_built_in_endstop_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
|
||||
auto op = pos == COVER_CLOSED ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
|
||||
|
@ -21,6 +21,7 @@ class TimeBasedCover : public cover::Cover, public Component {
|
||||
void set_close_duration(uint32_t close_duration) { this->close_duration_ = close_duration; }
|
||||
cover::CoverTraits get_traits() override;
|
||||
void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; }
|
||||
void set_manual_control(bool value) { this->manual_control_ = value; }
|
||||
void set_assumed_state(bool value) { this->assumed_state_ = value; }
|
||||
|
||||
protected:
|
||||
@ -44,6 +45,7 @@ class TimeBasedCover : public cover::Cover, public Component {
|
||||
uint32_t last_publish_time_{0};
|
||||
float target_position_{0};
|
||||
bool has_built_in_endstop_{false};
|
||||
bool manual_control_{false};
|
||||
bool assumed_state_{false};
|
||||
cover::CoverOperation last_operation_{cover::COVER_OPERATION_OPENING};
|
||||
};
|
||||
|
@ -137,7 +137,7 @@ void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color
|
||||
if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
|
||||
return;
|
||||
|
||||
const uint32_t pos = (x + y * this->get_width_internal()) / 8u;
|
||||
const uint32_t pos = (x + y * this->get_width_controller()) / 8u;
|
||||
const uint8_t subpos = x & 0x07;
|
||||
// flip logic
|
||||
if (!color.is_on()) {
|
||||
@ -146,7 +146,9 @@ void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color
|
||||
this->buffer_[pos] &= ~(0x80 >> subpos);
|
||||
}
|
||||
}
|
||||
uint32_t WaveshareEPaper::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal() / 8u; }
|
||||
uint32_t WaveshareEPaper::get_buffer_length_() {
|
||||
return this->get_width_controller() * this->get_height_internal() / 8u;
|
||||
}
|
||||
void WaveshareEPaper::start_command_() {
|
||||
this->dc_pin_->digital_write(false);
|
||||
this->enable();
|
||||
@ -291,7 +293,7 @@ void HOT WaveshareEPaperTypeA::display() {
|
||||
// COMMAND SET RAM X ADDRESS START END POSITION
|
||||
this->command(0x44);
|
||||
this->data(0x00);
|
||||
this->data((this->get_width_internal() - 1) >> 3);
|
||||
this->data((this->get_width_controller() - 1) >> 3);
|
||||
// COMMAND SET RAM Y ADDRESS START END POSITION
|
||||
this->command(0x45);
|
||||
this->data(this->get_height_internal() - 1);
|
||||
@ -392,12 +394,26 @@ int WaveshareEPaperTypeA::get_width_internal() {
|
||||
case TTGO_EPAPER_2_13_IN_B73:
|
||||
case TTGO_EPAPER_2_13_IN_B74:
|
||||
case TTGO_EPAPER_2_13_IN_B1:
|
||||
return 122;
|
||||
case WAVESHARE_EPAPER_2_9_IN:
|
||||
case WAVESHARE_EPAPER_2_9_IN_V2:
|
||||
return 128;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// The controller of the 2.13" displays has a buffer larger than screen size
|
||||
int WaveshareEPaperTypeA::get_width_controller() {
|
||||
switch (this->model_) {
|
||||
case WAVESHARE_EPAPER_2_13_IN:
|
||||
case TTGO_EPAPER_2_13_IN:
|
||||
case TTGO_EPAPER_2_13_IN_B73:
|
||||
case TTGO_EPAPER_2_13_IN_B74:
|
||||
case TTGO_EPAPER_2_13_IN_B1:
|
||||
return 128;
|
||||
default:
|
||||
return this->get_width_internal();
|
||||
}
|
||||
}
|
||||
int WaveshareEPaperTypeA::get_height_internal() {
|
||||
switch (this->model_) {
|
||||
case WAVESHARE_EPAPER_1_54_IN:
|
||||
|
@ -54,6 +54,8 @@ class WaveshareEPaper : public PollingComponent,
|
||||
}
|
||||
}
|
||||
|
||||
virtual int get_width_controller() { return this->get_width_internal(); };
|
||||
|
||||
uint32_t get_buffer_length_();
|
||||
uint32_t reset_duration_{200};
|
||||
|
||||
@ -111,6 +113,8 @@ class WaveshareEPaperTypeA : public WaveshareEPaper {
|
||||
|
||||
int get_height_internal() override;
|
||||
|
||||
int get_width_controller() override;
|
||||
|
||||
uint32_t full_update_every_{30};
|
||||
uint32_t at_update_{0};
|
||||
WaveshareEPaperTypeAModel model_;
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2023.4.0-dev"
|
||||
__version__ = "2023.5.0-dev"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
|
||||
|
@ -10,7 +10,7 @@ platformio==6.1.6 # When updating platformio, also update Dockerfile
|
||||
esptool==4.5.1
|
||||
click==8.1.3
|
||||
esphome-dashboard==20230214.0
|
||||
aioesphomeapi==13.5.1
|
||||
aioesphomeapi==13.7.0
|
||||
zeroconf==0.56.0
|
||||
|
||||
# esp-idf requires this, but doesn't bundle it by default
|
||||
|
@ -368,6 +368,32 @@ sensor:
|
||||
- binary_sensor: bin3
|
||||
value: 100.0
|
||||
|
||||
- platform: binary_sensor_map
|
||||
name: Binary Sensor Map
|
||||
type: sum
|
||||
channels:
|
||||
- binary_sensor: bin1
|
||||
value: 10.0
|
||||
- binary_sensor: bin2
|
||||
value: 15.0
|
||||
- binary_sensor: bin3
|
||||
value: 100.0
|
||||
|
||||
- platform: binary_sensor_map
|
||||
name: Binary Sensor Map
|
||||
type: bayesian
|
||||
prior: 0.4
|
||||
observations:
|
||||
- binary_sensor: bin1
|
||||
prob_given_true: 0.9
|
||||
prob_given_false: 0.4
|
||||
- binary_sensor: bin2
|
||||
prob_given_true: 0.7
|
||||
prob_given_false: 0.05
|
||||
- binary_sensor: bin3
|
||||
prob_given_true: 0.8
|
||||
prob_given_false: 0.2
|
||||
|
||||
- platform: bl0939
|
||||
uart_id: uart_8
|
||||
voltage:
|
||||
|
Loading…
Reference in New Issue
Block a user