release
This commit is contained in:
195
lib/home-assistant-integration/src/utils/HADictionary.cpp
Normal file
195
lib/home-assistant-integration/src/utils/HADictionary.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
#include <Arduino.h>
|
||||
#include "HADictionary.h"
|
||||
|
||||
// components
|
||||
const char HAComponentBinarySensor[] PROGMEM = {"binary_sensor"};
|
||||
const char HAComponentButton[] PROGMEM = {"button"};
|
||||
const char HAComponentCamera[] PROGMEM = {"camera"};
|
||||
const char HAComponentCover[] PROGMEM = {"cover"};
|
||||
const char HAComponentDeviceTracker[] PROGMEM = {"device_tracker"};
|
||||
const char HAComponentDeviceAutomation[] PROGMEM = {"device_automation"};
|
||||
const char HAComponentLock[] PROGMEM = {"lock"};
|
||||
const char HAComponentNumber[] PROGMEM = {"number"};
|
||||
const char HAComponentSelect[] PROGMEM = {"select"};
|
||||
const char HAComponentSensor[] PROGMEM = {"sensor"};
|
||||
const char HAComponentSwitch[] PROGMEM = {"switch"};
|
||||
const char HAComponentTag[] PROGMEM = {"tag"};
|
||||
const char HAComponentScene[] PROGMEM = {"scene"};
|
||||
const char HAComponentFan[] PROGMEM = {"fan"};
|
||||
const char HAComponentLight[] PROGMEM = {"light"};
|
||||
const char HAComponentClimate[] PROGMEM = {"climate"};
|
||||
|
||||
// decorators
|
||||
const char HASerializerSlash[] PROGMEM = {"/"};
|
||||
const char HASerializerJsonDataPrefix[] PROGMEM = {"{"};
|
||||
const char HASerializerJsonDataSuffix[] PROGMEM = {"}"};
|
||||
const char HASerializerJsonPropertyPrefix[] PROGMEM = {"\""};
|
||||
const char HASerializerJsonPropertySuffix[] PROGMEM = {"\":"};
|
||||
const char HASerializerJsonEscapeChar[] PROGMEM = {"\""};
|
||||
const char HASerializerJsonPropertiesSeparator[] PROGMEM = {","};
|
||||
const char HASerializerJsonArrayPrefix[] PROGMEM = {"["};
|
||||
const char HASerializerJsonArraySuffix[] PROGMEM = {"]"};
|
||||
const char HASerializerUnderscore[] PROGMEM = {"_"};
|
||||
|
||||
// properties
|
||||
const char HADeviceIdentifiersProperty[] PROGMEM = {"ids"};
|
||||
const char HADeviceManufacturerProperty[] PROGMEM = {"mf"};
|
||||
const char HADeviceModelProperty[] PROGMEM = {"mdl"};
|
||||
const char HADeviceSoftwareVersionProperty[] PROGMEM = {"sw"};
|
||||
const char HANameProperty[] PROGMEM = {"name"};
|
||||
const char HAUniqueIdProperty[] PROGMEM = {"uniq_id"};
|
||||
const char HADeviceProperty[] PROGMEM = {"dev"};
|
||||
const char HADeviceClassProperty[] PROGMEM = {"dev_cla"};
|
||||
const char HAIconProperty[] PROGMEM = {"ic"};
|
||||
const char HARetainProperty[] PROGMEM = {"ret"};
|
||||
const char HASourceTypeProperty[] PROGMEM = {"src_type"};
|
||||
const char HAEncodingProperty[] PROGMEM = {"e"};
|
||||
const char HAOptimisticProperty[] PROGMEM = {"opt"};
|
||||
const char HAAutomationTypeProperty[] PROGMEM = {"atype"};
|
||||
const char HATypeProperty[] PROGMEM = {"type"};
|
||||
const char HASubtypeProperty[] PROGMEM = {"stype"};
|
||||
const char HAForceUpdateProperty[] PROGMEM = {"frc_upd"};
|
||||
const char HAUnitOfMeasurementProperty[] PROGMEM = {"unit_of_meas"};
|
||||
const char HAValueTemplateProperty[] PROGMEM = {"val_tpl"};
|
||||
const char HAOptionsProperty[] PROGMEM = {"options"};
|
||||
const char HAMinProperty[] PROGMEM = {"min"};
|
||||
const char HAMaxProperty[] PROGMEM = {"max"};
|
||||
const char HAStepProperty[] PROGMEM = {"step"};
|
||||
const char HAModeProperty[] PROGMEM = {"mode"};
|
||||
const char HACommandTemplateProperty[] PROGMEM = {"cmd_tpl"};
|
||||
const char HASpeedRangeMaxProperty[] PROGMEM = {"spd_rng_max"};
|
||||
const char HASpeedRangeMinProperty[] PROGMEM = {"spd_rng_min"};
|
||||
const char HABrightnessScaleProperty[] PROGMEM = {"bri_scl"};
|
||||
const char HAMinMiredsProperty[] PROGMEM = {"min_mirs"};
|
||||
const char HAMaxMiredsProperty[] PROGMEM = {"max_mirs"};
|
||||
const char HATemperatureUnitProperty[] PROGMEM = {"temp_unit"};
|
||||
const char HAMinTempProperty[] PROGMEM = {"min_temp"};
|
||||
const char HAMaxTempProperty[] PROGMEM = {"max_temp"};
|
||||
const char HATempStepProperty[] PROGMEM = {"temp_step"};
|
||||
const char HAFanModesProperty[] PROGMEM = {"fan_modes"};
|
||||
const char HASwingModesProperty[] PROGMEM = {"swing_modes"};
|
||||
const char HAModesProperty[] PROGMEM = {"modes"};
|
||||
const char HATemperatureCommandTemplateProperty[] PROGMEM = {"temp_cmd_tpl"};
|
||||
const char HAPayloadOnProperty[] PROGMEM = {"pl_on"};
|
||||
|
||||
// topics
|
||||
const char HAConfigTopic[] PROGMEM = {"config"};
|
||||
const char HAAvailabilityTopic[] PROGMEM = {"avty_t"};
|
||||
const char HATopic[] PROGMEM = {"t"};
|
||||
const char HAStateTopic[] PROGMEM = {"stat_t"};
|
||||
const char HACommandTopic[] PROGMEM = {"cmd_t"};
|
||||
const char HAPositionTopic[] PROGMEM = {"pos_t"};
|
||||
const char HAPercentageStateTopic[] PROGMEM = {"pct_stat_t"};
|
||||
const char HAPercentageCommandTopic[] PROGMEM = {"pct_cmd_t"};
|
||||
const char HABrightnessCommandTopic[] PROGMEM = {"bri_cmd_t"};
|
||||
const char HABrightnessStateTopic[] PROGMEM = {"bri_stat_t"};
|
||||
const char HAColorTemperatureCommandTopic[] PROGMEM = {"clr_temp_cmd_t"};
|
||||
const char HAColorTemperatureStateTopic[] PROGMEM = {"clr_temp_stat_t"};
|
||||
const char HACurrentTemperatureTopic[] PROGMEM = {"curr_temp_t"};
|
||||
const char HAActionTopic[] PROGMEM = {"act_t"};
|
||||
const char HAAuxCommandTopic[] PROGMEM = {"aux_cmd_t"};
|
||||
const char HAAuxStateTopic[] PROGMEM = {"aux_stat_t"};
|
||||
const char HAPowerCommandTopic[] PROGMEM = {"pow_cmd_t"};
|
||||
const char HAFanModeCommandTopic[] PROGMEM = {"fan_mode_cmd_t"};
|
||||
const char HAFanModeStateTopic[] PROGMEM = {"fan_mode_stat_t"};
|
||||
const char HASwingModeCommandTopic[] PROGMEM = {"swing_mode_cmd_t"};
|
||||
const char HASwingModeStateTopic[] PROGMEM = {"swing_mode_stat_t"};
|
||||
const char HAModeCommandTopic[] PROGMEM = {"mode_cmd_t"};
|
||||
const char HAModeStateTopic[] PROGMEM = {"mode_stat_t"};
|
||||
const char HATemperatureCommandTopic[] PROGMEM = {"temp_cmd_t"};
|
||||
const char HATemperatureStateTopic[] PROGMEM = {"temp_stat_t"};
|
||||
const char HARGBCommandTopic[] PROGMEM = {"rgb_cmd_t"};
|
||||
const char HARGBStateTopic[] PROGMEM = {"rgb_stat_t"};
|
||||
|
||||
// misc
|
||||
const char HAOnline[] PROGMEM = {"online"};
|
||||
const char HAOffline[] PROGMEM = {"offline"};
|
||||
const char HAStateOn[] PROGMEM = {"ON"};
|
||||
const char HAStateOff[] PROGMEM = {"OFF"};
|
||||
const char HAStateLocked[] PROGMEM = {"LOCKED"};
|
||||
const char HAStateUnlocked[] PROGMEM = {"UNLOCKED"};
|
||||
const char HAStateNone[] PROGMEM = {"None"};
|
||||
const char HATrue[] PROGMEM = {"true"};
|
||||
const char HAFalse[] PROGMEM = {"false"};
|
||||
const char HAHome[] PROGMEM = {"home"};
|
||||
const char HANotHome[] PROGMEM = {"not_home"};
|
||||
const char HATrigger[] PROGMEM = {"trigger"};
|
||||
const char HAModeBox[] PROGMEM = {"box"};
|
||||
const char HAModeSlider[] PROGMEM = {"slider"};
|
||||
|
||||
// covers
|
||||
const char HAClosedState[] PROGMEM = {"closed"};
|
||||
const char HAClosingState[] PROGMEM = {"closing"};
|
||||
const char HAOpenState[] PROGMEM = {"open"};
|
||||
const char HAOpeningState[] PROGMEM = {"opening"};
|
||||
const char HAStoppedState[] PROGMEM = {"stopped"};
|
||||
|
||||
// commands
|
||||
const char HAOpenCommand[] PROGMEM = {"OPEN"};
|
||||
const char HACloseCommand[] PROGMEM = {"CLOSE"};
|
||||
const char HAStopCommand[] PROGMEM = {"STOP"};
|
||||
const char HALockCommand[] PROGMEM = {"LOCK"};
|
||||
const char HAUnlockCommand[] PROGMEM = {"UNLOCK"};
|
||||
|
||||
// device tracker
|
||||
const char HAGPSType[] PROGMEM = {"gps"};
|
||||
const char HARouterType[] PROGMEM = {"router"};
|
||||
const char HABluetoothType[] PROGMEM = {"bluetooth"};
|
||||
const char HABluetoothLEType[] PROGMEM = {"bluetooth_le"};
|
||||
|
||||
// camera
|
||||
const char HAEncodingBase64[] PROGMEM = {"b64"};
|
||||
|
||||
// trigger
|
||||
const char HAButtonShortPressType[] PROGMEM = {"button_short_press"};
|
||||
const char HAButtonShortReleaseType[] PROGMEM = {"button_short_release"};
|
||||
const char HAButtonLongPressType[] PROGMEM = {"button_long_press"};
|
||||
const char HAButtonLongReleaseType[] PROGMEM = {"button_long_release"};
|
||||
const char HAButtonDoublePressType[] PROGMEM = {"button_double_press"};
|
||||
const char HAButtonTriplePressType[] PROGMEM = {"button_triple_press"};
|
||||
const char HAButtonQuadruplePressType[] PROGMEM = {"button_quadruple_press"};
|
||||
const char HAButtonQuintuplePressType[] PROGMEM = {"button_quintuple_press"};
|
||||
const char HATurnOnSubtype[] PROGMEM = {"turn_on"};
|
||||
const char HATurnOffSubtype[] PROGMEM = {"turn_off"};
|
||||
const char HAButton1Subtype[] PROGMEM = {"button_1"};
|
||||
const char HAButton2Subtype[] PROGMEM = {"button_2"};
|
||||
const char HAButton3Subtype[] PROGMEM = {"button_3"};
|
||||
const char HAButton4Subtype[] PROGMEM = {"button_4"};
|
||||
const char HAButton5Subtype[] PROGMEM = {"button_5"};
|
||||
const char HAButton6Subtype[] PROGMEM = {"button_6"};
|
||||
|
||||
// actions
|
||||
const char HAActionOff[] PROGMEM = {"off"};
|
||||
const char HAActionHeating[] PROGMEM = {"heating"};
|
||||
const char HAActionCooling[] PROGMEM = {"cooling"};
|
||||
const char HAActionDrying[] PROGMEM = {"drying"};
|
||||
const char HAActionIdle[] PROGMEM = {"idle"};
|
||||
const char HAActionFan[] PROGMEM = {"fan"};
|
||||
|
||||
// fan modes
|
||||
const char HAFanModeAuto[] PROGMEM = {"auto"};
|
||||
const char HAFanModeLow[] PROGMEM = {"low"};
|
||||
const char HAFanModeMedium[] PROGMEM = {"medium"};
|
||||
const char HAFanModeHigh[] PROGMEM = {"high"};
|
||||
|
||||
// swing modes
|
||||
const char HASwingModeOn[] PROGMEM = {"on"};
|
||||
const char HASwingModeOff[] PROGMEM = {"off"};
|
||||
|
||||
// HVAC modes
|
||||
const char HAModeAuto[] PROGMEM = {"auto"};
|
||||
const char HAModeOff[] PROGMEM = {"off"};
|
||||
const char HAModeCool[] PROGMEM = {"cool"};
|
||||
const char HAModeHeat[] PROGMEM = {"heat"};
|
||||
const char HAModeDry[] PROGMEM = {"dry"};
|
||||
const char HAModeFanOnly[] PROGMEM = {"fan_only"};
|
||||
|
||||
// other
|
||||
const char HAHexMap[] PROGMEM = {"0123456789abcdef"};
|
||||
|
||||
// value templates
|
||||
const char HAValueTemplateFloatP1[] PROGMEM = {"{{int(float(value)*10**1)}}"};
|
||||
const char HAValueTemplateFloatP2[] PROGMEM = {"{{int(float(value)*10**2)}}"};
|
||||
const char HAValueTemplateFloatP3[] PROGMEM = {"{{int(float(value)*10**3)}}"};
|
||||
const char HATemperatureUnitC[] PROGMEM = {"C"};
|
||||
const char HATemperatureUnitF[] PROGMEM = {"F"};
|
||||
197
lib/home-assistant-integration/src/utils/HADictionary.h
Normal file
197
lib/home-assistant-integration/src/utils/HADictionary.h
Normal file
@@ -0,0 +1,197 @@
|
||||
#ifndef AHA_HADICTIONARY_H
|
||||
#define AHA_HADICTIONARY_H
|
||||
|
||||
// components
|
||||
extern const char HAComponentBinarySensor[];
|
||||
extern const char HAComponentButton[];
|
||||
extern const char HAComponentCamera[];
|
||||
extern const char HAComponentCover[];
|
||||
extern const char HAComponentDeviceTracker[];
|
||||
extern const char HAComponentDeviceAutomation[];
|
||||
extern const char HAComponentLock[];
|
||||
extern const char HAComponentNumber[];
|
||||
extern const char HAComponentSelect[];
|
||||
extern const char HAComponentSensor[];
|
||||
extern const char HAComponentSwitch[];
|
||||
extern const char HAComponentTag[];
|
||||
extern const char HAComponentScene[];
|
||||
extern const char HAComponentFan[];
|
||||
extern const char HAComponentLight[];
|
||||
extern const char HAComponentClimate[];
|
||||
|
||||
// decorators
|
||||
extern const char HASerializerSlash[];
|
||||
extern const char HASerializerJsonDataPrefix[];
|
||||
extern const char HASerializerJsonDataSuffix[];
|
||||
extern const char HASerializerJsonPropertyPrefix[];
|
||||
extern const char HASerializerJsonPropertySuffix[];
|
||||
extern const char HASerializerJsonEscapeChar[];
|
||||
extern const char HASerializerJsonPropertiesSeparator[];
|
||||
extern const char HASerializerJsonArrayPrefix[];
|
||||
extern const char HASerializerJsonArraySuffix[];
|
||||
extern const char HASerializerUnderscore[];
|
||||
|
||||
// properties
|
||||
extern const char HADeviceIdentifiersProperty[];
|
||||
extern const char HADeviceManufacturerProperty[];
|
||||
extern const char HADeviceModelProperty[];
|
||||
extern const char HADeviceSoftwareVersionProperty[];
|
||||
extern const char HANameProperty[];
|
||||
extern const char HAUniqueIdProperty[];
|
||||
extern const char HADeviceProperty[];
|
||||
extern const char HADeviceClassProperty[];
|
||||
extern const char HAIconProperty[];
|
||||
extern const char HARetainProperty[];
|
||||
extern const char HASourceTypeProperty[];
|
||||
extern const char HAEncodingProperty[];
|
||||
extern const char HAOptimisticProperty[];
|
||||
extern const char HAAutomationTypeProperty[];
|
||||
extern const char HATypeProperty[];
|
||||
extern const char HASubtypeProperty[];
|
||||
extern const char HAForceUpdateProperty[];
|
||||
extern const char HAUnitOfMeasurementProperty[];
|
||||
extern const char HAValueTemplateProperty[];
|
||||
extern const char HAOptionsProperty[];
|
||||
extern const char HAMinProperty[];
|
||||
extern const char HAMaxProperty[];
|
||||
extern const char HAStepProperty[];
|
||||
extern const char HAModeProperty[];
|
||||
extern const char HACommandTemplateProperty[];
|
||||
extern const char HASpeedRangeMaxProperty[];
|
||||
extern const char HASpeedRangeMinProperty[];
|
||||
extern const char HABrightnessScaleProperty[];
|
||||
extern const char HAMinMiredsProperty[];
|
||||
extern const char HAMaxMiredsProperty[];
|
||||
extern const char HATemperatureUnitProperty[];
|
||||
extern const char HAMinTempProperty[];
|
||||
extern const char HAMaxTempProperty[];
|
||||
extern const char HATempStepProperty[];
|
||||
extern const char HAFanModesProperty[];
|
||||
extern const char HASwingModesProperty[];
|
||||
extern const char HAModesProperty[];
|
||||
extern const char HATemperatureCommandTemplateProperty[];
|
||||
extern const char HAPayloadOnProperty[];
|
||||
|
||||
// topics
|
||||
extern const char HAConfigTopic[];
|
||||
extern const char HAAvailabilityTopic[];
|
||||
extern const char HATopic[];
|
||||
extern const char HAStateTopic[];
|
||||
extern const char HACommandTopic[];
|
||||
extern const char HAPositionTopic[];
|
||||
extern const char HAPercentageStateTopic[];
|
||||
extern const char HAPercentageCommandTopic[];
|
||||
extern const char HABrightnessCommandTopic[];
|
||||
extern const char HABrightnessStateTopic[];
|
||||
extern const char HAColorTemperatureCommandTopic[];
|
||||
extern const char HAColorTemperatureStateTopic[];
|
||||
extern const char HACurrentTemperatureTopic[];
|
||||
extern const char HAActionTopic[];
|
||||
extern const char HAAuxCommandTopic[];
|
||||
extern const char HAAuxStateTopic[];
|
||||
extern const char HAPowerCommandTopic[];
|
||||
extern const char HAFanModeCommandTopic[];
|
||||
extern const char HAFanModeStateTopic[];
|
||||
extern const char HASwingModeCommandTopic[];
|
||||
extern const char HASwingModeStateTopic[];
|
||||
extern const char HAModeCommandTopic[];
|
||||
extern const char HAModeStateTopic[];
|
||||
extern const char HATemperatureCommandTopic[];
|
||||
extern const char HATemperatureStateTopic[];
|
||||
extern const char HARGBCommandTopic[];
|
||||
extern const char HARGBStateTopic[];
|
||||
|
||||
// misc
|
||||
extern const char HAOnline[];
|
||||
extern const char HAOffline[];
|
||||
extern const char HAStateOn[];
|
||||
extern const char HAStateOff[];
|
||||
extern const char HAStateLocked[];
|
||||
extern const char HAStateUnlocked[];
|
||||
extern const char HAStateNone[];
|
||||
extern const char HATrue[];
|
||||
extern const char HAFalse[];
|
||||
extern const char HAHome[];
|
||||
extern const char HANotHome[];
|
||||
extern const char HATrigger[];
|
||||
extern const char HAModeBox[];
|
||||
extern const char HAModeSlider[];
|
||||
|
||||
// covers
|
||||
extern const char HAClosedState[];
|
||||
extern const char HAClosingState[];
|
||||
extern const char HAOpenState[];
|
||||
extern const char HAOpeningState[];
|
||||
extern const char HAStoppedState[];
|
||||
|
||||
// commands
|
||||
extern const char HAOpenCommand[];
|
||||
extern const char HACloseCommand[];
|
||||
extern const char HAStopCommand[];
|
||||
extern const char HALockCommand[];
|
||||
extern const char HAUnlockCommand[];
|
||||
|
||||
// device tracker
|
||||
extern const char HAGPSType[];
|
||||
extern const char HARouterType[];
|
||||
extern const char HABluetoothType[];
|
||||
extern const char HABluetoothLEType[];
|
||||
|
||||
// camera
|
||||
extern const char HAEncodingBase64[];
|
||||
|
||||
// trigger
|
||||
extern const char HAButtonShortPressType[];
|
||||
extern const char HAButtonShortReleaseType[];
|
||||
extern const char HAButtonLongPressType[];
|
||||
extern const char HAButtonLongReleaseType[];
|
||||
extern const char HAButtonDoublePressType[];
|
||||
extern const char HAButtonTriplePressType[];
|
||||
extern const char HAButtonQuadruplePressType[];
|
||||
extern const char HAButtonQuintuplePressType[];
|
||||
extern const char HATurnOnSubtype[];
|
||||
extern const char HATurnOffSubtype[];
|
||||
extern const char HAButton1Subtype[];
|
||||
extern const char HAButton2Subtype[];
|
||||
extern const char HAButton3Subtype[];
|
||||
extern const char HAButton4Subtype[];
|
||||
extern const char HAButton5Subtype[];
|
||||
extern const char HAButton6Subtype[];
|
||||
|
||||
// actions
|
||||
extern const char HAActionOff[];
|
||||
extern const char HAActionHeating[];
|
||||
extern const char HAActionCooling[];
|
||||
extern const char HAActionDrying[];
|
||||
extern const char HAActionIdle[];
|
||||
extern const char HAActionFan[];
|
||||
|
||||
// fan modes
|
||||
extern const char HAFanModeAuto[];
|
||||
extern const char HAFanModeLow[];
|
||||
extern const char HAFanModeMedium[];
|
||||
extern const char HAFanModeHigh[];
|
||||
|
||||
// swing modes
|
||||
extern const char HASwingModeOn[];
|
||||
extern const char HASwingModeOff[];
|
||||
|
||||
// HVAC modes
|
||||
extern const char HAModeAuto[];
|
||||
extern const char HAModeOff[];
|
||||
extern const char HAModeCool[];
|
||||
extern const char HAModeHeat[];
|
||||
extern const char HAModeDry[];
|
||||
extern const char HAModeFanOnly[];
|
||||
|
||||
// other
|
||||
extern const char HAHexMap[];
|
||||
|
||||
// value templates
|
||||
extern const char HAValueTemplateFloatP1[];
|
||||
extern const char HAValueTemplateFloatP2[];
|
||||
extern const char HAValueTemplateFloatP3[];
|
||||
extern const char HATemperatureUnitC[];
|
||||
extern const char HATemperatureUnitF[];
|
||||
|
||||
#endif
|
||||
214
lib/home-assistant-integration/src/utils/HANumeric.cpp
Normal file
214
lib/home-assistant-integration/src/utils/HANumeric.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
#include "HANumeric.h"
|
||||
|
||||
const uint8_t HANumeric::MaxDigitsNb = 19;
|
||||
|
||||
HANumeric HANumeric::fromStr(const uint8_t* buffer, const uint16_t length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return HANumeric();
|
||||
}
|
||||
|
||||
const uint8_t* firstCh = &buffer[0];
|
||||
int64_t out = 0;
|
||||
bool isSigned = false;
|
||||
|
||||
if (*firstCh == '-') {
|
||||
isSigned = true;
|
||||
firstCh++;
|
||||
}
|
||||
|
||||
uint8_t digitsNb = isSigned ? length - 1 : length;
|
||||
if (digitsNb > MaxDigitsNb) {
|
||||
return HANumeric();
|
||||
}
|
||||
|
||||
uint64_t base = 1;
|
||||
const uint8_t* ptr = &buffer[length - 1];
|
||||
|
||||
while (ptr >= firstCh) {
|
||||
uint8_t digit = *ptr - '0';
|
||||
if (digit > 9) {
|
||||
return HANumeric();
|
||||
}
|
||||
|
||||
out += digit * base;
|
||||
ptr--;
|
||||
base *= 10;
|
||||
}
|
||||
|
||||
return HANumeric(isSigned ? out * -1 : out);
|
||||
}
|
||||
|
||||
HANumeric::HANumeric():
|
||||
_isSet(false),
|
||||
_value(0),
|
||||
_precision(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const float value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * static_cast<float>(getPrecisionBase());
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const int8_t value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * static_cast<int32_t>(getPrecisionBase());
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const int16_t value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * static_cast<int32_t>(getPrecisionBase());
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const int32_t value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * static_cast<int32_t>(getPrecisionBase());
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const uint8_t value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * getPrecisionBase();
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const uint16_t value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * getPrecisionBase();
|
||||
}
|
||||
|
||||
HANumeric::HANumeric(const uint32_t value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * getPrecisionBase();
|
||||
}
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
HANumeric::HANumeric(const int value, const uint8_t precision):
|
||||
_isSet(true),
|
||||
_precision(precision)
|
||||
{
|
||||
_value = value * static_cast<int>(getPrecisionBase());
|
||||
}
|
||||
#endif
|
||||
|
||||
HANumeric::HANumeric(const int64_t value):
|
||||
_isSet(true),
|
||||
_value(value),
|
||||
_precision(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t HANumeric::getPrecisionBase() const
|
||||
{
|
||||
// using pow() increases the flash size by ~2KB
|
||||
switch (_precision) {
|
||||
case 1:
|
||||
return 10;
|
||||
|
||||
case 2:
|
||||
return 100;
|
||||
|
||||
case 3:
|
||||
return 1000;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t HANumeric::calculateSize() const
|
||||
{
|
||||
if (!_isSet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t value = _value;
|
||||
const bool isSigned = value < 0;
|
||||
|
||||
if (isSigned) {
|
||||
value *= -1;
|
||||
}
|
||||
|
||||
uint8_t digitsNb = 1;
|
||||
while (value > 9) {
|
||||
value /= 10;
|
||||
digitsNb++;
|
||||
}
|
||||
|
||||
if (isSigned) {
|
||||
digitsNb++; // sign
|
||||
}
|
||||
|
||||
if (_precision > 0) {
|
||||
if (value == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// one digit + dot + decimal digits (+ sign)
|
||||
const uint8_t minValue = isSigned ? _precision + 3 : _precision + 2;
|
||||
return digitsNb >= minValue ? digitsNb + 1 : minValue;
|
||||
}
|
||||
|
||||
return digitsNb;
|
||||
}
|
||||
|
||||
uint16_t HANumeric::toStr(char* dst) const
|
||||
{
|
||||
char* prefixCh = &dst[0];
|
||||
if (!_isSet || _value == 0) {
|
||||
*prefixCh = '0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
int64_t value = _value;
|
||||
const uint8_t numberLength = calculateSize();
|
||||
if (value < 0) {
|
||||
value *= -1;
|
||||
*prefixCh = '-';
|
||||
prefixCh++;
|
||||
}
|
||||
|
||||
if (_precision > 0) {
|
||||
uint8_t i = _precision;
|
||||
char* dotPtr = prefixCh + 1;
|
||||
do {
|
||||
*prefixCh = '0';
|
||||
prefixCh++;
|
||||
} while(i-- > 0);
|
||||
|
||||
*dotPtr = '.';
|
||||
}
|
||||
|
||||
char* ch = &dst[numberLength - 1];
|
||||
char* lastCh = ch;
|
||||
char* dotPos = _precision > 0 ? &dst[numberLength - 1 - _precision] : nullptr;
|
||||
|
||||
while (value != 0) {
|
||||
if (ch == dotPos) {
|
||||
*dotPos = '.';
|
||||
ch--;
|
||||
continue;
|
||||
}
|
||||
|
||||
*ch = (value % 10) + '0';
|
||||
value /= 10;
|
||||
ch--;
|
||||
}
|
||||
|
||||
return lastCh - &dst[0] + 1;
|
||||
}
|
||||
233
lib/home-assistant-integration/src/utils/HANumeric.h
Normal file
233
lib/home-assistant-integration/src/utils/HANumeric.h
Normal file
@@ -0,0 +1,233 @@
|
||||
|
||||
#ifndef AHA_NUMERIC_H
|
||||
#define AHA_NUMERIC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* This class represents a numeric value that simplifies use of different types of numbers across the library.
|
||||
*/
|
||||
class HANumeric
|
||||
{
|
||||
public:
|
||||
/// The maximum number of digits that the base value can have (int64_t).
|
||||
static const uint8_t MaxDigitsNb;
|
||||
|
||||
/**
|
||||
* Deserializes number from the given buffer.
|
||||
* Please note that the class expected buffer to contain the base number.
|
||||
* For example, deserializing `1234` number and setting precision to `1`
|
||||
* results in representation of `123.4` float.
|
||||
*
|
||||
* @param buffer The buffer that contains the number.
|
||||
* @param length The length of the buffer.
|
||||
*/
|
||||
static HANumeric fromStr(const uint8_t* buffer, const uint16_t length);
|
||||
|
||||
/**
|
||||
* Creates an empty number representation.
|
||||
*/
|
||||
HANumeric();
|
||||
|
||||
/**
|
||||
* Converts the given float into number representation of the given precision.
|
||||
* If the precision is set to zero the given float will be converted into integer.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const float value, const uint8_t precision);
|
||||
|
||||
/**
|
||||
* Converts the given int8_t into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const int8_t value, const uint8_t precision);
|
||||
|
||||
/**
|
||||
* Converts the given int16_t into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const int16_t value, const uint8_t precision);
|
||||
|
||||
/**
|
||||
* Converts the given int32_t into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const int32_t value, const uint8_t precision);
|
||||
|
||||
/**
|
||||
* Converts the given uint8_t into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const uint8_t value, const uint8_t precision);
|
||||
|
||||
/**
|
||||
* Converts the given uint16_t into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const uint16_t value, const uint8_t precision);
|
||||
|
||||
/**
|
||||
* Converts the given uint32_t into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const uint32_t value, const uint8_t precision);
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
/**
|
||||
* Converts the given int into number representation of the given precision.
|
||||
* If the precision is greater than zero the given value will be converted to float.
|
||||
*
|
||||
* @param value The value that should be used as a base.
|
||||
* @param precision The number of digits in the decimal part.
|
||||
*/
|
||||
HANumeric(const int value, const uint8_t precision);
|
||||
#endif
|
||||
|
||||
void operator= (const HANumeric& a) {
|
||||
if (!a.isSet()) {
|
||||
reset();
|
||||
} else {
|
||||
_isSet = a.isSet();
|
||||
_value = a.getBaseValue();
|
||||
_precision = a.getPrecision();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator== (const HANumeric& a) const {
|
||||
return (
|
||||
isSet() == a.isSet() &&
|
||||
getBaseValue() == a.getBaseValue() &&
|
||||
getPrecision() == a.getPrecision()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns multiplier that used to generate base value based on the precision.
|
||||
* The multiplier is generated using the formula: `pow(precision, 10)`.
|
||||
*/
|
||||
uint32_t getPrecisionBase() const;
|
||||
|
||||
/**
|
||||
* Returns size of the number
|
||||
*/
|
||||
uint8_t calculateSize() const;
|
||||
|
||||
/**
|
||||
* Converts the number to the string.
|
||||
*
|
||||
* @param dst Destination where the number will be saved.
|
||||
* The null terminator is not added at the end.
|
||||
* @return The number of written characters.
|
||||
* @note The `dst` size should be calculated using HANumeric::calculateSize() method plus 1 extra byte for the null terminator.
|
||||
*/
|
||||
uint16_t toStr(char* dst) const;
|
||||
|
||||
/**
|
||||
* Returns true if the base value is set.
|
||||
*/
|
||||
inline bool isSet() const
|
||||
{ return _isSet; }
|
||||
|
||||
/**
|
||||
* Sets the base value without converting it to the proper precision.
|
||||
*/
|
||||
inline void setBaseValue(int64_t value)
|
||||
{ _isSet = true; _value = value; }
|
||||
|
||||
/**
|
||||
* Returns the base value of the number.
|
||||
*/
|
||||
inline int64_t getBaseValue() const
|
||||
{ return _value; }
|
||||
|
||||
/**
|
||||
* Sets the precision of the number (number of digits in the decimal part).
|
||||
*
|
||||
* @param precision The precision to use.
|
||||
*/
|
||||
inline void setPrecision(const uint8_t precision)
|
||||
{ _precision = precision; }
|
||||
|
||||
/**
|
||||
* Returns the precision of the number.
|
||||
*/
|
||||
inline uint8_t getPrecision() const
|
||||
{ return _precision; }
|
||||
|
||||
/**
|
||||
* Resets the number to the defaults.
|
||||
*/
|
||||
inline void reset()
|
||||
{ _isSet = false; _value = 0; _precision = 0; }
|
||||
|
||||
inline bool isUInt8() const
|
||||
{ return _isSet && _precision == 0 && _value >= 0 && _value <= UINT8_MAX; }
|
||||
|
||||
inline bool isUInt16() const
|
||||
{ return _isSet && _precision == 0 && _value >= 0 && _value <= UINT16_MAX; }
|
||||
|
||||
inline bool isUInt32() const
|
||||
{ return _isSet && _precision == 0 && _value >= 0 && _value <= UINT32_MAX; }
|
||||
|
||||
inline bool isInt8() const
|
||||
{ return _isSet && _precision == 0 && _value >= INT8_MIN && _value <= INT8_MAX; }
|
||||
|
||||
inline bool isInt16() const
|
||||
{ return _isSet && _precision == 0 && _value >= INT16_MIN && _value <= INT16_MAX; }
|
||||
|
||||
inline bool isInt32() const
|
||||
{ return _isSet && _precision == 0 && _value >= INT32_MIN && _value <= INT32_MAX; }
|
||||
|
||||
inline bool isFloat() const
|
||||
{ return _isSet && _precision > 0; }
|
||||
|
||||
inline uint8_t toUInt8() const
|
||||
{ return static_cast<uint8_t>(_value); }
|
||||
|
||||
inline uint16_t toUInt16() const
|
||||
{ return static_cast<uint16_t>(_value); }
|
||||
|
||||
inline uint32_t toUInt32() const
|
||||
{ return static_cast<uint32_t>(_value); }
|
||||
|
||||
inline int8_t toInt8() const
|
||||
{ return static_cast<int8_t>(_value); }
|
||||
|
||||
inline int16_t toInt16() const
|
||||
{ return static_cast<int16_t>(_value); }
|
||||
|
||||
inline int32_t toInt32() const
|
||||
{ return static_cast<int32_t>(_value); }
|
||||
|
||||
inline float toFloat() const
|
||||
{ return _value / (float)getPrecisionBase(); }
|
||||
|
||||
private:
|
||||
bool _isSet;
|
||||
int64_t _value;
|
||||
uint8_t _precision;
|
||||
|
||||
explicit HANumeric(const int64_t value);
|
||||
};
|
||||
|
||||
#endif
|
||||
526
lib/home-assistant-integration/src/utils/HASerializer.cpp
Normal file
526
lib/home-assistant-integration/src/utils/HASerializer.cpp
Normal file
@@ -0,0 +1,526 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef ARDUINO_ARCH_SAMD
|
||||
#include <avr/dtostrf.h>
|
||||
#endif
|
||||
|
||||
#include "HASerializer.h"
|
||||
#include "../ArduinoHADefines.h"
|
||||
#include "../HADevice.h"
|
||||
#include "../HAMqtt.h"
|
||||
#include "../utils/HAUtils.h"
|
||||
#include "../utils/HANumeric.h"
|
||||
#include "../device-types/HABaseDeviceType.h"
|
||||
|
||||
uint16_t HASerializer::calculateConfigTopicLength(
|
||||
const __FlashStringHelper* componentName,
|
||||
const char* objectId
|
||||
)
|
||||
{
|
||||
const HAMqtt* mqtt = HAMqtt::instance();
|
||||
if (
|
||||
!componentName ||
|
||||
!objectId ||
|
||||
!mqtt ||
|
||||
!mqtt->getDiscoveryPrefix() ||
|
||||
!mqtt->getDevice()
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return
|
||||
strlen(mqtt->getDiscoveryPrefix()) + 1 + // prefix with slash
|
||||
strlen_P(AHAFROMFSTR(componentName)) + 1 + // component name with slash
|
||||
strlen(mqtt->getDevice()->getUniqueId()) + 1 + // device ID with slash
|
||||
strlen(objectId) + 1 + // object ID with slash
|
||||
strlen_P(HAConfigTopic) + 1; // including null terminator
|
||||
}
|
||||
|
||||
bool HASerializer::generateConfigTopic(
|
||||
char* output,
|
||||
const __FlashStringHelper* componentName,
|
||||
const char* objectId
|
||||
)
|
||||
{
|
||||
const HAMqtt* mqtt = HAMqtt::instance();
|
||||
if (
|
||||
!output ||
|
||||
!componentName ||
|
||||
!objectId ||
|
||||
!mqtt ||
|
||||
!mqtt->getDiscoveryPrefix() ||
|
||||
!mqtt->getDevice()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(output, mqtt->getDiscoveryPrefix());
|
||||
strcat_P(output, HASerializerSlash);
|
||||
|
||||
strcat_P(output, AHAFROMFSTR(componentName));
|
||||
strcat_P(output, HASerializerSlash);
|
||||
|
||||
strcat(output, mqtt->getDevice()->getUniqueId());
|
||||
strcat_P(output, HASerializerSlash);
|
||||
|
||||
strcat(output, objectId);
|
||||
strcat_P(output, HASerializerSlash);
|
||||
|
||||
strcat_P(output, HAConfigTopic);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t HASerializer::calculateDataTopicLength(
|
||||
const char* objectId,
|
||||
const __FlashStringHelper* topic
|
||||
)
|
||||
{
|
||||
const HAMqtt* mqtt = HAMqtt::instance();
|
||||
if (
|
||||
!topic ||
|
||||
!mqtt ||
|
||||
!mqtt->getDataPrefix() ||
|
||||
!mqtt->getDevice()
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t size =
|
||||
strlen(mqtt->getDataPrefix()) + 1 + // prefix with slash
|
||||
strlen(mqtt->getDevice()->getUniqueId()) + 1 + // device ID with slash
|
||||
strlen_P(AHAFROMFSTR(topic));
|
||||
|
||||
if (objectId) {
|
||||
size += strlen(objectId) + 1; // object ID with slash;
|
||||
}
|
||||
|
||||
return size + 1; // including null terminator
|
||||
}
|
||||
|
||||
bool HASerializer::generateDataTopic(
|
||||
char* output,
|
||||
const char* objectId,
|
||||
const __FlashStringHelper* topic
|
||||
)
|
||||
{
|
||||
const HAMqtt* mqtt = HAMqtt::instance();
|
||||
if (
|
||||
!output ||
|
||||
!topic ||
|
||||
!mqtt ||
|
||||
!mqtt->getDataPrefix() ||
|
||||
!mqtt->getDevice()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(output, mqtt->getDataPrefix());
|
||||
strcat_P(output, HASerializerSlash);
|
||||
|
||||
strcat(output, mqtt->getDevice()->getUniqueId());
|
||||
strcat_P(output, HASerializerSlash);
|
||||
|
||||
if (objectId) {
|
||||
strcat(output, objectId);
|
||||
strcat_P(output, HASerializerSlash);
|
||||
}
|
||||
|
||||
strcat_P(output, AHAFROMFSTR(topic));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HASerializer::compareDataTopics(
|
||||
const char* actualTopic,
|
||||
const char* objectId,
|
||||
const __FlashStringHelper* topic
|
||||
)
|
||||
{
|
||||
if (!actualTopic) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t topicLength = calculateDataTopicLength(objectId, topic);
|
||||
if (topicLength == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char expectedTopic[topicLength];
|
||||
if (!generateDataTopic(expectedTopic, objectId, topic)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(actualTopic, expectedTopic, topicLength) == 0;
|
||||
}
|
||||
|
||||
HASerializer::HASerializer(
|
||||
HABaseDeviceType* deviceType,
|
||||
const uint8_t maxEntriesNb
|
||||
) :
|
||||
_deviceType(deviceType),
|
||||
_entriesNb(0),
|
||||
_maxEntriesNb(maxEntriesNb),
|
||||
_entries(new SerializerEntry[maxEntriesNb])
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HASerializer::~HASerializer()
|
||||
{
|
||||
delete[] _entries;
|
||||
}
|
||||
|
||||
void HASerializer::set(
|
||||
const __FlashStringHelper* property,
|
||||
const void* value,
|
||||
PropertyValueType valueType
|
||||
)
|
||||
{
|
||||
if (!property || !value) {
|
||||
return;
|
||||
}
|
||||
|
||||
SerializerEntry* entry = addEntry();
|
||||
entry->type = PropertyEntryType;
|
||||
entry->subtype = static_cast<uint8_t>(valueType);
|
||||
entry->property = property;
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
void HASerializer::set(const FlagType flag)
|
||||
{
|
||||
if (flag == WithDevice) {
|
||||
SerializerEntry* entry = addEntry();
|
||||
entry->type = FlagEntryType;
|
||||
entry->subtype = static_cast<uint8_t>(WithDevice);
|
||||
entry->property = nullptr;
|
||||
entry->value = nullptr;
|
||||
} else if (flag == WithAvailability) {
|
||||
HAMqtt* mqtt = HAMqtt::instance();
|
||||
const bool isSharedAvailability = mqtt->getDevice()->isSharedAvailabilityEnabled();
|
||||
const bool isAvailabilityConfigured = _deviceType->isAvailabilityConfigured();
|
||||
|
||||
if (!isSharedAvailability && !isAvailabilityConfigured) {
|
||||
return; // not configured
|
||||
}
|
||||
|
||||
SerializerEntry* entry = addEntry();
|
||||
entry->type = TopicEntryType;
|
||||
entry->property = AHATOFSTR(HAAvailabilityTopic);
|
||||
entry->value = isSharedAvailability
|
||||
? mqtt->getDevice()->getAvailabilityTopic()
|
||||
: nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HASerializer::topic(const __FlashStringHelper* topic)
|
||||
{
|
||||
if (!_deviceType || !topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
SerializerEntry* entry = addEntry();
|
||||
entry->type = TopicEntryType;
|
||||
entry->property = topic;
|
||||
}
|
||||
|
||||
HASerializer::SerializerEntry* HASerializer::addEntry()
|
||||
{
|
||||
return &_entries[_entriesNb++]; // intentional lack of protection against overflow
|
||||
}
|
||||
|
||||
uint16_t HASerializer::calculateSize() const
|
||||
{
|
||||
uint16_t size =
|
||||
strlen_P(HASerializerJsonDataPrefix) +
|
||||
strlen_P(HASerializerJsonDataSuffix);
|
||||
|
||||
for (uint8_t i = 0; i < _entriesNb; i++) {
|
||||
const uint16_t entrySize = calculateEntrySize(&_entries[i]);
|
||||
if (entrySize == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size += entrySize;
|
||||
|
||||
// items separator
|
||||
if (i > 0) {
|
||||
size += strlen_P(HASerializerJsonPropertiesSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool HASerializer::flush() const
|
||||
{
|
||||
HAMqtt* mqtt = HAMqtt::instance();
|
||||
if (!mqtt || (_deviceType && !mqtt->getDevice())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonDataPrefix));
|
||||
|
||||
for (uint8_t i = 0; i < _entriesNb; i++) {
|
||||
if (i > 0) {
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertiesSeparator));
|
||||
}
|
||||
|
||||
if (!flushEntry(&_entries[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonDataSuffix));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t HASerializer::calculateEntrySize(const SerializerEntry* entry) const
|
||||
{
|
||||
switch (entry->type) {
|
||||
case PropertyEntryType:
|
||||
return
|
||||
// property name
|
||||
strlen_P(HASerializerJsonPropertyPrefix) +
|
||||
strlen_P(AHAFROMFSTR(entry->property)) +
|
||||
strlen_P(HASerializerJsonPropertySuffix) +
|
||||
// property value
|
||||
calculatePropertyValueSize(entry);
|
||||
|
||||
case TopicEntryType:
|
||||
return calculateTopicEntrySize(entry);
|
||||
|
||||
case FlagEntryType:
|
||||
return calculateFlagSize(
|
||||
static_cast<FlagType>(entry->subtype)
|
||||
);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t HASerializer::calculateTopicEntrySize(
|
||||
const SerializerEntry* entry
|
||||
) const
|
||||
{
|
||||
uint16_t size = 0;
|
||||
|
||||
// property name
|
||||
size +=
|
||||
strlen_P(HASerializerJsonPropertyPrefix) +
|
||||
strlen_P(AHAFROMFSTR(entry->property)) +
|
||||
strlen_P(HASerializerJsonPropertySuffix);
|
||||
|
||||
// topic escape
|
||||
size += 2 * strlen_P(HASerializerJsonEscapeChar);
|
||||
|
||||
// topic
|
||||
if (entry->value) {
|
||||
size += strlen(static_cast<const char*>(entry->value));
|
||||
} else {
|
||||
if (!_deviceType) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size += calculateDataTopicLength(
|
||||
_deviceType->uniqueId(),
|
||||
entry->property
|
||||
) - 1; // exclude null terminator
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16_t HASerializer::calculateFlagSize(const FlagType flag) const
|
||||
{
|
||||
const HAMqtt* mqtt = HAMqtt::instance();
|
||||
const HADevice* device = mqtt->getDevice();
|
||||
|
||||
if (flag == WithDevice && device->getSerializer()) {
|
||||
const uint16_t deviceLength = device->getSerializer()->calculateSize();
|
||||
if (deviceLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return
|
||||
strlen_P(HASerializerJsonPropertyPrefix) +
|
||||
strlen_P(HADeviceProperty) +
|
||||
strlen_P(HASerializerJsonPropertySuffix) +
|
||||
deviceLength;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t HASerializer::calculatePropertyValueSize(
|
||||
const SerializerEntry* entry
|
||||
) const
|
||||
{
|
||||
switch (entry->subtype) {
|
||||
case ConstCharPropertyValue:
|
||||
case ProgmemPropertyValue: {
|
||||
const char* value = static_cast<const char*>(entry->value);
|
||||
const uint16_t len =
|
||||
entry->subtype == ConstCharPropertyValue ? strlen(value) : strlen_P(value);
|
||||
return 2 * strlen_P(HASerializerJsonEscapeChar) + len;
|
||||
}
|
||||
|
||||
case BoolPropertyType: {
|
||||
const bool value = *static_cast<const bool*>(entry->value);
|
||||
return value ? strlen_P(HATrue) : strlen_P(HAFalse);
|
||||
}
|
||||
|
||||
case NumberPropertyType: {
|
||||
const HANumeric* value = static_cast<const HANumeric*>(
|
||||
entry->value
|
||||
);
|
||||
return value->calculateSize();
|
||||
}
|
||||
|
||||
case ArrayPropertyType: {
|
||||
const HASerializerArray* array = static_cast<const HASerializerArray*>(
|
||||
entry->value
|
||||
);
|
||||
return array->calculateSize();
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool HASerializer::flushEntry(const SerializerEntry* entry) const
|
||||
{
|
||||
HAMqtt* mqtt = HAMqtt::instance();
|
||||
|
||||
switch (entry->type) {
|
||||
case PropertyEntryType: {
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertyPrefix));
|
||||
mqtt->writePayload(entry->property);
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertySuffix));
|
||||
|
||||
return flushEntryValue(entry);
|
||||
}
|
||||
|
||||
case TopicEntryType:
|
||||
return flushTopic(entry);
|
||||
|
||||
case FlagEntryType:
|
||||
return flushFlag(entry);
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HASerializer::flushEntryValue(const SerializerEntry* entry) const
|
||||
{
|
||||
HAMqtt* mqtt = HAMqtt::instance();
|
||||
|
||||
switch (entry->subtype) {
|
||||
case ConstCharPropertyValue:
|
||||
case ProgmemPropertyValue: {
|
||||
const char* value = static_cast<const char*>(entry->value);
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonEscapeChar));
|
||||
|
||||
if (entry->subtype == ConstCharPropertyValue) {
|
||||
mqtt->writePayload(value, strlen(value));
|
||||
} else {
|
||||
mqtt->writePayload(AHATOFSTR(value));
|
||||
}
|
||||
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonEscapeChar));
|
||||
return true;
|
||||
}
|
||||
|
||||
case BoolPropertyType: {
|
||||
const bool value = *static_cast<const bool*>(entry->value);
|
||||
mqtt->writePayload(AHATOFSTR(value ? HATrue : HAFalse));
|
||||
return true;
|
||||
}
|
||||
|
||||
case NumberPropertyType: {
|
||||
const HANumeric* value = static_cast<const HANumeric*>(
|
||||
entry->value
|
||||
);
|
||||
|
||||
char tmp[HANumeric::MaxDigitsNb + 1];
|
||||
const uint16_t length = value->toStr(tmp);
|
||||
|
||||
mqtt->writePayload(tmp, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
case ArrayPropertyType: {
|
||||
const HASerializerArray* array = static_cast<const HASerializerArray*>(
|
||||
entry->value
|
||||
);
|
||||
const uint16_t size = array->calculateSize();
|
||||
char tmp[size + 1]; // including null terminator
|
||||
tmp[0] = 0;
|
||||
array->serialize(tmp);
|
||||
mqtt->writePayload(tmp, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HASerializer::flushTopic(const SerializerEntry* entry) const
|
||||
{
|
||||
HAMqtt* mqtt = HAMqtt::instance();
|
||||
|
||||
// property name
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertyPrefix));
|
||||
mqtt->writePayload(entry->property);
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertySuffix));
|
||||
|
||||
// value (escaped)
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonEscapeChar));
|
||||
|
||||
if (entry->value) {
|
||||
const char* topic = static_cast<const char*>(entry->value);
|
||||
mqtt->writePayload(topic, strlen(topic));
|
||||
} else {
|
||||
const uint16_t length = calculateDataTopicLength(
|
||||
_deviceType->uniqueId(),
|
||||
entry->property
|
||||
);
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char topic[length];
|
||||
generateDataTopic(
|
||||
topic,
|
||||
_deviceType->uniqueId(),
|
||||
entry->property
|
||||
);
|
||||
|
||||
mqtt->writePayload(topic, length - 1);
|
||||
}
|
||||
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonEscapeChar));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HASerializer::flushFlag(const SerializerEntry* entry) const
|
||||
{
|
||||
HAMqtt* mqtt = HAMqtt::instance();
|
||||
const HADevice* device = mqtt->getDevice();
|
||||
const FlagType flag = static_cast<FlagType>(entry->subtype);
|
||||
|
||||
if (flag == WithDevice && device) {
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertyPrefix));
|
||||
mqtt->writePayload(AHATOFSTR(HADeviceProperty));
|
||||
mqtt->writePayload(AHATOFSTR(HASerializerJsonPropertySuffix));
|
||||
|
||||
return device->getSerializer()->flush();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
269
lib/home-assistant-integration/src/utils/HASerializer.h
Normal file
269
lib/home-assistant-integration/src/utils/HASerializer.h
Normal file
@@ -0,0 +1,269 @@
|
||||
|
||||
#ifndef AHA_SERIALIZER_H
|
||||
#define AHA_SERIALIZER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "HADictionary.h"
|
||||
#include "HASerializerArray.h"
|
||||
|
||||
class HAMqtt;
|
||||
class HABaseDeviceType;
|
||||
|
||||
/**
|
||||
* This class allows to create JSON objects easily.
|
||||
* Its main purpose is to handle configuration of a device type that's going to
|
||||
* be published to the MQTT broker.
|
||||
*/
|
||||
class HASerializer
|
||||
{
|
||||
public:
|
||||
/// Type of the object's entry.
|
||||
enum EntryType {
|
||||
UnknownEntryType = 0,
|
||||
PropertyEntryType,
|
||||
TopicEntryType,
|
||||
FlagEntryType
|
||||
};
|
||||
|
||||
/// The type of a flag for a FlagEntryType.
|
||||
enum FlagType {
|
||||
WithDevice = 1,
|
||||
WithAvailability
|
||||
};
|
||||
|
||||
/// Available data types of entries.
|
||||
enum PropertyValueType {
|
||||
UnknownPropertyValueType = 0,
|
||||
ConstCharPropertyValue,
|
||||
ProgmemPropertyValue,
|
||||
BoolPropertyType,
|
||||
NumberPropertyType,
|
||||
ArrayPropertyType
|
||||
};
|
||||
|
||||
/// Representation of a single entry in the object.
|
||||
struct SerializerEntry {
|
||||
/// Type of the entry.
|
||||
EntryType type;
|
||||
|
||||
/// Subtype of the entry. It can be `FlagType`, `PropertyValueType` or `TopicType`.
|
||||
uint8_t subtype;
|
||||
|
||||
/// Pointer to the property name (progmem string).
|
||||
const __FlashStringHelper* property;
|
||||
|
||||
/// Pointer to the property value. The value type is determined by `subtype`.
|
||||
const void* value;
|
||||
|
||||
SerializerEntry():
|
||||
type(UnknownEntryType),
|
||||
subtype(0),
|
||||
property(nullptr),
|
||||
value(nullptr)
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the size of a configuration topic for the given component and object ID.
|
||||
* The configuration topic has structure as follows: `[discovery prefix]/[component]/[device ID]_[objectId]/config`
|
||||
*
|
||||
* @param component The name of the HA component (e.g. `binary_sensor`).
|
||||
* @param objectId The unique ID of a device type that's going to publish the config.
|
||||
*/
|
||||
static uint16_t calculateConfigTopicLength(
|
||||
const __FlashStringHelper* component,
|
||||
const char* objectId
|
||||
);
|
||||
|
||||
/**
|
||||
* Generates the configuration topic for the given component and object ID.
|
||||
* The topic will be stored in the `output` variable.
|
||||
*
|
||||
* @param output Buffer where the topic will be written.
|
||||
* @param component The name of the HA component (e.g. `binary_sensor`).
|
||||
* @param objectId The unique ID of a device type that's going to publish the config.
|
||||
*/
|
||||
static bool generateConfigTopic(
|
||||
char* output,
|
||||
const __FlashStringHelper* component,
|
||||
const char* objectId
|
||||
);
|
||||
|
||||
/**
|
||||
* Calculates the size of the given data topic for the given objectId.
|
||||
* The data topic has structure as follows: `[data prefix]/[device ID]_[objectId]/[topic]`
|
||||
*
|
||||
* @param objectId The unique ID of a device type that's going to publish the data.
|
||||
* @param topic The topic name (progmem string).
|
||||
*/
|
||||
static uint16_t calculateDataTopicLength(
|
||||
const char* objectId,
|
||||
const __FlashStringHelper* topic
|
||||
);
|
||||
|
||||
/**
|
||||
* Generates the data topic for the given object ID.
|
||||
* The topic will be stored in the `output` variable.
|
||||
*
|
||||
* @param output Buffer where the topic will be written.
|
||||
* @param objectId The unique ID of a device type that's going to publish the data.
|
||||
* @param topic The topic name (progmem string).
|
||||
*/
|
||||
static bool generateDataTopic(
|
||||
char* output,
|
||||
const char* objectId,
|
||||
const __FlashStringHelper* topic
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks whether the given topic matches the data topic that can be generated
|
||||
* using the given objectId and topicP.
|
||||
* This method can be used to check if the received message matches some data topic.
|
||||
*
|
||||
* @param actualTopic The actual topic to compare.
|
||||
* @param objectId The unique ID of a device type that may be the owner of the topic.
|
||||
* @param topic The topic name (progmem string).
|
||||
*/
|
||||
static bool compareDataTopics(
|
||||
const char* actualTopic,
|
||||
const char* objectId,
|
||||
const __FlashStringHelper* topic
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates instance of the serializer for the given device type.
|
||||
* Please note that the number JSON object's entries needs to be known upfront.
|
||||
* This approach reduces number of memory allocations.
|
||||
*
|
||||
* @param deviceType The device type that owns the serializer.
|
||||
* @param maxEntriesNb Maximum number of the output object entries.
|
||||
*/
|
||||
HASerializer(HABaseDeviceType* deviceType, const uint8_t maxEntriesNb);
|
||||
|
||||
/**
|
||||
* Frees the dynamic memory allocated by the class.
|
||||
*/
|
||||
~HASerializer();
|
||||
|
||||
/**
|
||||
* Returns the number of items that were added to the serializer.
|
||||
*/
|
||||
inline uint8_t getEntriesNb() const
|
||||
{ return _entriesNb; }
|
||||
|
||||
/**
|
||||
* Returns pointer to the serializer's entries.
|
||||
*/
|
||||
inline SerializerEntry* getEntries() const
|
||||
{ return _entries; }
|
||||
|
||||
/**
|
||||
* Adds a new entry to the serialized with a type of `PropertyEntryType`.
|
||||
*
|
||||
* @param property Pointer to the name of the property (progmem string).
|
||||
* @param value Pointer to the value that's being set.
|
||||
* @param valueType The type of the value that's passed to the method.
|
||||
*/
|
||||
void set(
|
||||
const __FlashStringHelper* property,
|
||||
const void* value,
|
||||
PropertyValueType valueType = ConstCharPropertyValue
|
||||
);
|
||||
|
||||
/**
|
||||
* Adds a new entry to the serializer with a type of `FlagEntryType`.
|
||||
*
|
||||
* @param flag Flag to add.
|
||||
*/
|
||||
void set(const FlagType flag);
|
||||
|
||||
/**
|
||||
* Adds a new entry to the serialize with a type of `TopicEntryType`.
|
||||
*
|
||||
* @param topic The topic name to add (progmem string).
|
||||
*/
|
||||
void topic(const __FlashStringHelper* topic);
|
||||
|
||||
/**
|
||||
* Calculates the output size of the serialized JSON object.
|
||||
*/
|
||||
uint16_t calculateSize() const;
|
||||
|
||||
/**
|
||||
* Flushes the JSON object to the MQTT stream.
|
||||
* Please note that this method only writes the MQTT payload.
|
||||
* The MQTT session needs to be opened before.
|
||||
*/
|
||||
bool flush() const;
|
||||
|
||||
private:
|
||||
/// Pointer to the device type that owns the serializer.
|
||||
HABaseDeviceType* _deviceType;
|
||||
|
||||
/// The number of entries added to the serializer.
|
||||
uint8_t _entriesNb;
|
||||
|
||||
/// Maximum number of entries that can be added to the serializer.
|
||||
uint8_t _maxEntriesNb;
|
||||
|
||||
/// Pointer to the serializer entries.
|
||||
SerializerEntry* _entries;
|
||||
|
||||
/**
|
||||
* Creates a new entry in the serializer's memory.
|
||||
* If the limit of entries is hit, the nullptr is returned.
|
||||
*/
|
||||
SerializerEntry* addEntry();
|
||||
|
||||
/**
|
||||
* Calculates the serialized size of the given entry.
|
||||
* Internally, this method recognizes the type of the entry and calls
|
||||
* a proper calculate method listed below.
|
||||
*/
|
||||
uint16_t calculateEntrySize(const SerializerEntry* entry) const;
|
||||
|
||||
/**
|
||||
* Calculates the size of the entry of type `TopicEntryType`.
|
||||
*/
|
||||
uint16_t calculateTopicEntrySize(const SerializerEntry* entry) const;
|
||||
|
||||
/**
|
||||
* Calculates the size of the entry of type `FlagEntryType`.
|
||||
*/
|
||||
uint16_t calculateFlagSize(const FlagType flag) const;
|
||||
|
||||
/**
|
||||
* Calculates the size of the entry's value if the entry is `PropertyEntryType`.
|
||||
*/
|
||||
uint16_t calculatePropertyValueSize(const SerializerEntry* entry) const;
|
||||
|
||||
/**
|
||||
* Calculates the size of the array if the property's value is a type of `ArrayPropertyType`.
|
||||
*/
|
||||
uint16_t calculateArraySize(const HASerializerArray* array) const;
|
||||
|
||||
/**
|
||||
* Flushes the given entry to the MQTT.
|
||||
* Internally this method recognizes the type of the entry and calls
|
||||
* a proper flush method listed below.
|
||||
*/
|
||||
bool flushEntry(const SerializerEntry* entry) const;
|
||||
|
||||
/**
|
||||
* Flushes the value of the `PropertyEntryType` entry.
|
||||
*/
|
||||
bool flushEntryValue(const SerializerEntry* entry) const;
|
||||
|
||||
/**
|
||||
* Flushes the entry of type `TopicEntryType` to the MQTT.
|
||||
*/
|
||||
bool flushTopic(const SerializerEntry* entry) const;
|
||||
|
||||
/**
|
||||
* Flushes the entry of type `FlagEntryType` to the MQTT.
|
||||
*/
|
||||
bool flushFlag(const SerializerEntry* entry) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "HASerializerArray.h"
|
||||
#include "HADictionary.h"
|
||||
|
||||
HASerializerArray::HASerializerArray(const uint8_t size, const bool progmemItems) :
|
||||
_progmemItems(progmemItems),
|
||||
_size(size),
|
||||
_itemsNb(0),
|
||||
_items(new ItemType[size])
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HASerializerArray::~HASerializerArray()
|
||||
{
|
||||
delete[] _items;
|
||||
}
|
||||
|
||||
bool HASerializerArray::add(ItemType item)
|
||||
{
|
||||
if (_itemsNb >= _size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_items[_itemsNb++] = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t HASerializerArray::calculateSize() const
|
||||
{
|
||||
uint16_t size =
|
||||
strlen_P(HASerializerJsonArrayPrefix) +
|
||||
strlen_P(HASerializerJsonArraySuffix);
|
||||
|
||||
if (_itemsNb == 0) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// separators between elements
|
||||
size += (_itemsNb - 1) * strlen_P(HASerializerJsonPropertiesSeparator);
|
||||
|
||||
for (uint8_t i = 0; i < _itemsNb; i++) {
|
||||
size +=
|
||||
2 * strlen_P(HASerializerJsonEscapeChar)
|
||||
+ (_progmemItems ? strlen_P(_items[i]) : strlen(_items[i]));
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool HASerializerArray::serialize(char* output) const
|
||||
{
|
||||
if (!output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcat_P(output, HASerializerJsonArrayPrefix);
|
||||
|
||||
for (uint8_t i = 0; i < _itemsNb; i++) {
|
||||
if (i > 0) {
|
||||
strcat_P(output, HASerializerJsonPropertiesSeparator);
|
||||
}
|
||||
|
||||
strcat_P(output, HASerializerJsonEscapeChar);
|
||||
|
||||
if (_progmemItems) {
|
||||
strcat_P(output, _items[i]);
|
||||
} else {
|
||||
strcat(output, _items[i]);
|
||||
}
|
||||
|
||||
strcat_P(output, HASerializerJsonEscapeChar);
|
||||
}
|
||||
|
||||
strcat_P(output, HASerializerJsonArraySuffix);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HASerializerArray::clear()
|
||||
{
|
||||
_itemsNb = 0;
|
||||
}
|
||||
75
lib/home-assistant-integration/src/utils/HASerializerArray.h
Normal file
75
lib/home-assistant-integration/src/utils/HASerializerArray.h
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
#ifndef AHA_SERIALIZERARRAY_H
|
||||
#define AHA_SERIALIZERARRAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* HASerializerArray represents array of items that can be used as a HASerializer property.
|
||||
*/
|
||||
class HASerializerArray
|
||||
{
|
||||
public:
|
||||
typedef const char* ItemType;
|
||||
|
||||
/**
|
||||
* Constructs HASerializerArray with the static size (number of elements).
|
||||
* The array is allocated dynamically in the memory based on the given size.
|
||||
*
|
||||
* @param size The desired number of elements that will be stored in the array.
|
||||
* @param progmemItems Specifies whether items are going to be stored in the flash memory.
|
||||
*/
|
||||
HASerializerArray(const uint8_t size, const bool progmemItems = true);
|
||||
~HASerializerArray();
|
||||
|
||||
/**
|
||||
* Returns the number of elements that were added to the array.
|
||||
* It can be lower than size of the array.
|
||||
*/
|
||||
inline uint8_t getItemsNb() const
|
||||
{ return _itemsNb; }
|
||||
|
||||
/**
|
||||
* Returns pointer to the array.
|
||||
*/
|
||||
inline ItemType* getItems() const
|
||||
{ return _items; }
|
||||
|
||||
/**
|
||||
* Adds a new element to the array.
|
||||
*
|
||||
* @param itemP Item to add (string).
|
||||
* @returns Returns `true` if item has been added to the array successfully.
|
||||
*/
|
||||
bool add(ItemType item);
|
||||
|
||||
/**
|
||||
* Calculates the size of the serialized array (JSON representation).
|
||||
*/
|
||||
uint16_t calculateSize() const;
|
||||
|
||||
/**
|
||||
* Serializes array as JSON to the given output.
|
||||
*/
|
||||
bool serialize(char* output) const;
|
||||
|
||||
/**
|
||||
* Clears the array.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private:
|
||||
/// Specifies whether items are stored in the flash memory.
|
||||
const bool _progmemItems;
|
||||
|
||||
/// The maximum size of the array.
|
||||
const uint8_t _size;
|
||||
|
||||
/// The number of items that were added to the array.
|
||||
uint8_t _itemsNb;
|
||||
|
||||
/// Pointer to the array elements.
|
||||
ItemType* _items;
|
||||
};
|
||||
|
||||
#endif
|
||||
48
lib/home-assistant-integration/src/utils/HAUtils.cpp
Normal file
48
lib/home-assistant-integration/src/utils/HAUtils.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifdef ARDUINO_ARCH_SAMD
|
||||
#include <avr/dtostrf.h>
|
||||
#endif
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "HAUtils.h"
|
||||
#include "HADictionary.h"
|
||||
|
||||
bool HAUtils::endsWith(const char* str, const char* suffix)
|
||||
{
|
||||
if (str == nullptr || suffix == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t lenstr = strlen(str);
|
||||
const uint16_t lensuffix = strlen(suffix);
|
||||
|
||||
if (lensuffix > lenstr || lenstr == 0 || lensuffix == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0);
|
||||
}
|
||||
|
||||
void HAUtils::byteArrayToStr(
|
||||
char* dst,
|
||||
const byte* src,
|
||||
const uint16_t length
|
||||
)
|
||||
{
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
dst[i*2] = pgm_read_byte(&HAHexMap[((char)src[i] & 0XF0) >> 4]);
|
||||
dst[i*2+1] = pgm_read_byte(&HAHexMap[((char)src[i] & 0x0F)]);
|
||||
}
|
||||
|
||||
dst[length * 2] = 0;
|
||||
}
|
||||
|
||||
char* HAUtils::byteArrayToStr(
|
||||
const byte* src,
|
||||
const uint16_t length
|
||||
)
|
||||
{
|
||||
char* dst = new char[(length * 2) + 1]; // include null terminator
|
||||
byteArrayToStr(dst, src, length);
|
||||
|
||||
return dst;
|
||||
}
|
||||
52
lib/home-assistant-integration/src/utils/HAUtils.h
Normal file
52
lib/home-assistant-integration/src/utils/HAUtils.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef AHA_HAUTILS_H
|
||||
#define AHA_HAUTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* This class provides some useful methods to make life easier.
|
||||
*/
|
||||
class HAUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Checks whether the given `str` ends with the given `suffix`.
|
||||
*
|
||||
* @param str Input string to check.
|
||||
* @param suffix Suffix to find
|
||||
* @returns True if the given suffix is present at the end of the given string.
|
||||
*/
|
||||
static bool endsWith(
|
||||
const char* str,
|
||||
const char* suffix
|
||||
);
|
||||
|
||||
/**
|
||||
* Converts the given byte array into hex string.
|
||||
* Each byte will be represented by two bytes, so the output size will be `length * 2`
|
||||
*
|
||||
* @param dst Destination where the string will be saved.
|
||||
* @param src Bytes array to convert.
|
||||
* @param length Length of the bytes array.
|
||||
*/
|
||||
static void byteArrayToStr(
|
||||
char* dst,
|
||||
const byte* src,
|
||||
const uint16_t length
|
||||
);
|
||||
|
||||
/**
|
||||
* Converts the given byte array into hex string.
|
||||
* This method allocates a new memory.
|
||||
*
|
||||
* @param src Bytes array to convert.
|
||||
* @param length Length of the bytes array.
|
||||
* @returns Newly allocated string containing the hex representation.
|
||||
*/
|
||||
static char* byteArrayToStr(
|
||||
const byte* src,
|
||||
const uint16_t length
|
||||
);
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user