1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-14 13:55:45 +00:00

Compare commits

..

12 Commits

Author SHA1 Message Date
Jesse Hills
1a98e882dc Merge pull request #3718 from esphome/bump-2022.8.0b3
2022.8.0b3
2022-08-16 15:16:37 +12:00
Jesse Hills
c943d84036 Bump version to 2022.8.0b3 2022-08-16 14:47:48 +12:00
rbaron
d07a6704d5 Makes ble_client.ble_write's action value templatable (#3715) 2022-08-16 14:47:48 +12:00
rbaron
8cfcd5904c Fixes BLE remote address type when connecting (#3702) 2022-08-16 14:47:48 +12:00
buxtronix
fb8846bb45 Only trigger ble_client on_connect after discovering services (#3710) 2022-08-16 14:47:48 +12:00
anatoly-savchenkov
0d0733dd94 Webui small fixes (#3713) 2022-08-16 14:47:47 +12:00
Jesse Hills
a67d58948d Merge pull request #3714 from esphome/bump-2022.8.0b2
2022.8.0b2
2022-08-15 09:08:44 +12:00
Jesse Hills
84c051d097 Bump version to 2022.8.0b2 2022-08-15 08:23:35 +12:00
NP v/d Spek
b918abfd54 add gradient color V2.0 (#3709) 2022-08-15 08:23:35 +12:00
Peter Galantha
7f41b7cd93 Add state_class total (#3608)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2022-08-15 08:23:35 +12:00
Jesse Hills
4759b4fe2e Add vector include (#3707) 2022-08-15 08:23:35 +12:00
anatoly-savchenkov
e2c8e69d12 Improve Web view for Climate components (#3706) 2022-08-15 08:23:35 +12:00
20 changed files with 700 additions and 605 deletions

View File

@@ -473,6 +473,7 @@ enum SensorStateClass {
STATE_CLASS_NONE = 0;
STATE_CLASS_MEASUREMENT = 1;
STATE_CLASS_TOTAL_INCREASING = 2;
STATE_CLASS_TOTAL = 3;
}
enum SensorLastResetType {

View File

@@ -108,6 +108,8 @@ template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::Sens
return "STATE_CLASS_MEASUREMENT";
case enums::STATE_CLASS_TOTAL_INCREASING:
return "STATE_CLASS_TOTAL_INCREASING";
case enums::STATE_CLASS_TOTAL:
return "STATE_CLASS_TOTAL";
default:
return "UNKNOWN";
}

View File

@@ -53,6 +53,7 @@ enum SensorStateClass : uint32_t {
STATE_CLASS_NONE = 0,
STATE_CLASS_MEASUREMENT = 1,
STATE_CLASS_TOTAL_INCREASING = 2,
STATE_CLASS_TOTAL = 3,
};
enum SensorLastResetType : uint32_t {
LAST_RESET_NONE = 0,

View File

@@ -82,7 +82,7 @@ BLE_WRITE_ACTION_SCHEMA = cv.Schema(
cv.Required(CONF_ID): cv.use_id(BLEClient),
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
cv.Required(CONF_VALUE): cv.ensure_list(cv.hex_uint8_t),
cv.Required(CONF_VALUE): cv.templatable(cv.ensure_list(cv.hex_uint8_t)),
}
)
@@ -93,8 +93,14 @@ BLE_WRITE_ACTION_SCHEMA = cv.Schema(
async def ble_write_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
value = config[CONF_VALUE]
cg.add(var.set_value(value))
if cg.is_template(value):
templ = await cg.templatable(value, args, cg.std_vector.template(cg.uint8))
cg.add(var.set_value_template(templ))
else:
cg.add(var.set_value_simple(value))
serv_uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID])
cg.add(var.set_service_uuid128(serv_uuid128))
char_uuid128 = esp32_ble_tracker.as_reversed_hex_array(

View File

@@ -10,7 +10,7 @@ namespace esphome {
namespace ble_client {
static const char *const TAG = "ble_client.automation";
void BLEWriterClientNode::write() {
void BLEWriterClientNode::write(const std::vector<uint8_t> &value) {
if (this->node_state != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "Cannot write to BLE characteristic - not connected");
return;
@@ -29,9 +29,10 @@ void BLEWriterClientNode::write() {
ESP_LOGE(TAG, "Characteristic %s does not allow writing", this->char_uuid_.to_string().c_str());
return;
}
ESP_LOGVV(TAG, "Will write %d bytes: %s", this->value_.size(), format_hex_pretty(this->value_).c_str());
esp_err_t err = esp_ble_gattc_write_char(this->parent()->gattc_if, this->parent()->conn_id, this->ble_char_handle_,
value_.size(), value_.data(), write_type, ESP_GATT_AUTH_REQ_NONE);
ESP_LOGVV(TAG, "Will write %d bytes: %s", value.size(), format_hex_pretty(value).c_str());
esp_err_t err =
esp_ble_gattc_write_char(this->parent()->gattc_if, this->parent()->conn_id, this->ble_char_handle_, value.size(),
const_cast<uint8_t *>(value.data()), write_type, ESP_GATT_AUTH_REQ_NONE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error writing to characteristic: %s!", esp_err_to_name(err));
}

View File

@@ -15,10 +15,10 @@ class BLEClientConnectTrigger : public Trigger<>, public BLEClientNode {
void loop() override {}
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override {
if (event == ESP_GATTC_OPEN_EVT && param->open.status == ESP_GATT_OK)
this->trigger();
if (event == ESP_GATTC_SEARCH_CMPL_EVT)
if (event == ESP_GATTC_SEARCH_CMPL_EVT) {
this->node_state = espbt::ClientState::ESTABLISHED;
this->trigger();
}
}
};
@@ -42,10 +42,8 @@ class BLEWriterClientNode : public BLEClientNode {
ble_client_ = ble_client;
}
void set_value(std::vector<uint8_t> value) { value_ = std::move(value); }
// Attempts to write the contents of value_ to char_uuid_.
void write();
// Attempts to write the contents of value to char_uuid_.
void write(const std::vector<uint8_t> &value);
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
@@ -60,14 +58,34 @@ class BLEWriterClientNode : public BLEClientNode {
esp_gatt_char_prop_t char_props_;
espbt::ESPBTUUID service_uuid_;
espbt::ESPBTUUID char_uuid_;
std::vector<uint8_t> value_;
};
template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, public BLEWriterClientNode {
public:
BLEClientWriteAction(BLEClient *ble_client) : BLEWriterClientNode(ble_client) {}
void play(Ts... x) override { return write(); }
void play(Ts... x) override {
if (has_simple_value_) {
return write(this->value_simple_);
} else {
return write(this->value_template_(x...));
}
}
void set_value_template(std::function<std::vector<uint8_t>(Ts...)> func) {
this->value_template_ = std::move(func);
has_simple_value_ = false;
}
void set_value_simple(const std::vector<uint8_t> &value) {
this->value_simple_ = value;
has_simple_value_ = true;
}
private:
bool has_simple_value_ = true;
std::vector<uint8_t> value_simple_;
std::function<std::vector<uint8_t>(Ts...)> value_template_{};
};
} // namespace ble_client

View File

@@ -54,6 +54,7 @@ bool BLEClient::parse_device(const espbt::ESPBTDevice &device) {
this->remote_bda[3] = (addr >> 16) & 0xFF;
this->remote_bda[4] = (addr >> 8) & 0xFF;
this->remote_bda[5] = (addr >> 0) & 0xFF;
this->remote_addr_type = device.get_address_type();
return true;
}
@@ -83,7 +84,7 @@ void BLEClient::set_enabled(bool enabled) {
void BLEClient::connect() {
ESP_LOGI(TAG, "Attempting BLE connection to %s", this->address_str().c_str());
auto ret = esp_ble_gattc_open(this->gattc_if, this->remote_bda, BLE_ADDR_TYPE_PUBLIC, true);
auto ret = esp_ble_gattc_open(this->gattc_if, this->remote_bda, this->remote_addr_type, true);
if (ret) {
ESP_LOGW(TAG, "esp_ble_gattc_open error, address=%s status=%d", this->address_str().c_str(), ret);
this->set_states_(espbt::ClientState::IDLE);

View File

@@ -115,6 +115,7 @@ class BLEClient : public espbt::ESPBTClient, public Component {
int gattc_if;
esp_bd_addr_t remote_bda;
esp_ble_addr_type_t remote_addr_type;
uint16_t conn_id;
uint64_t address;
bool enabled;

View File

@@ -1,19 +1,10 @@
#include "climate_traits.h"
#include <cstdio>
namespace esphome {
namespace climate {
int8_t ClimateTraits::get_temperature_accuracy_decimals() const {
// use printf %g to find number of digits based on temperature step
char buf[32];
sprintf(buf, "%.5g", this->visual_temperature_step_);
std::string str{buf};
size_t dot_pos = str.find('.');
if (dot_pos == std::string::npos)
return 0;
return str.length() - dot_pos - 1;
return step_to_accuracy_decimals(this->visual_temperature_step_);
}
} // namespace climate

View File

@@ -4,9 +4,10 @@
#include "esphome/core/component.h"
#include <map>
#include <memory>
#include <set>
#include <map>
#include <vector>
class UDP;

View File

@@ -109,6 +109,7 @@ STATE_CLASSES = {
"": StateClasses.STATE_CLASS_NONE,
"measurement": StateClasses.STATE_CLASS_MEASUREMENT,
"total_increasing": StateClasses.STATE_CLASS_TOTAL_INCREASING,
"total": StateClasses.STATE_CLASS_TOTAL,
}
validate_state_class = cv.enum(STATE_CLASSES, lower=True, space="_")

View File

@@ -12,6 +12,8 @@ std::string state_class_to_string(StateClass state_class) {
return "measurement";
case STATE_CLASS_TOTAL_INCREASING:
return "total_increasing";
case STATE_CLASS_TOTAL:
return "total";
case STATE_CLASS_NONE:
default:
return "";

View File

@@ -36,6 +36,7 @@ enum StateClass : uint8_t {
STATE_CLASS_NONE = 0,
STATE_CLASS_MEASUREMENT = 1,
STATE_CLASS_TOTAL_INCREASING = 2,
STATE_CLASS_TOTAL = 3,
};
std::string state_class_to_string(StateClass state_class);

File diff suppressed because it is too large Load Diff

View File

@@ -360,9 +360,14 @@ void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlM
}
std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail start_config) {
return json::build_json([obj, value, start_config](JsonObject root) {
std::string state = value_accuracy_to_string(value, obj->get_accuracy_decimals());
if (!obj->get_unit_of_measurement().empty())
state += " " + obj->get_unit_of_measurement();
std::string state;
if (isnan(value)) {
state = "NA";
} else {
state = value_accuracy_to_string(value, obj->get_accuracy_decimals());
if (!obj->get_unit_of_measurement().empty())
state += " " + obj->get_unit_of_measurement();
}
set_json_icon_state_value(root, obj, "sensor-" + obj->get_object_id(), state, value, start_config);
});
}
@@ -719,12 +724,15 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail
root["step"] = obj->traits.get_step();
root["mode"] = (int) obj->traits.get_mode();
}
std::string state = str_sprintf("%f", value);
root["state"] = state;
if (isnan(value)) {
root["value"] = "\"NaN\"";
root["state"] = "NA";
} else {
root["value"] = value;
std::string state = value_accuracy_to_string(value, step_to_accuracy_decimals(obj->traits.get_step()));
if (!obj->traits.get_unit_of_measurement().empty())
state += " " + obj->traits.get_unit_of_measurement();
root["state"] = state;
}
});
}
@@ -839,6 +847,7 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
return json::build_json([obj, start_config](JsonObject root) {
set_json_id(root, obj, "climate-" + obj->get_object_id(), start_config);
const auto traits = obj->get_traits();
int8_t accuracy = traits.get_temperature_accuracy_decimals();
char __buf[16];
if (start_config == DETAIL_ALL) {
@@ -873,12 +882,15 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
}
}
bool has_state = false;
root["mode"] = PSTR_LOCAL(climate_mode_to_string(obj->mode));
root["max_temp"] = traits.get_visual_max_temperature();
root["min_temp"] = traits.get_visual_min_temperature();
root["max_temp"] = value_accuracy_to_string(traits.get_visual_max_temperature(), accuracy);
root["min_temp"] = value_accuracy_to_string(traits.get_visual_min_temperature(), accuracy);
root["step"] = traits.get_visual_temperature_step();
if (traits.get_supports_action()) {
root["action"] = PSTR_LOCAL(climate_action_to_string(obj->action));
root["state"] = root["action"];
has_state = true;
}
if (traits.get_supports_fan_modes() && obj->fan_mode.has_value()) {
root["fan_mode"] = PSTR_LOCAL(climate_fan_mode_to_string(obj->fan_mode.value()));
@@ -896,14 +908,23 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
root["swing_mode"] = PSTR_LOCAL(climate_swing_mode_to_string(obj->swing_mode));
}
if (traits.get_supports_current_temperature()) {
root["current_temperature"] = obj->current_temperature;
if (!std::isnan(obj->current_temperature)) {
root["current_temperature"] = value_accuracy_to_string(obj->current_temperature, accuracy);
} else {
root["current_temperature"] = "NA";
}
}
if (traits.get_supports_two_point_target_temperature()) {
root["current_temperature_low"] = obj->target_temperature_low;
root["current_temperature_high"] = obj->target_temperature_low;
root["target_temperature_low"] = value_accuracy_to_string(obj->target_temperature_low, accuracy);
root["target_temperature_high"] = value_accuracy_to_string(obj->target_temperature_high, accuracy);
if (!has_state) {
root["state"] =
value_accuracy_to_string((obj->target_temperature_high + obj->target_temperature_low) / 2.0f, accuracy);
}
} else {
root["target_temperature"] = obj->target_temperature;
root["state"] = obj->target_temperature;
root["target_temperature"] = value_accuracy_to_string(obj->target_temperature, accuracy);
if (!has_state)
root["state"] = root["target_temperature"];
}
});
}

View File

@@ -1,6 +1,6 @@
"""Constants used by esphome."""
__version__ = "2022.8.0b1"
__version__ = "2022.8.0b3"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
@@ -956,6 +956,9 @@ STATE_CLASS_MEASUREMENT = "measurement"
# The state represents a total that only increases, a decrease is considered a reset.
STATE_CLASS_TOTAL_INCREASING = "total_increasing"
# The state represents a total amount that can both increase and decrease, e.g. a net energy meter.
STATE_CLASS_TOTAL = "total"
KEY_CORE = "core"
KEY_TARGET_PLATFORM = "target_platform"
KEY_TARGET_FRAMEWORK = "target_framework"

View File

@@ -139,9 +139,19 @@ struct Color {
return Color(uint8_t((uint16_t(r) * 255U / max_rgb)), uint8_t((uint16_t(g) * 255U / max_rgb)),
uint8_t((uint16_t(b) * 255U / max_rgb)), w);
}
Color fade_to_white(uint8_t amnt) { return Color(255, 255, 255, 255) - (*this * amnt); }
Color fade_to_black(uint8_t amnt) { return *this * amnt; }
Color gradient(const Color &to_color, uint8_t amnt) { return (*this * amnt) + (to_color * (255 - amnt)); }
Color gradient(const Color &to_color, uint8_t amnt) {
Color new_color;
float amnt_f = float(amnt) / 255.0f;
new_color.r = amnt_f * (to_color.r - (*this).r) + (*this).r;
new_color.g = amnt_f * (to_color.g - (*this).g) + (*this).g;
new_color.b = amnt_f * (to_color.b - (*this).b) + (*this).b;
new_color.w = amnt_f * (to_color.w - (*this).w) + (*this).w;
return new_color;
}
Color fade_to_white(uint8_t amnt) { return (*this).gradient(Color::WHITE, amnt); }
Color fade_to_black(uint8_t amnt) { return (*this).gradient(Color::BLACK, amnt); }
Color lighten(uint8_t delta) { return *this + delta; }
Color darken(uint8_t delta) { return *this - delta; }

View File

@@ -258,6 +258,19 @@ std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) {
return std::string(tmp);
}
int8_t step_to_accuracy_decimals(float step) {
// use printf %g to find number of digits based on temperature step
char buf[32];
sprintf(buf, "%.5g", step);
std::string str{buf};
size_t dot_pos = str.find('.');
if (dot_pos == std::string::npos)
return 0;
return str.length() - dot_pos - 1;
}
// Colors
float gamma_correct(float value, float gamma) {

View File

@@ -415,6 +415,9 @@ ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const ch
/// Create a string from a value and an accuracy in decimals.
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals);
/// Derive accuracy in decimals from an increment step.
int8_t step_to_accuracy_decimals(float step);
///@}
/// @name Colors

View File

@@ -615,3 +615,9 @@ switch:
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
value: [0x01, 0xab, 0xff]
- ble_client.ble_write:
id: airthings01
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
value: !lambda |-
return {0x13, 0x37};