Add Home Assistant custom integration and ESP availability tracking
- Add custom HA integration (config flow, switch, water_for service) - Add MQTT Last Will & Testament for offline detection - Publish 'online' on successful MQTT connect - Update README with integration docs
This commit is contained in:
@@ -1,15 +1,41 @@
|
||||
# Irrigation with an ESP8266
|
||||
Tested with D1 mini. Connect a pump with a relais. Relais activation on D4.
|
||||
|
||||
## Homeassistant integration
|
||||
payload_on can also contain the duration of the pump in ms.
|
||||
Example:
|
||||
`
|
||||
switch 5:
|
||||
## Home Assistant Integration
|
||||
|
||||
### Custom Integration (recommended)
|
||||
|
||||
A full custom integration with config flow, device registry, and a `water_for` service is included in the [`homeassistant/`](homeassistant/) directory.
|
||||
|
||||
See [homeassistant/README.md](homeassistant/README.md) for installation and usage.
|
||||
|
||||
### YAML-only (built-in MQTT platform)
|
||||
|
||||
`payload_on` can also contain the duration of the pump in ms.
|
||||
|
||||
```yaml
|
||||
switch:
|
||||
- platform: mqtt
|
||||
name: "Irrigation Pump"
|
||||
command_topic: greenhousino/pump
|
||||
state_topic: greenhousino/pumpstate
|
||||
payload_on: "on"
|
||||
payload_off: "off"
|
||||
name: "Pumpe"
|
||||
`
|
||||
state_on: "on"
|
||||
state_off: "off"
|
||||
availability_topic: greenhousino/pump/status
|
||||
payload_available: "online"
|
||||
payload_not_available: "offline"
|
||||
qos: 1
|
||||
```
|
||||
|
||||
For duration-based watering via YAML, use an automation:
|
||||
```yaml
|
||||
automation:
|
||||
- alias: "Water for 5 minutes"
|
||||
action:
|
||||
- service: mqtt.publish
|
||||
data:
|
||||
topic: greenhousino/pump
|
||||
payload: "300000" # 300000 ms = 5 minutes
|
||||
```
|
||||
124
irrigation/homeassistant/README.md
Normal file
124
irrigation/homeassistant/README.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Greenhousino Irrigation — Home Assistant Integration
|
||||
|
||||
Custom Home Assistant integration for the Greenhousino ESP8266/ESP32 irrigation controller.
|
||||
|
||||
## Features
|
||||
|
||||
- **Pump switch** — Turn the irrigation pump on/off from Home Assistant
|
||||
- **State tracking** — Real-time pump state via MQTT
|
||||
- **Availability** — Shows online/offline status
|
||||
- **`water_for` service** — Water for a specific duration (1–3600 seconds)
|
||||
- **Config flow** — Set up via Home Assistant UI (Settings → Devices & Services → Add Integration)
|
||||
- **Device registry** — Appears as a proper device with manufacturer/model info
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: HACS (recommended)
|
||||
|
||||
1. Install [HACS](https://hacs.xyz/) in Home Assistant
|
||||
2. Add this repository as a custom repository
|
||||
3. Search for "Greenhousino Irrigation" and install
|
||||
4. Restart Home Assistant
|
||||
|
||||
### Option 2: Manual installation
|
||||
|
||||
1. Copy the `greenhousino` folder to your Home Assistant config directory:
|
||||
|
||||
```bash
|
||||
cp -r greenhousino /config/custom_components/
|
||||
```
|
||||
|
||||
2. Restart Home Assistant
|
||||
|
||||
3. Go to **Settings → Devices & Services → Add Integration** and search for "Greenhousino Irrigation"
|
||||
|
||||
## Configuration
|
||||
|
||||
The config flow will guide you through two steps:
|
||||
|
||||
### Step 1: Host
|
||||
- **Host IP address** — The IP of your ESP device (e.g., `192.168.178.50`). This is used for the web UI link in device info.
|
||||
|
||||
### Step 2: MQTT Topics
|
||||
- **Command topic** — MQTT topic to send commands (default: `greenhousino/pump`)
|
||||
- **State topic** — MQTT topic for state updates (default: `greenhousino/pumpstate`)
|
||||
|
||||
## Usage
|
||||
|
||||
### Switch entity
|
||||
|
||||
The integration creates a switch entity (`switch.greenhousino_irrigation_pump`) that you can:
|
||||
- Toggle on/off from the Home Assistant UI
|
||||
- Use in automations
|
||||
- Add to dashboards
|
||||
|
||||
### `water_for` service
|
||||
|
||||
Water for a specific duration:
|
||||
|
||||
```yaml
|
||||
service: greenhousino.water_for
|
||||
data:
|
||||
duration: 60 # seconds
|
||||
```
|
||||
|
||||
Or from an automation:
|
||||
```yaml
|
||||
automation:
|
||||
- alias: "Water garden every morning"
|
||||
trigger:
|
||||
- platform: time
|
||||
at: "06:00:00"
|
||||
action:
|
||||
- service: greenhousino.water_for
|
||||
data:
|
||||
duration: 300 # 5 minutes
|
||||
```
|
||||
|
||||
## MQTT Topics
|
||||
|
||||
| Direction | Topic | Payload | Description |
|
||||
|-----------|-------|---------|-------------|
|
||||
| HA → ESP | `greenhousino/pump` | `on` | Turn pump on (default 30s) |
|
||||
| HA → ESP | `greenhousino/pump` | `off` | Turn pump off |
|
||||
| HA → ESP | `greenhousino/pump` | `5000` | Turn pump on for 5000ms |
|
||||
| ESP → HA | `greenhousino/pumpstate` | `on` | Pump is active |
|
||||
| ESP → HA | `greenhousino/pumpstate` | `off` | Pump is off |
|
||||
| ESP → HA | `greenhousino/pump/status` | `offline` | Device disconnected |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Home Assistant 2024.x or later
|
||||
- MQTT integration configured and connected to the same broker as your ESP device
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Switch shows "unavailable"
|
||||
- Make sure the MQTT integration is connected
|
||||
- Verify the ESP device is publishing to the state topic
|
||||
- Check that topics match between the ESP firmware and HA config
|
||||
|
||||
### Service call doesn't work
|
||||
- Ensure MQTT integration is set up
|
||||
- Check HA logs: `Logger → greenhousino`
|
||||
- Verify the ESP is subscribed to the command topic
|
||||
|
||||
## YAML-only alternative (no custom component)
|
||||
|
||||
If you don't want a custom integration, you can use the built-in MQTT platform:
|
||||
|
||||
```yaml
|
||||
switch:
|
||||
- platform: mqtt
|
||||
name: "Irrigation Pump"
|
||||
command_topic: "greenhousino/pump"
|
||||
state_topic: "greenhousino/pumpstate"
|
||||
payload_on: "on"
|
||||
payload_off: "off"
|
||||
state_on: "on"
|
||||
state_off: "off"
|
||||
availability_topic: "greenhousino/pump/status"
|
||||
payload_available: "online"
|
||||
payload_not_available: "offline"
|
||||
qos: 1
|
||||
```
|
||||
143
irrigation/homeassistant/greenhousino/__init__.py
Normal file
143
irrigation/homeassistant/greenhousino/__init__.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""Greenhousino Irrigation integration."""
|
||||
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from .const import (
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_HOST,
|
||||
CONF_STATE_TOPIC,
|
||||
DEFAULT_COMMAND_TOPIC,
|
||||
DEFAULT_STATE_TOPIC,
|
||||
DOMAIN,
|
||||
MANUFACTURER,
|
||||
MODEL,
|
||||
SERVICE_DATA_DURATION,
|
||||
SERVICE_WATER_FOR,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = ["switch"]
|
||||
|
||||
# Service schema
|
||||
WATER_FOR_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(SERVICE_DATA_DURATION): vol.All(
|
||||
vol.Coerce(float),
|
||||
vol.Range(min=1, max=3600),
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Greenhousino from a config entry."""
|
||||
hass_data = entry.runtime_data = GreenhousinoData(entry)
|
||||
|
||||
host = entry.data.get(CONF_HOST, "")
|
||||
|
||||
# Register device in HA device registry
|
||||
await _register_device(hass, entry, host)
|
||||
|
||||
# Store entry data for service access
|
||||
if DOMAIN not in hass.data:
|
||||
hass.data[DOMAIN] = {"entries": {}}
|
||||
|
||||
hass.data[DOMAIN]["entries"][entry.entry_id] = hass_data
|
||||
|
||||
# Register the water_for service (only once)
|
||||
if "service_registered" not in hass.data[DOMAIN]:
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_WATER_FOR,
|
||||
_make_water_for_handler(hass),
|
||||
schema=WATER_FOR_SCHEMA,
|
||||
)
|
||||
hass.data[DOMAIN]["service_registered"] = True
|
||||
_LOGGER.info("Registered %s.%s service", DOMAIN, SERVICE_WATER_FOR)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN]["entries"].pop(entry.entry_id, None)
|
||||
|
||||
if len(hass.data[DOMAIN]["entries"]) == 0:
|
||||
hass.services.async_remove(DOMAIN, SERVICE_WATER_FOR)
|
||||
hass.data[DOMAIN].clear()
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
def _make_water_for_handler(hass: HomeAssistant):
|
||||
"""Create the water_for service handler with hass in closure."""
|
||||
|
||||
async def async_water_for(call) -> None:
|
||||
"""Handle the water_for service call."""
|
||||
duration_seconds = call.data[SERVICE_DATA_DURATION]
|
||||
duration_ms = int(duration_seconds * 1000)
|
||||
|
||||
# Use first available command topic (or default)
|
||||
entries = hass.data[DOMAIN].get("entries", {})
|
||||
command_topic = DEFAULT_COMMAND_TOPIC
|
||||
for entry_id, data in entries.items():
|
||||
command_topic = data.command_topic
|
||||
_LOGGER.info(
|
||||
"Watering for %d seconds (%d ms) on topic %s (entry: %s)",
|
||||
duration_seconds,
|
||||
duration_ms,
|
||||
command_topic,
|
||||
entry_id,
|
||||
)
|
||||
await hass.services.async_call(
|
||||
"mqtt",
|
||||
"publish",
|
||||
{
|
||||
"topic": command_topic,
|
||||
"payload": str(duration_ms),
|
||||
"qos": 1,
|
||||
"retain": False,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
if not entries:
|
||||
_LOGGER.warning("No Greenhousino entries configured")
|
||||
|
||||
return async_water_for
|
||||
|
||||
|
||||
async def _register_device(hass: HomeAssistant, entry: ConfigEntry, host: str):
|
||||
"""Register the device in the device registry."""
|
||||
dr.async_get(hass).async_get_or_create(
|
||||
config_entry_id=entry.entry_id,
|
||||
connections=set(),
|
||||
identifiers={(DOMAIN, entry.entry_id)},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=MODEL,
|
||||
name=entry.title,
|
||||
configuration_url=f"http://{host}" if host else None,
|
||||
)
|
||||
|
||||
|
||||
class GreenhousinoData:
|
||||
"""Container for integration data."""
|
||||
|
||||
def __init__(self, entry: ConfigEntry) -> None:
|
||||
self.entry = entry
|
||||
self.command_topic = entry.data.get(
|
||||
CONF_COMMAND_TOPIC, DEFAULT_COMMAND_TOPIC
|
||||
)
|
||||
self.state_topic = entry.data.get(CONF_STATE_TOPIC, DEFAULT_STATE_TOPIC)
|
||||
88
irrigation/homeassistant/greenhousino/config_flow.py
Normal file
88
irrigation/homeassistant/greenhousino/config_flow.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""Config flow for Greenhousino Irrigation integration."""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import (
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_HOST,
|
||||
CONF_STATE_TOPIC,
|
||||
DEFAULT_COMMAND_TOPIC,
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_STATE_TOPIC,
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
STEP_ONE_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST, description={"suggested_value": ""}): str,
|
||||
}
|
||||
)
|
||||
|
||||
STEP_TWO_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_COMMAND_TOPIC,
|
||||
description={"suggested_value": DEFAULT_COMMAND_TOPIC},
|
||||
): str,
|
||||
vol.Required(
|
||||
CONF_STATE_TOPIC,
|
||||
description={"suggested_value": DEFAULT_STATE_TOPIC},
|
||||
): str,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class GreenhousinoConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Greenhousino Irrigation."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle the initial step (host)."""
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
if user_input is not None:
|
||||
try:
|
||||
self._tmp_data = user_input
|
||||
return await self.async_step_mqtt()
|
||||
except Exception:
|
||||
errors["base"] = "unknown"
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=STEP_ONE_DATA_SCHEMA,
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_mqtt(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle the MQTT topics step."""
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
if user_input is not None:
|
||||
try:
|
||||
data = {**self._tmp_data, **user_input}
|
||||
title = DEFAULT_NAME
|
||||
if data.get(CONF_HOST):
|
||||
title = f"{DEFAULT_NAME} ({data[CONF_HOST]})"
|
||||
|
||||
return self.async_create_entry(title=title, data=data)
|
||||
except Exception:
|
||||
errors["base"] = "unknown"
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="mqtt",
|
||||
data_schema=STEP_TWO_DATA_SCHEMA,
|
||||
errors=errors,
|
||||
)
|
||||
25
irrigation/homeassistant/greenhousino/const.py
Normal file
25
irrigation/homeassistant/greenhousino/const.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""Constants for Greenhousino Irrigation integration."""
|
||||
|
||||
DOMAIN = "greenhousino"
|
||||
MANUFACTURER = "Greenhousino"
|
||||
MODEL = "Irrigation Controller"
|
||||
|
||||
# Defaults
|
||||
DEFAULT_NAME = "Greenhousino Irrigation"
|
||||
DEFAULT_COMMAND_TOPIC = "greenhousino/pump"
|
||||
DEFAULT_STATE_TOPIC = "greenhousino/pumpstate"
|
||||
DEFAULT_PAYLOAD_ON = "on"
|
||||
DEFAULT_PAYLOAD_OFF = "off"
|
||||
|
||||
# Config flow keys
|
||||
CONF_COMMAND_TOPIC = "command_topic"
|
||||
CONF_STATE_TOPIC = "state_topic"
|
||||
CONF_HOST = "host"
|
||||
|
||||
# Service
|
||||
SERVICE_WATER_FOR = "water_for"
|
||||
SERVICE_DATA_DURATION = "duration"
|
||||
|
||||
# State
|
||||
ATTR_DURATION_MS = "duration_ms"
|
||||
ATTR_PUMP_ACTIVE = "pump_active"
|
||||
14
irrigation/homeassistant/greenhousino/manifest.json
Normal file
14
irrigation/homeassistant/greenhousino/manifest.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"domain": "greenhousino",
|
||||
"name": "Greenhousino Irrigation",
|
||||
"codeowners": [],
|
||||
"config_flow": true,
|
||||
"dependencies": ["mqtt"],
|
||||
"documentation": "https://github.com/greenhousino/irrigation",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"issue_tracker": "https://github.com/greenhousino/irrigation/issues",
|
||||
"loggers": ["greenhousino"],
|
||||
"requirements": [],
|
||||
"version": "1.0.0"
|
||||
}
|
||||
14
irrigation/homeassistant/greenhousino/services.yaml
Normal file
14
irrigation/homeassistant/greenhousino/services.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
water_for:
|
||||
name: Water for duration
|
||||
description: Activate the irrigation pump for a specified number of seconds.
|
||||
fields:
|
||||
duration:
|
||||
name: Duration
|
||||
description: How long to water, in seconds (1-3600).
|
||||
required: true
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 3600
|
||||
unit_of_measurement: "seconds"
|
||||
mode: box
|
||||
39
irrigation/homeassistant/greenhousino/strings.json
Normal file
39
irrigation/homeassistant/greenhousino/strings.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Greenhousino Irrigation",
|
||||
"description": "Enter the IP address of your ESP irrigation controller.",
|
||||
"data": {
|
||||
"host": "Host IP address"
|
||||
}
|
||||
},
|
||||
"mqtt": {
|
||||
"title": "MQTT Topics",
|
||||
"description": "Configure the MQTT topics for your irrigation controller.",
|
||||
"data": {
|
||||
"command_topic": "Command topic",
|
||||
"state_topic": "State topic"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"unknown": "An unknown error occurred."
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured."
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"water_for": {
|
||||
"name": "Water for duration",
|
||||
"description": "Activate the irrigation pump for a specified number of seconds.",
|
||||
"fields": {
|
||||
"duration": {
|
||||
"name": "Duration",
|
||||
"description": "How long to water, in seconds."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
151
irrigation/homeassistant/greenhousino/switch.py
Normal file
151
irrigation/homeassistant/greenhousino/switch.py
Normal file
@@ -0,0 +1,151 @@
|
||||
"""Switch platform for Greenhousino Irrigation."""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
ATTR_PUMP_ACTIVE,
|
||||
DOMAIN,
|
||||
MANUFACTURER,
|
||||
MODEL,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Greenhousino switch from config entry."""
|
||||
hass_data = entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
GreenhousinoPumpSwitch(
|
||||
entry,
|
||||
hass_data.command_topic,
|
||||
hass_data.state_topic,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class GreenhousinoPumpSwitch(SwitchEntity):
|
||||
"""Representation of a Greenhousino pump switch."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = "Pump"
|
||||
_attr_should_poll = False
|
||||
_attr_unique_id = None # will be set from entry_id
|
||||
_entry_id = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
entry: ConfigEntry,
|
||||
command_topic: str,
|
||||
state_topic: str,
|
||||
) -> None:
|
||||
"""Initialize the switch."""
|
||||
self._command_topic = command_topic
|
||||
self._state_topic = state_topic
|
||||
self._entry_id = entry.entry_id
|
||||
self._attr_unique_id = f"{entry.entry_id}-pump"
|
||||
self._attr_available = False
|
||||
self._state = False
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
"""Return device info."""
|
||||
return {
|
||||
"identifiers": {(DOMAIN, self._entry_id)},
|
||||
"manufacturer": MANUFACTURER,
|
||||
"model": MODEL,
|
||||
}
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
entry = self.config_entry
|
||||
|
||||
self.async_on_remove(
|
||||
mqtt.async_subscribe(
|
||||
self.hass,
|
||||
self._state_topic,
|
||||
self._state_received,
|
||||
qos=1,
|
||||
)
|
||||
)
|
||||
|
||||
# Publish availability via MQTT discovery-style
|
||||
# The device publishes to greenhousino/pump/status with "offline" on disconnect
|
||||
status_topic = self._state_topic.replace("pumpstate", "pump/status")
|
||||
self.async_on_remove(
|
||||
mqtt.async_subscribe(
|
||||
self.hass,
|
||||
status_topic,
|
||||
self._availability_received,
|
||||
qos=1,
|
||||
)
|
||||
)
|
||||
|
||||
def _state_received(self, msg: mqtt.MqttReceivePayload) -> None:
|
||||
"""Handle new MQTT state message."""
|
||||
payload = msg.decode().strip()
|
||||
self._state = payload == "on"
|
||||
self._attr_available = True
|
||||
self.async_write_ha_state()
|
||||
_LOGGER.debug("State received: %s -> pump_active=%s", payload, self._state)
|
||||
|
||||
def _availability_received(self, msg: mqtt.MqttReceivePayload) -> None:
|
||||
"""Handle availability message."""
|
||||
payload = msg.decode().strip()
|
||||
self._attr_available = payload != "offline"
|
||||
self.async_write_ha_state()
|
||||
_LOGGER.debug("Availability: %s", payload)
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return True if the pump is on."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return device state attributes."""
|
||||
return {
|
||||
ATTR_PUMP_ACTIVE: self._state,
|
||||
"command_topic": self._command_topic,
|
||||
"state_topic": self._state_topic,
|
||||
"manufacturer": MANUFACTURER,
|
||||
"model": MODEL,
|
||||
}
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the pump on."""
|
||||
await mqtt.async_publish(
|
||||
self.hass,
|
||||
self._command_topic,
|
||||
"on",
|
||||
qos=1,
|
||||
retain=False,
|
||||
)
|
||||
self._state = True
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the pump off."""
|
||||
await mqtt.async_publish(
|
||||
self.hass,
|
||||
self._command_topic,
|
||||
"off",
|
||||
qos=1,
|
||||
retain=False,
|
||||
)
|
||||
self._state = False
|
||||
self.async_write_ha_state()
|
||||
39
irrigation/homeassistant/greenhousino/translations/en.json
Normal file
39
irrigation/homeassistant/greenhousino/translations/en.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Greenhousino Irrigation",
|
||||
"description": "Enter the IP address of your ESP irrigation controller.",
|
||||
"data": {
|
||||
"host": "Host IP address"
|
||||
}
|
||||
},
|
||||
"mqtt": {
|
||||
"title": "MQTT Topics",
|
||||
"description": "Configure the MQTT topics for your irrigation controller.",
|
||||
"data": {
|
||||
"command_topic": "Command topic",
|
||||
"state_topic": "State topic"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"unknown": "An unknown error occurred."
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured."
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"water_for": {
|
||||
"name": "Water for duration",
|
||||
"description": "Activate the irrigation pump for a specified number of seconds.",
|
||||
"fields": {
|
||||
"duration": {
|
||||
"name": "Duration",
|
||||
"description": "How long to water, in seconds."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,8 @@ void reconnect()
|
||||
{
|
||||
Serial.println("INFO: Attempting MQTT connection...");
|
||||
// Attempt to connect
|
||||
if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_CLIENT_USER, MQTT_CLIENT_PW))
|
||||
if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_CLIENT_USER, MQTT_CLIENT_PW,
|
||||
MQTT_LAST_WILL_TOPIC, 1, true, MQTT_LAST_WILL_MSG))
|
||||
{
|
||||
Serial.println("INFO: connected");
|
||||
|
||||
@@ -136,6 +137,9 @@ void reconnect()
|
||||
mqttClient.publish(MQTT_STATE_TOPIC, MQTT_OFF);
|
||||
}
|
||||
|
||||
// Signal online to Home Assistant availability tracker
|
||||
mqttClient.publish(MQTT_LAST_WILL_TOPIC, "online");
|
||||
|
||||
mqttClient.subscribe(MQTT_TF_TOPIC);
|
||||
} else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user