feat: prepare ArduinoHA 3.0.0

This commit is contained in:
2026-08-27 14:25:38 +10:00
parent 9d3eaa61f7
commit 96c5aa6e78
11 changed files with 231 additions and 144 deletions
+12 -2
View File
@@ -2,22 +2,32 @@ name: Build
on: on:
push: push:
branches: [main]
pull_request: pull_request:
concurrency:
group: build-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: permissions:
contents: read contents: read
jobs: jobs:
documentation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/check-docs.sh
compile-tests: compile-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
environment: ["esp8266", "esp32"] platform: [esp8266, esp32]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
with: with:
python-version: '3.11' python-version: '3.11'
- run: python -m pip install --upgrade platformio==6.1.19 - run: python -m pip install --upgrade platformio==6.1.19
- run: pio test -e ${{ matrix.environment }} --without-uploading --without-testing - run: ./scripts/test.sh compile --platform ${{ matrix.platform }}
+5 -1
View File
@@ -17,7 +17,11 @@ jobs:
with: with:
python-version: '3.11' python-version: '3.11'
- run: python -m pip install --upgrade platformio==6.1.19 - run: python -m pip install --upgrade platformio==6.1.19
- run: ./scripts/test.sh compile --platform esp8266
- run: ./scripts/test.sh compile --platform esp32
- run: ./scripts/check-docs.sh
- run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME" - run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME"
- run: gh release create "$GITHUB_REF_NAME" --generate-notes --title "$GITHUB_REF_NAME" - run: ./scripts/release-notes.sh "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md"
- run: gh release create "$GITHUB_REF_NAME" --title "ArduinoHA $GITHUB_REF_NAME" --notes-file "$RUNNER_TEMP/release-notes.md"
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
+57 -139
View File
@@ -1,160 +1,78 @@
# Arduino Home Assistant integration 🏠 # Arduino Home Assistant integration
[![](https://img.shields.io/github/v/release/alexhopeoconnor/arduino-home-assistant?label=Version)](https://github.com/alexhopeoconnor/arduino-home-assistant/releases) [![](https://img.shields.io/github/v/release/alexhopeoconnor/arduino-home-assistant?label=Version)](https://github.com/alexhopeoconnor/arduino-home-assistant/releases)
[![](https://img.shields.io/badge/Documentation-40BC13)](https://github.com/alexhopeoconnor/arduino-home-assistant/blob/main/docs/README.md) [![](https://img.shields.io/badge/Documentation-40BC13)](docs/README.md)
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/dawidchyrzynski)
ArduinoHA integrates Arduino- and ESP-based devices with Home Assistant over MQTT. ArduinoHA is the maintained MQTT-discovery library behind compact Arduino, ESP8266, and ESP32 integrations with Home Assistant. It uses Arduino's standard network `Client` API and is continuously compile-tested on ESP8266 and ESP32.
It is designed to keep RAM and flash use low. The original project targeted the
Arduino Uno with an Ethernet Shield; this maintained fork is continuously tested ## Why use it
on ESP8266 and ESP32 release targets.
- **Home Assistant discovery:** entities appear automatically from retained MQTT discovery payloads.
- **Two-way entities:** report local state and receive Home Assistant commands with a small, explicit API.
- **One physical device:** group multiple entities, metadata, shared availability, and MQTT Last Will under `HADevice`.
- **Control the footprint:** compile out entity implementations a firmware does not use.
- **Two discovery shapes:** start with one payload per entity or opt into a single device-discovery payload.
## Start with a sensor
```cpp
#include <ESP8266WiFi.h>
#include <ArduinoHA.h>
WiFiClient client;
HADevice device;
HAMqtt mqtt(client, device);
HASensorNumber temperature("temperature");
void setup() {
byte mac[WL_MAC_ADDR_LENGTH];
WiFi.macAddress(mac);
device.setUniqueId(mac, sizeof(mac));
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(500);
temperature.setName("Temperature");
temperature.setUnitOfMeasurement("°C");
mqtt.begin("mqtt.local", "mqtt_user", "mqtt_password");
}
void loop() {
mqtt.loop();
// Call temperature.setValue(...) when your reading changes.
}
```
Read [Getting started](docs/getting-started.md) before copying this into production: it explains object lifetime, MQTT lifecycle, ESP32 includes, and install routes.
## Install ## Install
### PlatformIO
[`library.json`](library.json) declares the **PubSubClient** dependency. Pin the
maintained release tag in an application:
```ini ```ini
lib_deps = lib_deps =
home-assistant-integration=https://github.com/alexhopeoconnor/arduino-home-assistant.git#v3.0.0 home-assistant-integration=https://github.com/alexhopeoconnor/arduino-home-assistant.git#v3.0.0
``` ```
The suffix after `#` is a Git ref. PlatformIO clones this repository and checks PlatformIO clones the Git repository and checks out the ref after `#`; that ref is a release tag, not a GitHub Release asset. Arduino IDE is supported through the included [`library.properties`](library.properties); see [Getting started](docs/getting-started.md#install-the-library).
out that tag; it does not download a GitHub Release asset.
### Arduino IDE ## Documentation
This maintained fork is not published through the Arduino Library Manager. The [documentation map](docs/README.md) is the starting point:
Download the source archive for a release, extract it, move the extracted library
directory to `<sketchbook>/libraries/home-assistant-integration`, then restart the IDE.
[`library.properties`](library.properties) provides the local library name and
metadata expected by the Arduino IDE.
## Tests and releases - [Getting started](docs/getting-started.md): connection lifecycle and minimal sketches.
- [Device and discovery](docs/device-and-discovery.md): device metadata, discovery modes, and runtime refresh.
- [MQTT usage](docs/mqtt-usage.md): callbacks, availability, custom MQTT, logging, and footprint flags.
- [Entity guide](docs/entities.md): supported entity types and the best matching example.
- [Examples](examples/README.md): curated entry points and the full example index.
CI compile-checks the PlatformIO Unity suite for the ESP8266 and ESP32 without ## Development and releases
a board:
```bash
pio test -e esp8266 --without-uploading --without-testing
pio test -e esp32 --without-uploading --without-testing
```
Before publishing a version, update `library.json`, `library.properties`,
`CHANGELOG.md`, and the relevant documentation. Validate and create the
annotated tag with:
```bash ```bash
./scripts/test.sh compile --platform esp8266
./scripts/test.sh compile --platform esp32
./scripts/check-docs.sh
./scripts/prepare-release.sh vMAJOR.MINOR.PATCH --tag ./scripts/prepare-release.sh vMAJOR.MINOR.PATCH --tag
``` ```
Push the branch and tag. The tag workflow validates the PlatformIO package The release preflight validates both package manifests and the matching changelog section. A pushed tag repeats the board-free compile checks and creates a GitHub Release from that section; it does not publish to the PlatformIO Registry or deploy firmware.
again and creates the GitHub Release.
## Features See the [changelog](CHANGELOG.md) and [licence](LICENSE).
* Two-way communication (state reporting and command execution)
* MQTT discovery (device is added to the Home Assistant panel automatically)
* Rich discovery metadata for entities, devices, origin, templates and availability
* MQTT Last Will and Testament
* Support for custom MQTT messages (publishing and subscribing)
* Auto reconnect with MQTT broker
* Reporting availability (online/offline states) of a device
* Markdown documentation in [`docs/`](docs/README.md); class-level notes in headers under `src/`
* Covered by unit tests ([PlatformIO](https://platformio.org/) + [Unity](https://github.com/ThrowTheSwitch/Unity); see `test/test_*`)
## Discovery Notes
ArduinoHA supports two MQTT discovery modes:
* Single-component discovery, which remains the default behavior and publishes one retained discovery payload per entity.
* Device discovery, which can be enabled explicitly with `HAMqtt::enableDeviceDiscovery()` and publishes a single retained `homeassistant/device/.../config` payload with component mappings under `cmps`.
For entity ID suggestions in Home Assistant, prefer `setDefaultEntityId()` over `setObjectId()`.
`setObjectId()` is still available as a legacy fallback, but newer Home Assistant versions are moving toward `default_entity_id`.
If you need to manage discovery at runtime:
* Use `HABaseDeviceType::republishDiscovery()` after changing discovery-relevant config at runtime.
* Use `HABaseDeviceType::removeFromDiscovery()` to clear the retained discovery payload for a single entity.
When device discovery mode is enabled, runtime discovery refreshes automatically clear any stale retained per-entity config before republishing the device discovery payload.
Recent discovery additions include:
* Shared entity metadata such as `enabled_by_default`, `entity_picture`, `qos`, `encoding`
* Device/origin metadata such as `model_id`, `hw_version`, `serial_number`, `suggested_area`, `via_device`, `connections`, `support_url`
* Availability payload overrides and multi-topic availability discovery metadata
## Supported HA types
| Home Assistant type | Supported |
| ------------------- | :--------: |
| Alarm control panel | ❌ |
| Binary sensor | ✅ |
| Button | ✅ |
| Camera | ✅ |
| Cover | ✅ |
| Device tracker | ✅ |
| Device trigger | ✅ |
| Event | ❌ |
| Fan | ✅ |
| Humidifier | ❌ |
| Image | ❌ |
| HVAC | ✅ |
| Lawn mower | ❌ |
| Light | ✅ |
| Lock | ✅ |
| Number | ✅ |
| Scene | ✅ |
| Select | ✅ |
| Sensor | ✅ |
| Siren | ❌ |
| Switch | ✅ |
| Update | ❌ |
| Tag scanner | ✅ |
| Text | ✅ |
| Vacuum | ❌ |
| Valve | ❌ |
| Water heater | ❌ |
## Examples
|Example|Description |
|-------|-----------------------------|
|[Binary sensor](examples/binary-sensor/binary-sensor.ino)|Using the binary sensor as a door contact sensor.|
|[Button](examples/button/button.ino)|Adding simple buttons to the Home Assistant panel.|
|[Camera](examples/esp32-cam/esp32-cam.ino)|Publishing the preview from the ESP32-CAM module.|
|[Cover](examples/cover/cover.ino)|Controlling a window cover (open / close / stop).|
|[Device trigger](examples/multi-state-button/multi-state-button.ino)|Implementation of a simple wall switch that reports press and hold states.|
|[Fan](examples/fan/fan.ino)|Controlling a simple fan (state + speed).|
|[HVAC](examples/hvac/hvac.ino)|HVAC controller with multiple modes, power control and target temperature.|
|[Lock](examples/lock/lock.ino)|A simple door lock that's controlled by the Home Assistant.|
|[Light](examples/light/light.ino)|A simple light that allows changing brightness, color temperature and RGB color.|
|[Number](examples/number/number.ino)|Adding an interactive numeric slider in the Home Assistant panel.|
|[Scene](examples/scene/scene.ino)|Adding a custom scene in the Home Assistant panel. |
|[Select](examples/select/select.ino)|A dropdown selector that's displayed in the Home Assistant panel.|
|[Sensor](examples/sensor/sensor.ino)|A simple sensor that reports a state in a string representation (open / opening / close).|
|[Analog sensor](examples/sensor-analog/sensor-analog.ino)|Reporting the analog pin's voltage to the Home Assistant.|
|[Integer sensor](examples/sensor-integer/sensor-integer.ino)|Reporting the device's uptime to the Home Assistant.|
|[Switch](examples/led-switch/led-switch.ino)|The LED that's controlled by the Home Assistant.|
|[Multi-switch](examples/multi-switch/multi-switch.ino)|Multiple switches controlled by the Home Assistant.|
|[Tag scanner](examples/tag-scanner/tag-scanner.ino)|Scanning RFID tags using the MFRC522 module.|
|[Availability](examples/availability/availability.ino)|Reporting entities' availability (online / offline) to the Home Assistant.|
|[Advanced availability](examples/advanced-availability/advanced-availability.ino)|Advanced availability reporting with MQTT LWT (Last Will and Testament).|
|[MQTT advanced](examples/mqtt-advanced/mqtt-advanced.ino)|Subscribing to custom topics and publishing custom messages.|
|[MQTT with credentials](examples/mqtt-with-credentials/mqtt-with-credentials.ino)|Establishing connection with a MQTT broker using the credentials. |
|[NodeMCU (ESP8266)](examples/nodemcu/nodemcu.ino)|Basic example for ESP8266 devices.|
|[Arduino Nano 33 IoT](examples/nano33iot/nano33iot.ino)|Basic example for Arduino Nano 33 IoT (SAMD family).|
|[mDNS discovery](examples/mdns/mdns.ino)|Make your ESP8266 discoverable via the mDNS.|
## Supported and compatible hardware
ArduinoHA is designed around Arduino's network `Client` API and can be used
with Ethernet or Wi-Fi clients that implement it. This fork's automated
PlatformIO coverage is ESP8266 (Wemos D1 mini) and ESP32 (ESP32 DevKit).
Other Arduino targets may work, but they are compatibility targets rather than
a tested release guarantee; validate the compiler, network client, memory
budget, and Home Assistant discovery behavior in the consuming project.
+3 -1
View File
@@ -7,5 +7,7 @@ User-facing notes for this library. API details live in the headers under [`src/
| [Getting started](getting-started.md) | Prerequisites, installing the library, minimal sketches | | [Getting started](getting-started.md) | Prerequisites, installing the library, minimal sketches |
| [Device & discovery](device-and-discovery.md) | `HADevice`, MQTT connection, discovery prefixes, entity IDs | | [Device & discovery](device-and-discovery.md) | `HADevice`, MQTT connection, discovery prefixes, entity IDs |
| [MQTT usage](mqtt-usage.md) | Callbacks, custom topics, availability, compiler flags | | [MQTT usage](mqtt-usage.md) | Callbacks, custom topics, availability, compiler flags |
| [Entities](entities.md) | Supported Home Assistant entity classes and example selection |
| [Examples](../examples/README.md) | Curated paths through the standalone sketches |
The [project README](../README.md) lists supported Home Assistant entity types, discovery notes, and links to [`examples/`](../examples/). Class-level API details live in headers under [`src/`](../src/). Return to the [project overview](../README.md).
+33
View File
@@ -0,0 +1,33 @@
# Entities
ArduinoHA supports these Home Assistant MQTT discovery entity classes. Choose the focused example where possible; it shows the entity's update or command callback pattern in a runnable sketch.
| Entity | Example |
| --- | --- |
| Binary sensor | [binary-sensor](../examples/binary-sensor/binary-sensor.ino) |
| Button | [button](../examples/button/button.ino) |
| Camera | [esp32-cam](../examples/esp32-cam/esp32-cam.ino) |
| Cover | [cover](../examples/cover/cover.ino) |
| Device tracker | Use the API header; no dedicated sketch yet |
| Device trigger | [multi-state-button](../examples/multi-state-button/multi-state-button.ino) |
| Fan | [fan](../examples/fan/fan.ino) |
| HVAC | [hvac](../examples/hvac/hvac.ino) |
| Light | [light](../examples/light/light.ino) |
| Lock | [lock](../examples/lock/lock.ino) |
| Number | [number](../examples/number/number.ino) |
| Scene | [scene](../examples/scene/scene.ino) |
| Select | [select](../examples/select/select.ino) |
| Sensor | [sensor](../examples/sensor/sensor.ino), [sensor-analog](../examples/sensor-analog/sensor-analog.ino), or [sensor-integer](../examples/sensor-integer/sensor-integer.ino) |
| Switch | [led-switch](../examples/led-switch/led-switch.ino) or [multi-switch](../examples/multi-switch/multi-switch.ino) |
| Tag scanner | [tag-scanner](../examples/tag-scanner/tag-scanner.ino) |
| Text | Use the API header; no dedicated sketch yet |
The library does not currently implement alarm control panels, events, humidifiers, images, lawn mowers, sirens, updates, vacuums, valves, or water heaters. Those are deliberate unsupported surfaces, not configuration switches.
## Common lifecycle
Create `HADevice`, `HAMqtt`, then entities in that order; create them before `mqtt.begin(...)`. Call `mqtt.loop()` regularly. Read [Getting started](getting-started.md) for the connection flow and [device discovery](device-and-discovery.md) for discovery settings.
For shared online/offline state, use `device.enableSharedAvailability()` and `device.enableLastWill()` before connecting. The [availability examples](../examples/availability/) show the simplest setup, while [advanced availability](../examples/advanced-availability/) covers custom payloads and Last Will behaviour.
Back to the [documentation map](README.md).
+39
View File
@@ -0,0 +1,39 @@
# ArduinoHA examples
Each directory is an Arduino sketch. Start with the network example matching your board, then pick an entity example from the table. Copy credentials into your local development configuration; do not commit them in a sketch.
| Starting point | Use it for |
| --- | --- |
| [nodemcu](nodemcu/nodemcu.ino) | Basic ESP8266 Wi-Fi and MQTT connection |
| [nano33iot](nano33iot/nano33iot.ino) | Basic Arduino Nano 33 IoT connection |
| [mqtt-with-credentials](mqtt-with-credentials/mqtt-with-credentials.ino) | MQTT authentication |
| [mqtt-advanced](mqtt-advanced/mqtt-advanced.ino) | Custom MQTT subscriptions and publishing |
| [availability](availability/availability.ino) | Per-entity availability |
| [advanced-availability](advanced-availability/advanced-availability.ino) | Shared availability and MQTT Last Will |
## Entity examples
| Example | Home Assistant behaviour |
| --- | --- |
| [binary-sensor](binary-sensor/binary-sensor.ino) | Door/contact-style binary state |
| [button](button/button.ino) | Press action |
| [cover](cover/cover.ino) | Open, close, and stop commands |
| [esp32-cam](esp32-cam/esp32-cam.ino) | ESP32 camera preview |
| [fan](fan/fan.ino) | State and speed commands |
| [hvac](hvac/hvac.ino) | Modes, power, and target temperature |
| [led-switch](led-switch/led-switch.ino) | Basic writable switch |
| [light](light/light.ino) | Brightness, colour temperature, and RGB |
| [lock](lock/lock.ino) | Writable lock state |
| [multi-state-button](multi-state-button/multi-state-button.ino) | Device triggers from a wall switch |
| [multi-switch](multi-switch/multi-switch.ino) | Multiple writable switches |
| [number](number/number.ino) | Writable numeric value |
| [scene](scene/scene.ino) | Scene trigger |
| [select](select/select.ino) | Writable option list |
| [sensor](sensor/sensor.ino) | String state sensor |
| [sensor-analog](sensor-analog/sensor-analog.ino) | Analog voltage measurement |
| [sensor-integer](sensor-integer/sensor-integer.ino) | Integer uptime measurement |
| [tag-scanner](tag-scanner/tag-scanner.ino) | RFID tag reporting |
The examples are intentionally small, not production firmware frameworks. For reusable Wi-Fi configuration, MQTT wiring, profiles, OTA, and migrations, use [DeviceFramework](https://github.com/alexhopeoconnor/DeviceFramework) in a consuming firmware.
See the [entity guide](../docs/entities.md) and [project overview](../README.md).
-1
View File
@@ -37,7 +37,6 @@
"include": [ "include": [
"src", "src",
"examples", "examples",
"docs",
"library.properties", "library.properties",
"library.json", "library.json",
"README.md", "README.md",
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
required=(
README.md CHANGELOG.md
docs/README.md docs/getting-started.md docs/device-and-discovery.md docs/mqtt-usage.md docs/entities.md
examples/README.md
)
for path in "${required[@]}"; do
[[ -f "$root/$path" ]] || { echo "Missing required documentation: $path" >&2; exit 1; }
done
while IFS= read -r -d '' markdown; do
while IFS= read -r target; do
[[ -z "$target" || "$target" == \#* || "$target" == http://* || "$target" == https://* || "$target" == mailto:* ]] && continue
target="${target%%#*}"
case "$target" in
/*) candidate="$root/${target#/}" ;;
*) candidate="$(dirname "$markdown")/$target" ;;
esac
[[ -e "$candidate" ]] || { echo "Broken relative link in ${markdown#$root/}: $target" >&2; exit 1; }
done < <(sed -nE 's/.*\]\(([^ )]+)( "[^"]*")?\).*/\1/p' "$markdown")
done < <(find "$root" -path "$root/.git" -prune -o -name '*.md' -type f -print0)
echo "Documentation links and required files passed"
+7
View File
@@ -27,6 +27,13 @@ if [[ -f "$root/library.properties" ]]; then
fi fi
fi fi
if ! grep -q "^## ${version}$" "$root/CHANGELOG.md"; then
echo "CHANGELOG.md is missing a ## ${version} section" >&2
exit 1
fi
git -C "$root" diff --check
package_dir="$(mktemp -d)" package_dir="$(mktemp -d)"
trap 'rm -rf "$package_dir"' EXIT trap 'rm -rf "$package_dir"' EXIT
pio pkg pack "$root" --output "$package_dir/package.tar.gz" >/dev/null pio pkg pack "$root" --output "$package_dir/package.tar.gz" >/dev/null
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 vMAJOR.MINOR.PATCH" >&2
exit 2
}
tag="${1:-}"
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || usage
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
version="${tag#v}"
changelog="$root/CHANGELOG.md"
output="$(mktemp)"
trap 'rm -f "$output"' EXIT
awk -v version="$version" '
$0 == "## " version { capture = 1; next }
capture && /^## / { exit }
capture { print }
' "$changelog" > "$output"
if [[ ! -s "$output" ]]; then
echo "No release notes found for $tag in CHANGELOG.md" >&2
exit 1
fi
printf '%s\n\n' "# ArduinoHA $tag"
cat "$output"
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 compile --platform esp8266|esp32" >&2
exit 2
}
[[ "${1:-}" == "compile" && "${2:-}" == "--platform" && $# -eq 3 ]] || usage
case "${3:-}" in
esp8266|esp32) environment="${3}" ;;
*) usage ;;
esac
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
pio test -d "$root" -e "$environment" --without-uploading --without-testing
echo "ArduinoHA compile check passed for ${3}"