finished HASwitch

This commit is contained in:
Dawid Chyrzynski
2020-12-03 19:16:02 +01:00
parent f142eb41e8
commit c09c2ab25f
6 changed files with 329 additions and 25 deletions
+1
View File
@@ -1,3 +1,4 @@
#include "HADevice.h"
#include "HAMqtt.h"
#include "device-types/HASwitch.h"
#include "device-types/HATriggers.h"
+8
View File
@@ -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
+254
View File
@@ -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
+35
View File
@@ -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
+29 -25
View File
@@ -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
+2
View File
@@ -36,6 +36,8 @@ protected:
) const;
private:
void publishConfig();
uint16_t calculateSerializedLength(
const HATrigger* trigger,
const char* serializedDevice