mirror of
https://github.com/anklimov/lighthub
synced 2026-07-29 01:52:43 +00:00
Compare commits
8 Commits
641b314218
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c839091b6 | |||
| 7e7abce6b6 | |||
| 565195d60a | |||
| 84ce56fdde | |||
| c1937a045b | |||
| fd23dc3567 | |||
| 898dca260c | |||
| 985d058c50 |
@@ -17,4 +17,5 @@
|
||||
-DRESTART_LAN_ON_MQTT_ERRORS
|
||||
-DOTA_PORT=80
|
||||
-DMERCURY_ENABLE
|
||||
-D ROTARYENCODER
|
||||
-D ROTARYENCODER
|
||||
-D SPRINKLER_ENABLE
|
||||
@@ -59,4 +59,5 @@
|
||||
-D CORS=\"*\"
|
||||
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
|
||||
#-DMERCURY_ENABLE
|
||||
-D ROTARYENCODER
|
||||
-D ROTARYENCODER
|
||||
-D SPRINKLER_ENABLE
|
||||
@@ -74,4 +74,5 @@
|
||||
-D CORS=\"*\"
|
||||
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
|
||||
#-DMERCURY_ENABLE
|
||||
-D ROTARYENCODER
|
||||
-D ROTARYENCODER
|
||||
-D SPRINKLER_ENABLE
|
||||
@@ -17,4 +17,5 @@
|
||||
-D CORS=\"*\"
|
||||
-D REDIRECTION_URL=\"http://lazyhome.ru/pwa\"
|
||||
#-DMERCURY_ENABLE
|
||||
-D ROTARYENCODER
|
||||
-D ROTARYENCODER
|
||||
-D SPRINKLER_ENABLE
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
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/$rVIN"
|
||||
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 (а также, состояния ошибки автомата наполнения бака)
|
||||
|
||||
|
||||
### Передача статусных значений
|
||||
|
||||
|
||||
@@ -171,11 +204,155 @@ root/s_out/sprinkler/$wMin - ON/OFF достигнут минимум воды
|
||||
root/s_out/sprinkler/$rDren - ON/OFF включено реле дренажного насоса
|
||||
root/s_out/sprinkler/$rPump - ON/OFF включено реле основного насоса
|
||||
root/s_out/sprinkler/set - значение счетчика воды (восстанавливается при перезагрузке из данного топика)
|
||||
root/s_out/sprinkler/$vIN - ON/OFF - признак открытия клапана налива бака из водопровода
|
||||
root/s_out/sprinkler/$rVIN - ON/OFF - признак открытия клапана налива бака из водопровода
|
||||
|
||||
root/s_out/sprinkler/garden/set - требуемый обьем (или время) полива зоны
|
||||
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/$rVIN"
|
||||
|
||||
- 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"
|
||||
|
||||
- name: "Полив осушение бака"
|
||||
command_topic: "root/air/sprinkler/cmd"
|
||||
payload_press: "DRY"
|
||||
#Такую проверку можно добавить везде, при ее наличии обьекты станут недоступными если контроллер оффлайн
|
||||
availability_topic: "root/air/$state"
|
||||
payload_available: "ready"
|
||||
payload_not_available: "disconnected"
|
||||
|
||||
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) && setVal > 0)
|
||||
{
|
||||
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