跳转到内容

喷淋控制器

sprinkler 控制器组件旨在像喷淋/灌溉阀门控制器一样运行, 类似于 Rain Bird 或 Hunter 等公司制造的产品。它通过自动控制多个 switch 组件来实现这一点, 每个组件通常用于通过继电器或其他开关设备控制单个电动阀门。它提供了 您对喷淋控制器所期望的许多功能,包括:

  • 每个控制器实例几乎可以有任意数量的区域(喷淋系统的部分), 仅受 ESP 上可用内存和/或 GPIO(包括 I/O 扩展器!)引脚可用性限制

  • 运行能力:

    • 系统的一个或多个完整循环(遍历所有区域)
    • 仅单个区域
  • 自动循环重复

  • 一个乘数值,用于按比例增加或减少所有区域的运行时长

  • 支持位于分配阀门上游的水泵/主阀门

  • 暂停和恢复区域/循环

  • 按正向或反向顺序遍历区域

  • 支持锁存式(“脉冲式”)和非锁存式阀门(可以任意混合使用!)

然而,它更进一步,还提供了几个更高级的功能:

  • 多个喷淋控制器实例可以在单个(ESP)设备上同时运行

  • 多个水泵,每个都可以在控制器实例之间共享

  • 每个单独区域的启用/禁用开关,允许在系统的完整循环中省略区域

  • 阀门/区域排队机制,旨在为自动化提供高级支持

  • 多种阀门管理策略,以适应不同类型的硬件/安装:

    • 可调节的”阀门开启延迟”,以帮助确保在打开下一个阀门之前阀门已完全关闭
    • 可调节的”阀门重叠”,以帮助最大程度减少因水锤效应导致的管道撞击
    • 可调节的延迟间隔,以协调水泵启动和停止相对于分配阀门开启和关闭的时间

NOTE

虽然本文档中使用了术语”水泵”,但受控设备不一定是 物理水泵。相反,它可能只是位于分配阀门上游的另一个电动阀门 (在行业中通常称为”主阀门”或”总阀门”)。水泵或上游阀门 仅控制向其他下游阀门的供水。

喷淋控制器用户界面示例 -- 注意此示例使用 number 组件来设置运行时长、重复次数和乘数值。更多详情请见下文。
# 示例最小配置条目
# (...但请参阅下面更详细的示例!)
sprinkler:
- id: sprinkler_ctrlr
main_switch: "喷淋器"
auto_advance_switch: "喷淋器自动前进"
valves:
- valve_switch: "前草坪"
enable_switch: "启用前草坪"
run_duration: 1800s
valve_switch_id: lawn_sprinkler_valve_sw0
- valve_switch: "后草坪"
enable_switch: "启用后草坪"
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw1

请参阅下面的 控制器示例 部分,获取可直接复制粘贴的详细配置示例!

  • main_switch (可选, 字符串): 当有多个阀门时为必需。喷淋控制器主开关在前端显示的名称。 此开关打开时,调用 sprinkler.resume_or_start_full_cycle 动作;关闭时,调用 sprinkler.shutdown 动作(见下文)。当控制器上的任何阀门处于活动状态时,它将显示为”开启”状态。如果控制器 仅配置了一个阀门,则此开关不会出现在前端。

  • auto_advance_switch (可选, 字符串): 当有多个阀门时为必需。喷淋控制器”自动前进”开关 在前端显示的名称。当阀门处于活动状态时打开此开关,当阀门的 run_duration 到达时, 喷淋控制器将自动前进到下一个启用的阀门,作为系统”完整循环”的一部分。关闭时, 喷淋控制器将在活动阀门的 run_duration 到达后关闭(除非队列中有阀门 — 请参阅 下面的 喷淋控制器队列 部分了解更多详情)。如果控制器仅配置了一个阀门, 则此开关不会出现在前端。

  • manual_selection_delay (可选, 时间): 调用 next_valveprevious_valve 动作后,控制器在激活阀门之前应等待的时间量。如果控制界面仅由 前进/后退按钮组成,则此功能很有用,因为按钮可能被按下多次以进行选择。

  • queue_enable_switch (可选, 字符串): 喷淋控制器队列启用开关在前端显示的名称。 当此开关打开或未提供时,控制器将根据队列内容选择下一个要运行的阀门/区域; 队列优先于作为系统完整循环的一部分运行的阀门(当自动前进打开/启用时)。 请参阅下面的 喷淋控制器队列 部分了解更多详情。

  • reverse_switch (可选, 字符串): 喷淋控制器反向开关在前端显示的名称。 当此开关打开时,控制器将以相反的顺序遍历阀门(按控制器配置中的最后到最先顺序)。 当此开关关闭或未提供时,控制器将按最先到最后的顺序遍历阀门。 如果控制器仅配置了一个阀门,则此开关不会出现在前端。

  • standby_switch (可选, 字符串): 喷淋控制器待机开关在前端显示的名称。 当此开关打开时,控制器 将不会启动任何阀门。 如果没有此状态的视觉指示,这可能会导致混乱/意外的行为!

  • valve_open_delay (可选, 时间): 在(分配)阀门切换之间应插入的 最小延迟秒数 — 换句话说,一个阀门关闭和下一个阀门打开之间必须经过的时间量。 对于阀门依赖足够水压来关闭的系统很有用。不能与 valve_overlap 一起使用。

  • valve_overlap (可选, 时间): 当前阀门和下一个阀门在下一个阀门/区域 启动时应同时运行的秒数。这可以帮助防止阀门关闭时管道撞击。不能与 valve_open_delay 一起使用。

  • pump_switch_off_during_valve_open_delay (可选, 布尔值): 如果设置为 true,水泵将在 valve_open_delay 期间关闭;否则保持开启。仅在配置了 valve_open_delay 时 可以指定(见上文)。默认为 false

  • pump_start_pump_delay (可选, 时间): 从分配阀门打开到 关联水泵启动的延迟秒数。用于确保在无分配阀门打开时运行水泵不会导致压力积聚。 不能与 pump_start_valve_delay 一起使用。

  • pump_start_valve_delay (可选, 时间): 从水泵启动到 关联分配阀门打开的延迟秒数。对于分配阀门需要足够压力才能完全/快速关闭的系统很有用。 不能与 pump_start_pump_delay 一起使用。

  • pump_stop_pump_delay (可选, 时间): 从分配阀门关闭到 相应水泵停用的延迟秒数。对于分配阀门需要足够压力才能完全/快速关闭的系统很有用。 不能与 pump_stop_valve_delay 一起使用。

  • pump_stop_valve_delay (可选, 时间): 从水泵停用到 相应分配阀门关闭的延迟秒数。用于确保在无分配阀门打开时运行水泵不会导致压力积聚, 或允许通往分配阀门的主管道排水。不能与 pump_stop_pump_delay 一起使用。

  • multiplier_number (可选, 字符串): 应在前端(Home Assistant)显示的 number 组件的名称,以启用对喷淋控制器 multiplier 值的控制。 请参阅下文的 使用喷淋控制器的数值组件 了解更多详情。

  • repeat_number (可选, 字符串): 应在前端(Home Assistant)显示的 number 组件的名称,以启用对喷淋控制器 repeat 值的控制。 不能与 repeat 一起使用。请参阅下文的 使用喷淋控制器的数值组件 了解更多详情。

  • repeat (可选, 整数): 完整循环应重复的次数。默认为 0。不能与 repeat_number 一起使用。

  • next_prev_ignore_disabled (可选, 布尔值): 设置为 true 可使 sprinkler.next_valve 动作sprinkler.previous_valve 动作 跳过未启用的阀门。默认为 false

  • id (可选, ID): 手动指定用于代码生成的 ID。虽然是可选的, 但在调用控制器动作(见下文)如 start_full_cycleshutdown 时,这对于识别控制器实例 (特别是在定义了多个实例的情况下)是必需的。

  • valves (必需, 列表): 控制器应使用的阀门列表。每个阀门包括:

    • enable_switch (可选, 字符串): 用于启用此阀门作为系统完整循环一部分运行的 开关组件的名称。当此开关关闭时,该阀门将从系统的完整循环中排除。 当此开关打开或未提供时,控制器将在系统的完整循环中包含该阀门。

    • valve_switch (*必需, 字符串): 用于控制喷淋系统此部分的阀门 (通常称为”区域”)的开关组件名称。当此开关打开时,控制器的”自动前进”功能被禁用, 它将激活关联阀门,运行时长为其 run_duration 乘以控制器的乘数值。 当此开关关闭时,调用 sprinkler.shutdown 动作(见下文)。

    • pump_switch_id (可选, 开关): 这是用于控制阀门水泵或 上游电动阀门的 switch 组件。通常这会是一个 GPIO switch,连接控制继电器或其他开关设备,进而激活相应的 水泵/阀门。对于锁存式阀门/水泵,使用 H-Bridge switch不建议将此开关暴露给前端;请参阅 关于 GPIO 开关和控制的重要说明 了解更多详情。

    • run_duration_number (可选, 字符串): 应在前端(Home Assistant)显示的 number 组件名称,以启用对阀门 run_duration 值的控制。 不能与 run_duration 一起使用。请参阅下文的 使用喷淋控制器的数值组件 了解更多详情。专业提示: 想要以分钟为单位显示时间?在数值配置中添加 unit_of_measurement: min。 请参阅 使用喷淋控制器的数值组件 了解更多详情。

    • run_duration (可选, 时间): 当未提供 run_duration_number 时为必需。 此阀门在激活后应保持开启/打开的秒数。当给定阀门被激活时, 控制器的乘数值乘以此值以确定阀门的实际运行时长,从而允许按需按比例增加或减少 所有阀门/区域的运行时长。不能与 run_duration_number 一起使用。

    • valve_switch_id (必需, 开关): 这是用于控制操作喷淋系统 给定部分或区域的阀门的 switch 组件。通常这会是一个 GPIO switch,连接控制继电器或其他开关设备,进而激活相应的阀门。 对于锁存式阀门,使用 H-Bridge switch不建议将此开关暴露给前端;请参阅 关于 GPIO 开关和控制的重要说明 了解更多详情。

关于 GPIO 开关和控制的重要说明

Section titled “关于 GPIO 开关和控制的重要说明”

精明和/或经验丰富的 ESPHome 用户会很快意识到,pump_switch_idvalve_switch_id(如上所述) 实际上只是指向 ESPHome yaml 配置中其他位置的开关的指针。

假设这些开关(通常是 GPIO switchesH-Bridge switches) 可以用来开关各种喷淋区域似乎是合理的,然而,这 不是 正确的做法。重要的是要注意, 喷淋控制器为每个配置的区域提供了一个开关 — 最终,这个开关才是用来开关任何给定区域 的开关,而不是 该区域配置所基于的底层开关。

请记住,开关直接控制其关联的硬件(GPIO 引脚、H-Bridge 电路等)。虽然在技术上可以 “覆盖”此行为,但这可能并不总是可取的。例如,如果您 想要 在测试系统/配置期间 手动控制开关状态,这将使这样做变得不可能(或至少比必要的更困难),并带来其他复杂性。 最终,灵活性是关键,正如我们从 ESPHome Discord 服务器上的许多对话中学到的那样。

如引言中所述,喷淋控制器自动化控制您提供给它的开关 — 它不会”覆盖”这些开关的控制, 也不会改变它们的行为方式,只是根据配置的调度要求简单地开关它们。

那么,为什么不直接使用底层开关来控制各种喷淋区域呢?就喷淋控制器本身而言, 主要原因与 状态 有关 — 也就是说,我们需要能够确保开关状态与喷淋控制器的配置保持一致。 对于仅由每个区域一个阀门组成的简单系统,这不太重要,但对于具有一些额外复杂性的系统, 这变得非常重要。考虑一个带有水泵和连接到该水泵的多个分配阀门的系统示例; 在这种情况下,控制器配置为在关闭任何给定分配阀门 之前 三秒关闭水泵。 如果您突然手动关闭连接到这些分配阀门之一的底层开关,水泵会发生什么? 喷淋控制器应该怎么做?它应该把分配阀门重新打开吗?…还是只是把水泵也关掉? 无论哪种情况,根据其配置,水泵本应在阀门之前关闭,但您刚刚关闭了阀门。 水泵可能会损坏。还有许多其他类似的情况可能发生,最简单的情况不过是确保任何给定阀门 在 持续时间后关闭,而不会无限期地保持开启/打开。

总之,为确保您的喷淋控制器始终按预期运行:

  • 仅使用喷淋控制器组件提供的开关来开关任何给定的喷淋区域。

  • 不要使用配置中的底层开关(GPIO、H-Bridge 等)在设备配置的初始测试之外控制喷淋区域/阀门。

  • 为帮助防止意外,最好将每个喷淋区域的底层开关 暴露给前端。这可以通过两种方式实现:

    • 不要为您的开关提供 name: 参数,或
    • 在每个开关配置中添加 internal: true

这些简单的配置调整将有助于防止许多错误(人为、自动化或其他),并可能有助于避免灾难!

启动系统的完整循环。这将启用控制器的”自动前进”功能并禁用队列。 控制器将遍历所有启用的阀门/区域。每个阀门将运行其配置的 run_duration 乘以控制器的乘数值。请注意,如果调用此动作时没有启用任何阀门, 控制器将自动启用所有阀门。

on_...:
then:
- sprinkler.start_full_cycle: sprinkler_ctrlr

启动控制器从其队列运行阀门。如果队列中没有阀门,此动作不执行任何操作; 否则,这将禁用控制器的”自动前进”功能,以便仅运行排队的阀门/区域。 排队阀门将保持开启的时间为队列请求中指定的时间,或其配置的 run_duration 乘以控制器的乘数值(如果队列请求运行时长未指定或为零)。 请注意,排队阀门忽略阀门是否启用;也就是说,一旦控制器启动,排队的阀门 将始终运行,当然,除非在队列到达它们之前(手动)清除了队列。 另请注意,目前队列为限制内存使用设置了 100 个条目的硬编码限制。 请参阅下文的 喷淋控制器队列 部分了解更多详情。

on_...:
then:
- sprinkler.start_from_queue:
id: sprinkler_ctrlr

启动单个阀门。这将禁用控制器的”自动前进”和队列功能,以便仅运行此阀门/区域。 阀门将保持开启指定的时长,或(如果 run_duration 未指定或为零)运行其配置的 run_duration 乘以控制器的乘数值。请注意,此动作忽略阀门是否启用; 也就是说,调用时,指定的阀门将始终运行。 阀门按其在喷淋控制器配置中出现的顺序编号, 从零(0)开始。

on_...:
then:
- sprinkler.start_single_valve:
id: sprinkler_ctrlr
valve_number: 0
run_duration: 600s # 可选

启动所有阀门/系统的关闭,遵守任何配置的水泵或阀门停止延迟。

on_...:
then:
- sprinkler.shutdown: sprinkler_ctrlr

前进到下一个阀门(按编号)。如果配置了 manual_selection_delay,控制器将在激活 选定的阀门之前等待。如果没有活动的阀门,将启动第一个阀门(按其在控制器配置中 出现的顺序)。将 next_prev_ignore_disabled 设置为 true 将使此动作跳过 未通过阀门启用开关启用的阀门(见上文)。

on_...:
then:
- sprinkler.next_valve: sprinkler_ctrlr

后退到上一个阀门(按编号)。如果配置了 manual_selection_delay,控制器将在激活 选定的阀门之前等待。如果没有活动的阀门,将启动最后一个阀门(按其在控制器配置中 出现的顺序)。将 next_prev_ignore_disabled 设置为 true 将使此动作跳过 未通过阀门启用开关启用的阀门(见上文)。

on_...:
then:
- sprinkler.previous_valve: sprinkler_ctrlr

立即关闭所有阀门,保存活动阀门和剩余时间,以便稍后可以恢复循环。

on_...:
then:
- sprinkler.pause: sprinkler_ctrlr

恢复通过 sprinkler.pause 暂停的循环。如果没有暂停的循环,此动作不执行任何操作。

on_...:
then:
- sprinkler.resume: sprinkler_ctrlr

sprinkler.resume_or_start_full_cycle 动作

Section titled “sprinkler.resume_or_start_full_cycle 动作”

恢复通过 sprinkler.pause 暂停的循环,但如果没有暂停的循环,则启动完整循环 (相当于 sprinkler.start_full_cycle)。

on_...:
then:
- sprinkler.resume_or_start_full_cycle: sprinkler_ctrlr

将指定的阀门添加到控制器的队列中。当队列启用时,队列中的阀门优先于 作为系统完整循环的一部分调度的阀门(当自动前进启用时)。 如果 run_duration 未指定或为零,喷淋控制器将使用阀门的配置运行时长。 阀门按其在喷淋控制器配置中出现的顺序编号,从零(0)开始。 请注意,目前队列为限制内存使用设置了 100 个条目的硬编码限制。 请参阅下文的 喷淋控制器队列 部分了解更多详情和示例。

on_...:
then:
- sprinkler.queue_valve:
id: sprinkler_ctrlr
valve_number: 2
run_duration: 900s

从控制器队列中移除所有排队的阀门。请参阅下文的 喷淋控制器队列 部分了解更多详情和示例。

on_...:
then:
- sprinkler.clear_queued_valves:
id: sprinkler_ctrlr

设置用于按比例增加或减少所有阀门/区域运行时长的乘数值。 对于季节性变化,使用乘数调整浇水时间比直接调整运行时长更容易。 将运行时长设置为您想要的”温和”天气(春季/秋季)的时间,然后 使用乘数增加(夏季)或减少(冬季)计算出的运行时间。当给定阀门被激活时, 此值乘以阀门的运行时长(见下文)以确定阀门的实际运行时长。 请注意,乘数值为零是允许的;如果乘数值为零,喷淋控制器将不会启动任何阀门。 如果没有此状态的视觉指示,这可能会导致混乱/意外的行为!

on_...:
then:
- sprinkler.set_multiplier:
id: sprinkler_ctrlr
multiplier: 1.5

指定完整循环应重复的次数。请注意,控制器将运行的循环总数等于重复值加一。 例如,repeat 值为 1 时,初始循环将运行,然后重复循环将运行,总共两个循环。

on_...:
then:
- sprinkler.set_repeat:
id: sprinkler_ctrlr
repeat: 2 # 将运行三个循环

分割值同时设置乘数和重复值,如下所示:

  • 乘数值设置为 1 / divider 的值
  • 重复值设置为 divider - 1

例如,给定分割值为 4,乘数将设置为 0.25,重复值将设置为 3。

这对于将每个阀门的运行时长分成多个较短的循环很有用,因此 可以通过让地面有更多时间吸收水来避免径流。

on_...:
then:
- sprinkler.set_divider:
id: sprinkler_ctrlr
divider: 2

设置指定阀门的运行时长。当阀门被激活时,此值乘以乘数值(见上文) 以确定阀门的实际运行时长。

on_...:
then:
- sprinkler.set_valve_run_duration:
id: sprinkler_ctrlr
valve_number: 0
run_duration: 600s

NOTE

  • start_single_valve 动作忽略阀门是否通过其启用开关启用。

  • 如果配置了 manual_selection_delay 或下文 水泵和分配阀门协调 部分中描述的各种延迟机制中的任何一个,next_valveprevious_valve 动作可能不会立即响应。 如果您正在使用任何这些配置选项,请务必让延迟间隔过去后再假设某些东西不工作!

  • 如果在阀门的 run_duration 或乘数值更改时阀门处于活动状态,则活动阀门的运行时长 将保持不受影响,直到下次启动时。

喷淋控制器允许在水泵和阀门切换方面具有广泛的灵活性。 让我们仔细看看如何使用这些功能来调整您的系统。

水泵或阀门的延迟启动和/或停止

Section titled “水泵或阀门的延迟启动和/或停止”

对于带有水泵的系统,在没有分配阀门打开的情况下运行水泵通常是个坏主意。 这会导致压力积聚,甚至可能在一段时间后损坏水泵。对于带有水泵的系统, 您可能需要添加两个配置选项:

sprinkler:
- id: lawn_sprinkler_ctrlr
pump_start_pump_delay: 3s
pump_stop_valve_delay: 3s
...

这将导致任何给定的水泵在(本例中)任何关联的分配阀门打开 之后 三秒启动。 此外,它将在水泵停止 之后 等待三秒关闭 最后一个 分配阀门。 这将允许水泵减速、压力下降,并在关闭(最后一个)关联的分配阀门之前让管道排水。 (在这些配置中,可能还需要启用 valve_overlap — 下文有更多相关内容。)

某些类型的电动阀门需要足够的水压才能(完全/快速)关闭。这些类型的阀门, 当与分配阀门上游的电动阀门(在行业中通常称为”主阀门”或”总阀门”)结合使用时, 可能需要在上游阀门在任何给定分配阀门 之前 打开,让水压稳定并强制所有分配阀门关闭, 然后 再打开任何单个分配阀门。在这些情况下,可能需要上述配置的反向设置:

sprinkler:
- id: lawn_sprinkler_ctrlr
pump_start_valve_delay: 3s
pump_stop_pump_delay: 3s
...

在本例中,上游阀门将在任何给定关联分配阀门 之前 三秒打开,让水压强制任何连接的分配阀门关闭。 延迟之后,所需的分配阀门打开,循环开始。循环完成后,(最后一个)分配阀门将在上游阀门 之前 三秒关闭。(在这些配置中,可能还需要启用 valve_open_delay。)

NOTE

pump_stop_valve_delaypump_stop_pump_delayvalve_open_delaypump_switch_off_during_valve_open_delay 一起使用可能会增加每个区域操作之间插入的关闭时间, 因为控制器必须等待给定区域(水泵 阀门)完全关闭后才能再次启动。

人们对喷淋系统的一个常见抱怨是管道撞击。在其他不太常见的情况下, 一些系统存在阀门无法(完全/快速)关闭的问题。有三个控制器选项可以解决这些问题:

  • valve_overlap
  • valve_open_delay
  • pump_switch_off_during_valve_open_delay

第一个选项 valve_overlap,导致当前阀门和下一个阀门(当控制器遍历阀门时) 在指定的持续时间内同时运行。这里的想法是,这会在下一个区域启动时降低水压, 从而最小化正在结束的阀门最终关闭时的管道撞击(即”水锤效应”)。

第二个和第三个选项可用于确保有足够的水压可用于强制阀门关闭。 这对于在低水压时不能快速和/或完全关闭的压力敏感阀门可能很有用。

对于带有水泵的系统,可能需要在切换到下一个分配阀门/区域之前关闭水泵。 在这些情况下,pump_switch_off_during_valve_open_delayvalve_open_delay 结合使用可能会很有用。

无论如何,下一节的示例说明了如何/在哪里将这些选项添加到您的配置中。

第一个示例展示了一个完整的单阀门系统,没有水泵/上游阀门。它可能对独立于 任何其他喷淋控制器控制单个阀门很有用。可以通过添加 pump_switch_id 参数和 一个 switch 轻松添加水泵。

esphome:
name: esp-sprinkler-controller
esp32:
board: esp32dev
wifi:
ssid: "wifi_ssid"
password: "wifi_password"
logger:
sprinkler:
- id: garden_sprinkler_ctrlr
valves:
- valve_switch: "花园"
run_duration: 300s
valve_switch_id: garden_sprinkler_valve
switch:
- platform: gpio
id: garden_sprinkler_valve
pin: GPIOXX

此示例展示了一个完整的简单三阀门系统,没有水泵/上游阀门:

esphome:
name: esp-sprinkler-controller
esp32:
board: esp32dev
wifi:
ssid: "wifi_ssid"
password: "wifi_password"
logger:
sprinkler:
- id: lawn_sprinkler_ctrlr
main_switch: "草坪喷淋器"
auto_advance_switch: "草坪喷淋器自动前进"
reverse_switch: "草坪喷淋器反向"
multiplier_number: "草坪喷淋器乘数"
repeat_number: "草坪喷淋器重复"
valve_overlap: 5s
valves:
- valve_switch: "前草坪"
enable_switch: "启用前草坪"
run_duration_number: "前院运行时长"
valve_switch_id: lawn_sprinkler_valve_sw0
- valve_switch: "侧草坪"
enable_switch: "启用侧草坪"
run_duration_number: "前院运行时长"
valve_switch_id: lawn_sprinkler_valve_sw1
- valve_switch: "后草坪"
enable_switch: "启用后草坪"
run_duration_number: "前院运行时长"
valve_switch_id: lawn_sprinkler_valve_sw2
switch:
- platform: gpio
id: lawn_sprinkler_valve_sw0
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw1
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw2
pin: GPIOXX

此示例展示了一个完整的三阀门系统,带有单个水泵/上游阀门:

esphome:
name: esp-sprinkler-controller
esp32:
board: esp32dev
wifi:
ssid: "wifi_ssid"
password: "wifi_password"
logger:
sprinkler:
- id: lawn_sprinkler_ctrlr
main_switch: "草坪喷淋器"
auto_advance_switch: "草坪喷淋器自动前进"
reverse_switch: "草坪喷淋器反向"
valve_open_delay: 5s
valves:
- valve_switch: "前草坪"
enable_switch: "启用前草坪"
pump_switch_id: sprinkler_pump_sw
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw0
- valve_switch: "侧草坪"
enable_switch: "启用侧草坪"
pump_switch_id: sprinkler_pump_sw
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw1
- valve_switch: "后草坪"
enable_switch: "启用后草坪"
pump_switch_id: sprinkler_pump_sw
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw2
switch:
- platform: gpio
id: sprinkler_pump_sw
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw0
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw1
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw2
pin: GPIOXX

单控制器、三锁存式阀门、单锁存式水泵

Section titled “单控制器、三锁存式阀门、单锁存式水泵”

此示例与上一个示例类似,但它展示了如何使用 H-Bridge switches 配置”锁存式”或”脉冲式”阀门。这种类型的阀门需要两个 GPIO 引脚才能操作 — 一个用于打开阀门,另一个用于关闭阀门。

请注意,虽然此示例展示了仅使用锁存式阀门的配置, 但锁存式和非锁存式阀门可以在任何配置中混合使用,即使连接到共同的水泵/上游阀门。

esphome:
name: esp-sprinkler-controller
esp32:
board: esp32dev
wifi:
ssid: "wifi_ssid"
password: "wifi_password"
logger:
sprinkler:
- id: lawn_sprinkler_ctrlr
main_switch: "草坪喷淋器"
auto_advance_switch: "草坪喷淋器自动前进"
queue_enable_switch: "草坪喷淋器队列启用"
reverse_switch: "草坪喷淋器反向"
valve_open_delay: 5s
valves:
- valve_switch: "前草坪"
enable_switch: "启用前草坪"
pump_switch_id: sprinkler_pump_sw
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw0
- valve_switch: "侧草坪"
enable_switch: "启用侧草坪"
pump_switch_id: sprinkler_pump_sw
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw1
- valve_switch: "后草坪"
enable_switch: "启用后草坪"
pump_switch_id: sprinkler_pump_sw
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw2
switch:
- platform: hbridge
id: sprinkler_pump_sw
on_pin: GPIOXX
off_pin: GPIOXX
pulse_length: 250ms
- platform: hbridge
id: lawn_sprinkler_valve_sw0
on_pin: GPIOXX
off_pin: GPIOXX
pulse_length: 250ms
- platform: hbridge
id: lawn_sprinkler_valve_sw1
on_pin: GPIOXX
off_pin: GPIOXX
pulse_length: 250ms
- platform: hbridge
id: lawn_sprinkler_valve_sw2
on_pin: GPIOXX
off_pin: GPIOXX
pulse_length: 250ms

此示例展示了一个完整且更复杂的双控制器系统,共有五个阀门 (第一个控制器三个,第二个控制器两个)和两个水泵/上游阀门, 每个水泵都在两个控制器之间共享:

esphome:
name: esp-sprinkler-controller
esp32:
board: esp32dev
wifi:
ssid: "wifi_ssid"
password: "wifi_password"
logger:
sprinkler:
- id: lawn_sprinkler_ctrlr
main_switch: "草坪喷淋器"
auto_advance_switch: "草坪喷淋器自动前进"
reverse_switch: "草坪喷淋器反向"
valve_overlap: 5s
valves:
- valve_switch: "前草坪"
enable_switch: "启用前草坪"
pump_switch_id: sprinkler_pump_sw0
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw0
- valve_switch: "侧草坪"
enable_switch: "启用侧草坪"
pump_switch_id: sprinkler_pump_sw0
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw1
- valve_switch: "后草坪"
enable_switch: "启用后草坪"
pump_switch_id: sprinkler_pump_sw1
run_duration: 900s
valve_switch_id: lawn_sprinkler_valve_sw2
- id: garden_sprinkler_ctrlr
main_switch: "花园喷淋器"
auto_advance_switch: "花园喷淋器自动前进"
reverse_switch: "花园喷淋器反向"
valve_open_delay: 5s
valves:
- valve_switch: "前花园"
enable_switch: "启用前花园"
pump_switch_id: sprinkler_pump_sw0
run_duration_number:
id: garden_sprinkler_ctrlr_front_run_duration
name: "前花园运行时长"
initial_value: 10
unit_of_measurement: min
valve_switch_id: garden_sprinkler_valve_sw0
- valve_switch: "后花园"
enable_switch: "启用后花园"
pump_switch_id: sprinkler_pump_sw1
run_duration_number:
id: garden_sprinkler_ctrlr_back_run_duration
name: "后花园运行时长"
initial_value: 10
unit_of_measurement: min
valve_switch_id: garden_sprinkler_valve_sw1
switch:
- platform: gpio
id: sprinkler_pump_sw0
pin: GPIOXX
- platform: gpio
id: sprinkler_pump_sw1
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw0
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw1
pin: GPIOXX
- platform: gpio
id: lawn_sprinkler_valve_sw2
pin: GPIOXX
- platform: gpio
id: garden_sprinkler_valve_sw0
pin: GPIOXX
- platform: gpio
id: garden_sprinkler_valve_sw1
pin: GPIOXX

NOTE

在此最终完整配置示例中,水泵控制分在两个喷淋控制器实例之间。 这将按预期工作;控制器的多个实例将进行通信,以确保任何给定水泵仅在必要时激活和停用, 即使控制器同时运行。

喷淋控制器可以利用 ESPHome/Home Assistant 的 number 组件, 使阀门运行时长可以从前端(Home Assistant)轻松调整。

sprinkler:
- id: lawn_sprinkler_ctrlr
multiplier_number: "草坪喷淋器乘数"
repeat_number: "草坪喷淋器重复"
...

使用 number 组件的另一个好处是,修改后的阀门运行时长、 乘数和重复值可以在 ESP 设备的重置/重启后保持。如果这是您想要的行为, 您应该在喷淋控制器配置中配置 number 组件。

喷淋控制器对 number 组件的实现基于 ESPHome 的 Number, 支持其所有 配置变量,以及 模板数值组件 配置变量的一个子集,包括:

  • initial_value(阀门默认为 900,乘数默认为 1,重复默认为 0)
  • max_value(阀门默认为 86400,乘数和重复默认为 10)
  • min_value(阀门默认为 1,乘数和重复默认为 0)
  • step(阀门和重复默认为 1,乘数默认为 0.1)
  • restore_value(默认为 true;设置为 false 以在启动时始终恢复 initial_value
  • set_action
  • unit_of_measurement(仅用于运行时长;默认为 s 表示秒,或指定 min 表示分钟)

以下是一个简短示例:

sprinkler:
- id: lawn_sprinkler_ctrlr
main_switch: "草坪喷淋器"
...
multiplier_number:
id: controller_multiplier_number
name: "草坪喷淋器乘数"
initial_value: 1.5
min_value: 0.1
max_value: 5
set_action:
- lambda: "some_function();"
...

值得注意的是,喷淋控制器配置中的各种开关都是标准的 ESPHome switch 组件。 它们的配置可以按照类似于以下示例的方式进行扩展:

# 'main_switch' 的扩展开关配置
sprinkler:
- id: sprinkler_ctrlr
main_switch:
name: "草坪喷淋器"
id: sprinkler_ctrlr_main_switch_id
on_turn_on:
light.turn_on: my_light
...

这种安排对于喷淋控制器配置块中的任何其他开关都是可能的,除了 pump_switch_idvalve_switch_id (因为这些是已在配置其他位置定义的其他开关组件的 ID)。此外,指定每个开关 ID 使得能够 从配置的其他位置引用任何喷淋控制器的开关。以下是另一个简短示例:

# 作为次要主开关的模板开关
switch:
- platform: template
id: my_switch
name: "我的特殊喷淋开关"
on_turn_off:
- switch.turn_off: sprinkler_ctrlr_main_switch_id
- light.turn_off: sprinkler_indicator_light
on_turn_on:
- switch.turn_on: sprinkler_ctrlr_main_switch_id
- light.turn_on: sprinkler_indicator_light
...

虽然上面的示例仅说明创建了一个次要”主”开关,但此方法可以扩展以利用其他设备, 如湿度 sensor — 当湿度水平过低时(查找 on_valueon_value_range), 可以通过调用控制器的一个启动动作来激活喷淋控制器(或特定阀门),例如 sprinkler.start_full_cyclesprinkler.start_from_queuesprinkler.start_single_valvesprinkler.resume_or_start_full_cycle

排队机制对于喷淋控制器来说是一个不寻常的功能;由于 ESPHome 和 Home Assistant 的极大灵活性,它变得很有用。考虑到当今可用的广泛设备生态系统, 喷淋控制器的排队机制提供了一项高级功能,旨在允许更高级的自动化。

一般来说,这归结为灵活性:更传统的”运行完整循环”和”运行单个阀门”功能 旨在供人类使用(通过前端或物理控制界面),而排队机制旨在支持自动化。

以下是一个实际示例:

考虑一个庭院被划分为多个喷淋区域的房屋 — 甚至可能包括一两个花园 (当然是鲜花和蔬菜!)。可以在各个区域和花园部署一系列土壤湿度传感器, 当给定传感器低于某个定义的阈值时,该传感器的区域将被加入喷淋控制器的队列。

然后,每天早上在某个特定时间,Home Assistant(甚至是 ESP 设备本身!)调用喷淋控制器的 sprinkler.start_from_queue 动作,导致控制器仅遍历排队的区域。 由于运行时长可以作为队列请求的一部分指定,这可以扩展为根据任何给定日期土壤的具体湿度水平 计算每个区域的具体运行时长。可能性是无限的,仅受您的创造力限制!

重要的是要注意,如果自动前进和队列开关 打开/启用,排队的阀门优先于 作为系统完整循环的一部分运行的阀门。 换句话说,如果队列启用且在完整循环活动时 有阀门加入队列,在下一个阀门切换时,队列条目将在作为完整循环一部分运行的 下一个阀门 之前 被处理。目前,此行为无法更改。还应注意,队列为限制内存使用 设置了 100 个条目的硬编码限制。

通过用户 API 暴露喷淋控制器动作

Section titled “通过用户 API 暴露喷淋控制器动作”

此配置片段说明了如何使用用户定义的 ESPHome API 动作将各种喷淋控制器动作暴露给前端。 这对于使用自动化更改设置和/或触发喷淋控制器动作可能很有用。

api:
actions:
- action: set_multiplier
variables:
multiplier: float
then:
- sprinkler.set_multiplier:
id: lawn_sprinkler_ctrlr
multiplier: !lambda 'return multiplier;'
- action: start_full_cycle
then:
- sprinkler.start_full_cycle: lawn_sprinkler_ctrlr
- action: start_single_valve
variables:
valve: int
then:
- sprinkler.start_single_valve:
id: lawn_sprinkler_ctrlr
valve_number: !lambda 'return valve;'
- action: next_valve
then:
- sprinkler.next_valve: lawn_sprinkler_ctrlr
- action: previous_valve
then:
- sprinkler.previous_valve: lawn_sprinkler_ctrlr
- action: shutdown
then:
- sprinkler.shutdown: lawn_sprinkler_ctrlr

许多人询问如何确定喷淋控制器的状态。本节旨在概述如何使用喷淋控制器的 API Reference: API 来确定它在做什么,通常目标是在某种形式的 display 硬件上指示这一点。请注意,此讨论主要围绕 C++ 代码 (如 ESPHome lambda 中使用的)。

用于确定喷淋控制器状态的许多方法返回一种称为 optional 的值类型。 如果您好奇,可以在 cppreference.com 上找到 optional 类型的通用参考, 但现在重要的是:

  • optional 类型 可能可能不 包含值

    • 方法 has_value() 用于确定是否存在值。例如: id(lawn_sprinkler_ctrlr).active_valve().has_value()

    • 方法 value() 用于确定值,如果 确定存在值。例如: auto running_valve = id(lawn_sprinkler_ctrlr).active_valve().value()

  • optional 类型可以包含任何 C++ 类型的值(boolintfloat 等)(用 C++ 术语来说,它是一个模板。)

随后的示例说明了在 display lambda 中使用喷淋控制器的方法。 这些示例旨在说明一种模式,并且(为了简洁起见)不完整;至少您需要填写 display 组件的具体配置详细信息才能使用它们。

记住这些要点,让我们讨论一些指示喷淋控制器状态的方法。 我们将从 “我如何…” 的角度来处理这个问题

  • …确定喷淋控制器是否正在运行?

    使用方法 optional<size_t> active_valve() 检查是否有活动阀门。如果返回的 optional has_value(),喷淋控制器正在运行,您可以使用 value() 方法检查具体哪个阀门处于活动状态。

    示例:

display:
- platform: ...
# ...显示配置...
lambda: |-
if (id(lawn_sprinkler_ctrlr).active_valve().has_value()) {
// 控制器正在运行,获取活动阀门到 running_valve 并打印
auto running_valve = id(lawn_sprinkler_ctrlr).active_valve().value();
it.printf(0, 0, "阀门 %u 活动", running_valve);
} else {
// 控制器未运行
it.print(0, 0, "空闲");
}
  • …确定喷淋控制器是否暂停,如果是,哪个阀门暂停?

    使用方法 optional<size_t> paused_valve() 检查是否有暂停的阀门。如果返回的 optional has_value(),喷淋控制器已暂停,您可以使用 value() 方法检查具体哪个阀门暂停。 一般来说,这遵循与 active_valve() 示例 相同的模式。

  • …确定喷淋控制器的当前模式?

    如果您指的是”是否启用了自动前进/队列/反向/待机?“,您来对地方了。存在专门用于此目的的方法:

    • bool auto_advance()
    • bool queue_enabled()
    • bool reverse()
    • bool standby()

    如果各自的”模式”启用,每个方法将返回 true

    示例:

display:
- platform: ...
# ...显示配置...
lambda: |-
if (id(lawn_sprinkler_ctrlr).auto_advance()) {
// 自动前进已启用
it.print(0, 0, "自动前进已启用");
} else {
// 自动前进未启用
it.print(0, 0, "自动前进已禁用");
}
if (id(lawn_sprinkler_ctrlr).queue_enabled()) {
// 队列已启用
it.print(0, 10, "队列已启用");
} else {
// 队列未启用
it.print(0, 10, "队列已禁用");
}
  • …确定喷淋控制器的乘数/重复值?

    在这种情况下,感兴趣的方法有:

    • float multiplier()
    • optional<uint32_t> repeat()
    • optional<uint32_t> repeat_count()

    再次注意,每个 repeat 方法都返回一个 optional 类型;如果返回的 optional has_value(),重复已启用,您可以使用 optionalvalue() 方法获取重复目标 (repeat())或当前重复计数(repeat_count())。

    multiplier() 方法返回一个 float 类型,因此它始终有一个值。

    示例:

display:
- platform: ...
# ...显示配置...
lambda: |-
it.printf(0, 0, "乘数: %f", id(lawn_sprinkler_ctrlr).multiplier());
if (id(lawn_sprinkler_ctrlr).repeat().has_value()) {
// 控制器正在重复,打印重复目标值
it.printf(0, 10, "重复 %u", id(lawn_sprinkler_ctrlr).repeat().value());
}
  • …确定还剩多少时间/需要多少时间?

    为此目的提供了几种方法:

    • uint32_t total_cycle_time_all_valves()
    • uint32_t total_cycle_time_enabled_valves()
    • uint32_t total_cycle_time_enabled_incomplete_valves()
    • uint32_t total_queue_time()
    • optional<uint32_t> time_remaining_active_valve()
    • optional<uint32_t> time_remaining_current_operation()

    请注意,与前面的几个示例一样,time_remaining_... 方法各自返回一个 optional 类型。 如果返回的 optional has_value(),则阀门处于活动/运行状态;如果没有 has_value(), 则没有活动阀门,意味着控制器空闲。

    示例:

display:
- platform: ...
# ...显示配置...
lambda: |-
if (id(lawn_sprinkler_ctrlr).time_remaining_active_valve().has_value()) {
// 控制器正在运行,打印剩余秒数
it.printf(0, 0, "剩余时间: %u", id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value());
} else {
// 控制器未运行
it.print(0, 0, "空闲");
}