mirror of
https://github.com/esphome/esphome.git
synced 2025-01-05 12:21:43 +01:00
Introduces ble_client.ble_write Action (#3398)
This commit is contained in:
parent
a12c6b5f35
commit
baad92515b
8 changed files with 157 additions and 4 deletions
|
@ -2,12 +2,15 @@ import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import esp32_ble_tracker
|
from esphome.components import esp32_ble_tracker
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_CHARACTERISTIC_UUID,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_MAC_ADDRESS,
|
CONF_MAC_ADDRESS,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_ON_CONNECT,
|
CONF_ON_CONNECT,
|
||||||
CONF_ON_DISCONNECT,
|
CONF_ON_DISCONNECT,
|
||||||
|
CONF_SERVICE_UUID,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
|
CONF_VALUE,
|
||||||
)
|
)
|
||||||
from esphome import automation
|
from esphome import automation
|
||||||
|
|
||||||
|
@ -27,6 +30,8 @@ BLEClientConnectTrigger = ble_client_ns.class_(
|
||||||
BLEClientDisconnectTrigger = ble_client_ns.class_(
|
BLEClientDisconnectTrigger = ble_client_ns.class_(
|
||||||
"BLEClientDisconnectTrigger", automation.Trigger.template(BLEClientNodeConstRef)
|
"BLEClientDisconnectTrigger", automation.Trigger.template(BLEClientNodeConstRef)
|
||||||
)
|
)
|
||||||
|
# Actions
|
||||||
|
BLEWriteAction = ble_client_ns.class_("BLEClientWriteAction", automation.Action)
|
||||||
|
|
||||||
# Espressif platformio framework is built with MAX_BLE_CONN to 3, so
|
# Espressif platformio framework is built with MAX_BLE_CONN to 3, so
|
||||||
# enforce this in yaml checks.
|
# enforce this in yaml checks.
|
||||||
|
@ -72,6 +77,33 @@ async def register_ble_node(var, config):
|
||||||
cg.add(parent.register_ble_node(var))
|
cg.add(parent.register_ble_node(var))
|
||||||
|
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"ble_client.ble_write", BLEWriteAction, BLE_WRITE_ACTION_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))
|
||||||
|
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(
|
||||||
|
config[CONF_CHARACTERISTIC_UUID]
|
||||||
|
)
|
||||||
|
cg.add(var.set_char_uuid128(char_uuid128))
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
74
esphome/components/ble_client/automation.cpp
Normal file
74
esphome/components/ble_client/automation.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include "automation.h"
|
||||||
|
|
||||||
|
#include <esp_gap_ble_api.h>
|
||||||
|
#include <esp_gattc_api.h>
|
||||||
|
#include <esp_bt_defs.h>
|
||||||
|
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ble_client {
|
||||||
|
static const char *const TAG = "ble_client.automation";
|
||||||
|
|
||||||
|
void BLEWriterClientNode::write() {
|
||||||
|
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||||
|
ESP_LOGW(TAG, "Cannot write to BLE characteristic - not connected");
|
||||||
|
return;
|
||||||
|
} else if (this->ble_char_handle_ == 0) {
|
||||||
|
ESP_LOGW(TAG, "Cannot write to BLE characteristic - characteristic not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
esp_gatt_write_type_t write_type;
|
||||||
|
if (this->char_props_ & ESP_GATT_CHAR_PROP_BIT_WRITE) {
|
||||||
|
write_type = ESP_GATT_WRITE_TYPE_RSP;
|
||||||
|
ESP_LOGD(TAG, "Write type: ESP_GATT_WRITE_TYPE_RSP");
|
||||||
|
} else if (this->char_props_ & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) {
|
||||||
|
write_type = ESP_GATT_WRITE_TYPE_NO_RSP;
|
||||||
|
ESP_LOGD(TAG, "Write type: ESP_GATT_WRITE_TYPE_NO_RSP");
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Error writing to characteristic: %s!", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEWriterClientNode::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
|
esp_ble_gattc_cb_param_t *param) {
|
||||||
|
switch (event) {
|
||||||
|
case ESP_GATTC_REG_EVT:
|
||||||
|
break;
|
||||||
|
case ESP_GATTC_OPEN_EVT:
|
||||||
|
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||||
|
ESP_LOGD(TAG, "Connection established with %s", ble_client_->address_str().c_str());
|
||||||
|
break;
|
||||||
|
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||||
|
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
|
||||||
|
if (chr == nullptr) {
|
||||||
|
ESP_LOGW("ble_write_action", "Characteristic %s was not found in service %s",
|
||||||
|
this->char_uuid_.to_string().c_str(), this->service_uuid_.to_string().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->ble_char_handle_ = chr->handle;
|
||||||
|
this->char_props_ = chr->properties;
|
||||||
|
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||||
|
ESP_LOGD(TAG, "Found characteristic %s on device %s", this->char_uuid_.to_string().c_str(),
|
||||||
|
ble_client_->address_str().c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_GATTC_DISCONNECT_EVT:
|
||||||
|
this->node_state = espbt::ClientState::IDLE;
|
||||||
|
this->ble_char_handle_ = 0;
|
||||||
|
ESP_LOGD(TAG, "Disconnected from %s", ble_client_->address_str().c_str());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ble_client
|
||||||
|
} // namespace esphome
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/components/ble_client/ble_client.h"
|
#include "esphome/components/ble_client/ble_client.h"
|
||||||
|
|
||||||
|
@ -33,6 +35,41 @@ class BLEClientDisconnectTrigger : public Trigger<>, public BLEClientNode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BLEWriterClientNode : public BLEClientNode {
|
||||||
|
public:
|
||||||
|
BLEWriterClientNode(BLEClient *ble_client) {
|
||||||
|
ble_client->register_ble_node(this);
|
||||||
|
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();
|
||||||
|
|
||||||
|
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
|
|
||||||
|
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||||
|
|
||||||
|
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
|
esp_ble_gattc_cb_param_t *param) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BLEClient *ble_client_;
|
||||||
|
int ble_char_handle_ = 0;
|
||||||
|
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(); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ble_client
|
} // namespace ble_client
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import ble_client, esp32_ble_tracker, output
|
from esphome.components import ble_client, esp32_ble_tracker, output
|
||||||
from esphome.const import CONF_ID, CONF_SERVICE_UUID
|
from esphome.const import CONF_CHARACTERISTIC_UUID, CONF_ID, CONF_SERVICE_UUID
|
||||||
|
|
||||||
from .. import ble_client_ns
|
from .. import ble_client_ns
|
||||||
|
|
||||||
DEPENDENCIES = ["ble_client"]
|
DEPENDENCIES = ["ble_client"]
|
||||||
|
|
||||||
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
|
|
||||||
CONF_REQUIRE_RESPONSE = "require_response"
|
CONF_REQUIRE_RESPONSE = "require_response"
|
||||||
|
|
||||||
BLEBinaryOutput = ble_client_ns.class_(
|
BLEBinaryOutput = ble_client_ns.class_(
|
||||||
|
|
|
@ -2,6 +2,7 @@ import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import sensor, ble_client, esp32_ble_tracker
|
from esphome.components import sensor, ble_client, esp32_ble_tracker
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_CHARACTERISTIC_UUID,
|
||||||
CONF_LAMBDA,
|
CONF_LAMBDA,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_SERVICE_UUID,
|
CONF_SERVICE_UUID,
|
||||||
|
@ -11,7 +12,6 @@ from .. import ble_client_ns
|
||||||
|
|
||||||
DEPENDENCIES = ["ble_client"]
|
DEPENDENCIES = ["ble_client"]
|
||||||
|
|
||||||
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
|
|
||||||
CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
||||||
|
|
||||||
CONF_NOTIFY = "notify"
|
CONF_NOTIFY = "notify"
|
||||||
|
|
|
@ -2,6 +2,7 @@ import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import text_sensor, ble_client, esp32_ble_tracker
|
from esphome.components import text_sensor, ble_client, esp32_ble_tracker
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_CHARACTERISTIC_UUID,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_SERVICE_UUID,
|
CONF_SERVICE_UUID,
|
||||||
|
@ -11,7 +12,6 @@ from .. import ble_client_ns
|
||||||
|
|
||||||
DEPENDENCIES = ["ble_client"]
|
DEPENDENCIES = ["ble_client"]
|
||||||
|
|
||||||
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
|
|
||||||
CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
CONF_DESCRIPTOR_UUID = "descriptor_uuid"
|
||||||
|
|
||||||
CONF_NOTIFY = "notify"
|
CONF_NOTIFY = "notify"
|
||||||
|
|
|
@ -88,6 +88,7 @@ CONF_CERTIFICATE_AUTHORITY = "certificate_authority"
|
||||||
CONF_CHANGE_MODE_EVERY = "change_mode_every"
|
CONF_CHANGE_MODE_EVERY = "change_mode_every"
|
||||||
CONF_CHANNEL = "channel"
|
CONF_CHANNEL = "channel"
|
||||||
CONF_CHANNELS = "channels"
|
CONF_CHANNELS = "channels"
|
||||||
|
CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
|
||||||
CONF_CHIPSET = "chipset"
|
CONF_CHIPSET = "chipset"
|
||||||
CONF_CLEAR_IMPEDANCE = "clear_impedance"
|
CONF_CLEAR_IMPEDANCE = "clear_impedance"
|
||||||
CONF_CLIENT_ID = "client_id"
|
CONF_CLIENT_ID = "client_id"
|
||||||
|
|
|
@ -605,3 +605,13 @@ cap1188:
|
||||||
touch_threshold: 0x20
|
touch_threshold: 0x20
|
||||||
allow_multiple_touches: true
|
allow_multiple_touches: true
|
||||||
reset_pin: 14
|
reset_pin: 14
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: template
|
||||||
|
name: "Test BLE Write Action"
|
||||||
|
turn_on_action:
|
||||||
|
- ble_client.ble_write:
|
||||||
|
id: airthings01
|
||||||
|
service_uuid: F61E3BE9-2826-A81B-970A-4D4DECFABBAE
|
||||||
|
characteristic_uuid: 6490FAFE-0734-732C-8705-91B653A081FC
|
||||||
|
value: [0x01, 0xab, 0xff]
|
||||||
|
|
Loading…
Reference in a new issue