1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-05 01:21:50 +00:00

Compare commits

...

42 Commits

Author SHA1 Message Date
Jesse Hills
e43dcded62 Merge pull request #2074 from esphome/bump-1.20.1
1.20.1
2021-07-27 11:00:48 +12:00
Jesse Hills
887081fd71 Bump version to v1.20.1 2021-07-27 09:43:05 +12:00
Otto Winter
71ded24fce Fix MQTT climate custom fan modes without regular ones (#2071) 2021-07-27 09:43:05 +12:00
Chris Nussbaum
1e2a9e8348 Couple more updates for the Tuya component (#2065)
Co-authored-by: Chris Nussbaum <chris.nussbaum@protolabs.com>
2021-07-27 09:43:05 +12:00
buxtronix
64a3aa7092 Log warning about lack of support for Anova nano (#2063)
Co-authored-by: Ben Buxton <bb@cactii.net>
2021-07-27 09:43:05 +12:00
carstenschroeder
fda8dd4ce3 Fixes new auto mode COOL and HEAT after #1994 (#2053) 2021-07-27 09:43:04 +12:00
Sergey V. DUDANOV
1efabd27d8 midea_ac: fix presets implementation (#2054) 2021-07-27 09:43:04 +12:00
Maurice Makaay
caa651e55b Accept change as proposed by black. (#2055) 2021-07-27 09:43:04 +12:00
Jesse Hills
10a6e9b4ee Merge pull request #2051 from esphome/bump-1.20.0
1.20.0
2021-07-22 08:32:30 +12:00
Jesse Hills
4b8ec44262 Bump version to v1.20.0 2021-07-22 07:55:49 +12:00
Jesse Hills
bd74ed4bc0 Merge branch 'beta' into bump-1.20.0 2021-07-22 07:55:49 +12:00
Jesse Hills
d01f296420 Merge pull request #2048 from esphome/bump-1.20.0b6
1.20.0b6
2021-07-21 11:35:27 +12:00
Jesse Hills
27112e2ace Bump version to v1.20.0b6 2021-07-21 10:52:48 +12:00
Sean Vig
837930234f Remove superfluous polling on ADS1115 (#2015) 2021-07-21 10:52:48 +12:00
Jesse Hills
e19aa3bbe0 Adding last_reset_type to sensors that should support it. (#2039) 2021-07-21 10:52:48 +12:00
Oxan van Leeuwen
35b5c1ed56 Fix white value transition for addressable lights (#2045) 2021-07-21 10:52:48 +12:00
Jesse Hills
a91e6a6bdf Merge pull request #1959 from esphome/bump-1.19.4
1.19.4
2021-06-24 13:31:01 +12:00
Jesse Hills
8600620305 Bump version to v1.19.4 2021-06-24 12:49:45 +12:00
Jesse Hills
96721f305f Bump dashboard to 20210623.0 (#1958) 2021-06-24 12:49:45 +12:00
Otto Winter
2bf70d7d00 Compat argv parsing improvements (#1952) 2021-06-24 12:49:45 +12:00
Otto Winter
1d8c170f48 Add climate preset NONE again (#1951) 2021-06-24 12:49:45 +12:00
Otto Winter
6009c7edb4 Disallow power_save_mode NONE if used together with BLE (#1950) 2021-06-24 12:49:44 +12:00
Otto Winter
e3f36c033e API raise minor version for climate changes (#1947) 2021-06-24 12:49:44 +12:00
Otto Winter
d4eb0f1655 Rework climate traits (#1941)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2021-06-24 12:49:36 +12:00
Jesse Hills
e20ec00071 Merge pull request #1956 from esphome/bump-1.19.3
1.19.3
2021-06-23 20:16:42 +12:00
Jesse Hills
150114d774 Bump version to v1.19.3 2021-06-23 19:39:37 +12:00
Jesse Hills
89dfa5ea82 Bump esphome-dashboard to 20210622.0 (#1955) 2021-06-23 19:39:31 +12:00
Jesse Hills
97aa930ad2 Merge pull request #1943 from esphome/bump-1.19.2
1.19.2
2021-06-21 14:59:11 +12:00
Jesse Hills
2a5def10e7 Bump version to v1.19.2 2021-06-21 14:40:05 +12:00
Jesse Hills
969834e037 Fix bad climate control enum (#1942) 2021-06-21 14:40:05 +12:00
Jesse Hills
d73a44c504 Allow wifi setup to proceed when there is no sta or ap (#1931) 2021-06-21 14:40:05 +12:00
Sergey V. DUDANOV
8aec092ab6 Fix midea_ac query frame (#1940) 2021-06-21 14:40:05 +12:00
Chris Nussbaum
4fa959ba45 Don't send Tuya commands while currently receiving a message (#1886)
Co-authored-by: Chris Nussbaum <chris.nussbaum@protolabs.com>
2021-06-21 14:40:05 +12:00
Jesse Hills
b43712d78d Merge pull request #1936 from esphome/bump-1.19.1
1.19.1
2021-06-18 12:10:30 +12:00
Jesse Hills
01904a0f10 Bump version to v1.19.1 2021-06-18 11:52:02 +12:00
Jesse Hills
dd875e7529 Replace CLIMATE_MODE_AUTO with CLIMATE_MODE_HEAT_COOL in most cases (#1933) 2021-06-18 11:52:02 +12:00
Otto Winter
f1dcf0f0b8 Improve config final validation (#1917) 2021-06-18 11:52:02 +12:00
Sergey V. DUDANOV
a045d001bf Fix: midea_ac: fixed query status frame (#1922) 2021-06-18 11:52:01 +12:00
Paulus Schoutsen
066c1022d0 Update dashboard to 20210617.0 (#1930) 2021-06-18 11:52:01 +12:00
Jesse Hills
59c192becc Merge pull request #1923 from esphome/bump-1.19.0
1.19.0
2021-06-17 06:09:09 +12:00
Jesse Hills
a800816750 Merge branch 'beta' into bump-1.19.0 2021-06-17 05:59:02 +12:00
Jesse Hills
970563e07b Bump version to v1.19.0 2021-06-16 21:00:51 +12:00
26 changed files with 222 additions and 46 deletions

View File

@@ -64,11 +64,6 @@ void ADS1115Component::setup() {
return;
}
this->prev_config_ = config;
for (auto *sensor : this->sensors_) {
this->set_interval(sensor->get_name(), sensor->update_interval(),
[this, sensor] { this->request_measurement(sensor); });
}
}
void ADS1115Component::dump_config() {
ESP_LOGCONFIG(TAG, "Setting up ADS1115...");

View File

@@ -60,6 +60,7 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
auto chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str());
break;
}
this->char_handle_ = chr->handle;

View File

@@ -422,6 +422,12 @@ enum SensorStateClass {
STATE_CLASS_MEASUREMENT = 1;
}
enum SensorLastResetType {
LAST_RESET_NONE = 0;
LAST_RESET_NEVER = 1;
LAST_RESET_AUTO = 2;
}
message ListEntitiesSensorResponse {
option (id) = 16;
option (source) = SOURCE_SERVER;
@@ -438,6 +444,7 @@ message ListEntitiesSensorResponse {
bool force_update = 8;
string device_class = 9;
SensorStateClass state_class = 10;
SensorLastResetType last_reset_type = 11;
}
message SensorStateResponse {
option (id) = 25;

View File

@@ -399,6 +399,7 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
msg.force_update = sensor->get_force_update();
msg.device_class = sensor->get_device_class();
msg.state_class = static_cast<enums::SensorStateClass>(sensor->state_class);
msg.last_reset_type = static_cast<enums::SensorLastResetType>(sensor->last_reset_type);
return this->send_list_entities_sensor_response(msg);
}

View File

@@ -72,6 +72,18 @@ template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::Sens
return "UNKNOWN";
}
}
template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::SensorLastResetType value) {
switch (value) {
case enums::LAST_RESET_NONE:
return "LAST_RESET_NONE";
case enums::LAST_RESET_NEVER:
return "LAST_RESET_NEVER";
case enums::LAST_RESET_AUTO:
return "LAST_RESET_AUTO";
default:
return "UNKNOWN";
}
}
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
switch (value) {
case enums::LOG_LEVEL_NONE:
@@ -1592,6 +1604,10 @@ bool ListEntitiesSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt va
this->state_class = value.as_enum<enums::SensorStateClass>();
return true;
}
case 11: {
this->last_reset_type = value.as_enum<enums::SensorLastResetType>();
return true;
}
default:
return false;
}
@@ -1647,6 +1663,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bool(8, this->force_update);
buffer.encode_string(9, this->device_class);
buffer.encode_enum<enums::SensorStateClass>(10, this->state_class);
buffer.encode_enum<enums::SensorLastResetType>(11, this->last_reset_type);
}
void ListEntitiesSensorResponse::dump_to(std::string &out) const {
char buffer[64];
@@ -1692,6 +1709,10 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const {
out.append(" state_class: ");
out.append(proto_enum_to_string<enums::SensorStateClass>(this->state_class));
out.append("\n");
out.append(" last_reset_type: ");
out.append(proto_enum_to_string<enums::SensorLastResetType>(this->last_reset_type));
out.append("\n");
out.append("}");
}
bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {

View File

@@ -36,6 +36,11 @@ enum SensorStateClass : uint32_t {
STATE_CLASS_NONE = 0,
STATE_CLASS_MEASUREMENT = 1,
};
enum SensorLastResetType : uint32_t {
LAST_RESET_NONE = 0,
LAST_RESET_NEVER = 1,
LAST_RESET_AUTO = 2,
};
enum LogLevel : uint32_t {
LOG_LEVEL_NONE = 0,
LOG_LEVEL_ERROR = 1,
@@ -429,6 +434,7 @@ class ListEntitiesSensorResponse : public ProtoMessage {
bool force_update{false};
std::string device_class{};
enums::SensorStateClass state_class{};
enums::SensorLastResetType last_reset_type{};
void encode(ProtoWriteBuffer buffer) const override;
void dump_to(std::string &out) const override;

View File

@@ -21,6 +21,7 @@ from esphome.const import (
ICON_EMPTY,
ICON_LIGHTBULB,
ICON_CURRENT_AC,
LAST_RESET_TYPE_AUTO,
STATE_CLASS_MEASUREMENT,
UNIT_HERTZ,
UNIT_VOLT,
@@ -91,10 +92,20 @@ ATM90E32_PHASE_SCHEMA = cv.Schema(
STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema(
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT
UNIT_WATT_HOURS,
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema(
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT
UNIT_WATT_HOURS,
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t,
cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t,

View File

@@ -109,9 +109,9 @@ def _compute_destination_path(key: str) -> Path:
return base_dir / h.hexdigest()[:8]
def _run_git_command(cmd):
def _run_git_command(cmd, cwd=None):
try:
ret = subprocess.run(cmd, capture_output=True, check=False)
ret = subprocess.run(cmd, cwd=cwd, capture_output=True, check=False)
except FileNotFoundError as err:
raise cv.Invalid(
"git is not installed but required for external_components.\n"
@@ -151,14 +151,16 @@ def _process_git_config(config: dict, refresh) -> str:
_LOGGER.info("Updating %s", key)
_LOGGER.debug("Location: %s", repo_dir)
# Stash local changes (if any)
_run_git_command(["git", "stash", "push", "--include-untracked"])
_run_git_command(
["git", "stash", "push", "--include-untracked"], str(repo_dir)
)
# Fetch remote ref
cmd = ["git", "fetch", "--", "origin"]
if CONF_REF in config:
cmd.append(config[CONF_REF])
_run_git_command(cmd)
_run_git_command(cmd, str(repo_dir))
# Hard reset to FETCH_HEAD (short-lived git ref corresponding to most recent fetch)
_run_git_command(["git", "reset", "--hard", "FETCH_HEAD"])
_run_git_command(["git", "reset", "--hard", "FETCH_HEAD"], str(repo_dir))
if (repo_dir / "esphome" / "components").is_dir():
components_dir = repo_dir / "esphome" / "components"

View File

@@ -15,6 +15,7 @@ from esphome.const import (
DEVICE_CLASS_VOLTAGE,
ICON_CURRENT_AC,
ICON_EMPTY,
LAST_RESET_TYPE_AUTO,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_AMPERE,
@@ -121,14 +122,16 @@ CONFIG_SCHEMA = (
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_TOTAL_ENERGY_PRODUCTION): sensor.sensor_schema(
UNIT_KILOWATT_HOURS,
ICON_EMPTY,
0,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_TOTAL_GENERATION_TIME): sensor.sensor_schema(
UNIT_HOURS,

View File

@@ -19,8 +19,8 @@ from esphome.const import (
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
ICON_EMPTY,
LAST_RESET_TYPE_AUTO,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
@@ -67,7 +67,12 @@ CONFIG_SCHEMA = cv.Schema(
UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
),
cv.Optional(CONF_ENERGY): sensor.sensor_schema(
UNIT_WATT_HOURS, ICON_EMPTY, 1, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE
UNIT_WATT_HOURS,
ICON_EMPTY,
1,
DEVICE_CLASS_ENERGY,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_CURRENT_RESISTOR, default=0.001): cv.resistance,
cv.Optional(CONF_VOLTAGE_DIVIDER, default=2351): cv.positive_float,

View File

@@ -68,10 +68,7 @@ void AddressableLight::write_state(LightState *state) {
// our transition will handle brightness, disable brightness in correction.
this->correction_.set_local_brightness(255);
uint8_t orig_w = target_color.w;
target_color *= static_cast<uint8_t>(roundf(end_values.get_brightness() * end_values.get_state() * 255.0f));
// w is not scaled by brightness
target_color.w = orig_w;
float denom = (1.0f - new_smoothed);
float alpha = denom == 0.0f ? 0.0f : (new_smoothed - prev_smoothed) / denom;

View File

@@ -100,7 +100,7 @@ bool MideaAC::allow_preset(climate::ClimatePreset preset) const {
ESP_LOGD(TAG, "BOOST preset is only available in HEAT or COOL mode");
}
break;
case climate::CLIMATE_PRESET_HOME:
case climate::CLIMATE_PRESET_NONE:
return true;
default:
break;
@@ -191,7 +191,7 @@ climate::ClimateTraits MideaAC::traits() {
if (traits_swing_both_)
traits.add_supported_swing_mode(climate::CLIMATE_SWING_BOTH);
traits.set_supported_presets({
climate::CLIMATE_PRESET_HOME,
climate::CLIMATE_PRESET_NONE,
});
if (traits_preset_eco_)
traits.add_supported_preset(climate::CLIMATE_PRESET_ECO);

View File

@@ -6,6 +6,9 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/midea_dongle/midea_dongle.h"
#include "esphome/components/climate/climate.h"
#include "esphome/components/midea_dongle/midea_dongle.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
#include "midea_frame.h"
namespace esphome {

View File

@@ -86,18 +86,17 @@ void PropertiesFrame::set_mode(climate::ClimateMode mode) {
}
optional<climate::ClimatePreset> PropertiesFrame::get_preset() const {
if (this->get_eco_mode()) {
if (this->get_eco_mode())
return climate::CLIMATE_PRESET_ECO;
} else if (this->get_sleep_mode()) {
if (this->get_sleep_mode())
return climate::CLIMATE_PRESET_SLEEP;
} else if (this->get_turbo_mode()) {
if (this->get_turbo_mode())
return climate::CLIMATE_PRESET_BOOST;
} else {
return climate::CLIMATE_PRESET_HOME;
}
return climate::CLIMATE_PRESET_NONE;
}
void PropertiesFrame::set_preset(climate::ClimatePreset preset) {
this->clear_presets();
switch (preset) {
case climate::CLIMATE_PRESET_ECO:
this->set_eco_mode(true);
@@ -113,14 +112,21 @@ void PropertiesFrame::set_preset(climate::ClimatePreset preset) {
}
}
void PropertiesFrame::clear_presets() {
this->set_eco_mode(false);
this->set_sleep_mode(false);
this->set_turbo_mode(false);
this->set_freeze_protection_mode(false);
}
bool PropertiesFrame::is_custom_preset() const { return this->get_freeze_protection_mode(); }
const std::string &PropertiesFrame::get_custom_preset() const { return midea_ac::MIDEA_FREEZE_PROTECTION_PRESET; };
void PropertiesFrame::set_custom_preset(const std::string &preset) {
if (preset == MIDEA_FREEZE_PROTECTION_PRESET) {
this->clear_presets();
if (preset == MIDEA_FREEZE_PROTECTION_PRESET)
this->set_freeze_protection_mode(true);
}
}
bool PropertiesFrame::is_custom_fan_mode() const {

View File

@@ -115,6 +115,7 @@ class PropertiesFrame : public midea_dongle::BaseFrame {
/* PRESET */
optional<climate::ClimatePreset> get_preset() const;
void set_preset(climate::ClimatePreset preset);
void clear_presets();
bool is_custom_preset() const;
const std::string &get_custom_preset() const;

View File

@@ -72,7 +72,7 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC
root["act_t"] = this->get_action_state_topic();
}
if (traits.get_supports_fan_modes()) {
if (traits.get_supports_fan_modes() || !traits.get_supported_custom_fan_modes().empty()) {
// fan_mode_command_topic
root["fan_mode_cmd_t"] = this->get_fan_mode_command_topic();
// fan_mode_state_topic

View File

@@ -35,8 +35,8 @@ void PIDClimate::control(const climate::ClimateCall &call) {
if (call.get_target_temperature().has_value())
this->target_temperature = *call.get_target_temperature();
// If switching to non-auto mode, set output immediately
if (this->mode != climate::CLIMATE_MODE_HEAT_COOL)
// If switching to off mode, set output immediately
if (this->mode == climate::CLIMATE_MODE_OFF)
this->handle_non_auto_mode_();
this->publish_state();

View File

@@ -12,8 +12,8 @@ from esphome.const import (
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
ICON_EMPTY,
LAST_RESET_TYPE_AUTO,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
@@ -47,7 +47,8 @@ CONFIG_SCHEMA = (
ICON_EMPTY,
0,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
}
)

View File

@@ -17,8 +17,8 @@ from esphome.const import (
DEVICE_CLASS_ENERGY,
ICON_EMPTY,
ICON_CURRENT_AC,
LAST_RESET_TYPE_AUTO,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_HERTZ,
UNIT_VOLT,
UNIT_AMPERE,
@@ -54,7 +54,8 @@ CONFIG_SCHEMA = (
ICON_EMPTY,
0,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
UNIT_HERTZ,

View File

@@ -25,8 +25,8 @@ from esphome.const import (
ICON_CURRENT_AC,
ICON_EMPTY,
ICON_FLASH,
LAST_RESET_TYPE_AUTO,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_NONE,
UNIT_AMPERE,
UNIT_DEGREES,
UNIT_EMPTY,
@@ -88,24 +88,36 @@ CONFIG_SCHEMA = (
STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_IMPORT_ACTIVE_ENERGY): sensor.sensor_schema(
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE
UNIT_WATT_HOURS,
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_EXPORT_ACTIVE_ENERGY): sensor.sensor_schema(
UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_NONE
UNIT_WATT_HOURS,
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_IMPORT_REACTIVE_ENERGY): sensor.sensor_schema(
UNIT_VOLT_AMPS_REACTIVE_HOURS,
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
cv.Optional(CONF_EXPORT_REACTIVE_ENERGY): sensor.sensor_schema(
UNIT_VOLT_AMPS_REACTIVE_HOURS,
ICON_EMPTY,
2,
DEVICE_CLASS_ENERGY,
STATE_CLASS_NONE,
STATE_CLASS_MEASUREMENT,
LAST_RESET_TYPE_AUTO,
),
}
)

View File

@@ -17,6 +17,7 @@ from esphome.const import (
CONF_ICON,
CONF_ID,
CONF_INTERNAL,
CONF_LAST_RESET_TYPE,
CONF_ON_RAW_VALUE,
CONF_ON_VALUE,
CONF_ON_VALUE_RANGE,
@@ -30,6 +31,9 @@ from esphome.const import (
CONF_NAME,
CONF_MQTT_ID,
CONF_FORCE_UPDATE,
LAST_RESET_TYPE_AUTO,
LAST_RESET_TYPE_NEVER,
LAST_RESET_TYPE_NONE,
UNIT_EMPTY,
ICON_EMPTY,
DEVICE_CLASS_EMPTY,
@@ -79,6 +83,15 @@ STATE_CLASSES = {
}
validate_state_class = cv.enum(STATE_CLASSES, lower=True, space="_")
LastResetTypes = sensor_ns.enum("LastResetType")
LAST_RESET_TYPES = {
LAST_RESET_TYPE_NONE: LastResetTypes.LAST_RESET_TYPE_NONE,
LAST_RESET_TYPE_NEVER: LastResetTypes.LAST_RESET_TYPE_NEVER,
LAST_RESET_TYPE_AUTO: LastResetTypes.LAST_RESET_TYPE_AUTO,
}
validate_last_reset_type = cv.enum(LAST_RESET_TYPES, lower=True, space="_")
IS_PLATFORM_COMPONENT = True
@@ -168,6 +181,7 @@ SENSOR_SCHEMA = cv.MQTT_COMPONENT_SCHEMA.extend(
cv.Optional(CONF_ACCURACY_DECIMALS): accuracy_decimals,
cv.Optional(CONF_DEVICE_CLASS): device_class,
cv.Optional(CONF_STATE_CLASS): validate_state_class,
cv.Optional(CONF_LAST_RESET_TYPE): validate_last_reset_type,
cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean,
cv.Optional(CONF_EXPIRE_AFTER): cv.All(
cv.requires_component("mqtt"),
@@ -202,6 +216,7 @@ def sensor_schema(
accuracy_decimals_: int,
device_class_: Optional[str] = DEVICE_CLASS_EMPTY,
state_class_: Optional[str] = STATE_CLASS_NONE,
last_reset_type_: Optional[str] = LAST_RESET_TYPE_NONE,
) -> cv.Schema:
schema = SENSOR_SCHEMA
if unit_of_measurement_ != UNIT_EMPTY:
@@ -230,6 +245,14 @@ def sensor_schema(
schema = schema.extend(
{cv.Optional(CONF_STATE_CLASS, default=state_class_): validate_state_class}
)
if last_reset_type_ != LAST_RESET_TYPE_NONE:
schema = schema.extend(
{
cv.Optional(
CONF_LAST_RESET_TYPE, default=last_reset_type_
): validate_last_reset_type
}
)
return schema
@@ -479,6 +502,8 @@ async def setup_sensor_core_(var, config):
cg.add(var.set_icon(config[CONF_ICON]))
if CONF_ACCURACY_DECIMALS in config:
cg.add(var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
if CONF_LAST_RESET_TYPE in config:
cg.add(var.set_last_reset_type(config[CONF_LAST_RESET_TYPE]))
cg.add(var.set_force_update(config[CONF_FORCE_UPDATE]))
if config.get(CONF_FILTERS): # must exist and not be empty
filters = await build_filters(config[CONF_FILTERS])

View File

@@ -16,6 +16,18 @@ const char *state_class_to_string(StateClass state_class) {
}
}
const char *last_reset_type_to_string(LastResetType last_reset_type) {
switch (last_reset_type) {
case LAST_RESET_TYPE_NEVER:
return "never";
case LAST_RESET_TYPE_AUTO:
return "auto";
case LAST_RESET_TYPE_NONE:
default:
return "";
}
}
void Sensor::publish_state(float state) {
this->raw_state = state;
this->raw_callback_.call(state);
@@ -64,6 +76,7 @@ void Sensor::set_state_class(const std::string &state_class) {
ESP_LOGW(TAG, "'%s' - Unrecognized state class %s", this->get_name().c_str(), state_class.c_str());
}
}
void Sensor::set_last_reset_type(LastResetType last_reset_type) { this->last_reset_type = last_reset_type; }
std::string Sensor::get_unit_of_measurement() {
if (this->unit_of_measurement_.has_value())
return *this->unit_of_measurement_;

View File

@@ -14,6 +14,10 @@ namespace sensor {
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \
} \
ESP_LOGCONFIG(TAG, "%s State Class: '%s'", prefix, state_class_to_string((obj)->state_class)); \
if ((obj)->state_class == sensor::STATE_CLASS_MEASUREMENT && \
(obj)->last_reset_type != sensor::LAST_RESET_TYPE_NONE) { \
ESP_LOGCONFIG(TAG, "%s Last Reset Type: '%s'", prefix, last_reset_type_to_string((obj)->last_reset_type)); \
} \
ESP_LOGCONFIG(TAG, "%s Unit of Measurement: '%s'", prefix, (obj)->get_unit_of_measurement().c_str()); \
ESP_LOGCONFIG(TAG, "%s Accuracy Decimals: %d", prefix, (obj)->get_accuracy_decimals()); \
if (!(obj)->get_icon().empty()) { \
@@ -37,6 +41,20 @@ enum StateClass : uint8_t {
const char *state_class_to_string(StateClass state_class);
/**
* Sensor last reset types
*/
enum LastResetType : uint8_t {
/// This sensor does not support resetting. ie, it is not accumulative
LAST_RESET_TYPE_NONE = 0,
/// This sensor is expected to never reset its value
LAST_RESET_TYPE_NEVER = 1,
/// This sensor may reset and Home Assistant will watch for this
LAST_RESET_TYPE_AUTO = 2,
};
const char *last_reset_type_to_string(LastResetType last_reset_type);
/** Base-class for all sensors.
*
* A sensor has unit of measurement and can use publish_state to send out a new value with the specified accuracy.
@@ -155,6 +173,12 @@ class Sensor : public Nameable {
*/
virtual std::string device_class();
// The Last reset type of this sensor
LastResetType last_reset_type{LAST_RESET_TYPE_NONE};
/// Manually set the Home Assistant last reset type for this sensor.
void set_last_reset_type(LastResetType last_reset_type);
/** A unique ID for this sensor, empty for no unique id. See unique ID requirements:
* https://developers.home-assistant.io/docs/en/entity_registry_index.html#unique-id-requirements
*

View File

@@ -8,9 +8,10 @@ namespace tuya {
static const char *const TAG = "tuya";
static const int COMMAND_DELAY = 50;
static const int RECEIVE_TIMEOUT = 300;
void Tuya::setup() {
this->set_interval("heartbeat", 10000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
this->set_interval("heartbeat", 15000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
}
void Tuya::loop() {
@@ -117,7 +118,13 @@ void Tuya::handle_char_(uint8_t c) {
}
void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len) {
switch ((TuyaCommandType) command) {
TuyaCommandType command_type = (TuyaCommandType) command;
if (this->expected_response_.has_value() && this->expected_response_ == command_type) {
this->expected_response_.reset();
}
switch (command_type) {
case TuyaCommandType::HEARTBEAT:
ESP_LOGV(TAG, "MCU Heartbeat (0x%02X)", buffer[0]);
this->protocol_version_ = version;
@@ -316,6 +323,25 @@ void Tuya::send_raw_command_(TuyaCommand command) {
uint8_t version = 0;
this->last_command_timestamp_ = millis();
switch (command.cmd) {
case TuyaCommandType::HEARTBEAT:
this->expected_response_ = TuyaCommandType::HEARTBEAT;
break;
case TuyaCommandType::PRODUCT_QUERY:
this->expected_response_ = TuyaCommandType::PRODUCT_QUERY;
break;
case TuyaCommandType::CONF_QUERY:
this->expected_response_ = TuyaCommandType::CONF_QUERY;
break;
case TuyaCommandType::DATAPOINT_DELIVER:
this->expected_response_ = TuyaCommandType::DATAPOINT_REPORT;
break;
case TuyaCommandType::DATAPOINT_QUERY:
this->expected_response_ = TuyaCommandType::DATAPOINT_REPORT;
break;
default:
break;
}
ESP_LOGV(TAG, "Sending Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", static_cast<uint8_t>(command.cmd),
version, hexencode(command.payload).c_str(), static_cast<uint8_t>(this->init_state_));
@@ -332,8 +358,14 @@ void Tuya::send_raw_command_(TuyaCommand command) {
void Tuya::process_command_queue_() {
uint32_t delay = millis() - this->last_command_timestamp_;
if (this->expected_response_.has_value() && delay > RECEIVE_TIMEOUT) {
this->expected_response_.reset();
}
// Left check of delay since last command in case theres ever a command sent by calling send_raw_command_ directly
if (delay > COMMAND_DELAY && !this->command_queue_.empty() && this->rx_message_.empty()) {
if (delay > COMMAND_DELAY && !this->command_queue_.empty() && this->rx_message_.empty() &&
!this->expected_response_.has_value()) {
this->send_raw_command_(command_queue_.front());
this->command_queue_.erase(command_queue_.begin());
}
@@ -345,7 +377,7 @@ void Tuya::send_command_(const TuyaCommand &command) {
}
void Tuya::send_empty_command_(TuyaCommandType command) {
send_command_(TuyaCommand{.cmd = command, .payload = std::vector<uint8_t>{0x04}});
send_command_(TuyaCommand{.cmd = command, .payload = std::vector<uint8_t>{}});
}
void Tuya::send_wifi_status_() {

View File

@@ -113,6 +113,7 @@ class Tuya : public Component, public uart::UARTDevice {
std::vector<uint8_t> rx_message_;
std::vector<uint8_t> ignore_mcu_update_on_datapoints_{};
std::vector<TuyaCommand> command_queue_;
optional<TuyaCommandType> expected_response_{};
uint8_t wifi_status_ = -1;
};

View File

@@ -1,6 +1,6 @@
"""Constants used by esphome."""
__version__ = "1.20.0b5"
__version__ = "1.20.1"
ESP_PLATFORM_ESP32 = "ESP32"
ESP_PLATFORM_ESP8266 = "ESP8266"
@@ -297,6 +297,7 @@ CONF_KEY = "key"
CONF_LAMBDA = "lambda"
CONF_LAST_CONFIDENCE = "last_confidence"
CONF_LAST_FINGER_ID = "last_finger_id"
CONF_LAST_RESET_TYPE = "last_reset_type"
CONF_LATITUDE = "latitude"
CONF_LENGTH = "length"
CONF_LEVEL = "level"
@@ -785,3 +786,10 @@ STATE_CLASS_NONE = ""
# The state represents a measurement in present time
STATE_CLASS_MEASUREMENT = "measurement"
# This sensor does not support resetting. ie, it is not accumulative
LAST_RESET_TYPE_NONE = ""
# This sensor is expected to never reset its value
LAST_RESET_TYPE_NEVER = "never"
# This sensor may reset and Home Assistant will watch for this
LAST_RESET_TYPE_AUTO = "auto"