Lambda 魔法
这里有一些在 ESPHome 中使用 Lambda 可以实现的各种有趣功能的配方。 这些不需要外部组件,展示了 Lambda 有多么强大。
显示页面替代方案
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, "页面1"); break; case 2: it.print(0, 1, "页面2"); break; case 3: it.print(0, 1, "页面3"); 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 数据包进行控制。 您可以使用脚本中的 Lambda 从 ESPHome 发送此类 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());
// 如果不想为传出数据包设置源端口,可以删除以下 4 行 source.sin_family = AF_INET; source.sin_addr.s_addr = htonl(INADDR_ANY); source.sin_port = htons(64998); // 源端口号 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", "已发送 %s 到 %s:%d,共 %d 字节", msg.c_str(), host.c_str(), port, n_bytes); ::close(sock);
button:- platform: template id: button_udp_sender name: "发送 UDP 命令" on_press: - script.execute: id: send_udp msg: "Hello World!" host: "192.168.1.10" port: 5000已在 arduino 和 esp-idf 平台上测试。
延迟远程传输
Section titled “延迟远程传输”下面的解决方案解决了 RF Bridge(或 远程发射器)发送 RF 帧太快的问题,当操作无线电控制的窗帘时。窗帘电机似乎需要在各个代码传输之间至少 600-700 毫秒的静默时间才能识别它们。
这可以通过建立一个原始 RF 代码队列并逐个发送它们(之间有可配置的延迟)来解决。延迟只添加到需要从 Home Assistant 同时操作的窗帘列表中接下来的命令。这对系统是透明的,看起来仍然像同时操作。
rf_bridge:
number:- platform: template name: 命令延迟 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: # 有多个窗帘 - platform: time_based name: '我的房间 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..关闭代码..XXXXXXXXXX"); - script.execute: rf_transmitter_queue close_duration: 26s
stop_action: - lambda: id(rf_code_queue).push_back("AAB0YXXXX..停止代码..XXXXXXXXXX"); - script.execute: rf_transmitter_queue
open_action: - lambda: id(rf_code_queue).push_back("AAB0ZXXXX..打开代码..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: # 循环运动的逻辑:打开->停止->关闭->停止->... - lambda: | if (id(my_cover).current_operation == COVER_OPERATION_IDLE) { // 窗帘空闲,检查当前状态并打开或关闭窗帘。 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 { // 窗帘正在打开/关闭。停止它。 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: "窗帘" 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: "数字输入" 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: "从文本转换的数字"