Skip to content

Commit 7d5a333

Browse files
committed
feat: replace Serial.printf with SINRICPRO_PRINTF for improved cross-platform compatibility
1 parent f593d4e commit 7d5a333

8 files changed

Lines changed: 130 additions & 49 deletions

File tree

examples/OTAUpdate/OTAUpdate.ino

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ bool handleOTAUpdate(const String& url, int major, int minor, int patch, bool fo
9696

9797
// setup function for WiFi connection
9898
void setupWiFi() {
99-
Serial.printf("\r\n[Wifi]: Connecting");
99+
SINRICPRO_PRINTF("\r\n[Wifi]: Connecting");
100100

101101
#if defined(ESP8266)
102102
WiFi.setSleepMode(WIFI_NONE_SLEEP);
@@ -109,11 +109,11 @@ void setupWiFi() {
109109
WiFi.begin(WIFI_SSID, WIFI_PASS);
110110

111111
while (WiFi.status() != WL_CONNECTED) {
112-
Serial.printf(".");
112+
SINRICPRO_PRINTF(".");
113113
delay(250);
114114
}
115115

116-
Serial.printf("connected!\r\n[WiFi]: IP-Address is %s\r\n", WiFi.localIP().toString().c_str());
116+
SINRICPRO_PRINTF("connected!\r\n[WiFi]: IP-Address is %s\r\n", WiFi.localIP().toString().c_str());
117117
}
118118

119119
// setup function for SinricPro
@@ -122,10 +122,10 @@ void setupSinricPro() {
122122

123123
// setup SinricPro
124124
SinricPro.onConnected([]() {
125-
Serial.printf("Connected to SinricPro\r\n");
125+
SINRICPRO_PRINTF("Connected to SinricPro\r\n");
126126
});
127127
SinricPro.onDisconnected([]() {
128-
Serial.printf("Disconnected from SinricPro\r\n");
128+
SINRICPRO_PRINTF("Disconnected from SinricPro\r\n");
129129
});
130130
SinricPro.onOTAUpdate(handleOTAUpdate);
131131
SinricPro.begin(APP_KEY, APP_SECRET);
@@ -134,7 +134,7 @@ void setupSinricPro() {
134134
// main setup function
135135
void setup() {
136136
Serial.begin(BAUD_RATE);
137-
Serial.printf("\r\n\r\n");
137+
SINRICPRO_PRINTF("\r\n\r\n");
138138
setupWiFi();
139139
setupSinricPro();
140140
}

examples/Settings/MultiWiFi/MultiWiFi.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ SinricProWiFiSettings spws(LittleFS, primarySSID, primaryPassword, secondarySSID
6464

6565
bool onSetModuleSetting(const String& id, SettingValue& value) {
6666
// Handle module settings.
67-
if (!std::holds_alternative<String>(value)) {
67+
if (!value.holds<String>()) {
6868
Serial.println(F("onSetModuleSetting: Expected string value"));
6969
return false;
7070
}
7171

7272
JsonDocument doc;
73-
DeserializationError error = deserializeJson(doc, std::get<String>(value));
73+
DeserializationError error = deserializeJson(doc, value.get<String>());
7474

7575
if (error) {
7676
Serial.print(F("onSetModuleSetting::deserializeJson() failed: "));

examples/Settings/SetFixedIPAddress/SetFixedIPAddress.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@
5050

5151
bool onSetModuleSetting(const String &id, SettingValue &value) {
5252
// Handle module settings.
53-
if (!std::holds_alternative<String>(value)) {
53+
if (!value.holds<String>()) {
5454
Serial.println(F("onSetModuleSetting: Expected string value"));
5555
return false;
5656
}
5757

5858
JsonDocument doc;
59-
DeserializationError error = deserializeJson(doc, std::get<String>(value));
59+
DeserializationError error = deserializeJson(doc, value.get<String>());
6060

6161
if (error) {
6262
Serial.print(F("onSetModuleSetting::deserializeJson() failed: "));

examples/Settings/Settings/Settings.ino

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,28 @@
4848

4949
bool onSetDeviceSetting(const String& deviceId, const String& settingId, SettingValue& settingValue) {
5050
// Handle device settings based on value type
51-
if (std::holds_alternative<int>(settingValue)) {
52-
SINRICPRO_PRINTF("Device %s: Setting %s = %d\r\n", deviceId.c_str(), settingId.c_str(), std::get<int>(settingValue));
53-
} else if (std::holds_alternative<float>(settingValue)) {
54-
SINRICPRO_PRINTF("Device %s: Setting %s = %.2f\r\n", deviceId.c_str(), settingId.c_str(), std::get<float>(settingValue));
55-
} else if (std::holds_alternative<bool>(settingValue)) {
56-
SINRICPRO_PRINTF("Device %s: Setting %s = %s\r\n", deviceId.c_str(), settingId.c_str(), std::get<bool>(settingValue) ? "true" : "false");
57-
} else if (std::holds_alternative<String>(settingValue)) {
58-
SINRICPRO_PRINTF("Device %s: Setting %s = %s\r\n", deviceId.c_str(), settingId.c_str(), std::get<String>(settingValue).c_str());
51+
if (settingValue.holds<int>()) {
52+
SINRICPRO_PRINTF("Device %s: Setting %s = %d\r\n", deviceId.c_str(), settingId.c_str(), settingValue.get<int>());
53+
} else if (settingValue.holds<float>()) {
54+
SINRICPRO_PRINTF("Device %s: Setting %s = %.2f\r\n", deviceId.c_str(), settingId.c_str(), settingValue.get<float>());
55+
} else if (settingValue.holds<bool>()) {
56+
SINRICPRO_PRINTF("Device %s: Setting %s = %s\r\n", deviceId.c_str(), settingId.c_str(), settingValue.get<bool>() ? "true" : "false");
57+
} else if (settingValue.holds<String>()) {
58+
SINRICPRO_PRINTF("Device %s: Setting %s = %s\r\n", deviceId.c_str(), settingId.c_str(), settingValue.get<String>().c_str());
5959
}
6060
return true;
6161
}
6262

6363
bool onSetModuleSetting(const String& id, SettingValue& value) {
6464
// Handle module settings based on value type
65-
if (std::holds_alternative<int>(value)) {
66-
SINRICPRO_PRINTF("Module setting %s = %d\r\n", id.c_str(), std::get<int>(value));
67-
} else if (std::holds_alternative<float>(value)) {
68-
SINRICPRO_PRINTF("Module setting %s = %.2f\r\n", id.c_str(), std::get<float>(value));
69-
} else if (std::holds_alternative<bool>(value)) {
70-
SINRICPRO_PRINTF("Module setting %s = %s\r\n", id.c_str(), std::get<bool>(value) ? "true" : "false");
71-
} else if (std::holds_alternative<String>(value)) {
72-
SINRICPRO_PRINTF("Module setting %s = %s\r\n", id.c_str(), std::get<String>(value).c_str());
65+
if (value.holds<int>()) {
66+
SINRICPRO_PRINTF("Module setting %s = %d\r\n", id.c_str(), value.get<int>());
67+
} else if (value.holds<float>()) {
68+
SINRICPRO_PRINTF("Module setting %s = %.2f\r\n", id.c_str(), value.get<float>());
69+
} else if (value.holds<bool>()) {
70+
SINRICPRO_PRINTF("Module setting %s = %s\r\n", id.c_str(), value.get<bool>() ? "true" : "false");
71+
} else if (value.holds<String>()) {
72+
SINRICPRO_PRINTF("Module setting %s = %s\r\n", id.c_str(), value.get<String>().c_str());
7373
}
7474
return true;
7575
}

src/Capabilities/SettingController.h

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#pragma once
22

3-
#include <variant>
4-
53
#include "../SinricProRequest.h"
64
#include "../SinricProStrings.h"
75
#include "../EventLimiter.h"
@@ -14,9 +12,77 @@ FSTR(SETTING, id); // "id"
1412
FSTR(SETTING, value); // "value"
1513

1614
/**
17-
* @brief Variant type for setting values that can hold int, float, bool, or String
15+
* @brief C++11-compatible variant type for setting values that can hold int, float, bool, or String
16+
*
17+
* This is a lightweight alternative to std::variant (C++17) for Arduino boards.
1818
*/
19-
using SettingValue = std::variant<int, float, bool, String>;
19+
class SettingValue {
20+
public:
21+
enum class Type { INT, FLOAT, BOOL, STRING, NONE };
22+
23+
SettingValue() : type_(Type::NONE), int_val(0) {}
24+
SettingValue(int val) : type_(Type::INT), int_val(val) {}
25+
SettingValue(float val) : type_(Type::FLOAT), float_val(val) {}
26+
SettingValue(bool val) : type_(Type::BOOL), bool_val(val) {}
27+
SettingValue(const String& val) : type_(Type::STRING), string_val(val) {}
28+
SettingValue(const char* val) : type_(Type::STRING), string_val(val) {}
29+
30+
SettingValue(const SettingValue& other) : type_(other.type_) {
31+
switch (type_) {
32+
case Type::INT: int_val = other.int_val; break;
33+
case Type::FLOAT: float_val = other.float_val; break;
34+
case Type::BOOL: bool_val = other.bool_val; break;
35+
case Type::STRING: string_val = other.string_val; break;
36+
case Type::NONE: break;
37+
}
38+
}
39+
40+
SettingValue& operator=(int val) { type_ = Type::INT; int_val = val; return *this; }
41+
SettingValue& operator=(float val) { type_ = Type::FLOAT; float_val = val; return *this; }
42+
SettingValue& operator=(bool val) { type_ = Type::BOOL; bool_val = val; return *this; }
43+
SettingValue& operator=(const String& val) { type_ = Type::STRING; string_val = val; return *this; }
44+
SettingValue& operator=(const char* val) { type_ = Type::STRING; string_val = val; return *this; }
45+
46+
SettingValue& operator=(const SettingValue& other) {
47+
if (this != &other) {
48+
type_ = other.type_;
49+
switch (type_) {
50+
case Type::INT: int_val = other.int_val; break;
51+
case Type::FLOAT: float_val = other.float_val; break;
52+
case Type::BOOL: bool_val = other.bool_val; break;
53+
case Type::STRING: string_val = other.string_val; break;
54+
case Type::NONE: break;
55+
}
56+
}
57+
return *this;
58+
}
59+
60+
template<typename T> bool holds() const;
61+
template<typename T> T get() const;
62+
63+
Type type() const { return type_; }
64+
65+
private:
66+
Type type_;
67+
union {
68+
int int_val;
69+
float float_val;
70+
bool bool_val;
71+
};
72+
String string_val; // Can't be in union
73+
};
74+
75+
// Template specializations for holds()
76+
template<> inline bool SettingValue::holds<int>() const { return type_ == Type::INT; }
77+
template<> inline bool SettingValue::holds<float>() const { return type_ == Type::FLOAT; }
78+
template<> inline bool SettingValue::holds<bool>() const { return type_ == Type::BOOL; }
79+
template<> inline bool SettingValue::holds<String>() const { return type_ == Type::STRING; }
80+
81+
// Template specializations for get()
82+
template<> inline int SettingValue::get<int>() const { return int_val; }
83+
template<> inline float SettingValue::get<float>() const { return float_val; }
84+
template<> inline bool SettingValue::get<bool>() const { return bool_val; }
85+
template<> inline String SettingValue::get<String>() const { return string_val; }
2086

2187
using SetSettingCallback = std::function<bool(const String&, const String&, SettingValue&)>;
2288

@@ -67,14 +133,14 @@ bool SettingController<T>::sendSettingEvent(String settingId, SettingValue setti
67133
eventMessage[FSTR_SINRICPRO_scope] = FSTR_SINRICPRO_device;
68134
event_value[FSTR_SETTING_id] = settingId;
69135

70-
if (std::holds_alternative<int>(settingValue)) {
71-
event_value[FSTR_SETTING_value] = std::get<int>(settingValue);
72-
} else if (std::holds_alternative<float>(settingValue)) {
73-
event_value[FSTR_SETTING_value] = std::get<float>(settingValue);
74-
} else if (std::holds_alternative<bool>(settingValue)) {
75-
event_value[FSTR_SETTING_value] = std::get<bool>(settingValue);
76-
} else if (std::holds_alternative<String>(settingValue)) {
77-
event_value[FSTR_SETTING_value] = std::get<String>(settingValue);
136+
if (settingValue.holds<int>()) {
137+
event_value[FSTR_SETTING_value] = settingValue.get<int>();
138+
} else if (settingValue.holds<float>()) {
139+
event_value[FSTR_SETTING_value] = settingValue.get<float>();
140+
} else if (settingValue.holds<bool>()) {
141+
event_value[FSTR_SETTING_value] = settingValue.get<bool>();
142+
} else if (settingValue.holds<String>()) {
143+
event_value[FSTR_SETTING_value] = settingValue.get<String>();
78144
}
79145

80146
return device->sendEvent(eventMessage);
@@ -112,14 +178,14 @@ bool SettingController<T>::handleSettingController(SinricProRequest &request) {
112178

113179
if (valueVariant.is<JsonObject>()) {
114180
request.response_value[FSTR_SETTING_value] = valueVariant;
115-
} else if (std::holds_alternative<int>(settingValue)) {
116-
request.response_value[FSTR_SETTING_value] = std::get<int>(settingValue);
117-
} else if (std::holds_alternative<float>(settingValue)) {
118-
request.response_value[FSTR_SETTING_value] = std::get<float>(settingValue);
119-
} else if (std::holds_alternative<bool>(settingValue)) {
120-
request.response_value[FSTR_SETTING_value] = std::get<bool>(settingValue);
121-
} else if (std::holds_alternative<String>(settingValue)) {
122-
request.response_value[FSTR_SETTING_value] = std::get<String>(settingValue);
181+
} else if (settingValue.holds<int>()) {
182+
request.response_value[FSTR_SETTING_value] = settingValue.get<int>();
183+
} else if (settingValue.holds<float>()) {
184+
request.response_value[FSTR_SETTING_value] = settingValue.get<float>();
185+
} else if (settingValue.holds<bool>()) {
186+
request.response_value[FSTR_SETTING_value] = settingValue.get<bool>();
187+
} else if (settingValue.holds<String>()) {
188+
request.response_value[FSTR_SETTING_value] = settingValue.get<String>();
123189
}
124190

125191
return success;

src/SinricProDebug.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@
1616
#define SINRICPRO_NO_SERIAL_PRINTF
1717
#endif
1818

19+
/**
20+
* @brief Buffer size for SINRICPRO_PRINTF output
21+
*
22+
* Define SINRICPRO_PRINTF_BUFFER_SIZE before including SinricPro headers
23+
* to customize the buffer size for memory-constrained boards.
24+
* Default is 256 bytes.
25+
*/
26+
#ifndef SINRICPRO_PRINTF_BUFFER_SIZE
27+
#define SINRICPRO_PRINTF_BUFFER_SIZE 256
28+
#endif
29+
1930
/**
2031
* @brief Portable printf function that works on all Arduino boards
2132
*
@@ -26,7 +37,7 @@
2637
* @param ... variable arguments
2738
*/
2839
inline void SINRICPRO_PRINTF(const char* format, ...) {
29-
char buf[256];
40+
char buf[SINRICPRO_PRINTF_BUFFER_SIZE];
3041
va_list args;
3142
va_start(args, format);
3243
vsnprintf(buf, sizeof(buf), format, args);
@@ -39,7 +50,7 @@ inline void SINRICPRO_PRINTF(const char* format, ...) {
3950
#ifdef SINRICPRO_NO_SERIAL_PRINTF
4051
// For boards without printf, use portable version
4152
#define DEBUG_SINRIC(...) do { \
42-
char _dbg_buf[256]; \
53+
char _dbg_buf[SINRICPRO_PRINTF_BUFFER_SIZE]; \
4354
snprintf(_dbg_buf, sizeof(_dbg_buf), __VA_ARGS__); \
4455
DEBUG_ESP_PORT.print(_dbg_buf); \
4556
} while(0)

src/SinricProSignature.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ String HMACbase64(const String &message, const String &key) {
5353
(const uint8_t*)message.c_str(), message.length(),
5454
hmacResult
5555
);
56+
#else
57+
#error "Unsupported platform: No HMAC-SHA256 implementation available. Please add support for your platform."
5658
#endif
5759

5860
// Base64 encode the HMAC result

src/SinricProWebsocket.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ void WebsocketListener::setExtraHeaders() {
112112
#endif
113113

114114
#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_UNOWIFIR4) || defined(ARDUINO_MINIMA)
115-
// WiFiNINA and WiFiS3 return byte array, format as string
115+
// WiFiNINA and WiFiS3 return MAC address as byte array in network order (LSB first).
116+
// mac[0] = LSB, mac[5] = MSB. We format it in standard notation (MSB:...:LSB).
117+
// This matches the format returned by ESP8266/ESP32 WiFi.macAddress() string.
116118
auto formatMacAddress = []() -> String {
117119
byte mac[6];
118120
WiFi.macAddress(mac);

0 commit comments

Comments
 (0)