Files

186 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MQTT usage
## Callbacks and tuning
The following snippets extend a sketch that already owns long-lived `HADevice`, `HAMqtt`, and entity objects. Configure callbacks, discovery metadata, and availability before `mqtt.begin(...)`; call the publishing snippets later from normal application logic.
`HAMqtt` supports optional callbacks and PubSubClient tuning:
```cpp
// These callbacks are registered before mqtt.begin(...).
void onMessage(const char* topic, const uint8_t* payload, uint16_t length) { /* ... */ }
void onConnected() { /* ... */ }
void onDisconnected() { /* ... */ }
void onStateChanged(HAMqtt::ConnectionState state) { /* ... */ }
void setup() {
// A successful reconnect creates a new MQTT session, so onConnected runs again.
mqtt.onMessage(onMessage);
mqtt.onConnected(onConnected);
mqtt.onDisconnected(onDisconnected);
mqtt.onStateChanged(onStateChanged);
mqtt.setBufferSize(512); // Increase only when a larger MQTT packet is required.
mqtt.setKeepAlive(60); // Seconds; the default is 15.
mqtt.begin("192.168.1.50", "user", "pass");
}
```
## Custom subscriptions
Subscribe after each successful connection (for example in `onConnected`), because subscriptions are tied to the MQTT session:
```cpp
void onConnected() {
// MQTT subscriptions belong to this session and must be restored after reconnecting.
mqtt.subscribe("my/custom/topic");
}
```
Handle payloads in `onMessage`.
## Publishing arbitrary payloads
```cpp
// Call after mqtt.begin(...); retain controls whether the broker keeps this value.
void publishApplicationState() {
mqtt.publish("customTopic", "payload", false); // Not retained.
mqtt.publish("customTopic", "payload", true); // Retained.
}
```
## Availability
**Shared availability (recommended):** one availability topic for the whole device — works well with **Last Will** (LWT):
```cpp
// Configure device-wide availability before mqtt.begin(...).
void configureSharedAvailability() {
device.enableSharedAvailability();
device.setPayloadAvailable("up");
device.setPayloadNotAvailable("down");
device.enableLastWill(); // Broker publishes offline when TCP drops.
// device.setAvailability(false); // Optional: start as offline.
}
```
**Per-entity availability:** call `someEntity.setAvailability(true/false)` on each type. Does not use LWT the same way as shared mode; see examples under `examples/availability/`.
Custom per-entity payloads are supported:
```cpp
// Configure the relevant entity before mqtt.begin(...).
void configureSensorAvailability() {
sensor.setPayloadAvailable("ready");
sensor.setPayloadNotAvailable("lost");
}
```
For multi-topic availability discovery, add full MQTT topics and a mode:
```cpp
// `sensor` is the entity whose availability depends on these external topics.
void configureExternalAvailability() {
sensor.setAvailabilityMode("all");
sensor.addAvailabilityEntry("bridge/status");
sensor.addAvailabilityEntry("sensor/status", "{{ value_json.state }}");
}
```
## Discovery helpers by entity
Common entity discovery metadata is available on most entity classes:
```cpp
// `entity` is an entity type that supports these common discovery fields.
void configureCommonDiscovery(HABaseDeviceType& entity) {
entity.setEnabledByDefault(false);
entity.setEntityPicture("https://example.com/entity.png");
entity.setQos(1);
entity.setEncoding("utf-8");
entity.setEntityCategory("diagnostic");
}
```
Read-only sensor presentation/template helpers:
```cpp
// `sensor` is a read-only HASensor instance.
void configureSensorPresentation(HASensor& sensor) {
sensor.setSuggestedDisplayPrecision(2);
sensor.setValueTemplate("{{ value_json.temperature }}");
sensor.setJsonAttributesTemplate("{{ value_json.attrs | tojson }}");
sensor.setLastResetValueTemplate("{{ value_json.last_reset }}");
sensor.setDeviceClass("enum");
sensor.setOptions("idle;charging;discharging;fault");
}
```
Writable entity template/payload helpers:
```cpp
// These names refer to the matching writable entity instances in the application.
void configureWritableEntities(HASwitch& mySwitch,
HANumber& myNumber,
HASelect& mySelect,
HAText& myText,
HAButton& myButton) {
mySwitch.setPayloadOn("ENABLE");
mySwitch.setPayloadOff("DISABLE");
mySwitch.setStateOn("running");
mySwitch.setStateOff("stopped");
mySwitch.setValueTemplate("{{ value_json.state }}");
mySwitch.setCommandTemplate("{{ value_json.command }}");
myNumber.setPayloadReset("RESET");
myNumber.setCommandTemplate("{{ value | float | round(1) }}");
mySelect.setCommandTemplate("{{ value_json.choice }}");
myText.setCommandTemplate("{{ value_json.text }}");
myButton.setPayloadPress("PRESS");
}
```
## Compiler macros
Defined in `ArduinoHADefines.h` or via build flags.
- **`ARDUINOHA_DISABLE_STDFUNCTION`** — disables the default capturing-lambda and
`std::bind` overloads on entity command APIs. Use it on targets without a complete
`std::function` implementation or where code size/RAM matters (constrained AVR
builds are the usual case). ESP8266/ESP32 support the overloads. `HAMqtt`
lifecycle callbacks remain ordinary function pointers.
- **`ARDUINOHA_DEBUG`** — enables ArduinoHA logging by default and sets the initial maximum verbosity to `Debug`. Without this flag, structured logs are compiled in but remain disabled until you call `arduinoHASetLogEnabled(true)`.
Structured logging is available through a long-lived sink:
```cpp
class MyLogSink : public ArduinoHALogSink {
public:
void log(const ArduinoHALogMessage& msg) override {
Serial.print("[");
Serial.print(arduinoHALogLevelTag(msg.level));
Serial.print("][aha.");
Serial.print(msg.subsystem);
Serial.print("] ");
Serial.println(msg.text);
}
};
MyLogSink logSink; // The installed sink must outlive ArduinoHA logging.
void setup() {
Serial.begin(115200);
arduinoHASetLogSink(&logSink);
arduinoHASetLogEnabled(true);
arduinoHASetLogLevel(ArduinoHALogLevel::Trace);
}
```
`arduinoHALog(...)` and `arduinoHALogf(...)` support subsystem-tagged messages such as `mqtt`, `discovery`, `availability`, `serializer`, `entity`, and `device`. Install a sink when you want those messages to join your application’s normal serial or structured log stream.
Applications that use Wi-Fi can register **`arduinoHASetNetworkStatusFn`** with a callback returning `WiFi.status()`. Publish failure diagnostics can then include the current Wi-Fi status without coupling ArduinoHA to a particular network library.
**Exclude unused device types** (saves flash from vtables), e.g.:
`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`