mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
Move the roam check into worthRoaming() and the memStatus routing into heapEmitTarget() in Utils so the native tests reach them. worthRoaming() roams for a gain of at least ROAM_MIN_GAIN_DB, as the comment and the 6 dB commit said. The old check needed one dB more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
121 lines
5.3 KiB
C++
121 lines
5.3 KiB
C++
#ifndef utils_h
|
|
#define utils_h
|
|
#include <Arduino.h>
|
|
|
|
|
|
#define DEBUG_SOMFY Serial
|
|
|
|
|
|
|
|
|
|
[[maybe_unused]] static void SETCHARPROP(char *prop, const char *value, size_t size) {strncpy(prop, value, size); prop[size - 1] = '\0';}
|
|
/*
|
|
namespace util {
|
|
// Createa a custom to_string function. C++ can be annoying
|
|
// with all the trailing 0s on number formats.
|
|
template <typename T> std::string to_string(const T& t) {
|
|
std::string str{std::to_string (t)};
|
|
int offset{1};
|
|
if (str.find_last_not_of('0') == str.find('.')) {
|
|
offset = 0;
|
|
}
|
|
str.erase ( str.find_last_not_of('0') + 1, std::string::npos );
|
|
str.erase ( str.find_last_not_of('.') + 1, std::string::npos );
|
|
return str;
|
|
}
|
|
}
|
|
*/
|
|
|
|
static void _ltrim(char *str) {
|
|
int s = 0, j, k = 0;
|
|
int e = strlen(str);
|
|
while(s < e && (str[s] == ' ' || str[s] == '\n' || str[s] == '\r' || str[s] == '\t' || str[s] == '"')) s++;
|
|
if(s > 0) {
|
|
for(j = s; j < e; j++) {
|
|
str[k] = str[j];
|
|
k++;
|
|
}
|
|
str[k] = '\0';
|
|
}
|
|
//if(s > 0) strcpy(str, &str[s]);
|
|
}
|
|
static void _rtrim(char *str) {
|
|
int e = strlen(str) - 1;
|
|
while(e >= 0 && (str[e] == ' ' || str[e] == '\n' || str[e] == '\r' || str[e] == '\t' || str[e] == '"')) {str[e] = '\0'; e--;}
|
|
}
|
|
[[maybe_unused]] static void _trim(char *str) { _ltrim(str); _rtrim(str); }
|
|
struct rebootDelay_t {
|
|
bool reboot = false;
|
|
int rebootTime = 0;
|
|
bool closed = false;
|
|
};
|
|
[[maybe_unused]] static bool toBoolean(const char *str, bool def) {
|
|
if(!str) return def;
|
|
if(strlen(str) == 0) return def;
|
|
else if(str[0] == 't' || str[0] == 'T' || str[0] == '1') return true;
|
|
else if(str[0] == 'f' || str[0] == 'F' || str[0] == '0') return false;
|
|
return def;
|
|
}
|
|
// Whether a wifiStrength broadcast is worth sending: always on a channel change,
|
|
// otherwise only for an RSSI change of at least minDelta dBm and not more often
|
|
// than every minMs.
|
|
bool rssiNeedsEmit(int rssi, int lastRssi, int channel, int lastChannel, uint32_t sinceLastMs, int minDelta, uint32_t minMs);
|
|
// What the last wifiStrength broadcast told every client. Only broadcasts
|
|
// move it: an emit to one new client tells the others nothing.
|
|
struct RssiBroadcast {
|
|
int rssi = 0;
|
|
int channel = 0;
|
|
uint32_t at = 0; // millis() of the last broadcast.
|
|
bool due(int rssi, int channel, uint32_t now, int minDelta, uint32_t minMs) const;
|
|
void sent(bool broadcast, int rssi, int channel, uint32_t now);
|
|
};
|
|
// Whether an AP a scan found for our SSID is worth connecting to. While
|
|
// connected it has to be at least minGain dBm stronger than the current AP so
|
|
// a small swing doesn't make the device hop between APs.
|
|
bool worthRoaming(bool connected, int currentRssi, int apRssi, int minGain);
|
|
// Who gets a memStatus event.
|
|
enum class heap_emit_t : uint8_t { none, client, broadcast, room };
|
|
// num is the socket client asked for, 255 for everyone. A broadcast goes out
|
|
// every intervalMs; in between only the clients in room 0 get one.
|
|
heap_emit_t heapEmitTarget(uint8_t num, uint32_t sinceLastMs, uint32_t intervalMs, bool roomHasClients);
|
|
|
|
class Timestamp {
|
|
char _timeBuffer[128];
|
|
public:
|
|
time_t getUTC();
|
|
time_t getUTC(time_t epoch);
|
|
char * getISOTime();
|
|
char * getISOTime(time_t epoch);
|
|
char * formatISO(struct tm *dt, int tz);
|
|
int tzOffset();
|
|
static time_t parseUTCTime(const char *buff);
|
|
static time_t mkUTCTime(struct tm *dt);
|
|
static int calcTZOffset(time_t *dt);
|
|
static time_t now();
|
|
static unsigned long epoch();
|
|
};
|
|
// Sort an array
|
|
template<typename AnyType> void sortArray(AnyType array[], size_t sizeOfArray);
|
|
// Sort in reverse
|
|
template<typename AnyType> void sortArrayReverse(AnyType array[], size_t sizeOfArray);
|
|
// Sort an array with custom comparison function
|
|
template<typename AnyType> void sortArray(AnyType array[], size_t sizeOfArray, bool (*largerThan)(AnyType, AnyType));
|
|
// Sort in reverse with custom comparison function
|
|
template<typename AnyType> void sortArrayReverse(AnyType array[], size_t sizeOfArray, bool (*largerThan)(AnyType, AnyType));
|
|
namespace ArduinoSort {
|
|
template<typename AnyType> bool builtinLargerThan(AnyType first, AnyType second) { return first > second; }
|
|
//template<> bool builtinLargerThan(char* first, char* second) { return strcmp(first, second) > 0; }
|
|
template<typename AnyType> void insertionSort(AnyType array[], size_t sizeOfArray, bool reverse, bool (*largerThan)(AnyType, AnyType)) { for (size_t i = 1; i < sizeOfArray; i++) {
|
|
for (size_t j = i; j > 0 && (largerThan(array[j-1], array[j]) != reverse); j--) {
|
|
AnyType tmp = array[j-1];
|
|
array[j-1] = array[j];
|
|
array[j] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
template<typename AnyType> void sortArray(AnyType array[], size_t sizeOfArray) { ArduinoSort::insertionSort(array, sizeOfArray, false, ArduinoSort::builtinLargerThan); }
|
|
template<typename AnyType> void sortArrayReverse(AnyType array[], size_t sizeOfArray) { ArduinoSort::insertionSort(array, sizeOfArray, true, ArduinoSort::builtinLargerThan); }
|
|
template<typename AnyType> void sortArray(AnyType array[], size_t sizeOfArray, bool (*largerThan)(AnyType, AnyType)) { ArduinoSort::insertionSort(array, sizeOfArray, false, largerThan); }
|
|
template<typename AnyType> void sortArrayReverse(AnyType array[], size_t sizeOfArray, bool (*largerThan)(AnyType, AnyType)) { ArduinoSort::insertionSort(array, sizeOfArray, true, largerThan); }
|
|
#endif
|