mirror of
https://github.com/anklimov/lighthub
synced 2026-07-29 01:52:43 +00:00
Compare commits
6 Commits
641b314218
...
565195d60a
| Author | SHA1 | Date | |
|---|---|---|---|
| 565195d60a | |||
| 84ce56fdde | |||
| c1937a045b | |||
| fd23dc3567 | |||
| 898dca260c | |||
| 985d058c50 |
894
documentation/Sprinkler_HomeAssistant.md
Normal file
894
documentation/Sprinkler_HomeAssistant.md
Normal file
@@ -0,0 +1,894 @@
|
||||
# Исчерпывающее руководство по настройке системы полива в Home Assistant
|
||||
|
||||
Это руководство шаг за шагом проведёт вас через установку и настройку многоканальной системы полива на базе [lighthub](https://github.com/anklimov/lighthub), интегрированной с Home Assistant через MQTT. В результате вы получите красивую и функциональную панель управления, которая включает:
|
||||
|
||||
- визуализацию уровня воды в баке (пусто / наполовину / полный),
|
||||
- индикацию работы водопровода, дренажного и основного насосов,
|
||||
- управление тремя зонами полива с заданием времени и прогресс-баром,
|
||||
- интерактивную корректировку выполненного времени через проценты,
|
||||
- историю ключевых параметров по клику на иконки.
|
||||
|
||||
---
|
||||
|
||||
## 1. Предварительные требования
|
||||
|
||||
- Установленный и настроенный [Home Assistant](https://www.home-assistant.io/) (любая версия, поддерживающая Lovelace).
|
||||
- Настроенный MQTT-брокер (например, Mosquitto) и интеграция MQTT в Home Assistant.
|
||||
- [HACS](https://hacs.xyz/) (Home Assistant Community Store) – для установки кастомных карт.
|
||||
|
||||
> **Примечание:** Конфигурация MQTT‑датчиков и устройств уже готова и будет приведена ниже. Предполагается, что ваш контроллер lighthub уже отправляет данные в соответствующие топики.
|
||||
|
||||
---
|
||||
|
||||
## 2. Установка кастомных карт через HACS
|
||||
|
||||
Для корректной работы панели необходимо установить следующие карты. Все они доступны в HACS.
|
||||
|
||||
1. Откройте **HACS** → **Frontend** → **Explore & Download Repositories**.
|
||||
2. Поочерёдно найдите и установите каждую из перечисленных ниже карт.
|
||||
3. После установки **обновите страницу** браузера (или перезагрузите интерфейс Home Assistant).
|
||||
|
||||
### Список обязательных карт
|
||||
|
||||
| Название | Репозиторий (для ручного добавления, если не находится) | Назначение |
|
||||
|------------------------------|----------------------------------------------------------|------------|
|
||||
| **Vertical Stack In Card** | `ofekashery/vertical-stack-in-card` | Объединение нескольких карточек в одну с общим фоном |
|
||||
| **Button Card** | `custom-cards/button-card` | Гибкая карточка с динамическими иконками, анимацией и состояниями |
|
||||
| **Bar Card** | `spacerokk/bar-card` (активный форк) | Прогресс-бар для отображения выполнения полива |
|
||||
| **Mushroom Cards** | `piitaya/lovelace-mushroom` | Компактные и стильные карточки для датчиков и переключателей |
|
||||
| **Slider Entity Row** | `thomasloven/lovelace-slider-entity-row` | Ползунок для настройки времени в more‑info окнах (не обязателен, но используется в стандартном окне `number`) |
|
||||
| **Card Mod** | `thomasloven/lovelace-card-mod` | Позволяет добавлять произвольные CSS‑стили к карточкам |
|
||||
|
||||
> **Важно:** Если какая‑то карта не отображается в HACS, добавьте её вручную через **HACS → ⋮ → Пользовательские репозитории**. В поле URL вставьте ссылку на GitHub‑репозиторий, категорию выберите **Lovelace**.
|
||||
|
||||
---
|
||||
|
||||
## 3. Настройка MQTT‑сущностей
|
||||
|
||||
Вся логика обмена данными с контроллером lighthub заложена в MQTT‑конфигурации. Скопируйте приведённый ниже блок в файл `configuration.yaml` (или в отдельный файл, подключённый через `mqtt: !include mqtt.yaml`).
|
||||
|
||||
```yaml
|
||||
# Пример размещения в configuration.yaml
|
||||
mqtt:
|
||||
switch:
|
||||
- name: "Полив"
|
||||
state_topic: "edem/s_out/sprinkler/cmd"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив север"
|
||||
state_topic: "edem/s_out/sprinkler/nord/cmd"
|
||||
command_topic: "edem/air/sprinkler/nord/cmd"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив юг"
|
||||
state_topic: "edem/s_out/sprinkler/south/cmd"
|
||||
command_topic: "edem/air/sprinkler/south/cmd"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив капельный"
|
||||
state_topic: "edem/s_out/sprinkler/trees/cmd"
|
||||
command_topic: "edem/air/sprinkler/trees/cmd"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив розетки"
|
||||
state_topic: "edem/s_out/sprinkler/outlets/cmd"
|
||||
command_topic: "edem/air/sprinkler/outlets/cmd"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
button:
|
||||
- name: "Полив сброс"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
payload_press: "RESET"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив блокировка"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
payload_press: "FREEZE"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив разблокировка"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
payload_press: "UNFREEZE"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив разрешить"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
payload_press: "ENABLE"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив запретить"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
payload_press: "DISABLE"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив осушение бака"
|
||||
command_topic: "edem/air/sprinkler/cmd"
|
||||
payload_press: "DRY"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
number:
|
||||
- name: "Полив юг"
|
||||
state_topic: "edem/s_out/sprinkler/south/set"
|
||||
command_topic: "edem/air/sprinkler/south/set"
|
||||
min: 0
|
||||
max: 6000
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив север"
|
||||
state_topic: "edem/s_out/sprinkler/nord/set"
|
||||
command_topic: "edem/air/sprinkler/nord/set"
|
||||
min: 0
|
||||
max: 6000
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив капельный"
|
||||
state_topic: "edem/s_out/sprinkler/trees/set"
|
||||
command_topic: "edem/air/sprinkler/trees/set"
|
||||
min: 0
|
||||
max: 6000
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив юг выполнено"
|
||||
state_topic: "edem/s_out/sprinkler/south/val"
|
||||
command_topic: "edem/air/sprinkler/south/val"
|
||||
min: 0
|
||||
max: 60000
|
||||
mode: slider
|
||||
icon: "mdi:timer-sand"
|
||||
unit_of_measurement: 'sec'
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив север выполнено"
|
||||
state_topic: "edem/s_out/sprinkler/nord/val"
|
||||
command_topic: "edem/air/sprinkler/nord/val"
|
||||
min: 0
|
||||
max: 60000
|
||||
mode: slider
|
||||
icon: "mdi:timer-sand"
|
||||
unit_of_measurement: 'sec'
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив капельный выполнено"
|
||||
state_topic: "edem/s_out/sprinkler/trees/val"
|
||||
command_topic: "edem/air/sprinkler/trees/val"
|
||||
min: 0
|
||||
max: 60000
|
||||
mode: slider
|
||||
icon: "mdi:timer-sand"
|
||||
unit_of_measurement: 'sec'
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
sensor:
|
||||
- name: "Полив бак Макс"
|
||||
state_topic: "edem/s_out/sprinkler/$wMax"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив бак Мin"
|
||||
state_topic: "edem/s_out/sprinkler/$wMin"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив водопровод"
|
||||
state_topic: "edem/s_out/sprinkler/$vIN"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив дренаж вкл"
|
||||
state_topic: "edem/s_out/sprinkler/$rDren"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив дренаж качает"
|
||||
state_topic: "edem/s_out/sprinkler/$fbDren"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив насос вкл"
|
||||
state_topic: "edem/s_out/sprinkler/$rPump"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив насос качает"
|
||||
state_topic: "edem/s_out/sprinkler/$fbPump"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив состояние"
|
||||
state_topic: "edem/s_out/sprinkler/$state"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив ошибка"
|
||||
state_topic: "edem/s_out/sprinkler/$fault"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Поливаем юг"
|
||||
state_topic: "edem/s_out/sprinkler/south/$state"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Поливаем север"
|
||||
state_topic: "edem/s_out/sprinkler/nord/$state"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Поливаем капельно"
|
||||
state_topic: "edem/s_out/sprinkler/trees/$state"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив розетка статус"
|
||||
state_topic: "edem/s_out/sprinkler/outlets/$state"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив блокировки"
|
||||
state_topic: "edem/s_out/sprinkler/ctrl"
|
||||
availability_topic: "edem/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
```
|
||||
|
||||
> **Пояснение:**
|
||||
> - `switch` – переключатели для запуска/остановки зон и общий переключатель.
|
||||
> - `button` – кнопки для сброса, блокировки, разрешения и осушения бака.
|
||||
> - `number` – задание времени полива (уставки) и выполненное время (с возможностью ручной корректировки).
|
||||
> - `sensor` – датчики состояния поплавков (`$wMax`, `$wMin`), водопровода, насосов, статуса полива, ошибок и т.д.
|
||||
|
||||
После добавления конфигурации **перезагрузите YAML** (Настройки → Сервер → Перезагрузить конфигурацию YAML).
|
||||
|
||||
---
|
||||
|
||||
## 4. Настройка template‑сущностей
|
||||
|
||||
Для работы панели необходимы два типа вычислимых объектов:
|
||||
|
||||
- **Уровень бака в процентах** (на основе поплавков).
|
||||
- **Прогресс полива в процентах** для каждой зоны (с возможностью двусторонней синхронизации: проценты ↔ секунды).
|
||||
|
||||
Добавьте следующий блок в `configuration.yaml` (если у вас уже есть секция `template:`, объедините её с этим содержимым, сохранив правильные отступы):
|
||||
|
||||
```yaml
|
||||
template:
|
||||
# Сенсор уровня бака
|
||||
- sensor:
|
||||
- name: "Полив бак уровень"
|
||||
state: >
|
||||
{% if states('sensor.poliv_bak_maks') == 'ON' %}
|
||||
100
|
||||
{% elif states('sensor.poliv_bak_min') == 'ON' %}
|
||||
50
|
||||
{% else %}
|
||||
0
|
||||
{% endif %}
|
||||
|
||||
# Числовые шаблоны прогресса (проценты)
|
||||
- number:
|
||||
- name: "Полив юг прогресс"
|
||||
state: >
|
||||
{% set zadanie = states('number.poliv_iug') | float(0) %}
|
||||
{% set vypolneno = states('number.poliv_iug_vypolneno') | float(0) %}
|
||||
{{ ((vypolneno / zadanie * 100) | round(0)) if zadanie > 0 else 0 }}
|
||||
set_value:
|
||||
- service: number.set_value
|
||||
target:
|
||||
entity_id: number.poliv_iug_vypolneno
|
||||
data:
|
||||
value: >
|
||||
{% set zadanie = states('number.poliv_iug') | float(0) %}
|
||||
{{ ((value | float(0)) * zadanie / 100) | round(0) }}
|
||||
min: 0
|
||||
max: 100
|
||||
step: 1
|
||||
unit_of_measurement: "%"
|
||||
icon: mdi:progress-clock
|
||||
|
||||
- name: "Полив север прогресс"
|
||||
state: >
|
||||
{% set zadanie = states('number.poliv_sever') | float(0) %}
|
||||
{% set vypolneno = states('number.poliv_sever_vypolneno') | float(0) %}
|
||||
{{ ((vypolneno / zadanie * 100) | round(0)) if zadanie > 0 else 0 }}
|
||||
set_value:
|
||||
- service: number.set_value
|
||||
target:
|
||||
entity_id: number.poliv_sever_vypolneno
|
||||
data:
|
||||
value: >
|
||||
{% set zadanie = states('number.poliv_sever') | float(0) %}
|
||||
{{ ((value | float(0)) * zadanie / 100) | round(0) }}
|
||||
min: 0
|
||||
max: 100
|
||||
step: 1
|
||||
unit_of_measurement: "%"
|
||||
icon: mdi:progress-clock
|
||||
|
||||
- name: "Полив капельный прогресс"
|
||||
state: >
|
||||
{% set zadanie = states('number.poliv_kapelnyi') | float(0) %}
|
||||
{% set vypolneno = states('number.poliv_kapelnyi_vypolneno') | float(0) %}
|
||||
{{ ((vypolneno / zadanie * 100) | round(0)) if zadanie > 0 else 0 }}
|
||||
set_value:
|
||||
- service: number.set_value
|
||||
target:
|
||||
entity_id: number.poliv_kapelnyi_vypolneno
|
||||
data:
|
||||
value: >
|
||||
{% set zadanie = states('number.poliv_kapelnyi') | float(0) %}
|
||||
{{ ((value | float(0)) * zadanie / 100) | round(0) }}
|
||||
min: 0
|
||||
max: 100
|
||||
step: 1
|
||||
unit_of_measurement: "%"
|
||||
icon: mdi:progress-clock
|
||||
```
|
||||
|
||||
**Как это работает:**
|
||||
- `state` динамически вычисляет процент выполнения на основе заданного времени (`number.poliv_...`) и выполненного (`number.poliv_..._vypolneno`).
|
||||
- `set_value` при ручном изменении процента (через ползунок или ввод) пересчитывает его в секунды и отправляет команду в контроллер через `number.set_value` для выполненного времени. Таким образом, можно вручную скорректировать прогресс, и значение сразу уйдёт в MQTT.
|
||||
- Бак определяется по поплавкам: если активен `$wMax` → 100%, если только `$wMin` → 50%, иначе 0%.
|
||||
|
||||
Снова **перезагрузите YAML‑конфигурацию**.
|
||||
|
||||
---
|
||||
|
||||
## 5. Создание панели управления (Dashboard)
|
||||
|
||||
### 5.1. Создание новой панели
|
||||
|
||||
1. Перейдите в **Настройки** → **Панели** (Dashboards).
|
||||
2. Нажмите **Создать панель** (Add Dashboard).
|
||||
- Название: `💧 Полив`
|
||||
- Режим панели: **Панель (одна карточка)** – *Panel (1 card)*.
|
||||
3. Нажмите **Создать**.
|
||||
|
||||
### 5.2. Переход в редактор YAML
|
||||
|
||||
Сразу после создания панель откроется в графическом редакторе.
|
||||
Нажмите на три точки **⋮** в правом верхнем углу и выберите **Редактор YAML**.
|
||||
|
||||
### 5.3. Вставка финального YAML
|
||||
|
||||
Удалите всё содержимое (обычно там `type: panel\npath: ""\ncards: []`) и вставьте следующий код:
|
||||
|
||||
```yaml
|
||||
views:
|
||||
- type: panel
|
||||
path: ''
|
||||
cards:
|
||||
- type: custom:vertical-stack-in-card
|
||||
title: 💧 Система полива
|
||||
cards:
|
||||
# ── Общее состояние ──
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: sensor.poliv_sostoianie
|
||||
name: Статус
|
||||
primary_info: state
|
||||
icon: mdi:state-machine
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: sensor.poliv_blokirovki
|
||||
name: Режим
|
||||
primary_info: state
|
||||
icon: mdi:lock
|
||||
|
||||
# ── Бак ──
|
||||
- type: custom:mushroom-template-card
|
||||
primary: Бак воды
|
||||
secondary: |
|
||||
{% set lvl = states('sensor.poliv_bak_uroven') %}
|
||||
{% if lvl == '100' %} Полный
|
||||
{% elif lvl == '50' %} Наполовину
|
||||
{% else %} Пустой {% endif %}
|
||||
icon: mdi:battery
|
||||
icon_color: |
|
||||
{% set lvl = states('sensor.poliv_bak_uroven') %}
|
||||
{% if lvl == '100' %} green
|
||||
{% elif lvl == '50' %} orange
|
||||
{% else %} grey {% endif %}
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.poliv_bak_uroven
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
- type: divider
|
||||
|
||||
# ── Водопровод ──
|
||||
- type: custom:mushroom-template-card
|
||||
primary: Водопровод
|
||||
secondary: |
|
||||
{% if states('sensor.poliv_vodoprovod') == 'ON' %} Вкл
|
||||
{% else %} Выкл {% endif %}
|
||||
icon: mdi:water-pump
|
||||
icon_color: |
|
||||
{% if states('sensor.poliv_vodoprovod') == 'ON' %} blue
|
||||
{% else %} grey {% endif %}
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.poliv_vodoprovod
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
# ── Насосы ──
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:mushroom-template-card
|
||||
primary: Дренаж
|
||||
secondary: |
|
||||
{% set pwr = states('sensor.poliv_drenazh_vkl') %}
|
||||
{% set pump = states('sensor.poliv_drenazh_kachaet') %}
|
||||
{% if pwr == 'ON' and pump == 'ON' %} Качает
|
||||
{% elif pwr == 'ON' %} Вкл
|
||||
{% else %} Выкл {% endif %}
|
||||
icon: mdi:pump
|
||||
icon_color: |
|
||||
{% set pwr = states('sensor.poliv_drenazh_vkl') %}
|
||||
{% set pump = states('sensor.poliv_drenazh_kachaet') %}
|
||||
{% if pwr == 'ON' and pump == 'ON' %} red
|
||||
{% elif pwr == 'ON' %} green
|
||||
{% else %} grey {% endif %}
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.poliv_drenazh_kachaet
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 65px;
|
||||
}
|
||||
|
||||
- type: custom:mushroom-template-card
|
||||
primary: Помпа
|
||||
secondary: |
|
||||
{% set pwr = states('sensor.poliv_nasos_vkl') %}
|
||||
{% set pump = states('sensor.poliv_nasos_kachaet') %}
|
||||
{% if pwr == 'ON' and pump == 'ON' %} Качает
|
||||
{% elif pwr == 'ON' %} Вкл
|
||||
{% else %} Выкл {% endif %}
|
||||
icon: mdi:pump
|
||||
icon_color: |
|
||||
{% set pwr = states('sensor.poliv_nasos_vkl') %}
|
||||
{% set pump = states('sensor.poliv_nasos_kachaet') %}
|
||||
{% if pwr == 'ON' and pump == 'ON' %} red
|
||||
{% elif pwr == 'ON' %} green
|
||||
{% else %} grey {% endif %}
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.poliv_nasos_kachaet
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 65px;
|
||||
}
|
||||
|
||||
- type: divider
|
||||
|
||||
# ── Управление циклом ──
|
||||
- type: entities
|
||||
title: Управление циклом
|
||||
show_header_toggle: false
|
||||
entities:
|
||||
- entity: switch.poliv
|
||||
name: Полив
|
||||
icon: mdi:sprinkler
|
||||
- entity: switch.poliv_rozetki
|
||||
name: Водяная розетка
|
||||
icon: mdi:pipe-valve
|
||||
- entity: button.poliv_sbros
|
||||
name: Запуск всех зон
|
||||
icon: mdi:play
|
||||
- entity: button.poliv_blokirovka
|
||||
name: Заморозить
|
||||
icon: mdi:snowflake
|
||||
- entity: button.poliv_razblokirovka
|
||||
name: Разморозить
|
||||
icon: mdi:snowflake-melt
|
||||
- entity: button.poliv_zapretit
|
||||
name: Запретить полив
|
||||
icon: mdi:cancel
|
||||
- entity: button.poliv_razreshit
|
||||
name: Разрешить полив
|
||||
icon: mdi:check-circle
|
||||
- entity: button.poliv_osushenie_baka
|
||||
name: Осушение бака
|
||||
icon: mdi:hair-dryer
|
||||
|
||||
- type: divider
|
||||
|
||||
# ── Северная зона ──
|
||||
- type: custom:vertical-stack-in-card
|
||||
title: 🌿 Северная зона
|
||||
cards:
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
# Выключатель
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: switch.poliv_sever
|
||||
show_name: false
|
||||
show_icon: false
|
||||
show_state: false
|
||||
layout: horizontal
|
||||
# Время
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: number.poliv_sever
|
||||
name: Время
|
||||
icon: mdi:timer-edit
|
||||
layout: horizontal
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 48px;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
- type: conditional
|
||||
conditions:
|
||||
- entity: number.poliv_sever
|
||||
state_not: '0'
|
||||
card:
|
||||
type: custom:vertical-stack-in-card
|
||||
title: ''
|
||||
cards:
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:button-card
|
||||
entity: sensor.polivaem_sever
|
||||
show_name: false
|
||||
show_state: false
|
||||
icon: mdi:sprinkler
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.polivaem_sever
|
||||
state:
|
||||
- value: 'ON'
|
||||
color: green
|
||||
styles:
|
||||
icon:
|
||||
- animation: pulse 1.5s infinite
|
||||
- value: 'OFF'
|
||||
color: grey
|
||||
styles:
|
||||
icon:
|
||||
- animation: none
|
||||
styles:
|
||||
card:
|
||||
- height: 40px
|
||||
- width: 40px
|
||||
icon:
|
||||
- width: 24px
|
||||
- height: 24px
|
||||
- type: custom:mushroom-template-card
|
||||
primary: ''
|
||||
secondary: >
|
||||
Выполнено: {{ states('number.poliv_sever_vypolneno')
|
||||
}} / {{ states('number.poliv_sever') }} с
|
||||
icon: ''
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: number.poliv_sever_progress
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
height: 40px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
- type: custom:bar-card
|
||||
entities:
|
||||
- entity: number.poliv_sever_progress
|
||||
name: Прогресс
|
||||
icon: mdi:progress-clock
|
||||
max: 100
|
||||
severity:
|
||||
- from: 0
|
||||
to: 25
|
||||
color: red
|
||||
- from: 26
|
||||
to: 75
|
||||
color: orange
|
||||
- from: 76
|
||||
to: 100
|
||||
color: green
|
||||
unit_of_measurement: '%'
|
||||
|
||||
- type: divider
|
||||
|
||||
# ── Южная зона ──
|
||||
- type: custom:vertical-stack-in-card
|
||||
title: 🌿 Южная зона
|
||||
cards:
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: switch.poliv_iug
|
||||
show_name: false
|
||||
show_icon: false
|
||||
show_state: false
|
||||
layout: horizontal
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: number.poliv_iug
|
||||
name: Время
|
||||
icon: mdi:timer-edit
|
||||
layout: horizontal
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 48px;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
- type: conditional
|
||||
conditions:
|
||||
- entity: number.poliv_iug
|
||||
state_not: '0'
|
||||
card:
|
||||
type: custom:vertical-stack-in-card
|
||||
title: ''
|
||||
cards:
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:button-card
|
||||
entity: sensor.polivaem_iug
|
||||
show_name: false
|
||||
show_state: false
|
||||
icon: mdi:sprinkler
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.polivaem_iug
|
||||
state:
|
||||
- value: 'ON'
|
||||
color: green
|
||||
styles:
|
||||
icon:
|
||||
- animation: pulse 1.5s infinite
|
||||
- value: 'OFF'
|
||||
color: grey
|
||||
styles:
|
||||
icon:
|
||||
- animation: none
|
||||
styles:
|
||||
card:
|
||||
- height: 40px
|
||||
- width: 40px
|
||||
icon:
|
||||
- width: 24px
|
||||
- height: 24px
|
||||
- type: custom:mushroom-template-card
|
||||
primary: ''
|
||||
secondary: >
|
||||
Выполнено: {{ states('number.poliv_iug_vypolneno')
|
||||
}} / {{ states('number.poliv_iug') }} с
|
||||
icon: ''
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: number.poliv_iug_progress
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
height: 40px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
- type: custom:bar-card
|
||||
entities:
|
||||
- entity: number.poliv_iug_progress
|
||||
name: Прогресс
|
||||
icon: mdi:progress-clock
|
||||
max: 100
|
||||
severity:
|
||||
- from: 0
|
||||
to: 25
|
||||
color: red
|
||||
- from: 26
|
||||
to: 75
|
||||
color: orange
|
||||
- from: 76
|
||||
to: 100
|
||||
color: green
|
||||
unit_of_measurement: '%'
|
||||
|
||||
- type: divider
|
||||
|
||||
# ── Капельная зона ──
|
||||
- type: custom:vertical-stack-in-card
|
||||
title: 🌿 Капельная зона
|
||||
cards:
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: switch.poliv_kapelnyi
|
||||
show_name: false
|
||||
show_icon: false
|
||||
show_state: false
|
||||
layout: horizontal
|
||||
- type: custom:mushroom-entity-card
|
||||
entity: number.poliv_kapelnyi
|
||||
name: Время
|
||||
icon: mdi:timer-edit
|
||||
layout: horizontal
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
--mush-icon-size: 24px;
|
||||
height: 48px;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
- type: conditional
|
||||
conditions:
|
||||
- entity: number.poliv_kapelnyi
|
||||
state_not: '0'
|
||||
card:
|
||||
type: custom:vertical-stack-in-card
|
||||
title: ''
|
||||
cards:
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: custom:button-card
|
||||
entity: sensor.polivaem_kapelno
|
||||
show_name: false
|
||||
show_state: false
|
||||
icon: mdi:watering-can
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: sensor.polivaem_kapelno
|
||||
state:
|
||||
- value: 'ON'
|
||||
color: green
|
||||
styles:
|
||||
icon:
|
||||
- animation: pulse 1.5s infinite
|
||||
- value: 'OFF'
|
||||
color: grey
|
||||
styles:
|
||||
icon:
|
||||
- animation: none
|
||||
styles:
|
||||
card:
|
||||
- height: 40px
|
||||
- width: 40px
|
||||
icon:
|
||||
- width: 24px
|
||||
- height: 24px
|
||||
- type: custom:mushroom-template-card
|
||||
primary: ''
|
||||
secondary: >
|
||||
Выполнено: {{
|
||||
states('number.poliv_kapelnyi_vypolneno') }} / {{
|
||||
states('number.poliv_kapelnyi') }} с
|
||||
icon: ''
|
||||
tap_action:
|
||||
action: more-info
|
||||
entity: number.poliv_kapelnyi_progress
|
||||
card_mod:
|
||||
style: |
|
||||
ha-card {
|
||||
height: 40px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
- type: custom:bar-card
|
||||
entities:
|
||||
- entity: number.poliv_kapelnyi_progress
|
||||
name: Прогресс
|
||||
icon: mdi:progress-clock
|
||||
max: 100
|
||||
severity:
|
||||
- from: 0
|
||||
to: 25
|
||||
color: red
|
||||
- from: 26
|
||||
to: 75
|
||||
color: orange
|
||||
- from: 76
|
||||
to: 100
|
||||
color: green
|
||||
unit_of_measurement: '%'
|
||||
```
|
||||
|
||||
Нажмите **Сохранить** – панель готова к использованию.
|
||||
|
||||
---
|
||||
|
||||
## 6. Как пользоваться панелью
|
||||
|
||||

|
||||

|
||||
- **Общее состояние:** Отображает статус системы и режим (заморозка/разрешено/запрещено). Ошибка не показывается, но иконка станет красной при неисправности.
|
||||
- **Бак:** Иконка батарейки меняет цвет и текст в зависимости от уровня воды (пусто/наполовину/полный). Нажатие открывает историю уровня.
|
||||
- **Водопровод и насосы:** Показывают текущий статус (Выкл/Вкл/Качает) с цветовой индикацией. Клик – история соответствующего датчика.
|
||||
- **Управление циклом:** Общий переключатель «Полив», кнопки запуска всех зон, заморозки, запрета, осушения бака. Работают как обычные MQTT‑команды.
|
||||
- **Зоны полива:**
|
||||
1. **Включение зоны** – крайний левый переключатель (тумблер).
|
||||
2. **Время** – поле с кнопками +/- для задания уставки полива в секундах.
|
||||
3. Если время > 0, под строкой появятся:
|
||||
- Индикатор полива (спринклер/лейка) – цветной, с анимацией пульсации при работе. Нажатие открывает историю активности зоны.
|
||||
- Строка «Выполнено: X / Y с» – абсолютное значение. Нажатие открывает окно редактирования прогресса в процентах.
|
||||
- Прогресс-бар – визуальное отображение процента выполнения (красный → оранжевый → зелёный).
|
||||
- **Корректировка прогресса:** Кликните на строку «Выполнено…» → появится слайдер 0-100%. Измените процент, и соответствующее количество секунд сразу отправится в контроллер (автоматический пересчёт).
|
||||
|
||||
---
|
||||
|
||||
## 7. Возможные проблемы и их решение
|
||||
|
||||
| Проблема | Вероятная причина | Решение |
|
||||
|----------|-------------------|---------|
|
||||
| Не отображаются прогресс‑бары | Отсутствует `bar-card` или не созданы `template number` | Проверьте HACS, установите карту. Убедитесь, что template‑числа добавлены и конфигурация перезагружена. |
|
||||
| Иконка полива не меняет цвет | Неправильное имя датчика `sensor.polivaem_...` | Проверьте точное название в разделе **Состояния**. Поправьте в YAML панели. |
|
||||
| Тумблер включения зоны не видим | Не установлена карта `mushroom-entity-card` или перекрыт стилями | Убедитесь, что `mushroom-cards` установлены. В нашем финальном YAML тумблер видим всегда. |
|
||||
| Ошибка «expected float» при движении слайдера прогресса | Используется `slider-entity-row` в активном режиме, а динамический `max` задан некорректно | В нашем решении прогресс‑бар только визуальный (`bar-card`), ручная корректировка – через `template number` с собственным `set_value`. Ошибки быть не должно. |
|
||||
| Бак всегда показывает «Пустой» | Неправильно работают поплавки или датчики `$wMax`/`$wMin` не обновляются | Проверьте в MQTT‑топиках фактические значения. Убедитесь, что поплавки подключены и отправляют ON/OFF. |
|
||||
|
||||
---
|
||||
|
||||
## 8. Дополнительная информация
|
||||
|
||||
- Все команды управления (вкл/выкл зон, сброс, заморозка и т.д.) отправляются напрямую в контроллер lighthub через MQTT.
|
||||
- Система использует `availability_topic` для отслеживания связи с контроллером. При пропадании сигнала все элементы станут недоступны (серые).
|
||||
- При желании можно расширить панель новыми зонами, копируя структуру существующих и добавляя соответствующие `number`, `switch` и `sensor` в MQTT‑конфигурацию и `template`.
|
||||
|
||||
---
|
||||
|
||||
## Приложение: полный финальный YAML панели
|
||||
|
||||
Код уже приведён в разделе 5.3. Используйте его как окончательную версию.
|
||||
|
||||
---
|
||||
|
||||
Теперь ваша система полива полностью интегрирована в Home Assistant. Вы можете управлять поливом с мобильного телефона, отслеживать историю и быть уверенными, что всё под контролем!
|
||||
@@ -28,13 +28,13 @@ INIT | true | OFF | выключить клапана
|
||||
OFF | vMax && !FREEZE | FULL | выключить vIN, rDren|
|
||||
OFF | ! vMax && !FREEZE | DREN\_ON|включить rDren|
|
||||
DREN\_ON|fbDren (насос дренажа реально работает)|DREN\_OPERATE|
|
||||
DREN\_ON|таймаут 10 сек|DREN\_EMPTY|
|
||||
DREN\_ON|таймаут 10 сек|DREN\_EMPTY| насос так и не заработал - видимо в колодце пусто
|
||||
DREN\_EMPTY|включен цикл полива и бак не полон|VIN|включить клапан vIN для набора бака из водопровода|
|
||||
DREN\_OPERATE|fbDren (насос дренажа более не работает)|DREN\_EMPTY||
|
||||
VIN|fbDren|DREN\_OPERATE|вылючить клапан vIN для набора бака из водопровода|
|
||||
VIN, DREN\_OPERATE|vMax|FULL | выключить vIN, rDren|
|
||||
VIN|таймаут 1200 сек | FAULT\_VIN| выключить vIN|
|
||||
DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN||
|
||||
DREN\_OPERATE| ! fbDren (насос дренажа более не работает)|DREN\_EMPTY||
|
||||
VIN|fbDren|DREN\_OPERATE|вылючить клапан vIN для набора бака из водопровода - заработал дренажный насос|
|
||||
VIN, DREN\_OPERATE|vMax|FULL | выключить vIN, rDren - бак полон|
|
||||
VIN|таймаут 1200 сек | FAULT\_VIN| выключить vIN - бак так и не наполнился|
|
||||
DREN\_OPERATE|таймаут 2000 сек |FAULT_DREN|выключить rDren - не смотря на продолжительную работу насоса бак не наполнен|
|
||||
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN||
|
||||
},
|
||||
"nord":{"pin":6,"set":60,"cmd":1},
|
||||
"south":{"pin":7,"set":100,"cmd":1},
|
||||
"trees":{"pin":10,"set":60,"cmd":2}
|
||||
"trees":{"pin":10,"set":60,"cmd":2},
|
||||
"outlets:{}
|
||||
|
||||
}]
|
||||
}
|
||||
@@ -79,18 +80,35 @@ DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN||
|
||||
|
||||
Контроллер должен передать это значение в выходной топик ```root/name/s_out/sprinkrer/garden/set``` и оно будет восстановлено при перезагрузке контроллера
|
||||
|
||||
|
||||
отработанный обьем воды или время будет сохраняться в параметре "val" каждой зоны (параметр будет автоматически увеличиваться при работе зоны, передаваться в соответствующий зоне топик для мониторинга и восстановления в случае перезагрузки контроллера)
|
||||
|
||||
**Пример топика:** ```root/s_out/sprinkler/garden/val```
|
||||
|
||||
Когда данный параметр достигнет значения, заданного в параметре "set" контроллер завершит полив данной зоны и перейдет к следующей.
|
||||
Когда данный параметр достигнет значения (или времени), заданного в параметре "set" контроллер завершит полив данной зоны и перейдет к следующей.
|
||||
|
||||
Важно: если set=0 (по умолчанию) то время работы зоны не лимитируется. Если такая зона включена - система полива не будет отключаться после окончания полива прочих зон и насос не будет обесточиваться. Это удобно, если в системе полива есть водяная розетка для подключения поливочного шланга, которая всегда должна находиться под давлением. Такую зону конфигурируйте последней в списке.
|
||||
|
||||
Для сброса счетчиков можно использовать как непосредственную установку значения параметра "val" для каждой зоны так и команду RESET, отправленную в нужную зону или в объект sprinkler через суффикс /cmd.
|
||||
|
||||
В последнем случае, контроллер итерационно сбросит счетчики в значение 0 для каждой зоны полива.
|
||||
|
||||
**Пример:** ```root/name/sprinkler/cmd -> RESET```
|
||||
|
||||
В последнем случае, контроллер итерационно сбросит счетчики в значение 0 для каждой зоны полива.
|
||||
Это инициирует старт программы полива, если система находится в состоянии ON
|
||||
|
||||
Команда RESET не отработает если обьект полива находится в состоянии DISABLE или FREEZE
|
||||
|
||||
Также, в этих режимах, в принципе, не отработает запуск полива какой-либо зоны (команды set/RESET), если для нее задано время/обьем полива.
|
||||
|
||||
Если обьем полива не задан (set==0) - это например водяная розетка для мытья машины, то такая зона запустится даже в режиме DISABLE
|
||||
|
||||
Если в процессе полива придет команда DISABLE (начался дождь) - полив прекратится, программа полива возобновится после ENABLE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Управление
|
||||
|
||||
@@ -105,7 +123,9 @@ DREN\_OPERATE|таймаут 1200 сек |FAULT_DREN||
|
||||
### Включение/выключение цикла полива:
|
||||
|
||||
**Включить** ```root/name/sprinkler/cmd -> ON```
|
||||
Система начнет или продолжит цикл полива, переходя от зоны к зоне по мере завершения работы с каждой предыдущей зоной. После завершения работы со всеми зонами, sprinkler перейдет в состояние OFF
|
||||
Система начнет или продолжит цикл полива, переходя от зоны к зоне по мере завершения работы с каждой предыдущей зоной. После завершения работы со всеми зонами, sprinkler НЕ перейдет в состояние OFF автоматически, но полив прекратится для тех зон, где показатель val достиг параметра set
|
||||
|
||||
Если не будет ни одной активной зоны - насос обесточится.
|
||||
|
||||
Перед включением полива, система убедится что бак наполнен или до-наполнит его до максимума из водопровода.
|
||||
|
||||
@@ -157,6 +177,19 @@ root/name/sprinkler/val -> -1 //система перейдет в режим FR
|
||||
|
||||
```
|
||||
|
||||
Так как команда FREEZE блокирует запуск каких либо насосов и открытие клапанов, это делает невозможным слив системы в процессе подготовки к зиме
|
||||
|
||||
Когда требуется слить систему, необходимо отключить дренажный насос, перекрыть водопроводный кран
|
||||
|
||||
Данный режим реализован при помощи команды DRY
|
||||
|
||||
Дополнительно к перекрытию поступления воды в бак (заблокирован автомат пополнения бака из дренажного насоса и водопровода) данная команда включает помпу.
|
||||
|
||||
Далее, требуется слить бак включением выбранных зон полива или через водяные розетки.
|
||||
Только после осушения бака (насос выключится) - систему необходимо перевести в режим FREEZE
|
||||
Перевод в этот редим сбрасывает режим DRY (а также, состояния ошибки автомата наполнения бака)
|
||||
|
||||
|
||||
### Передача статусных значений
|
||||
|
||||
|
||||
@@ -178,4 +211,140 @@ root/s_out/sprinkler/garden/cmd - ON или OFF - признак включен
|
||||
root/s_out/sprinkler/garden/$state - ON или OFF - признак того что зона поливается в настоящее время
|
||||
root/s_out/sprinkler/garden/val - текущее время или обьем полива данной зоны
|
||||
|
||||
```
|
||||
|
||||
### Пример конфигурации Home Assistant
|
||||
```
|
||||
sensor:
|
||||
- name: "Полив бак Макс"
|
||||
state_topic: "root/s_out/sprinkler/$wMax"
|
||||
|
||||
- name: "Полив бак Мin"
|
||||
state_topic: "root/s_out/sprinkler/$wMin"
|
||||
|
||||
- name: "Полив водопровод"
|
||||
state_topic: "root/s_out/sprinkler/$vIN"
|
||||
|
||||
- name: "Полив дренаж вкл"
|
||||
state_topic: "root/s_out/sprinkler/$rDren"
|
||||
|
||||
- name: "Полив дренаж качает"
|
||||
state_topic: "root/s_out/sprinkler/$fbDren"
|
||||
|
||||
- name: "Полив насос вкл"
|
||||
state_topic: "root/s_out/sprinkler/$rPump"
|
||||
|
||||
- name: "Полив насос качает"
|
||||
state_topic: "root/s_out/sprinkler/$fbPump"
|
||||
|
||||
- name: "Полив состояние"
|
||||
state_topic: "root/s_out/sprinkler/$state"
|
||||
|
||||
- name: "Полив ошибка"
|
||||
state_topic: "root/s_out/sprinkler/$fault"
|
||||
|
||||
- name: "Полив юг выполнено"
|
||||
state_topic: "root/s_out/sprinkler/south/val"
|
||||
|
||||
- name: "Полив север выполнено"
|
||||
state_topic: "root/s_out/sprinkler/nord/val"
|
||||
|
||||
- name: "Полив капельный выполнено"
|
||||
state_topic: "edem/s_out/sprinkler/trees/val"
|
||||
|
||||
- name: "Поливаем юг"
|
||||
state_topic: "root/s_out/sprinkler/south/$state"
|
||||
|
||||
- name: "Поливаем север"
|
||||
state_topic: "root/s_out/sprinkler/nord/$state"
|
||||
|
||||
- name: "Поливаем капельно"
|
||||
state_topic: "root/s_out/sprinkler/trees/$state"
|
||||
|
||||
- name: "Полив розетка статус"
|
||||
state_topic: "root/s_out/sprinkler/outlets/$state"
|
||||
|
||||
- name: "Полив блокировки"
|
||||
state_topic: "root/s_out/sprinkler/ctrl"
|
||||
|
||||
switch:
|
||||
|
||||
- name: "Полив"
|
||||
state_topic: "root/s_out/sprinkler/cmd"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
availability_topic: "root/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив север"
|
||||
state_topic: "root/s_out/sprinkler/nord/cmd"
|
||||
command_topic: "root/air/sprinkler/nord/cmd"
|
||||
availability_topic: "root/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив юг"
|
||||
state_topic: "root/s_out/sprinkler/south/cmd"
|
||||
command_topic: "root/air/sprinkler/south/cmd"
|
||||
availability_topic: "root/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив капельный"
|
||||
state_topic: "root/s_out/sprinkler/trees/cmd"
|
||||
command_topic: "root/air/sprinkler/trees/cmd"
|
||||
availability_topic: "root/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
- name: "Полив розетки"
|
||||
state_topic: "root/s_out/sprinkler/outlets/cmd"
|
||||
command_topic: "root/air/sprinkler/outlets/cmd"
|
||||
availability_topic: "root/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
button:
|
||||
- name: "Полив сброс"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
payload_press: "RESET"
|
||||
|
||||
- name: "Полив блокировка"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
payload_press: "FREEZE"
|
||||
|
||||
- name: "Полив разблокировка"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
payload_press: "UNFREEZE"
|
||||
|
||||
- name: "Полив разрешить"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
payload_press: "ENABLE"
|
||||
|
||||
- name: "Полив запретить"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
payload_press: "DISABLE"
|
||||
|
||||
number:
|
||||
|
||||
- name: "Полив юг"
|
||||
state_topic: "root/s_out/sprinkler/south/set"
|
||||
command_topic: "root/air/sprinkler/south/set"
|
||||
min: 0
|
||||
max: 6000
|
||||
|
||||
- name: "Полив север"
|
||||
state_topic: "root/s_out/sprinkler/nord/set"
|
||||
command_topic: "root/air/sprinkler/nord/set"
|
||||
min: 0
|
||||
max: 6000
|
||||
|
||||
- name: "Полив капельный"
|
||||
state_topic: "root/s_out/sprinkler/trees/set"
|
||||
command_topic: "root/air/sprinkler/trees/set"
|
||||
min: 0
|
||||
max: 6000
|
||||
|
||||
|
||||
|
||||
```
|
||||
BIN
documentation/sprinkler_1.jpeg
Normal file
BIN
documentation/sprinkler_1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 436 KiB |
BIN
documentation/sprinkler_2.jpeg
Normal file
BIN
documentation/sprinkler_2.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 501 KiB |
@@ -2171,18 +2171,11 @@ int Item::SendStatus(long sendFlags, char * subItem) {
|
||||
// Send ctrl
|
||||
if (sendFlags & FLAG_FLAGS)
|
||||
{
|
||||
if (getFlag(FLAG_DISABLED))
|
||||
strcpy_P(cmdstr, DISABLE_P);
|
||||
|
||||
else if (getFlag(FLAG_FREEZED) == FLAG_FREEZED)
|
||||
strcpy_P(cmdstr, FREEZE_P);
|
||||
|
||||
if (getFlag(FLAG_FREEZED)) strcpy_P(cmdstr, FREEZE_P);
|
||||
else if (getFlag(FLAG_DISABLED)) strcpy_P(cmdstr, DISABLE_P);
|
||||
else strcpy_P(cmdstr, ENABLE_P);
|
||||
|
||||
|
||||
//else strcpy_P(cmdstr, UNFREEZE_P);
|
||||
|
||||
|
||||
setTopic(addrstr,sizeof(addrstr),T_OUT);
|
||||
strncat(addrstr, itemArr->name, sizeof(addrstr)-1);
|
||||
if (subItem)
|
||||
|
||||
@@ -1250,6 +1250,7 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
|
||||
case CMD_ENABLE:
|
||||
case CMD_FREEZE:
|
||||
case CMD_UNFREEZE:
|
||||
case CMD_RESET:
|
||||
break;
|
||||
default:
|
||||
item->setCmd(cmd.cmdCode);
|
||||
|
||||
@@ -99,7 +99,7 @@ int out_sprinkler::Setup()
|
||||
|
||||
debugSerial << F("SPRINKLER: ") << " wMax=" << wMaxPin << " wMin=" << wMinPin << " fbDren=" << fbDrenPin << " fbPump=" << fbPumpPin << " wCtr=" << wCtrPin << endl;
|
||||
uint16_t lastVals = 0;
|
||||
if (wCtrPin != PINS_COUNT)
|
||||
if (abs(wCtrPin) < PINS_COUNT)
|
||||
{
|
||||
setupInPin(wCtrPin);
|
||||
lastVals |= (readInPin(wCtrPin) ? LASTWCTRLSTATE : 0);
|
||||
@@ -165,7 +165,7 @@ bool out_sprinkler::isNeedPump(bool steelNeed)
|
||||
{
|
||||
long setVal = getIntFromJson(zone, "set", 0);
|
||||
long valVal = getIntFromJson(zone, "val", 0);
|
||||
if (valVal < setVal) return true;
|
||||
if (!setVal || (valVal < setVal)) return true;
|
||||
}
|
||||
}
|
||||
zone = zone->next;
|
||||
@@ -199,6 +199,20 @@ void out_sprinkler::dren(bool state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void out_sprinkler::vin(bool state)
|
||||
{
|
||||
if (!isValidControlPin(vinPin)) return;
|
||||
uint32_t lastVals = getIntFromJson (gatesObj, "@lastVals", 0);
|
||||
setOutput(vinPin, state);
|
||||
if (state != (bool)(lastVals & LASTVINSTATE))
|
||||
{
|
||||
if(state) lastVals |= LASTVINSTATE; else lastVals &= ~LASTVINSTATE;
|
||||
setValToJson(gatesObj, "@lastVals", (long)lastVals);
|
||||
publishBooleanState("/$rVIN", state);
|
||||
}
|
||||
}
|
||||
|
||||
void out_sprinkler::turnOffAllZones()
|
||||
{
|
||||
if (!gatesObj) return;
|
||||
@@ -208,7 +222,7 @@ void out_sprinkler::turnOffAllZones()
|
||||
if (zone->name && *zone->name && zone->type == aJson_Object)
|
||||
{
|
||||
short pin = getIntFromJson(zone, "pin", PINS_COUNT);
|
||||
setOutput(pin, false);
|
||||
if (isValidControlPin(pin)) setOutput(pin, false);
|
||||
if (getIntFromJson(zone, "@active", 0))
|
||||
{
|
||||
setZoneActive(zone, false);
|
||||
@@ -241,8 +255,9 @@ long fault = 0;
|
||||
|
||||
if (!gatesObj) return;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
|
||||
aJsonObject *faultObj = aJson.getArrayItem(item->itemArg, 3);
|
||||
aJsonObject * rootCfg = aJson.getObjectItem(gatesObj, "");
|
||||
if (!rootCfg) rootCfg = gatesObj;
|
||||
aJsonObject * faultObj = aJson.getObjectItem(rootCfg, "onFault");
|
||||
switch (state) {
|
||||
|
||||
case SP_OFF:
|
||||
@@ -269,6 +284,10 @@ switch (state) {
|
||||
strcpy(val,"FULL");
|
||||
break;
|
||||
|
||||
case SP_DRYING:
|
||||
strcpy(val,"DRYING");
|
||||
break;
|
||||
|
||||
case SP_FAULT_VIN:
|
||||
strcpy(val,"FAULT_VIN");
|
||||
fault = 1;
|
||||
@@ -298,7 +317,7 @@ publishTopic(item->itemArr->name,val,"/$state");
|
||||
|
||||
|
||||
|
||||
int out_sprinkler::shutdown(sprinklerState nextState)
|
||||
int out_sprinkler::moveToState(sprinklerState nextState)
|
||||
{
|
||||
if (!gatesObj) return 0;
|
||||
|
||||
@@ -306,36 +325,42 @@ int out_sprinkler::shutdown(sprinklerState nextState)
|
||||
{
|
||||
case SP_OFF:
|
||||
case SP_FULL:
|
||||
setOutput(drenPin, false);
|
||||
setOutput(vinPin, false);
|
||||
dren(false);
|
||||
vin(false);
|
||||
break;
|
||||
case SP_DREN_ON:
|
||||
case SP_DREN_OPERATE:
|
||||
setOutput(drenPin, true);
|
||||
setOutput(vinPin, false);
|
||||
dren(true);
|
||||
vin(false);
|
||||
break;
|
||||
case SP_VIN:
|
||||
setOutput(vinPin, true);
|
||||
setOutput(drenPin, false);
|
||||
vin(true);
|
||||
//setOutput(drenPin, false);
|
||||
break;
|
||||
case SP_DREN_EMPTY:
|
||||
setOutput(drenPin, false);
|
||||
setOutput(vinPin, false);
|
||||
//setOutput(drenPin, false);
|
||||
vin(false);
|
||||
break;
|
||||
case SP_FAULT_VIN:
|
||||
setOutput(vinPin, false);
|
||||
vin(false);
|
||||
break;
|
||||
case SP_FAULT_DREN:
|
||||
setOutput(drenPin, false);
|
||||
dren(false);
|
||||
break;
|
||||
case SP_UNKNOWN:
|
||||
setOutput(drenPin, false);
|
||||
setOutput(vinPin, false);
|
||||
dren(false);
|
||||
vin(false);
|
||||
break;
|
||||
case SP_DRYING:
|
||||
dren(false);
|
||||
vin(false);
|
||||
pump(true);
|
||||
item->On();
|
||||
break;
|
||||
}
|
||||
|
||||
publishBooleanState("/$rDren", nextState == SP_DREN_ON || nextState == SP_DREN_OPERATE);
|
||||
publishBooleanState("/$vIN", nextState == SP_VIN);
|
||||
//publishBooleanState("/$rDren", nextState == SP_DREN_ON || nextState == SP_DREN_OPERATE);
|
||||
//publishBooleanState("/$vIN", nextState == SP_VIN);
|
||||
notifyState(nextState);
|
||||
return 1;
|
||||
}
|
||||
@@ -357,7 +382,8 @@ inline aJsonObject * out_sprinkler::findNextZone()
|
||||
{
|
||||
if (zone->name && *zone->name && zone->type == aJson_Object)
|
||||
{
|
||||
if (getIntFromJson(zone, "@active", 0)) return zone;
|
||||
long setVal = getIntFromJson(zone, "set", 0);
|
||||
if (getIntFromJson(zone, "@active", 0) && setVal) return zone;
|
||||
}
|
||||
zone = zone->next;
|
||||
}
|
||||
@@ -370,10 +396,23 @@ inline aJsonObject * out_sprinkler::findNextZone()
|
||||
int cmd = getIntFromJson(zone, "cmd", CMD_OFF);
|
||||
long setVal = getIntFromJson(zone, "set", 0);
|
||||
long valVal = getIntFromJson(zone, "val", 0);
|
||||
if (cmd == CMD_ON && valVal < setVal) return zone;
|
||||
if (cmd == CMD_ON && (setVal && valVal < setVal)) return zone;
|
||||
}
|
||||
zone = zone->next;
|
||||
}
|
||||
|
||||
zone = gatesObj->child;
|
||||
while (zone)
|
||||
{
|
||||
if (zone->name && *zone->name && zone->type == aJson_Object)
|
||||
{
|
||||
int cmd = getIntFromJson(zone, "cmd", CMD_OFF);
|
||||
long setVal = getIntFromJson(zone, "set", 0);
|
||||
if (cmd == CMD_ON && (!setVal )) return zone;
|
||||
}
|
||||
zone = zone->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -443,7 +482,7 @@ int out_sprinkler::Poll(short cause)
|
||||
bool lastWctrlState = lastVals & LASTWCTRLSTATE;
|
||||
bool lastWctrlStateAll = lastVals & LASTWCTRLSTATE_ALL;
|
||||
|
||||
if (wCtrPin != PINS_COUNT)
|
||||
if (abs(wCtrPin) < PINS_COUNT)
|
||||
{
|
||||
bool curr = readInPin(wCtrPin);
|
||||
if (curr && !lastWctrlStateAll)
|
||||
@@ -456,7 +495,7 @@ int out_sprinkler::Poll(short cause)
|
||||
|
||||
if (freeze)
|
||||
{
|
||||
shutdown(SP_OFF);
|
||||
moveToState(SP_OFF);
|
||||
turnOffValves();
|
||||
pump(false);
|
||||
return 0;
|
||||
@@ -477,7 +516,7 @@ int out_sprinkler::Poll(short cause)
|
||||
state = SP_DREN_ON;
|
||||
setValToJson(gatesObj, "@timer", (long)now);
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_DREN_ON);
|
||||
moveToState(SP_DREN_ON);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -487,13 +526,13 @@ int out_sprinkler::Poll(short cause)
|
||||
state = SP_DREN_OPERATE;
|
||||
setValToJson(gatesObj, "@timer", (long)now);
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_DREN_OPERATE);
|
||||
moveToState(SP_DREN_OPERATE);
|
||||
}
|
||||
else if (isTimeOver(timer, now, DRENAGE_ON_TIME))
|
||||
{
|
||||
state = SP_DREN_EMPTY;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_DREN_EMPTY);
|
||||
moveToState(SP_DREN_EMPTY);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -502,19 +541,19 @@ int out_sprinkler::Poll(short cause)
|
||||
{
|
||||
state = SP_DREN_EMPTY;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_DREN_EMPTY);
|
||||
moveToState(SP_DREN_EMPTY);
|
||||
}
|
||||
else if (wMax)
|
||||
{
|
||||
state = SP_FULL;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FULL);
|
||||
moveToState(SP_FULL);
|
||||
}
|
||||
else if (isTimeOver(timer, now, 1200000UL))
|
||||
else if (isTimeOver(timer, now, DRENAGE_MAX_TIME))
|
||||
{
|
||||
state = SP_FAULT_DREN;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FAULT_DREN);
|
||||
moveToState(SP_FAULT_DREN);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -523,14 +562,14 @@ int out_sprinkler::Poll(short cause)
|
||||
{
|
||||
state = SP_FULL;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FULL);
|
||||
moveToState(SP_FULL);
|
||||
}
|
||||
else if (item->getCmd() == CMD_ON)
|
||||
{
|
||||
state = SP_VIN;
|
||||
setValToJson(gatesObj, "@timer", (long)now);
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_VIN);
|
||||
moveToState(SP_VIN);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -540,19 +579,19 @@ int out_sprinkler::Poll(short cause)
|
||||
state = SP_DREN_OPERATE;
|
||||
setValToJson(gatesObj, "@timer", (long)now);
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_DREN_OPERATE);
|
||||
moveToState(SP_DREN_OPERATE);
|
||||
}
|
||||
else if (wMax)
|
||||
{
|
||||
state = SP_FULL;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FULL);
|
||||
moveToState(SP_FULL);
|
||||
}
|
||||
else if (isTimeOver(timer, now, VIN_MAX_TIME))
|
||||
{
|
||||
state = SP_FAULT_VIN;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FAULT_VIN);
|
||||
moveToState(SP_FAULT_VIN);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -562,7 +601,7 @@ int out_sprinkler::Poll(short cause)
|
||||
state = SP_DREN_ON;
|
||||
setValToJson(gatesObj, "@timer", (long)now);
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_DREN_ON);
|
||||
moveToState(SP_DREN_ON);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -571,7 +610,7 @@ int out_sprinkler::Poll(short cause)
|
||||
{
|
||||
state = SP_FULL;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FULL);
|
||||
moveToState(SP_FULL);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -580,7 +619,7 @@ int out_sprinkler::Poll(short cause)
|
||||
{
|
||||
state = SP_FULL;
|
||||
setValToJson(gatesObj, "@state", (long)state);
|
||||
shutdown(SP_FULL);
|
||||
moveToState(SP_FULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -595,64 +634,71 @@ int out_sprinkler::Poll(short cause)
|
||||
pump(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool isActiveZone = false;
|
||||
if (item->getCmd() == CMD_ON && tankReady)
|
||||
{
|
||||
currentZone = findNextZone();
|
||||
if (currentZone)
|
||||
{
|
||||
long setVal = getIntFromJson(currentZone, "set", 0);
|
||||
long valVal = getIntFromJson(currentZone, "val", 0);
|
||||
{
|
||||
long setVal = getIntFromJson(currentZone, "set", 0);
|
||||
long valVal = getIntFromJson(currentZone, "val", 0);
|
||||
// if not active - activate
|
||||
if (!getIntFromJson(currentZone, "@active", 0))
|
||||
{
|
||||
turnOffAllZones();
|
||||
if (!item->getFlag(FLAG_DISABLED) || !setVal)
|
||||
{
|
||||
setZoneActive(currentZone, true);
|
||||
short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT);
|
||||
if (isValidControlPin(zonePin)) setOutput(zonePin, true);
|
||||
setValToJson(gatesObj, "@flowTimer", (long)now);
|
||||
isActiveZone = true;
|
||||
}
|
||||
}
|
||||
else isActiveZone = true;
|
||||
|
||||
if (!getIntFromJson(currentZone, "@active", 0))
|
||||
{
|
||||
turnOffAllZones();
|
||||
setZoneActive(currentZone, true);
|
||||
short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT);
|
||||
setOutput(zonePin, true);
|
||||
setValToJson(gatesObj, "@flowTimer", (long)now);
|
||||
}
|
||||
if (isActiveZone)
|
||||
{
|
||||
if (abs(wCtrPin) < PINS_COUNT)
|
||||
{
|
||||
bool curr = readInPin(wCtrPin);
|
||||
if (curr && !lastWctrlState)
|
||||
{
|
||||
updateZoneValue(currentZone, 1);
|
||||
}
|
||||
if (curr) lastVals |= LASTWCTRLSTATE; else lastVals &= ~LASTWCTRLSTATE;
|
||||
setValToJson(gatesObj, "@lastVals", (long)lastVals);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t flowTimer = (uint32_t)getIntFromJson(gatesObj, "@flowTimer", now);
|
||||
if (isTimeOver(flowTimer, now, 1000UL))
|
||||
{
|
||||
updateZoneValue(currentZone, 1);
|
||||
setValToJson(gatesObj, "@flowTimer", (long)now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wCtrPin != PINS_COUNT)
|
||||
{
|
||||
bool curr = readInPin(wCtrPin);
|
||||
if (curr && !lastWctrlState)
|
||||
{
|
||||
updateZoneValue(currentZone, 1);
|
||||
}
|
||||
if (curr) lastVals |= LASTWCTRLSTATE; else lastVals &= ~LASTWCTRLSTATE;
|
||||
setValToJson(gatesObj, "@lastVals", (long)lastVals);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t flowTimer = (uint32_t)getIntFromJson(gatesObj, "@flowTimer", now);
|
||||
if (isTimeOver(flowTimer, now, 1000UL))
|
||||
{
|
||||
updateZoneValue(currentZone, 1);
|
||||
setValToJson(gatesObj, "@flowTimer", (long)now);
|
||||
}
|
||||
}
|
||||
if (setVal > 0 && (valVal >= setVal || item->getFlag(FLAG_DISABLED)))
|
||||
{
|
||||
short zonePin = getIntFromJson(currentZone, "pin", PINS_COUNT);
|
||||
if (isValidControlPin(zonePin)) setOutput(zonePin, false);
|
||||
setZoneActive(currentZone, false);
|
||||
currentZone = findNextZone();
|
||||
}
|
||||
|
||||
|
||||
if (setVal > 0 && valVal >= setVal)
|
||||
{
|
||||
setOutput(getIntFromJson(currentZone, "pin", PINS_COUNT), false);
|
||||
setZoneActive(currentZone, false);
|
||||
//////setValToJson(currentZone, "cmd", (long)CMD_OFF);
|
||||
//item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF).setSuffix(S_CMD), FLAG_COMMAND, currentZone->name);
|
||||
currentZone = findNextZone();
|
||||
}
|
||||
|
||||
if (currentZone)
|
||||
{
|
||||
needPump = true;
|
||||
}
|
||||
if (currentZone)
|
||||
{
|
||||
needPump = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!needPump)
|
||||
{
|
||||
pump(false);
|
||||
/*
|
||||
if (item->getCmd() == CMD_ON)
|
||||
{
|
||||
aJsonObject * resultZone = findNextZone();
|
||||
@@ -662,6 +708,7 @@ int out_sprinkler::Poll(short cause)
|
||||
item->SendStatus(FLAG_COMMAND);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -733,6 +780,7 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
|
||||
return 1;
|
||||
|
||||
case CMD_RESET:
|
||||
if (item->getFlag(FLAG_FREEZED | FLAG_DISABLED)) return -1;
|
||||
setValToJson(zone, "val", (long)0);
|
||||
if (sendStatus)
|
||||
{
|
||||
@@ -757,11 +805,18 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
|
||||
case CMD_OFF:
|
||||
turnOffAllZones();
|
||||
pump(false);
|
||||
//dren(false);
|
||||
return 1;
|
||||
|
||||
case CMD_DRY:
|
||||
setValToJson(gatesObj, "@state", (long)SP_DRYING);
|
||||
moveToState(SP_DRYING);
|
||||
notifyState(SP_DRYING);
|
||||
return 1;
|
||||
|
||||
case CMD_RESET:
|
||||
{
|
||||
if (item->getFlag(FLAG_FREEZED | FLAG_DISABLED)) return -1;
|
||||
|
||||
aJsonObject * zone = gatesObj->child;
|
||||
while (zone)
|
||||
{
|
||||
@@ -775,6 +830,10 @@ int out_sprinkler::Ctrl(itemCmd cmd, char* subItem, bool toExecute, bool authori
|
||||
}
|
||||
zone = zone->next;
|
||||
}
|
||||
|
||||
// turnOffAllZones();
|
||||
// pump(false);
|
||||
// item->Off();
|
||||
}
|
||||
return 1;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#define DRENAGE_ON_TIME 10000
|
||||
#define VIN_MAX_TIME 1200000UL
|
||||
#define DRENAGE_MAX_TIME 2000000UL
|
||||
|
||||
#define LASTWCTRLSTATE 1
|
||||
#define LASTWCTRLSTATE_ALL 2
|
||||
@@ -17,6 +18,7 @@
|
||||
#define LASTFBPUMPSTATE 32
|
||||
#define LASTPUMPSTATE 64
|
||||
#define LASTDRENSTATE 128
|
||||
#define LASTVINSTATE 256
|
||||
|
||||
enum sprinklerState {
|
||||
SP_UNKNOWN = 0,
|
||||
@@ -26,6 +28,7 @@ enum sprinklerState {
|
||||
SP_DREN_EMPTY = 4,
|
||||
SP_VIN = 5,
|
||||
SP_FULL = 6,
|
||||
SP_DRYING = 7,
|
||||
SP_FAULT_VIN = -1,
|
||||
SP_FAULT_DREN = -2
|
||||
};
|
||||
@@ -51,6 +54,7 @@ protected:
|
||||
|
||||
void pump(bool state);
|
||||
void dren(bool state);
|
||||
void vin(bool state);
|
||||
void setOutput(short pin, bool value);
|
||||
bool isNeedPump(bool steelNeed=false);
|
||||
void turnOffValves();
|
||||
@@ -64,7 +68,7 @@ protected:
|
||||
void publishBooleanStateIfChanged(const char * subItem, bool state, uint32_t flag, uint32_t & lastState);
|
||||
bool isFreeze();
|
||||
void notifyState(short state);
|
||||
int shutdown(sprinklerState nextState);
|
||||
int moveToState(sprinklerState nextState);
|
||||
void updateCounterValue();
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user