mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 09:44:12 +01:00
Add on_write callback and set_value automations
This commit is contained in:
parent
05617fa9d9
commit
0b0766654d
4 changed files with 76 additions and 36 deletions
|
@ -1,6 +1,7 @@
|
||||||
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_ID, CONF_MODEL
|
from esphome.const import CONF_ID, CONF_MODEL, CONF_UUID, CONF_SERVICES, CONF_VALUE, CONF_MAX_LENGTH, CONF_ON_CLIENT_CONNECTED, CONF_ON_CLIENT_DISCONNECTED
|
||||||
from esphome.components import esp32_ble
|
from esphome.components import esp32_ble
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||||
|
@ -12,15 +13,12 @@ DEPENDENCIES = ["esp32"]
|
||||||
|
|
||||||
CONF_MANUFACTURER = "manufacturer"
|
CONF_MANUFACTURER = "manufacturer"
|
||||||
CONF_MANUFACTURER_DATA = "manufacturer_data"
|
CONF_MANUFACTURER_DATA = "manufacturer_data"
|
||||||
CONF_SERVICES = "services"
|
|
||||||
CONF_UUID = "uuid"
|
|
||||||
CONF_ADVERTISE = "advertise"
|
CONF_ADVERTISE = "advertise"
|
||||||
CONF_NUM_HANDLES = "num_handles"
|
CONF_NUM_HANDLES = "num_handles"
|
||||||
|
CONF_ON_WRITE = "on_write"
|
||||||
CONF_CHARACTERISTICS = "characteristics"
|
CONF_CHARACTERISTICS = "characteristics"
|
||||||
CONF_PROPERTIES = "properties"
|
CONF_PROPERTIES = "properties"
|
||||||
CONF_VALUE = "value"
|
|
||||||
CONF_DESCRIPTORS = "descriptors"
|
CONF_DESCRIPTORS = "descriptors"
|
||||||
CONF_MAX_LENGTH = "max_length"
|
|
||||||
|
|
||||||
esp32_ble_server_ns = cg.esphome_ns.namespace("esp32_ble_server")
|
esp32_ble_server_ns = cg.esphome_ns.namespace("esp32_ble_server")
|
||||||
ESPBTUUID_ns = cg.esphome_ns.namespace("esp32_ble").namespace("ESPBTUUID")
|
ESPBTUUID_ns = cg.esphome_ns.namespace("esp32_ble").namespace("ESPBTUUID")
|
||||||
|
@ -31,9 +29,11 @@ BLEServer = esp32_ble_server_ns.class_(
|
||||||
esp32_ble.GATTsEventHandler,
|
esp32_ble.GATTsEventHandler,
|
||||||
cg.Parented.template(esp32_ble.ESP32BLE),
|
cg.Parented.template(esp32_ble.ESP32BLE),
|
||||||
)
|
)
|
||||||
|
BLEServerAutomationInterface = esp32_ble_server_ns.namespace("BLEServerAutomationInterface")
|
||||||
BLEDescriptor = esp32_ble_server_ns.class_("BLEDescriptor")
|
BLEDescriptor = esp32_ble_server_ns.class_("BLEDescriptor")
|
||||||
BLECharacteristic = esp32_ble_server_ns.class_("BLECharacteristic")
|
BLECharacteristic = esp32_ble_server_ns.class_("BLECharacteristic")
|
||||||
BLEService = esp32_ble_server_ns.class_("BLEService")
|
BLEService = esp32_ble_server_ns.class_("BLEService")
|
||||||
|
BLECharacteristicSetValueAction = BLEServerAutomationInterface.class_("BLECharacteristicSetValueAction", automation.Action)
|
||||||
|
|
||||||
|
|
||||||
def validate_uuid(value):
|
def validate_uuid(value):
|
||||||
|
@ -85,6 +85,7 @@ SERVICE_CHARACTERISTIC_SCHEMA = cv.Schema(
|
||||||
cv.Required(CONF_PROPERTIES): PROPERTIES_SCHEMA,
|
cv.Required(CONF_PROPERTIES): PROPERTIES_SCHEMA,
|
||||||
cv.Optional(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA,
|
cv.Optional(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA,
|
||||||
cv.Optional(CONF_DESCRIPTORS, default=[]): cv.ensure_list(SERVICE_CHARACTERISTIC_DESCRIPTOR_SCHEMA),
|
cv.Optional(CONF_DESCRIPTORS, default=[]): cv.ensure_list(SERVICE_CHARACTERISTIC_DESCRIPTOR_SCHEMA),
|
||||||
|
cv.Optional(CONF_ON_WRITE): automation.validate_automation({cv.GenerateID(): cv.declare_id(BLECharacteristic)}, single=True),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -141,9 +142,9 @@ def parse_value(value):
|
||||||
|
|
||||||
def calculate_num_handles(service_config):
|
def calculate_num_handles(service_config):
|
||||||
total = 1
|
total = 1
|
||||||
for characteristic in service_config[CONF_CHARACTERISTICS]:
|
for char_conf in service_config[CONF_CHARACTERISTICS]:
|
||||||
total += 2 # One for the characteristic itself and one for the value
|
total += 2 # One for the char_conf itself and one for the value
|
||||||
for _ in characteristic[CONF_DESCRIPTORS]:
|
for _ in char_conf[CONF_DESCRIPTORS]:
|
||||||
total += 1
|
total += 1
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
@ -171,22 +172,35 @@ async def to_code(config):
|
||||||
service_config[CONF_ADVERTISE],
|
service_config[CONF_ADVERTISE],
|
||||||
num_handles,
|
num_handles,
|
||||||
))
|
))
|
||||||
for characteristic in service_config[CONF_CHARACTERISTICS]:
|
for char_conf in service_config[CONF_CHARACTERISTICS]:
|
||||||
char_var = cg.Pvariable(characteristic[CONF_ID], service_var.create_characteristic(
|
char_var = cg.Pvariable(char_conf[CONF_ID], service_var.create_characteristic(
|
||||||
parse_uuid(characteristic[CONF_UUID]),
|
parse_uuid(char_conf[CONF_UUID]),
|
||||||
parse_properties(characteristic[CONF_PROPERTIES])
|
parse_properties(char_conf[CONF_PROPERTIES])
|
||||||
))
|
))
|
||||||
if CONF_VALUE in characteristic:
|
if CONF_ON_WRITE in char_conf:
|
||||||
cg.add(char_var.set_value(parse_value(characteristic[CONF_VALUE])))
|
on_write_conf = char_conf[CONF_ON_WRITE]
|
||||||
for descriptor in characteristic[CONF_DESCRIPTORS]:
|
if "WRITE" not in char_conf[CONF_PROPERTIES]:
|
||||||
max_length = descriptor[CONF_MAX_LENGTH]
|
raise cv.Invalid("on_write requires the WRITE property")
|
||||||
|
await automation.build_automation(BLEServerAutomationInterface.create_on_write_trigger(char_var), [(cg.std_string, "x")], on_write_conf)
|
||||||
|
if CONF_VALUE in char_conf:
|
||||||
|
cg.add(char_var.set_value(parse_value(char_conf[CONF_VALUE])))
|
||||||
|
for descriptor_conf in char_conf[CONF_DESCRIPTORS]:
|
||||||
|
max_length = descriptor_conf[CONF_MAX_LENGTH]
|
||||||
# If max_length is 0, calculate the optimal length based on the value
|
# If max_length is 0, calculate the optimal length based on the value
|
||||||
if max_length == 0:
|
if max_length == 0:
|
||||||
max_length = len(parse_value(descriptor[CONF_VALUE]))
|
max_length = len(parse_value(descriptor_conf[CONF_VALUE]))
|
||||||
desc_var = cg.new_Pvariable(descriptor[CONF_ID], parse_uuid(descriptor[CONF_UUID]), max_length)
|
desc_var = cg.new_Pvariable(descriptor_conf[CONF_ID], parse_uuid(descriptor_conf[CONF_UUID]), max_length)
|
||||||
if CONF_VALUE in descriptor:
|
if CONF_VALUE in descriptor_conf:
|
||||||
cg.add(desc_var.set_value(parse_value(descriptor[CONF_VALUE])))
|
cg.add(desc_var.set_value(parse_value(descriptor_conf[CONF_VALUE])))
|
||||||
cg.add(var.enqueue_start_service(service_var))
|
cg.add(var.enqueue_start_service(service_var))
|
||||||
cg.add_define("USE_ESP32_BLE_SERVER")
|
cg.add_define("USE_ESP32_BLE_SERVER")
|
||||||
if CORE.using_esp_idf:
|
if CORE.using_esp_idf:
|
||||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||||
|
|
||||||
|
@automation.register_action("ble_server.characteristic_set_value", BLECharacteristicSetValueAction, cv.Schema({
|
||||||
|
cv.Required(CONF_ID): cv.use_id(BLECharacteristic),
|
||||||
|
cv.Required(CONF_VALUE): CHARACTERISTIC_VALUE_SCHEMA,
|
||||||
|
}))
|
||||||
|
async def ble_enable_to_code(config, action_id, template_arg, args):
|
||||||
|
char_var = await cg.get_variable(config[CONF_ID])
|
||||||
|
return cg.new_Pvariable(action_id, template_arg, char_var)
|
||||||
|
|
|
@ -17,6 +17,15 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace esp32_ble_server {
|
namespace esp32_ble_server {
|
||||||
|
|
||||||
|
Trigger<std::string> *BLEServerAutomationInterface::create_on_write_trigger(BLECharacteristic *characteristic) {
|
||||||
|
Trigger<std::string> *on_write_trigger = new Trigger<std::string>();
|
||||||
|
characteristic->on_write([on_write_trigger](const std::vector<uint8_t> &data) {
|
||||||
|
std::string value(data.begin(), data.end());
|
||||||
|
on_write_trigger->trigger(value);
|
||||||
|
});
|
||||||
|
return on_write_trigger;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *const TAG = "esp32_ble_server";
|
static const char *const TAG = "esp32_ble_server";
|
||||||
|
|
||||||
static const uint16_t DEVICE_INFORMATION_SERVICE_UUID = 0x180A;
|
static const uint16_t DEVICE_INFORMATION_SERVICE_UUID = 0x180A;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "esphome/components/esp32_ble/ble_advertising.h"
|
#include "esphome/components/esp32_ble/ble_advertising.h"
|
||||||
#include "esphome/components/esp32_ble/ble_uuid.h"
|
#include "esphome/components/esp32_ble/ble_uuid.h"
|
||||||
#include "esphome/components/esp32_ble/queue.h"
|
#include "esphome/components/esp32_ble/queue.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/preferences.h"
|
#include "esphome/core/preferences.h"
|
||||||
|
@ -25,6 +26,21 @@ namespace esp32_ble_server {
|
||||||
|
|
||||||
using namespace esp32_ble;
|
using namespace esp32_ble;
|
||||||
|
|
||||||
|
class BLEServerAutomationInterface {
|
||||||
|
public:
|
||||||
|
static Trigger<std::string> *create_on_write_trigger(BLECharacteristic *characteristic);
|
||||||
|
|
||||||
|
template<typename... Ts> class BLECharacteristicSetValueAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
BLECharacteristicSetValueAction(BLECharacteristic *characteristic) : characteristic_(characteristic) {}
|
||||||
|
void play(Ts... x) override { this->characteristic_->set_value(x...); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BLECharacteristic *characteristic_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> {
|
class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|
|
@ -296,27 +296,28 @@ esp32_ble_server:
|
||||||
model: Test5
|
model: Test5
|
||||||
services:
|
services:
|
||||||
- uuid: 2a24b789-7aab-4535-af3e-ee76a35cc42d
|
- uuid: 2a24b789-7aab-4535-af3e-ee76a35cc42d
|
||||||
advertise: true
|
num_handles: 14
|
||||||
|
advertise: false
|
||||||
characteristics:
|
characteristics:
|
||||||
- uuid: cad48e28-7fbe-41cf-bae9-d77a6c233423
|
- uuid: cad48e28-7fbe-41cf-bae9-d77a6c233423
|
||||||
name: "Test Characteristic"
|
|
||||||
properties:
|
properties:
|
||||||
- READ
|
- read
|
||||||
- WRITE
|
value: [0, 1, 2]
|
||||||
- NOTIFY
|
- uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc42d
|
||||||
permissions:
|
advertise: false
|
||||||
- READ
|
characteristics:
|
||||||
- WRITE
|
- id: test_write_characteristic
|
||||||
value: "Hello World"
|
uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc12d
|
||||||
|
properties:
|
||||||
|
- read
|
||||||
|
- write
|
||||||
on_write:
|
on_write:
|
||||||
then:
|
then:
|
||||||
- logger.log: "Characteristic written"
|
- lambda: |-
|
||||||
on_read:
|
ESP_LOGD("BLE", "Received: %s", x.c_str());
|
||||||
then:
|
- ble_server.characteristic_set_value:
|
||||||
- logger.log: "Characteristic read"
|
id: test_write_characteristic
|
||||||
on_notify:
|
value: x
|
||||||
then:
|
|
||||||
- logger.log: "Characteristic notified"
|
|
||||||
|
|
||||||
esp32_improv:
|
esp32_improv:
|
||||||
authorizer: io0_button
|
authorizer: io0_button
|
||||||
|
|
Loading…
Reference in a new issue