mirror of
https://github.com/esphome/esphome.git
synced 2024-12-20 16:18:49 +01:00
commit
1a98e882dc
@ -82,7 +82,7 @@ BLE_WRITE_ACTION_SCHEMA = cv.Schema(
|
|||||||
cv.Required(CONF_ID): cv.use_id(BLEClient),
|
cv.Required(CONF_ID): cv.use_id(BLEClient),
|
||||||
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
||||||
cv.Required(CONF_CHARACTERISTIC_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):
|
async def ble_write_to_code(config, action_id, template_arg, args):
|
||||||
paren = await cg.get_variable(config[CONF_ID])
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
|
||||||
value = config[CONF_VALUE]
|
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])
|
serv_uuid128 = esp32_ble_tracker.as_reversed_hex_array(config[CONF_SERVICE_UUID])
|
||||||
cg.add(var.set_service_uuid128(serv_uuid128))
|
cg.add(var.set_service_uuid128(serv_uuid128))
|
||||||
char_uuid128 = esp32_ble_tracker.as_reversed_hex_array(
|
char_uuid128 = esp32_ble_tracker.as_reversed_hex_array(
|
||||||
|
@ -10,7 +10,7 @@ namespace esphome {
|
|||||||
namespace ble_client {
|
namespace ble_client {
|
||||||
static const char *const TAG = "ble_client.automation";
|
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) {
|
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||||
ESP_LOGW(TAG, "Cannot write to BLE characteristic - not connected");
|
ESP_LOGW(TAG, "Cannot write to BLE characteristic - not connected");
|
||||||
return;
|
return;
|
||||||
@ -29,9 +29,10 @@ void BLEWriterClientNode::write() {
|
|||||||
ESP_LOGE(TAG, "Characteristic %s does not allow writing", this->char_uuid_.to_string().c_str());
|
ESP_LOGE(TAG, "Characteristic %s does not allow writing", this->char_uuid_.to_string().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_LOGVV(TAG, "Will write %d bytes: %s", this->value_.size(), format_hex_pretty(this->value_).c_str());
|
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_,
|
esp_err_t err =
|
||||||
value_.size(), value_.data(), write_type, ESP_GATT_AUTH_REQ_NONE);
|
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) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Error writing to characteristic: %s!", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error writing to characteristic: %s!", esp_err_to_name(err));
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@ class BLEClientConnectTrigger : public Trigger<>, public BLEClientNode {
|
|||||||
void loop() override {}
|
void loop() override {}
|
||||||
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
esp_ble_gattc_cb_param_t *param) override {
|
esp_ble_gattc_cb_param_t *param) override {
|
||||||
if (event == ESP_GATTC_OPEN_EVT && param->open.status == ESP_GATT_OK)
|
if (event == ESP_GATTC_SEARCH_CMPL_EVT) {
|
||||||
this->trigger();
|
|
||||||
if (event == ESP_GATTC_SEARCH_CMPL_EVT)
|
|
||||||
this->node_state = espbt::ClientState::ESTABLISHED;
|
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||||
|
this->trigger();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,10 +42,8 @@ class BLEWriterClientNode : public BLEClientNode {
|
|||||||
ble_client_ = ble_client;
|
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(const std::vector<uint8_t> &value);
|
||||||
// Attempts to write the contents of value_ to char_uuid_.
|
|
||||||
void write();
|
|
||||||
|
|
||||||
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
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_;
|
esp_gatt_char_prop_t char_props_;
|
||||||
espbt::ESPBTUUID service_uuid_;
|
espbt::ESPBTUUID service_uuid_;
|
||||||
espbt::ESPBTUUID char_uuid_;
|
espbt::ESPBTUUID char_uuid_;
|
||||||
std::vector<uint8_t> value_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, public BLEWriterClientNode {
|
template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, public BLEWriterClientNode {
|
||||||
public:
|
public:
|
||||||
BLEClientWriteAction(BLEClient *ble_client) : BLEWriterClientNode(ble_client) {}
|
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
|
} // namespace ble_client
|
||||||
|
@ -54,6 +54,7 @@ bool BLEClient::parse_device(const espbt::ESPBTDevice &device) {
|
|||||||
this->remote_bda[3] = (addr >> 16) & 0xFF;
|
this->remote_bda[3] = (addr >> 16) & 0xFF;
|
||||||
this->remote_bda[4] = (addr >> 8) & 0xFF;
|
this->remote_bda[4] = (addr >> 8) & 0xFF;
|
||||||
this->remote_bda[5] = (addr >> 0) & 0xFF;
|
this->remote_bda[5] = (addr >> 0) & 0xFF;
|
||||||
|
this->remote_addr_type = device.get_address_type();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ void BLEClient::set_enabled(bool enabled) {
|
|||||||
|
|
||||||
void BLEClient::connect() {
|
void BLEClient::connect() {
|
||||||
ESP_LOGI(TAG, "Attempting BLE connection to %s", this->address_str().c_str());
|
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) {
|
if (ret) {
|
||||||
ESP_LOGW(TAG, "esp_ble_gattc_open error, address=%s status=%d", this->address_str().c_str(), 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);
|
this->set_states_(espbt::ClientState::IDLE);
|
||||||
|
@ -115,6 +115,7 @@ class BLEClient : public espbt::ESPBTClient, public Component {
|
|||||||
|
|
||||||
int gattc_if;
|
int gattc_if;
|
||||||
esp_bd_addr_t remote_bda;
|
esp_bd_addr_t remote_bda;
|
||||||
|
esp_ble_addr_type_t remote_addr_type;
|
||||||
uint16_t conn_id;
|
uint16_t conn_id;
|
||||||
uint64_t address;
|
uint64_t address;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
@ -1,19 +1,10 @@
|
|||||||
#include "climate_traits.h"
|
#include "climate_traits.h"
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace climate {
|
namespace climate {
|
||||||
|
|
||||||
int8_t ClimateTraits::get_temperature_accuracy_decimals() const {
|
int8_t ClimateTraits::get_temperature_accuracy_decimals() const {
|
||||||
// use printf %g to find number of digits based on temperature step
|
return step_to_accuracy_decimals(this->visual_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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace climate
|
} // namespace climate
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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) {
|
std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail start_config) {
|
||||||
return json::build_json([obj, value, start_config](JsonObject root) {
|
return json::build_json([obj, value, start_config](JsonObject root) {
|
||||||
std::string state = value_accuracy_to_string(value, obj->get_accuracy_decimals());
|
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())
|
if (!obj->get_unit_of_measurement().empty())
|
||||||
state += " " + obj->get_unit_of_measurement();
|
state += " " + obj->get_unit_of_measurement();
|
||||||
|
}
|
||||||
set_json_icon_state_value(root, obj, "sensor-" + obj->get_object_id(), state, value, start_config);
|
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["step"] = obj->traits.get_step();
|
||||||
root["mode"] = (int) obj->traits.get_mode();
|
root["mode"] = (int) obj->traits.get_mode();
|
||||||
}
|
}
|
||||||
std::string state = str_sprintf("%f", value);
|
|
||||||
root["state"] = state;
|
|
||||||
if (isnan(value)) {
|
if (isnan(value)) {
|
||||||
root["value"] = "\"NaN\"";
|
root["value"] = "\"NaN\"";
|
||||||
|
root["state"] = "NA";
|
||||||
} else {
|
} else {
|
||||||
root["value"] = value;
|
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Constants used by esphome."""
|
"""Constants used by esphome."""
|
||||||
|
|
||||||
__version__ = "2022.8.0b2"
|
__version__ = "2022.8.0b3"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
|
|
||||||
|
@ -258,6 +258,19 @@ std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) {
|
|||||||
return std::string(tmp);
|
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
|
// Colors
|
||||||
|
|
||||||
float gamma_correct(float value, float gamma) {
|
float gamma_correct(float value, float gamma) {
|
||||||
|
@ -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.
|
/// Create a string from a value and an accuracy in decimals.
|
||||||
std::string value_accuracy_to_string(float value, int8_t accuracy_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
|
/// @name Colors
|
||||||
|
@ -615,3 +615,9 @@ switch:
|
|||||||
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
|
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
|
||||||
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
|
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
|
||||||
value: [0x01, 0xab, 0xff]
|
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};
|
||||||
|
Loading…
Reference in New Issue
Block a user