Files
nixie-clock/firmware/uniclock/lib/arduino-home-assistant/src/utils/HANumeric.cpp
T
mangavalkandClaude Opus 5.5 9a7061383c Add Home Assistant controls over MQTT
Upgrade ArduinoHA from 1.3.0 to 2.1.0 and rewrite mqtt.ino for it.
The clock now shows up in Home Assistant (discovery prefix
"homeassistant") with:
- switches Tubes (blank the display, runtime only) and Auto dim
- numbers Day/Night brightness
- light Backlight (on/off, brightness, RGB mapped to the colour wheel)
- select LED effect, button Cathode protect
- sensors Light (LDR) and WiFi signal, plus the upstream sensors when
  the clock has them; master-clock subscriptions are kept

Settings changed from HA are saved to EEPROM 3 s after the last change.
Fixes the unbounded memcpy in the MQTT message handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:37:25 +01:00

215 lines
4.2 KiB
C++

#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 ARDUINOHA_INT_OVERLOAD
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;
}