This commit is contained in:
Stephan Mühl
2023-03-22 12:15:18 +01:00
committed by GitHub
parent 3e12414a87
commit adb5102869
203 changed files with 35010 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
Availability reporting
======================
Home Assistant allows to track online/offline states of devices and device types.
In this way controls available in the panel will be displayed as disabled if a device is offline.
The library allows to expose state of the entire device (i.e. shared availability) or specific type (sensor, switch, light, etc.).
By default this feature is not enabled to save resources (RAM and flash) but you can easily turn it on as shown below.
Shared availability
-------------------
I highly recommend to use shared availability feature as it allows to utilize MQTT LWT.
Basically, shared availability allows to control availability of all types related to a specific device.
For example: if your device has 5 switches and 2 buttons you can control their availability in the HA panel using a single method call.
See example below showing how to enable shared availability of the device.
By default, the device is considered online but you can control its state manually using ``HADevice::setAvailability(bool online)`` method.
In most cases you won't need to control availability manually as the library takes care of availability as long as the device is powered on.
::
#include <ArduinoHA.h>
HADevice device("myUniqueID");
void setup() {
device.enableSharedAvailability();
// device.setAvailability(false); // changes default state to offline
// ...
}
void loop() {
// ...
// device.setAvailability(true); // you can control availability manually if you want
}
MQTT LWT
--------
The shared availability feature is considered a complete solution only if it's used with MQTT LWT feature.
Without LWT if the device is powered off then Home Assistant displays it as online.
That's because availability tracking relies on MQTT messages and if you cut off power of your device then its not capable of publishing the offline message.
When LWT feature is enabled the device becomes offline in the HA panel even if you cut off power supply.
This solution is implemented by MQTT broker that automatically publishes the message when the TCP connection to the device is lost.
::
#include <ArduinoHA.h>
HADevice device("myUniqueID");
void setup() {
device.enableSharedAvailability();
device.enableLastWill();
// ...
}
void loop() {
// ...
}
Device type's availability
--------------------------
There also a way to control availability of specific device types.
Each type can be controlled separately as shown below.
Please note that this solution requires shared availability to be disabled and it's not supported by LWT.
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
HASwitch mySwitch("mySwitchId");
void setup() {
Ethernet.begin(mac);
// this line enables availability for your switch
mySwitch.setAvailability(true); // you can also set it to false
// ...
}
void loop() {
// ...
// you can control availability at runtime as follows:
mySwitch.setAvailability(true); // online
mySwitch.setAvailability(false); // offline
}

View File

@@ -0,0 +1,36 @@
Compiler macros
===============
The library supports couple of macros that are defined in the `ArduinoHADefines.h` file.
You can uncomment them in this specific file or provide flags directly to compiler (for example: via Makefile).
Debug mode
----------
Debug mode unlocks logging feature in the library.
Logs may be useful for debugging the communication with the Home Assistant.
To enable debug mode you need to defined `ARDUINOHA_DEBUG` macro.
Code optimization
-----------------
Defining one of the macros listed below results in truncating the corresponding device type.
It may be useful if you want to save some flash memory occupied by virtual tables of those classes.
* `EX_ARDUINOHA_BINARY_SENSOR`
* `EX_ARDUINOHA_BUTTON`
* `EX_ARDUINOHA_CAMERA`
* `EX_ARDUINOHA_COVER`
* `EX_ARDUINOHA_DEVICE_TRACKER`
* `EX_ARDUINOHA_DEVICE_TRIGGER`
* `EX_ARDUINOHA_FAN`
* `EX_ARDUINOHA_HVAC`
* `EX_ARDUINOHA_LIGHT`
* `EX_ARDUINOHA_LOCK`
* `EX_ARDUINOHA_NUMBER`
* `EX_ARDUINOHA_SCENE`
* `EX_ARDUINOHA_SELECT`
* `EX_ARDUINOHA_SENSOR`
* `EX_ARDUINOHA_SWITCH`
* `EX_ARDUINOHA_TAG_SCANNER`

View File

@@ -0,0 +1,46 @@
Connection parameters
=====================
:doc:`HAMqtt </documents/api/core/ha-mqtt>` class exposes a few variants of the ``begin`` method that allows specifying the MQTT connection parameters.
**This method should be called only once and at the end of the setup logic.**
The example below presents all possible variants. Pick one that meets your requirements.
.. NOTE::
Connection to the MQTT broker is established asynchronously.
The :doc:`HAMqtt::begin </documents/api/core/ha-mqtt>` method just sets the parameters of the connection.
The connection attempt is made during the loop cycle.
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
void setup() {
Ethernet.begin(mac);
// anoymous connection on default port 1883
mqtt.begin("192.168.1.50");
// anoymous connection on port 8888
mqtt.begin("192.168.1.50", 8888);
// connection with credentials on default port 1883
mqtt.begin("192.168.1.50", "username", "password");
// connection with credentials on port 8888
mqtt.begin("192.168.1.50", 8888, "username", "password");
// you can also use hostname in all variants
mqtt.begin("mybroker.local");
}
void loop() {
Ethernet.maintain();
mqtt.loop();
}

View File

@@ -0,0 +1,110 @@
Device configuration
====================
:doc:`HADevice </documents/api/core/ha-device>` represents the physical device where the library is installed.
Logically it's a group of types like sensors, switches, lights and so on.
In the Home Assistant, it's listed with properties that may be configured using the library's API.
Each property except the unique ID is optional.
Setting optional properties increases flash and RAM usage so it's not recommended to set them on lower-spec MCUs.
The supported properties are:
* unique ID*
* name
* software version
* manufacturer
* model
Unique ID
---------
The ID of a device needs to be unique in a scope of a Home Assistant instance.
The safest solution is to use the MAC address of an Ethernet or Wi-Fi chip but you can also implement your own solution.
There are three different ways to set the ID of the device.
You can pick one depending on your needs.
1) Providing string (const char*) to the :doc:`HADevice </documents/api/core/ha-device>` constructor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Try to keep the ID simple (alphanumeric characters) and short.
::
#include <ArduinoHA.h>
HADevice device("myUniqueID");
void setup() {
// ...
}
void loop() {
// ...
}
2) Providing byte array to the :doc:`HADevice </documents/api/core/ha-device>` constructor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
#include <ArduinoHA.h>
// use your own unique bytes sequence
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
HADevice device(mac, sizeof(mac));
void setup() {
// ...
}
void loop() {
// ...
}
3) Using :doc:`HADevice::setUniqueId </documents/api/core/ha-device>` method during the setup
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
#include <ArduinoHA.h>
HADevice device;
void setup() {
// any length is acceptable
byte myId[] = {0x05, 0xb4, 0xc6, 0x9f, 0xbe, 0xce, 0x8c, 0x1f, 0xc7};
device.setUniqueId(myId, sizeof(myId)); // the input array is cloned internally
// ...
}
void loop() {
// ...
}
Device properties
-----------------
Each property has its corresponding setter method in the :doc:`HADevice </documents/api/core/ha-device>` class.
Please note that all these methods accept const char pointer whose **content is not copied**.
::
#include <ArduinoHA.h>
HADevice device("myUniqueId");
void setup() {
device.setName("Bedroom Light Controller");
device.setSoftwareVersion("1.0.0");
device.setManufacturer("Developer Corp.");
device.setModel("ABC-123");
// ...
}
void loop() {
// ...
}

View File

@@ -0,0 +1,113 @@
Device types
============
Device type represents a single entity in the Home Assistant panel.
It can be a sensor, lock, camera or anything that's listed in the table below.
Your physical device (for example ESP-01 board) can have multiple device types assigned.
They will be displayed as child entities in the HA panel.
Limitations
-----------
Registering a new device type requires some flash and RAM memory to be utilized.
On less powerful units like Arduino Uno, you may quickly hit the limit of resources, so keeping the device simple is recommended.
Hitting the resource limit will result in random reboots of the device.
By default, the maximum number of device types is 6.
You can increase the limit using the :doc:`HAMqtt </documents/api/core/ha-mqtt>` class constructor as follows:
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device, 12); // <------------ 12 is a new limit of device types
void setup() {
Ethernet.begin(mac);
// your setup logic goes here
}
void loop() {
Ethernet.maintain();
mqtt.loop();
// your loop logic goes here
}
Please note that this limit cannot be changed at runtime.
Supported device types
----------------------
.. list-table::
:widths: 25 15 60
:header-rows: 1
:class: supported-device-types-table
* - Device type
- Supported
- Documentation
* - Binary sensor
- ✅
- :doc:`HABinarySensor </documents/api/device-types/ha-binary-sensor>`
* - Button
- ✅
- :doc:`HAButton </documents/api/device-types/ha-button>`
* - Camera
- ✅
- :doc:`HACamera </documents/api/device-types/ha-camera>`
* - Cover
- ✅
- :doc:`HACover </documents/api/device-types/ha-cover>`
* - Device tracker
- ✅
- :doc:`HADeviceTracker </documents/api/device-types/ha-device-tracker>`
* - Device trigger
- ✅
- :doc:`HADeviceTrigger </documents/api/device-types/ha-device-trigger>`
* - Fan
- ✅
- :doc:`HAFan </documents/api/device-types/ha-fan>`
* - Humidifier
- ❌
- --
* - HVAC
- ✅
- :doc:`HAHVAC </documents/api/device-types/ha-hvac>`
* - Light
- ✅
- :doc:`HALight </documents/api/device-types/ha-light>`
* - Lock
- ✅
- :doc:`HALock </documents/api/device-types/ha-lock>`
* - Number
- ✅
- :doc:`HANumber </documents/api/device-types/ha-number>`
* - Scene
- ✅
- :doc:`HAScene </documents/api/device-types/ha-scene>`
* - Select
- ✅
- :doc:`HASelect </documents/api/device-types/ha-select>`
* - | Sensor (text)
- ✅
- :doc:`HASensor </documents/api/device-types/ha-sensor>`
* - | Sensor (number)
- ✅
- :doc:`HASensorNumber </documents/api/device-types/ha-sensor-number>`
* - Switch
- ✅
- :doc:`HASwitch </documents/api/device-types/ha-switch>`
* - Tag scanner
- ✅
- :doc:`HATagScanner </documents/api/device-types/ha-tag-scanner>`
* - Vacuum
- ❌
- --

View File

@@ -0,0 +1,44 @@
Discovery
=========
The library automatically maintains connection to the MQTT broker and takes care of the discovery process.
Each device type that you create (sensor, switch, light, fan, etc.) is automatically registered in MQTT manager.
Whenever connection with the MQTT broker is acquired the configuration of all device types is pushed to the Home Assistant.
There is one basic rule that you need to follow: device types need to be constructed after :doc:`HAMqtt </documents/api/core/ha-mqtt>` class.
That's because device types are relying on :doc:`HAMqtt </documents/api/core/ha-mqtt>` instance internally.
Topics prefix
-------------
In some cases you may need to change prefix of MQTT topics.
There are two types of topics utilized by the library:
* **discovery topic** - used for publishing device types' configuration (default: ``homeassistant``)
* **data topic** - used for publishing states, data, etc. (default: ``aha``)
The discovery topic's prefix can be changed using ``HAMqtt::setDiscoveryPrefix(const char* prefix)`` method.
The data topic's prefix can be changed using ``HAMqtt::setDataPrefix(const char* prefix)`` method
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
// register your device types here
void setup() {
mqtt.setDiscoveryPrefix("myCustomPrefix");
mqtt.setDataPrefix("myDataPrefix");
// ...
}
void loop() {
// ...
}

View File

@@ -0,0 +1,19 @@
Library
=======
This chapter describes basic all of the library's core.
Solid understanding of foundations will allow you to utilize full potential of the library.
.. toctree::
:maxdepth: 2
introduction
device-configuration
availability-reporting
connection-params
discovery
device-types
mqtt-security
mqtt-advanced
compiler-macros

View File

@@ -0,0 +1,79 @@
Introduction
============
Before implementing the business logic of your application you will need to
add a few necessary pieces of code to your project.
Basically, everything comes up to a few basic rules:
1) :doc:`HADevice </documents/api/core/ha-device>` and :doc:`HAMqtt </documents/api/core/ha-mqtt>` instances need to be initialized once globally or as a part of another global object.
2) :doc:`HAMqtt::begin </documents/api/core/ha-mqtt>` needs to be called at the end of setup logic. It provides MQTT broker credentials that will be used for a connection.
3) :doc:`HAMqtt::loop </documents/api/core/ha-mqtt>` method needs to be called periodically (it doesn't need to be called on each tick).
4) Device types need to be initialized after :doc:`HAMqtt </documents/api/core/ha-mqtt>` class (it will be described later in the documentation).
Here are the minimal boilerplates that you can start with.
Don't worry if you have no idea what's going on here.
Everything will be covered in the following chapters.
Arduino Boilerplate
-------------------
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
void setup() {
Ethernet.begin(mac);
// your setup logic goes here
// MQTT broker connection (use your data here)
mqtt.begin("192.168.1.50", "username", "password");
}
void loop() {
Ethernet.maintain();
mqtt.loop();
// your loop logic goes here
}
ESP32/ESP8266 Boilerplate
-------------------------
::
#include <ESP8266WiFi.h>
#include <ArduinoHA.h>
WiFiClient client;
HADevice device;
HAMqtt mqtt(client, device);
void setup() {
byte mac[WL_MAC_ADDR_LENGTH];
WiFi.macAddress(mac);
device.setUniqueId(mac, sizeof(mac));
// you can skip this part if you're already maintaining the connection logic
WiFi.begin("MyNetworkSSID", "MyPassword");
while (WiFi.status() != WL_CONNECTED) {
delay(500); // waiting for the connection
}
// your setup logic goes here
// MQTT broker connection (use your data here)
mqtt.begin("192.168.1.50", "username", "password");
}
void loop() {
mqtt.loop();
// your loop logic goes here
}

View File

@@ -0,0 +1,110 @@
MQTT advanced features
======================
Callbacks
---------
:doc:`HAMqtt </documents/api/core/ha-mqtt>` class exposes some useful callbacks that you can bind to.
Please take a look at the example below.
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
void onMessage(const char* topic, const uint8_t* payload, uint16_t length) {
// this method will be called each time the device receives an MQTT message
}
void onConnected() {
// this method will be called when connection to MQTT broker is established
}
void setup() {
Ethernet.begin(mac);
mqtt.onMessage(onMessage);
mqtt.onConnected(onConnected);
mqtt.begin("192.168.1.50", "username", "password");
}
void loop() {
Ethernet.maintain();
mqtt.loop();
}
Subscriptions
-------------
You can also subscribe to a custom topic using ``HAMqtt::subscribe(const char* topic)`` method.
The subscription needs to be made each time a connection to the MQTT broker is established.
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
void onMessage(const char* topic, const uint8_t* payload, uint16_t length) {
if (strcmp(topic, "myTopic") == 0) {
// message on "myTopic" received
}
}
void onConnected() {
mqtt.subscribe("myTopic");
}
void setup() {
Ethernet.begin(mac);
mqtt.onMessage(onMessage);
mqtt.onConnected(onConnected);
mqtt.begin("192.168.1.50", "username", "password");
}
void loop() {
Ethernet.maintain();
mqtt.loop();
}
Publishing a message
--------------------
HAMqtt class also exposes the method that allows to publish custom messages.
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
void setup() {
Ethernet.begin(mac);
mqtt.begin("192.168.1.50", "username", "password");
}
void loop() {
Ethernet.maintain();
mqtt.loop();
// Publishing the non-retained message:
// mqtt.publish("customTopic", "customPayload");
// Publishing the retained message:
// mqtt.publish("customTopic", "customPayload", true);
}

View File

@@ -0,0 +1,40 @@
MQTT security
=============
The library allows you to use credentials for acquiring a TCP connection with the MQTT broker.
By default you can use the same credentials you use for login in the Home Assistant panel but you can also configure custom credentials in the Mosquitto broker.
.. DANGER::
This solution is not 100% secure because communication between Arduino and Home Assistant is not encrypted.
Username and password can be easily discovered by analyzing your local network traffic.
However, that's fine as long as your local network is secured against unattended access.
On more powerful devices (like ESP), you should consider using TLS/SSL connection.
::
#include <Ethernet.h>
#include <ArduinoHA.h>
byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
EthernetClient client;
HADevice device(mac, sizeof(mac));
HAMqtt mqtt(client, device);
void setup() {
// ...
// replace username and password with your credentials
mqtt.begin("192.168.1.50", "username", "password");
}
void loop() {
// ...
}
SSL connection
--------------
On ESP32/ESP8266 you can use ``WiFiClientSecure`` client to establish encrypted connection between your device and Home Assistant.
Please take a look at :example:`this example <mqtt-with-ssl/mqtt-with-ssl.ino>`.