mirror of
https://github.com/mrcory/arduino-home-assistant.git
synced 2026-08-02 15:24:26 -04:00
finished HASwitch
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#include "HADevice.h"
|
||||
#include "HAMqtt.h"
|
||||
#include "device-types/HASwitch.h"
|
||||
#include "device-types/HATriggers.h"
|
||||
|
||||
@@ -2,3 +2,11 @@
|
||||
// Please note that you need to initialize serial interface manually
|
||||
// by calling Serial.begin([baudRate]) before initializing ArduinoHA.
|
||||
#define ARDUINOHA_DEBUG
|
||||
|
||||
// You can easily reduce amount of required resources by removing unused components from the library.
|
||||
// Here is the list of available defines:
|
||||
|
||||
// #define NO_HA_TRIGGERS
|
||||
// #define NO_HA_SWITCH
|
||||
|
||||
// In order to get them working just put proper #define before including the ArduinoHA.h header
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
#ifndef NO_HA_SWITCH
|
||||
|
||||
#include "HASwitch.h"
|
||||
#include "../ArduinoHADefines.h"
|
||||
#include "../HAMqtt.h"
|
||||
#include "../HADevice.h"
|
||||
|
||||
// todo: move all variables to progmem
|
||||
static const char* HAComponentName = "switch";
|
||||
static const char* CommandTopic = "cmd";
|
||||
static const char* StateTopic = "state";
|
||||
static const char* StateOn = "ON";
|
||||
static const char* StateOff = "OFF";
|
||||
|
||||
HASwitch::HASwitch(const char* name, HAMqtt& mqtt) :
|
||||
BaseDeviceType(mqtt),
|
||||
_name(name),
|
||||
_stateCallback(nullptr),
|
||||
_currentState(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HASwitch::~HASwitch()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HASwitch::onMqttConnected()
|
||||
{
|
||||
publishConfig();
|
||||
}
|
||||
|
||||
void HASwitch::setState(bool state)
|
||||
{
|
||||
if (state) {
|
||||
turnOn();
|
||||
} else {
|
||||
turnOff();
|
||||
}
|
||||
}
|
||||
|
||||
void HASwitch::turnOn()
|
||||
{
|
||||
_currentState = true;
|
||||
triggerCallback(_currentState);
|
||||
publishCurrentState();
|
||||
}
|
||||
|
||||
void HASwitch::turnOff()
|
||||
{
|
||||
_currentState = false;
|
||||
triggerCallback(_currentState);
|
||||
publishCurrentState();
|
||||
}
|
||||
|
||||
void HASwitch::onStateChanged(HASWITCH_CALLBACK)
|
||||
{
|
||||
if (_stateCallback != nullptr) {
|
||||
return; // only one callback may be assigned to the switch
|
||||
}
|
||||
|
||||
_stateCallback = callback;
|
||||
}
|
||||
|
||||
void HASwitch::triggerCallback(bool state)
|
||||
{
|
||||
if (_stateCallback == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
_stateCallback(state, this);
|
||||
}
|
||||
|
||||
void HASwitch::publishConfig()
|
||||
{
|
||||
if (strlen(_name) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const HADevice* device = mqtt()->getDevice();
|
||||
uint16_t deviceLength = (device == nullptr ? 0 : device->calculateSerializedLength());
|
||||
char serializedDevice[deviceLength];
|
||||
|
||||
if (device != nullptr) {
|
||||
device->serialize(serializedDevice);
|
||||
}
|
||||
|
||||
const uint16_t& topicLength = calculateTopicLength(HAComponentName, _name, ConfigTopic);
|
||||
const uint16_t& dataLength = calculateSerializedLength(serializedDevice);
|
||||
|
||||
char topic[topicLength];
|
||||
generateTopic(topic, HAComponentName, _name, ConfigTopic);
|
||||
|
||||
if (mqtt()->beginPublish(topic, dataLength, true)) {
|
||||
writeSerializedTrigger(serializedDevice);
|
||||
mqtt()->endPublish();
|
||||
}
|
||||
}
|
||||
|
||||
void HASwitch::publishCurrentState()
|
||||
{
|
||||
if (strlen(_name) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16_t& topicSize = calculateTopicLength(
|
||||
HAComponentName,
|
||||
_name,
|
||||
StateTopic
|
||||
);
|
||||
char topic[topicSize];
|
||||
generateTopic(
|
||||
topic,
|
||||
HAComponentName,
|
||||
_name,
|
||||
StateTopic
|
||||
);
|
||||
|
||||
mqtt()->publish(topic, (_currentState ? StateOn : StateOff));
|
||||
}
|
||||
|
||||
uint16_t HASwitch::calculateSerializedLength(const char* serializedDevice) const
|
||||
{
|
||||
const uint16_t& cmdTopicLength = calculateTopicLength(
|
||||
HAComponentName,
|
||||
_name,
|
||||
CommandTopic,
|
||||
false
|
||||
);
|
||||
const uint16_t& stateTopicLength = calculateTopicLength(
|
||||
HAComponentName,
|
||||
_name,
|
||||
StateTopic,
|
||||
false
|
||||
);
|
||||
|
||||
uint16_t size =
|
||||
2 + // opening and closing bracket (without null terminator)
|
||||
cmdTopicLength + 10 +
|
||||
stateTopicLength + 12 +
|
||||
strlen(_name) + 10;
|
||||
|
||||
// unique ID
|
||||
if (serializedDevice == nullptr) {
|
||||
size += strlen(_name) + 13;
|
||||
} else {
|
||||
size += strlen(mqtt()->getDevice()->getUniqueId()) + strlen(_name) + 14;
|
||||
|
||||
// device
|
||||
size += strlen(serializedDevice) + 7;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool HASwitch::writeSerializedTrigger(const char* serializedDevice) const
|
||||
{
|
||||
static const char QuotationSign[] PROGMEM = {"\""};
|
||||
|
||||
// command topic
|
||||
{
|
||||
const uint16_t& topicSize = calculateTopicLength(
|
||||
HAComponentName,
|
||||
_name,
|
||||
CommandTopic
|
||||
);
|
||||
char cmdTopic[topicSize];
|
||||
generateTopic(
|
||||
cmdTopic,
|
||||
HAComponentName,
|
||||
_name,
|
||||
CommandTopic
|
||||
);
|
||||
|
||||
static const char DataBefore[] PROGMEM = {"{\"cmd_t\":\""};
|
||||
|
||||
mqtt()->writePayload_P(DataBefore);
|
||||
mqtt()->writePayload(cmdTopic, strlen(cmdTopic));
|
||||
mqtt()->writePayload_P(QuotationSign);
|
||||
}
|
||||
|
||||
// state topic
|
||||
{
|
||||
const uint16_t& topicSize = calculateTopicLength(
|
||||
HAComponentName,
|
||||
_name,
|
||||
StateTopic
|
||||
);
|
||||
char stateTopic[topicSize];
|
||||
generateTopic(
|
||||
stateTopic,
|
||||
HAComponentName,
|
||||
_name,
|
||||
StateTopic
|
||||
);
|
||||
|
||||
static const char DataBefore[] PROGMEM = {",\"stat_t\":\""};
|
||||
|
||||
mqtt()->writePayload_P(DataBefore);
|
||||
mqtt()->writePayload(stateTopic, strlen(stateTopic));
|
||||
mqtt()->writePayload_P(QuotationSign);
|
||||
}
|
||||
|
||||
// name
|
||||
{
|
||||
static const char DataBefore[] PROGMEM = {",\"name\":\""};
|
||||
|
||||
mqtt()->writePayload_P(DataBefore);
|
||||
mqtt()->writePayload(_name, strlen(_name));
|
||||
mqtt()->writePayload_P(QuotationSign);
|
||||
}
|
||||
|
||||
// unique ID
|
||||
{
|
||||
static const char DataBefore[] PROGMEM = {",\"uniq_id\":\""};
|
||||
const HADevice* device = mqtt()->getDevice();
|
||||
|
||||
mqtt()->writePayload_P(DataBefore);
|
||||
|
||||
if (device == nullptr) {
|
||||
mqtt()->writePayload(_name, strlen(_name));
|
||||
} else {
|
||||
static const char Underscore[] PROGMEM = {"_"};
|
||||
|
||||
uint8_t uniqueIdLength = strlen(_name) + strlen(device->getUniqueId()) + 2; // underscore and null temrinator
|
||||
char uniqueId[uniqueIdLength];
|
||||
strcpy(uniqueId, _name);
|
||||
strcat_P(uniqueId, Underscore);
|
||||
strcat(uniqueId, device->getUniqueId());
|
||||
|
||||
mqtt()->writePayload(uniqueId, strlen(uniqueId));
|
||||
}
|
||||
|
||||
mqtt()->writePayload_P(QuotationSign);
|
||||
}
|
||||
|
||||
// device
|
||||
if (serializedDevice != nullptr) {
|
||||
static const char Data[] PROGMEM = {",\"dev\":"};
|
||||
|
||||
mqtt()->writePayload_P(Data);
|
||||
mqtt()->writePayload(serializedDevice, strlen(serializedDevice));
|
||||
}
|
||||
|
||||
{
|
||||
static const char Data[] PROGMEM = {"}"};
|
||||
mqtt()->writePayload_P(Data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef HASWITCH_H
|
||||
#ifndef NO_HA_SWITCH
|
||||
#define HASWITCH_H
|
||||
|
||||
#include "BaseDeviceType.h"
|
||||
|
||||
#define HASWITCH_CALLBACK void (*callback)(bool, HASwitch*)
|
||||
|
||||
class HASwitch : public BaseDeviceType
|
||||
{
|
||||
public:
|
||||
HASwitch(const char* name, HAMqtt& mqtt);
|
||||
virtual ~HASwitch();
|
||||
|
||||
virtual void onMqttConnected() override;
|
||||
|
||||
void setState(bool state);
|
||||
void turnOn();
|
||||
void turnOff();
|
||||
void onStateChanged(HASWITCH_CALLBACK);
|
||||
|
||||
private:
|
||||
void triggerCallback(bool state);
|
||||
void publishConfig();
|
||||
void publishCurrentState();
|
||||
uint16_t calculateSerializedLength(const char* serializedDevice) const;
|
||||
bool writeSerializedTrigger(const char* serializedDevice) const;
|
||||
|
||||
const char* _name;
|
||||
void (*_stateCallback)(bool, HASwitch*);
|
||||
bool _currentState;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,6 +1,5 @@
|
||||
#ifndef NO_HA_TRIGGERS
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "HATriggers.h"
|
||||
#include "../ArduinoHADefines.h"
|
||||
#include "../HAMqtt.h"
|
||||
@@ -29,29 +28,7 @@ HATriggers::~HATriggers()
|
||||
|
||||
void HATriggers::onMqttConnected()
|
||||
{
|
||||
const HADevice* device = mqtt()->getDevice();
|
||||
if (device == nullptr) {
|
||||
return; // device is required for triggers
|
||||
}
|
||||
|
||||
uint16_t deviceLength = device->calculateSerializedLength();
|
||||
char serializedDevice[deviceLength];
|
||||
device->serialize(serializedDevice);
|
||||
|
||||
for (uint8_t i = 0; i < _triggersNb; i++) {
|
||||
const HATrigger* trigger = &_triggers[i];
|
||||
const uint16_t& topicLength = calculateTopicLength(HAComponentName, trigger, ConfigTopic);
|
||||
const uint16_t& dataLength = calculateSerializedLength(trigger, serializedDevice);
|
||||
|
||||
char topic[topicLength];
|
||||
char data[dataLength];
|
||||
generateTopic(topic, HAComponentName, trigger, ConfigTopic);
|
||||
|
||||
if (mqtt()->beginPublish(topic, dataLength, true)) {
|
||||
writeSerializedTrigger(trigger, serializedDevice);
|
||||
mqtt()->endPublish();
|
||||
}
|
||||
}
|
||||
publishConfig();
|
||||
}
|
||||
|
||||
bool HATriggers::add(const char* type, const char* subtype)
|
||||
@@ -103,6 +80,32 @@ bool HATriggers::trigger(const char* type, const char* subtype)
|
||||
mqtt()->publish(topic, "");
|
||||
}
|
||||
|
||||
void HATriggers::publishConfig()
|
||||
{
|
||||
const HADevice* device = mqtt()->getDevice();
|
||||
if (device == nullptr) {
|
||||
return; // device is required for triggers
|
||||
}
|
||||
|
||||
uint16_t deviceLength = device->calculateSerializedLength();
|
||||
char serializedDevice[deviceLength];
|
||||
device->serialize(serializedDevice);
|
||||
|
||||
for (uint8_t i = 0; i < _triggersNb; i++) {
|
||||
const HATrigger* trigger = &_triggers[i];
|
||||
const uint16_t& topicLength = calculateTopicLength(HAComponentName, trigger, ConfigTopic);
|
||||
const uint16_t& dataLength = calculateSerializedLength(trigger, serializedDevice);
|
||||
|
||||
char topic[topicLength];
|
||||
generateTopic(topic, HAComponentName, trigger, ConfigTopic);
|
||||
|
||||
if (mqtt()->beginPublish(topic, dataLength, true)) {
|
||||
writeSerializedTrigger(trigger, serializedDevice);
|
||||
mqtt()->endPublish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t HATriggers::calculateTopicLength(
|
||||
const char* component,
|
||||
HATrigger *trigger,
|
||||
@@ -188,7 +191,8 @@ bool HATriggers::writeSerializedTrigger(
|
||||
EventTopic
|
||||
);
|
||||
char eventTopic[topicSize];
|
||||
generateTopic(eventTopic,
|
||||
generateTopic(
|
||||
eventTopic,
|
||||
HAComponentName,
|
||||
trigger,
|
||||
EventTopic
|
||||
|
||||
@@ -36,6 +36,8 @@ protected:
|
||||
) const;
|
||||
|
||||
private:
|
||||
void publishConfig();
|
||||
|
||||
uint16_t calculateSerializedLength(
|
||||
const HATrigger* trigger,
|
||||
const char* serializedDevice
|
||||
|
||||
Reference in New Issue
Block a user