Add uart.write action (#567)

* Add uart.write action

* Lint
This commit is contained in:
Otto Winter 2019-05-29 19:32:18 +02:00
parent 4b7c5aa05c
commit 3b1ba27043
No known key found for this signature in database
GPG key ID: DB66C0BE6013F97E
6 changed files with 85 additions and 18 deletions

View file

@ -1,15 +1,27 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome import pins from esphome import pins, automation
from esphome.const import CONF_BAUD_RATE, CONF_ID, CONF_RX_PIN, CONF_TX_PIN, CONF_UART_ID from esphome.const import CONF_BAUD_RATE, CONF_ID, CONF_RX_PIN, CONF_TX_PIN, CONF_UART_ID, CONF_DATA
from esphome.core import CORE, coroutine from esphome.core import CORE, coroutine
from esphome.py_compat import text_type, binary_type, char_to_byte
uart_ns = cg.esphome_ns.namespace('uart') uart_ns = cg.esphome_ns.namespace('uart')
UARTComponent = uart_ns.class_('UARTComponent', cg.Component) UARTComponent = uart_ns.class_('UARTComponent', cg.Component)
UARTDevice = uart_ns.class_('UARTDevice') UARTDevice = uart_ns.class_('UARTDevice')
UARTWriteAction = uart_ns.class_('UARTWriteAction', automation.Action)
MULTI_CONF = True MULTI_CONF = True
def validate_raw_data(value):
if isinstance(value, text_type):
return value.encode('utf-8')
if isinstance(value, str):
return value
if isinstance(value, list):
return cv.Schema([cv.hex_uint8_t])(value)
raise cv.Invalid("data must either be a string wrapped in quotes or a list of bytes")
def validate_rx_pin(value): def validate_rx_pin(value):
value = pins.input_pin(value) value = pins.input_pin(value)
if CORE.is_esp8266 and value >= 16: if CORE.is_esp8266 and value >= 16:
@ -51,3 +63,22 @@ def register_uart_device(var, config):
""" """
parent = yield cg.get_variable(config[CONF_UART_ID]) parent = yield cg.get_variable(config[CONF_UART_ID])
cg.add(var.set_uart_parent(parent)) cg.add(var.set_uart_parent(parent))
@automation.register_action('uart.write', UARTWriteAction, cv.maybe_simple_value({
cv.GenerateID(): cv.use_id(UARTComponent),
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
}, key=CONF_DATA))
def uart_write_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
yield cg.register_parented(var, config[CONF_ID])
data = config[CONF_DATA]
if isinstance(data, binary_type):
data = [char_to_byte(x) for x in data]
if cg.is_template(data):
templ = yield cg.templatable(data, args, cg.std_vector.template(cg.uint8))
cg.add(var.set_data_template(templ))
else:
cg.add(var.set_data_static(data))
yield var

View file

@ -0,0 +1,36 @@
#pragma once
#include "uart.h"
#include "esphome/core/automation.h"
namespace esphome {
namespace uart {
template<typename... Ts> class UARTWriteAction : public Action<Ts...>, public Parented<UARTComponent> {
public:
void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) {
this->data_func_ = func;
this->static_ = false;
}
void set_data_static(const std::vector<uint8_t> &data) {
this->data_static_ = data;
this->static_ = true;
}
void play(Ts... x) override {
if (this->static_) {
this->parent_->write_array(this->data_static_);
} else {
auto val = this->data_func_(x...);
this->parent_->write_array(val);
}
}
protected:
bool static_{false};
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
std::vector<uint8_t> data_static_{};
};
} // namespace uart
} // namespace esphome

View file

@ -3,27 +3,17 @@ import esphome.config_validation as cv
from esphome.components import switch, uart from esphome.components import switch, uart
from esphome.const import CONF_DATA, CONF_ID, CONF_INVERTED from esphome.const import CONF_DATA, CONF_ID, CONF_INVERTED
from esphome.core import HexInt from esphome.core import HexInt
from esphome.py_compat import text_type, binary_type, char_to_byte from esphome.py_compat import binary_type, char_to_byte
from .. import uart_ns from .. import uart_ns, validate_raw_data
DEPENDENCIES = ['uart'] DEPENDENCIES = ['uart']
UARTSwitch = uart_ns.class_('UARTSwitch', switch.Switch, uart.UARTDevice, cg.Component) UARTSwitch = uart_ns.class_('UARTSwitch', switch.Switch, uart.UARTDevice, cg.Component)
def validate_data(value):
if isinstance(value, text_type):
return value.encode('utf-8')
if isinstance(value, str):
return value
if isinstance(value, list):
return cv.Schema([cv.hex_uint8_t])(value)
raise cv.Invalid("data must either be a string wrapped in quotes or a list of bytes")
CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({ CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(UARTSwitch), cv.GenerateID(): cv.declare_id(UARTSwitch),
cv.Required(CONF_DATA): validate_data, cv.Required(CONF_DATA): validate_raw_data,
cv.Optional(CONF_INVERTED): cv.invalid("UART switches do not support inverted mode!"), cv.Optional(CONF_INVERTED): cv.invalid("UART switches do not support inverted mode!"),
}).extend(uart.UART_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA) }).extend(uart.UART_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)

View file

@ -49,6 +49,7 @@ class UARTComponent : public Component, public Stream {
void write_byte(uint8_t data); void write_byte(uint8_t data);
void write_array(const uint8_t *data, size_t len); void write_array(const uint8_t *data, size_t len);
void write_array(const std::vector<uint8_t> &data) { this->write_array(&data[0], data.size()); }
void write_str(const char *str); void write_str(const char *str);
@ -97,6 +98,7 @@ class UARTDevice : public Stream {
void write_byte(uint8_t data) { this->parent_->write_byte(data); } void write_byte(uint8_t data) { this->parent_->write_byte(data); }
void write_array(const uint8_t *data, size_t len) { this->parent_->write_array(data, len); } void write_array(const uint8_t *data, size_t len) { this->parent_->write_array(data, len); }
void write_array(const std::vector<uint8_t> &data) { this->parent_->write_array(data); }
void write_str(const char *str) { this->parent_->write_str(str); } void write_str(const char *str) { this->parent_->write_str(str); }

View file

@ -1210,13 +1210,14 @@ def validate_registry(name, registry):
return ensure_list(validate_registry_entry(name, registry)) return ensure_list(validate_registry_entry(name, registry))
def maybe_simple_value(*validators): def maybe_simple_value(*validators, **kwargs):
key = kwargs.pop('key', CONF_VALUE)
validator = All(*validators) validator = All(*validators)
def validate(value): def validate(value):
if isinstance(value, dict) and CONF_VALUE in value: if isinstance(value, dict) and key in value:
return validator(value) return validator(value)
return validator({CONF_VALUE: value}) return validator({key: value})
return validate return validate

View file

@ -103,6 +103,12 @@ mqtt:
- light.control: - light.control:
id: living_room_lights id: living_room_lights
brightness: !lambda 'return id(living_room_lights).current_values.get_brightness() + 0.5;' brightness: !lambda 'return id(living_room_lights).current_values.get_brightness() + 0.5;'
- uart.write:
id: uart0
data: Hello World
- uart.write: [0x00, 0x20, 0x30]
- uart.write: !lambda |-
return {};
i2c: i2c:
sda: 21 sda: 21
@ -120,6 +126,7 @@ uart:
tx_pin: GPIO22 tx_pin: GPIO22
rx_pin: GPIO23 rx_pin: GPIO23
baud_rate: 115200 baud_rate: 115200
id: uart0
ota: ota:
safe_mode: True safe_mode: True