Lambda 魔法
以下是一些在 ESPHome 中使用 Lambdas 来做各种有趣事情的秘诀。 它们不需要外部组件,并展示出 Lambdas 的强大之处。
显示页面的替代方案
Section titled “显示页面的替代方案”有些显示器(如 lcd_pcf8574 组件)本身不支持页面,但您可以使用 Lambda 轻松实现它们:
display: - platform: lcd_pcf8574 dimensions: 20x4 address: 0x27 id: lcd lambda: |- switch (id(page)){ case 1: it.print(0, 1, "Page1"); break; case 2: it.print(0, 1, "Page2"); break; case 3: it.print(0, 1, "Page3"); break; }
globals:- id: page type: int initial_value: "1"
interval:- interval: 5s then: - lambda: |- id(page) = (id(page) + 1); if (id(page) > 3) { id(page) = 1; }发送 UDP 命令
Section titled “发送 UDP 命令”有各种网络设备可以通过包含命令字符串的 UDP 数据包进行控制。 您可以在 ESPHome 的脚本中使用 Lambda 来发送此类 UDP 命令。
script:- id: send_udp parameters: msg: string host: string port: int then: - lambda: |- int sock = ::socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in destination, source;
destination.sin_family = AF_INET; destination.sin_port = htons(port); destination.sin_addr.s_addr = inet_addr(host.c_str());
// you can remove the next 4 lines if you don't want to set the source port for outgoing packets source.sin_family = AF_INET; source.sin_addr.s_addr = htonl(INADDR_ANY); source.sin_port = htons(64998); // the source port number bind(sock, (struct sockaddr*)&source, sizeof(source));
int n_bytes = ::sendto(sock, msg.c_str(), msg.length(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination)); ESP_LOGD("lambda", "Sent %s to %s:%d in %d bytes", msg.c_str(), host.c_str(), port, n_bytes); ::close(sock);
button:- platform: template id: button_udp_sender name: "Send UDP Command" on_press: - script.execute: id: send_udp msg: "Hello World!" host: "192.168.1.10" port: 5000已在 arduino 和 esp-idf 平台上测试通过。
延迟遥控发送
Section titled “延迟遥控发送”以下方案解决了在操作无线电遥控窗帘时,RF 桥接器(或 远程发射器)一个接一个过于快速发送 RF 帧的问题。 窗帘电机似乎需要在每条代码传输之间有至少 600-700ms 的静默时间才能识别它们。
解决方案是建立一个原始 RF 代码队列,并按顺序逐个发送,两者之间带有(可配置的)延迟。 延迟只添加到来自窗帘列表中接下来的命令,这些命令需要从 Home Assistant 一次同时操作。 这对系统来说是透明的,系统看起来仍然像在同时操作。
rf_bridge:
number:- platform: template name: Delay commands icon: mdi:clock-fast entity_category: config optimistic: true restore_value: true initial_value: 750 unit_of_measurement: "ms" id: queue_delay min_value: 10 max_value: 1000 step: 50 mode: box
globals:- id: rf_code_queue type: 'std::vector<std::string>'
script:- id: rf_transmitter_queue mode: single then: while: condition: lambda: 'return !id(rf_code_queue).empty();' then: - rf_bridge.send_raw: raw: !lambda |- std::string rf_code = id(rf_code_queue).front(); id(rf_code_queue).erase(id(rf_code_queue).begin()); return rf_code; - delay: !lambda 'return id(queue_delay).state;'
cover: # have multiple covers - platform: time_based name: 'My Room 1' disabled_by_default: false device_class: shutter assumed_state: true has_built_in_endstop: true
close_action: - lambda: id(rf_code_queue).push_back("AAB0XXXXX..the.closing.code..XXXXXXXXXX"); - script.execute: rf_transmitter_queue close_duration: 26s
stop_action: - lambda: id(rf_code_queue).push_back("AAB0YXXXX..the.stopping.code..XXXXXXXXXX"); - script.execute: rf_transmitter_queue
open_action: - lambda: id(rf_code_queue).push_back("AAB0ZXXXX..the.opening.code..XXXXXXXXXX"); - script.execute: rf_transmitter_queue open_duration: 27s单按钮窗帘控制
Section titled “单按钮窗帘控制”以下配置展示了如何使用单个按钮通过循环:开→停→关→停→…来控制电动窗帘的运动。
在此示例中,使用了 基于时间 以及 Sonoff Dual R2 的 GPIO 配置。
NOTE
过快控制窗帘(在先前命令后一分钟内发送新的开/关命令) 可能会导致意外行为(例如:窗帘停在半途)。这是因为延迟继电器关闭 功能是使用异步自动化实现的。因此,每次发送开/关命令时, 都会添加一条延迟的继电器关闭命令,而旧的命令不会被移除。
esp8266: board: esp01_1m
binary_sensor:- platform: gpio pin: number: GPIO10 inverted: true id: button on_press: then: # logic for cycling through movements: open->stop->close->stop->... - lambda: | if (id(my_cover).current_operation == COVER_OPERATION_IDLE) { // Cover is idle, check current state and either open or close cover. if (id(my_cover).is_fully_closed()) { auto call = id(my_cover).make_call(); call.set_command_open(); call.perform(); } else { auto call = id(my_cover).make_call(); call.set_command_close(); call.perform(); } } else { // Cover is opening/closing. Stop it. auto call = id(my_cover).make_call(); call.set_command_stop(); call.perform(); }
switch:- platform: gpio pin: GPIO12 interlock: &interlock [open_cover, close_cover] id: open_cover- platform: gpio pin: GPIO5 interlock: *interlock id: close_cover
cover:- platform: time_based name: "Cover" id: my_cover open_action: - switch.turn_on: open_cover open_duration: 60s close_action: - switch.turn_on: close_cover close_duration: 60s stop_action: - switch.turn_off: open_cover - switch.turn_off: close_cover从文本输入更新数值
Section titled “从文本输入更新数值”有时使用 模板 从用户界面更改某些数值可能会更方便。 ESPHome 有一些不错的 辅助函数,其中 有一个可以将文本转换为数字。
在下面的示例中,我们有一个文本输入、以及一个可从文本输入字段更新的模板传感器。
Lambda 所做的是解析文本字符串并将其转换为数字——只有输入的字符串包含表示浮点数字的字符
(例如数字、- 和 . )时才会成功。如果输入的字符串包含任何其他字符,
Lambda 将返回 NaN,对应传感器的 unknown 状态。
text: - platform: template name: "Number type in" optimistic: true min_length: 0 max_length: 16 mode: text on_value: then: - sensor.template.publish: id: num_from_text state: !lambda |- auto n = parse_number<float>(x); return n.has_value() ? n.value() : NAN;
sensor: - platform: template id: num_from_text name: "Number from text"