| Force resend | " +
@@ -1228,6 +1245,7 @@ void handleInfo(void) {
"General"
"Hostname: " + String(Hostname) + " "
"IP address: " + WiFi.localIP().toString() + " "
+ "MAC address: " + WiFi.macAddress() + " "
"Booted: " + timeSince(1) + " " +
"Version: " _MY_VERSION_ " "
"Built: " __DATE__
@@ -1258,9 +1276,9 @@ void handleInfo(void) {
"Last IR Received: " + lastIrReceived +
" (" + timeSince(lastIrReceivedTime) + ") "
#endif // IR_RX
- "Duplicate Wifi networks: " +
+ "Duplicate " D_STR_WIFI " networks: " +
String(HIDE_DUPLICATE_NETWORKS ? "Hide" : "Show") + " "
- "Min Wifi signal required: "
+ "Min " D_STR_WIFI " signal required: "
#ifdef MIN_SIGNAL_STRENGTH
+ String(static_cast(MIN_SIGNAL_STRENGTH)) +
#else // MIN_SIGNAL_STRENGTH
@@ -1269,9 +1287,9 @@ void handleInfo(void) {
"% "
"Serial debugging: "
#if DEBUG
- + String(isSerialGpioUsedByIr() ? "Off" : "On") +
+ + String(isSerialGpioUsedByIr() ? D_STR_OFF : D_STR_ON) +
#else // DEBUG
- "Off"
+ D_STR_OFF
#endif // DEBUG
" "
#if REPORT_VCC
@@ -1287,6 +1305,7 @@ void handleInfo(void) {
: "Disconnected " + timeSince(lastConnectedTime)) +
") "
"Disconnections: " + String(mqttDisconnectCounter - 1) + " "
+ "Max Packet Size: " + MQTT_MAX_PACKET_SIZE + " bytes "
"Client id: " + MqttClientId + " "
"Command topic(s): " + listOfCommandTopics() + " "
"Acknowledgements topic: " + MqttAck + " "
@@ -1328,6 +1347,7 @@ void handleInfo(void) {
timeElapsed(lastDiscovery.elapsed()) :
String("Never"))) +
" "
+ "Discovery topic: " + MqttDiscovery + " " +
#endif // MQTT_DISCOVERY_ENABLE
"Command topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_CMND +
'/' + kClimateTopics +
@@ -1337,7 +1357,7 @@ void handleInfo(void) {
" "
// Page footer
"
"
- "(Note: Page will refresh every 60 seconds.)"
+ "(Note: Page will refresh every 60 " D_STR_SECONDS ".)"
" ";
html += addJsReloadUrl(kUrlInfo, 60, false);
html += htmlEnd();
@@ -1399,7 +1419,7 @@ void handleClearMqtt(void) {
htmlHeader(F("Clearing saved info from MQTT"),
F("Removing all saved settings for this device from "
"MQTT.")) +
- "Device restarting. Try connecting in a few seconds. " +
+ "Device restarting. Try connecting in a few " D_STR_SECONDS ". " +
addJsReloadUrl(kUrlRoot, 10, true) +
htmlEnd());
// Do the clearing.
@@ -1421,7 +1441,7 @@ void handleReset(void) {
server.send(200, "text/html",
htmlHeader(F("Reset WiFi Config"),
F("Resetting the WiFiManager config back to defaults.")) +
- "Device restarting. Try connecting in a few seconds. " +
+ "Device restarting. Try connecting in a few " D_STR_SECONDS ". " +
addJsReloadUrl(kUrlRoot, 10, true) +
htmlEnd());
// Do the reset.
@@ -1454,7 +1474,7 @@ void handleReboot() {
#endif
server.send(200, "text/html",
htmlHeader(F("Device restarting.")) +
- "Try connecting in a few seconds. " +
+ "Try connecting in a few " D_STR_SECONDS ". " +
addJsReloadUrl(kUrlRoot, kRebootTime, true) +
htmlEnd());
doRestart("Reboot requested");
@@ -1516,6 +1536,23 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType,
// Lastly, it should never exceed the maximum "normal" size.
stateSize = std::min(stateSize, kFujitsuAcStateLength);
break;
+ case HITACHI_AC3:
+ // HitachiAc3 has two distinct & different size states, so make a best
+ // guess which one we are being presented with based on the number of
+ // hexadecimal digits provided. i.e. Zero-pad if you need to to get
+ // the correct length/byte size.
+ stateSize = inputLength / 2; // Every two hex chars is a byte.
+ // Use at least the minimum size.
+ stateSize = std::max(stateSize,
+ (uint16_t) (kHitachiAc3MinStateLength));
+ // If we think it isn't a "short" message.
+ if (stateSize > kHitachiAc3MinStateLength)
+ // Then it probably the "normal" size.
+ stateSize = std::max(stateSize,
+ (uint16_t) (kHitachiAc3StateLength));
+ // Lastly, it should never exceed the maximum "normal" size.
+ stateSize = std::min(stateSize, kHitachiAc3StateLength);
+ break;
case MWM:
// MWM has variable size states, so make a best guess
// which one we are being presented with based on the number of
@@ -1993,7 +2030,8 @@ void setup_wifi(void) {
if (!wifiManager.autoConnect())
// Reboot. A.k.a. "Have you tried turning it Off and On again?"
- doRestart("Wifi failed to connect and hit timeout. Rebooting...", true);
+ doRestart(D_STR_WIFI " failed to connect and hit timeout. Rebooting...",
+ true);
#if MQTT_ENABLE
strncpy(MqttServer, custom_mqtt_server.getValue(), kHostnameLength);
@@ -2033,6 +2071,8 @@ void init_vars(void) {
// Sub-topic for the climate stat topics.
#if MQTT_DISCOVERY_ENABLE
MqttDiscovery = "homeassistant/climate/" + String(Hostname) + "/config";
+ MqttUniqueId = WiFi.macAddress();
+ MqttUniqueId.replace(":", "");
#endif // MQTT_DISCOVERY_ENABLE
MqttHAName = String(Hostname) + "_aircon";
// Create a unique MQTT client id.
@@ -2163,7 +2203,8 @@ void setup(void) {
server.send(200, "text/html",
htmlHeader(F("Updating firmware")) +
" "
- "Warning! Don't power off the device for 60 seconds!"
+ "Warning! Don't " D_STR_POWER " " D_STR_OFF " the device for "
+ "60 " D_STR_SECONDS "!"
"The firmware is uploading and will try to flash itself. "
"It is important to not interrupt the process. "
"The firmware upload seems to have " +
@@ -2531,7 +2572,16 @@ void sendMQTTDiscovery(const char *topic) {
"\"swing_mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_SWINGV "\","
"\"swing_modes\":[\"" D_STR_OFF "\",\"" D_STR_AUTO "\",\"" D_STR_HIGHEST
"\",\"" D_STR_HIGH "\",\"" D_STR_MIDDLE "\",\""
- D_STR_LOW "\",\"" D_STR_LOWEST "\"]"
+ D_STR_LOW "\",\"" D_STR_LOWEST "\"],"
+ "\"uniq_id\":\"" + MqttUniqueId + "\","
+ "\"device\":{"
+ "\"identifiers\":[\"" + MqttUniqueId + "\"],"
+ "\"connections\":[[\"mac\",\"" + WiFi.macAddress() + "\"]],"
+ "\"manufacturer\":\"IRremoteESP8266\","
+ "\"model\":\"IRMQTTServer\","
+ "\"name\":\"" + Hostname + "\","
+ "\"sw_version\":\"" _MY_VERSION_ "\""
+ "}"
"}").c_str(), true)) {
mqttLog("MQTT climate discovery successful sent.");
hasDiscoveryBeenSent = true;
@@ -2738,12 +2788,12 @@ bool sendIRCode(IRsend *irsend, decode_type_t const ir_type,
} else {
debug("Failed to send IR Message:");
}
- debug("Type:");
+ debug(D_STR_PROTOCOL ": ");
debug(String(ir_type).c_str());
// For "long" codes we basically repeat what we got.
if (hasACState(ir_type) || ir_type == PRONTO || ir_type == RAW ||
ir_type == GLOBALCACHE) {
- debug("Code: ");
+ debug(D_STR_CODE ": ");
debug(code_str);
// Confirm what we were asked to send was sent.
#if MQTT_ENABLE
@@ -2762,9 +2812,9 @@ bool sendIRCode(IRsend *irsend, decode_type_t const ir_type,
}
#endif // MQTT_ENABLE
} else { // For "short" codes, we break it down a bit more before we report.
- debug(("Code: 0x" + uint64ToString(code, 16)).c_str());
- debug(("Bits: " + String(bits)).c_str());
- debug(("Repeats: " + String(repeat)).c_str());
+ debug((D_STR_CODE ": 0x" + uint64ToString(code, 16)).c_str());
+ debug((D_STR_BITS ": " + String(bits)).c_str());
+ debug((D_STR_REPEAT ": " + String(repeat)).c_str());
#if MQTT_ENABLE
if (success) {
mqtt_client.publish(MqttAck.c_str(), (String(ir_type) +
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRMQTTServer/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRMQTTServer/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/IRMQTTServer/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266-2.7.6/examples/IRServer/IRServer.ino
similarity index 95%
rename from lib/IRremoteESP8266-2.7.4/examples/IRServer/IRServer.ino
rename to lib/IRremoteESP8266-2.7.6/examples/IRServer/IRServer.ino
index 96fad95d2..92bcd0302 100644
--- a/lib/IRremoteESP8266-2.7.4/examples/IRServer/IRServer.ino
+++ b/lib/IRremoteESP8266-2.7.6/examples/IRServer/IRServer.ino
@@ -65,7 +65,10 @@ IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message.
void handleRoot() {
server.send(200, "text/html",
"" \
- " " HOSTNAME " Demo" \
+ "" HOSTNAME " Demo " \
+ "" \
+ "" \
"" \
"Hello from " HOSTNAME ", you can send NEC encoded IR" \
"signals from here!" \
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRServer/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRServer/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRServer/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/IRServer/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDemo/IRrecvDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRrecvDemo/IRrecvDemo.ino
rename to lib/IRremoteESP8266-2.7.6/examples/IRrecvDemo/IRrecvDemo.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDemo/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRrecvDemo/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/IRrecvDemo/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDump/IRrecvDump.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRrecvDump/IRrecvDump.ino
rename to lib/IRremoteESP8266-2.7.6/examples/IRrecvDump/IRrecvDump.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDump/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRrecvDump/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/IRrecvDump/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDumpV2/IRrecvDumpV2.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRrecvDumpV2/IRrecvDumpV2.ino
rename to lib/IRremoteESP8266-2.7.6/examples/IRrecvDumpV2/IRrecvDumpV2.ino
diff --git a/lib/IRremoteESP8266-2.7.6/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDumpV2/platformio.ini
new file mode 100644
index 000000000..62fa06d3a
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/examples/IRrecvDumpV2/platformio.ini
@@ -0,0 +1,52 @@
+[platformio]
+src_dir = .
+
+[env]
+; Default platform
+platform = espressif8266
+; Default board
+board = nodemcuv2
+framework = arduino
+lib_extra_dirs = ../../
+lib_ldf_mode = deep+
+lib_ignore = examples
+build_flags = ; -D_IR_LOCALE_=en-AU
+
+[env:nodemcuv2]
+board = nodemcuv2
+; build_flags = -D_IR_LOCALE_=en-AU
+
+[env:esp32dev]
+platform = espressif32
+board = esp32dev
+; build_flags = -D_IR_LOCALE_=en-AU
+
+[env:de-CH]
+build_flags = -D_IR_LOCALE_=de-CH ; German (Swiss)
+
+[env:de-DE]
+build_flags = -D_IR_LOCALE_=de-DE ; German
+
+[env:en-AU]
+build_flags = -D_IR_LOCALE_=en-AU ; English (Australian) (Default)
+
+[env:en-IE]
+build_flags = -D_IR_LOCALE_=en-IE ; English (Irish)
+
+[env:en-UK]
+build_flags = -D_IR_LOCALE_=en-UK ; English (UK)
+
+[env:en-US]
+build_flags = -D_IR_LOCALE_=en-US ; English (Simplified) (USA)
+
+[env:es-ES]
+build_flags = -D_IR_LOCALE_=es-ES ; Spanish
+
+[env:fr-FR]
+build_flags = -D_IR_LOCALE_=fr-FR ; French
+
+[env:it-IT]
+build_flags = -D_IR_LOCALE_=it-IT ; Italian
+
+[env:zh-CN]
+build_flags = -D_IR_LOCALE_=zh-CN ; Chinese (Simplified)
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266-2.7.6/examples/IRsendDemo/IRsendDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRsendDemo/IRsendDemo.ino
rename to lib/IRremoteESP8266-2.7.6/examples/IRsendDemo/IRsendDemo.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRsendDemo/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRsendDemo/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/IRsendDemo/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266-2.7.6/examples/IRsendProntoDemo/IRsendProntoDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRsendProntoDemo/IRsendProntoDemo.ino
rename to lib/IRremoteESP8266-2.7.6/examples/IRsendProntoDemo/IRsendProntoDemo.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/IRsendProntoDemo/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/IRsendProntoDemo/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/IRsendProntoDemo/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266-2.7.6/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
rename to lib/IRremoteESP8266-2.7.6/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/JVCPanasonicSendDemo/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/JVCPanasonicSendDemo/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/JVCPanasonicSendDemo/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266-2.7.6/examples/LGACSend/LGACSend.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/LGACSend/LGACSend.ino
rename to lib/IRremoteESP8266-2.7.6/examples/LGACSend/LGACSend.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/LGACSend/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/LGACSend/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/LGACSend/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/SmartIRRepeater/SmartIRRepeater.ino b/lib/IRremoteESP8266-2.7.6/examples/SmartIRRepeater/SmartIRRepeater.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/SmartIRRepeater/SmartIRRepeater.ino
rename to lib/IRremoteESP8266-2.7.6/examples/SmartIRRepeater/SmartIRRepeater.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/SmartIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/SmartIRRepeater/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/SmartIRRepeater/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/SmartIRRepeater/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnArgoAC/TurnOnArgoAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnArgoAC/TurnOnArgoAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnArgoAC/TurnOnArgoAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnArgoAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnArgoAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnArgoAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnDaikinAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnDaikinAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnDaikinAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnFujitsuAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnFujitsuAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnFujitsuAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.6/examples/TurnOnGreeAC/TurnOnGreeAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnGreeAC/TurnOnGreeAC.ino
new file mode 100644
index 000000000..64c857f3d
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/examples/TurnOnGreeAC/TurnOnGreeAC.ino
@@ -0,0 +1,77 @@
+/* Copyright 2016, 2018 David Conran
+* Copyright 2020 Sadid Rafsun Tulon
+*
+* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
+* as specified by kIrLed below.
+*
+* TL;DR: The IR LED needs to be driven by a transistor for a good result.
+*
+* Suggested circuit:
+* https://github.com/crankyoldgit/IRremoteESP8266/wiki#ir-sending
+*
+* Common mistakes & tips:
+* * Don't just connect the IR LED directly to the pin, it won't
+* have enough current to drive the IR LED effectively.
+* * Make sure you have the IR LED polarity correct.
+* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
+* * Typical digital camera/phones can be used to see if the IR LED is flashed.
+* Replace the IR LED with a normal LED if you don't have a digital camera
+* when debugging.
+* * Avoid using the following pins unless you really know what you are doing:
+* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
+* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
+* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
+* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
+* for your first time. e.g. ESP-12 etc.
+*/
+#include
+#include
+#include
+#include
+
+const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
+IRGreeAC ac(kIrLed); // Set the GPIO to be used for sending messages.
+
+void printState() {
+ // Display the settings.
+ Serial.println("GREE A/C remote is in the following state:");
+ Serial.printf(" %s\n", ac.toString().c_str());
+ // Display the encoded IR sequence.
+ unsigned char* ir_code = ac.getRaw();
+ Serial.print("IR Code: 0x");
+ for (uint8_t i = 0; i < kGreeStateLength; i++)
+ Serial.printf("%02X", ir_code[i]);
+ Serial.println();
+}
+
+void setup() {
+ ac.begin();
+ Serial.begin(115200);
+ delay(200);
+
+ // Set up what we want to send. See ir_Gree.cpp for all the options.
+ // Most things default to off.
+ Serial.println("Default state of the remote.");
+ printState();
+ Serial.println("Setting desired state for A/C.");
+ ac.on();
+ ac.setFan(1);
+ // kGreeAuto, kGreeDry, kGreeCool, kGreeFan, kGreeHeat
+ ac.setMode(kGreeCool);
+ ac.setTemp(20); // 16-30C
+ ac.setSwingVertical(true, kGreeSwingAuto);
+ ac.setXFan(false);
+ ac.setLight(false);
+ ac.setSleep(false);
+ ac.setTurbo(false);
+}
+
+void loop() {
+ // Now send the IR signal.
+#if SEND_GREE
+ Serial.println("Sending IR command to A/C ...");
+ ac.send();
+#endif // SEND_GREE
+ printState();
+ delay(5000);
+}
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnGreeAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnKelvinatorAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnGreeAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnKelvinatorAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnKelvinatorAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiHeavyAc/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiHeavyAc/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnPanasonicAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnMitsubishiHeavyAc/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnPanasonicAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnToshibaAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnPanasonicAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnToshibaAC/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnTrotecAC/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnToshibaAC/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266-2.7.6/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
rename to lib/IRremoteESP8266-2.7.6/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
diff --git a/lib/IRremoteESP8266-2.7.6/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/TurnOnTrotecAC/platformio.ini
new file mode 100644
index 000000000..e6f6320da
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/examples/TurnOnTrotecAC/platformio.ini
@@ -0,0 +1,17 @@
+[platformio]
+src_dir = .
+
+[env]
+lib_extra_dirs = ../../
+lib_ldf_mode = deep+
+lib_ignore = examples
+framework = arduino
+build_flags = ; -D_IR_LOCALE_=en-AU
+
+[env:nodemcuv2]
+platform = espressif8266
+board = nodemcuv2
+
+[env:esp32dev]
+platform = espressif32
+board = esp32dev
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/README.md b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/README.md
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/README.md
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/README.md
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/Web-AC-control.ino b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/Web-AC-control.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/Web-AC-control.ino
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/Web-AC-control.ino
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/platformio.ini b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/platformio.ini
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/platformio.ini
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/platformio.ini
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/printscreen.png b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/printscreen.png
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/printscreen.png
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/printscreen.png
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/favicon.ico b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/favicon.ico
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/favicon.ico
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/favicon.ico
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_1_off.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_1_off.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_1_off.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_1_off.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_1_on.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_1_on.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_1_on.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_1_on.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_2_off.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_2_off.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_2_off.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_2_off.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_2_on.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_2_on.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_2_on.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_2_on.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_3_off.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_3_off.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_3_off.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_3_off.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_3_on.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_3_on.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_3_on.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_3_on.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_4_off.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_4_off.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_4_off.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_4_off.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_4_on.svg b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_4_on.svg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/level_4_on.svg
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/level_4_on.svg
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/ui.html b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/ui.html
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/ui.html
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/ui.html
diff --git a/lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/ui.js b/lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/ui.js
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/examples/Web-AC-control/upload/ui.js
rename to lib/IRremoteESP8266-2.7.6/examples/Web-AC-control/upload/ui.js
diff --git a/lib/IRremoteESP8266-2.7.4/keywords.txt b/lib/IRremoteESP8266-2.7.6/keywords.txt
similarity index 94%
rename from lib/IRremoteESP8266-2.7.4/keywords.txt
rename to lib/IRremoteESP8266-2.7.6/keywords.txt
index 077c0bc74..7b9e356af 100644
--- a/lib/IRremoteESP8266-2.7.4/keywords.txt
+++ b/lib/IRremoteESP8266-2.7.6/keywords.txt
@@ -29,6 +29,7 @@ IRDaikin160 KEYWORD1
IRDaikin176 KEYWORD1
IRDaikin2 KEYWORD1
IRDaikin216 KEYWORD1
+IRDaikin64 KEYWORD1
IRDaikinESP KEYWORD1
IRElectraAc KEYWORD1
IRFujitsuAC KEYWORD1
@@ -37,6 +38,8 @@ IRGreeAC KEYWORD1
IRHaierAC KEYWORD1
IRHaierACYRW02 KEYWORD1
IRHitachiAc KEYWORD1
+IRHitachiAc1 KEYWORD1
+IRHitachiAc3 KEYWORD1
IRHitachiAc424 KEYWORD1
IRKelvinatorAC KEYWORD1
IRLgAc KEYWORD1
@@ -66,6 +69,7 @@ decode_type_t KEYWORD1
fanspeed_t KEYWORD1
fujitsu_ac_remote_model_t KEYWORD1
gree_ac_remote_model_t KEYWORD1
+hitachi_ac1_remote_model_t KEYWORD1
irparams_t KEYWORD1
lg_ac_remote_model_t KEYWORD1
match_result_t KEYWORD1
@@ -141,7 +145,9 @@ daikin160 KEYWORD2
daikin176 KEYWORD2
daikin2 KEYWORD2
daikin216 KEYWORD2
+daikin64 KEYWORD2
decode KEYWORD2
+decodeAirwell KEYWORD2
decodeAiwaRCT501 KEYWORD2
decodeAmcor KEYWORD2
decodeArgo KEYWORD2
@@ -155,6 +161,7 @@ decodeDaikin160 KEYWORD2
decodeDaikin176 KEYWORD2
decodeDaikin2 KEYWORD2
decodeDaikin216 KEYWORD2
+decodeDaikin64 KEYWORD2
decodeDenon KEYWORD2
decodeElectraAC KEYWORD2
decodeEpson KEYWORD2
@@ -166,6 +173,7 @@ decodeHaierAC KEYWORD2
decodeHaierACYRW02 KEYWORD2
decodeHash KEYWORD2
decodeHitachiAC KEYWORD2
+decodeHitachiAc3 KEYWORD2
decodeHitachiAc424 KEYWORD2
decodeInax KEYWORD2
decodeJVC KEYWORD2
@@ -200,6 +208,7 @@ decodeSanyoLC7461 KEYWORD2
decodeSharp KEYWORD2
decodeSharpAc KEYWORD2
decodeSony KEYWORD2
+decodeSymphony KEYWORD2
decodeTeco KEYWORD2
decodeToState KEYWORD2
decodeToshibaAC KEYWORD2
@@ -243,6 +252,7 @@ get3D KEYWORD2
get8CHeat KEYWORD2
getBeep KEYWORD2
getBit KEYWORD2
+getBreeze KEYWORD2
getBufSize KEYWORD2
getButton KEYWORD2
getClean KEYWORD2
@@ -280,15 +290,18 @@ getMode KEYWORD2
getMold KEYWORD2
getNight KEYWORD2
getOffTime KEYWORD2
+getOffTimeEnabled KEYWORD2
getOffTimer KEYWORD2
getOffTimerEnabled KEYWORD2
getOnTime KEYWORD2
+getOnTimeEnabled KEYWORD2
getOnTimer KEYWORD2
getOnTimerEnabled KEYWORD2
getOutsideQuiet KEYWORD2
getPower KEYWORD2
getPowerToggle KEYWORD2
getPowerful KEYWORD2
+getPreviousPower KEYWORD2
getPurify KEYWORD2
getQuiet KEYWORD2
getRClevel KEYWORD2
@@ -309,6 +322,7 @@ getSuper KEYWORD2
getSwing KEYWORD2
getSwingH KEYWORD2
getSwingHorizontal KEYWORD2
+getSwingToggle KEYWORD2
getSwingV KEYWORD2
getSwingVToggle KEYWORD2
getSwingVertical KEYWORD2
@@ -336,8 +350,10 @@ haier KEYWORD2
haierYrwo2 KEYWORD2
handleSpecialState KEYWORD2
hasACState KEYWORD2
+hasInvertedStates KEYWORD2
hasStateChanged KEYWORD2
hitachi KEYWORD2
+hitachi1 KEYWORD2
hitachi424 KEYWORD2
htmlEscape KEYWORD2
initState KEYWORD2
@@ -364,6 +380,7 @@ matchAtLeast KEYWORD2
matchBytes KEYWORD2
matchData KEYWORD2
matchGeneric KEYWORD2
+matchManchester KEYWORD2
matchMark KEYWORD2
matchSpace KEYWORD2
midea KEYWORD2
@@ -394,6 +411,7 @@ reverseBits KEYWORD2
samsung KEYWORD2
send KEYWORD2
sendAc KEYWORD2
+sendAirwell KEYWORD2
sendAiwaRCT501 KEYWORD2
sendAmcor KEYWORD2
sendArgo KEYWORD2
@@ -407,6 +425,7 @@ sendDaikin160 KEYWORD2
sendDaikin176 KEYWORD2
sendDaikin2 KEYWORD2
sendDaikin216 KEYWORD2
+sendDaikin64 KEYWORD2
sendData KEYWORD2
sendDenon KEYWORD2
sendElectraAC KEYWORD2
@@ -423,6 +442,7 @@ sendHaierACYRW02 KEYWORD2
sendHitachiAC KEYWORD2
sendHitachiAC1 KEYWORD2
sendHitachiAC2 KEYWORD2
+sendHitachiAc3 KEYWORD2
sendHitachiAc424 KEYWORD2
sendInax KEYWORD2
sendJVC KEYWORD2
@@ -434,6 +454,8 @@ sendLegoPf KEYWORD2
sendLutron KEYWORD2
sendMWM KEYWORD2
sendMagiQuest KEYWORD2
+sendManchester KEYWORD2
+sendManchesterData KEYWORD2
sendMidea KEYWORD2
sendMitsubishi KEYWORD2
sendMitsubishi112 KEYWORD2
@@ -466,6 +488,7 @@ sendSharpRaw KEYWORD2
sendSherwood KEYWORD2
sendSony KEYWORD2
sendSony38 KEYWORD2
+sendSymphony KEYWORD2
sendTcl112Ac KEYWORD2
sendTeco KEYWORD2
sendToshibaAC KEYWORD2
@@ -480,6 +503,7 @@ setAuto KEYWORD2
setBeep KEYWORD2
setBit KEYWORD2
setBits KEYWORD2
+setBreeze KEYWORD2
setButton KEYWORD2
setClean KEYWORD2
setClock KEYWORD2
@@ -516,9 +540,13 @@ setMode KEYWORD2
setModel KEYWORD2
setMold KEYWORD2
setNight KEYWORD2
+setOffTime KEYWORD2
+setOffTimeEnabled KEYWORD2
setOffTimer KEYWORD2
setOffTimerActive KEYWORD2
setOffTimerEnabled KEYWORD2
+setOnTime KEYWORD2
+setOnTimeEnabled KEYWORD2
setOnTimer KEYWORD2
setOnTimerActive KEYWORD2
setOnTimerEnabled KEYWORD2
@@ -526,6 +554,7 @@ setOutsideQuiet KEYWORD2
setPower KEYWORD2
setPowerToggle KEYWORD2
setPowerful KEYWORD2
+setPreviousPower KEYWORD2
setPurify KEYWORD2
setQuiet KEYWORD2
setRaw KEYWORD2
@@ -543,6 +572,7 @@ setSuper KEYWORD2
setSwing KEYWORD2
setSwingH KEYWORD2
setSwingHorizontal KEYWORD2
+setSwingToggle KEYWORD2
setSwingV KEYWORD2
setSwingVToggle KEYWORD2
setSwingVertical KEYWORD2
@@ -599,7 +629,9 @@ xorBytes KEYWORD2
# Constants (LITERAL1)
#######################################
+*kAllProtocolNamesStr LITERAL1
// LITERAL1
+AIRWELL LITERAL1
AIWA_RC_T501 LITERAL1
AIWA_RC_T501_BITS LITERAL1
AKB75215403 LITERAL1
@@ -644,6 +676,7 @@ DAIKIN160 LITERAL1
DAIKIN176 LITERAL1
DAIKIN2 LITERAL1
DAIKIN216 LITERAL1
+DAIKIN64 LITERAL1
DAIKIN_AUTO LITERAL1
DAIKIN_COMMAND_LENGTH LITERAL1
DAIKIN_COOL LITERAL1
@@ -657,6 +690,7 @@ DAIKIN_HEAT LITERAL1
DAIKIN_MAX_TEMP LITERAL1
DAIKIN_MIN_TEMP LITERAL1
DECODE_AC LITERAL1
+DECODE_AIRWELL LITERAL1
DECODE_AIWA_RC_T501 LITERAL1
DECODE_AMCOR LITERAL1
DECODE_ARGO LITERAL1
@@ -669,6 +703,7 @@ DECODE_DAIKIN160 LITERAL1
DECODE_DAIKIN176 LITERAL1
DECODE_DAIKIN2 LITERAL1
DECODE_DAIKIN216 LITERAL1
+DECODE_DAIKIN64 LITERAL1
DECODE_DENON LITERAL1
DECODE_DISH LITERAL1
DECODE_ELECTRA_AC LITERAL1
@@ -684,6 +719,7 @@ DECODE_HASH LITERAL1
DECODE_HITACHI_AC LITERAL1
DECODE_HITACHI_AC1 LITERAL1
DECODE_HITACHI_AC2 LITERAL1
+DECODE_HITACHI_AC3 LITERAL1
DECODE_HITACHI_AC424 LITERAL1
DECODE_INAX LITERAL1
DECODE_JVC LITERAL1
@@ -719,6 +755,7 @@ DECODE_SHARP LITERAL1
DECODE_SHARP_AC LITERAL1
DECODE_SHERWOOD LITERAL1
DECODE_SONY LITERAL1
+DECODE_SYMPHONY LITERAL1
DECODE_TCL112AC LITERAL1
DECODE_TECO LITERAL1
DECODE_TOSHIBA_AC LITERAL1
@@ -855,6 +892,7 @@ HITACHI_AC1_STATE_LENGTH LITERAL1
HITACHI_AC2 LITERAL1
HITACHI_AC2_BITS LITERAL1
HITACHI_AC2_STATE_LENGTH LITERAL1
+HITACHI_AC3 LITERAL1
HITACHI_AC424 LITERAL1
HITACHI_AC_BITS LITERAL1
HITACHI_AC_STATE_LENGTH LITERAL1
@@ -950,6 +988,8 @@ RC6_36_BITS LITERAL1
RC6_MODE0_BITS LITERAL1
RCMM LITERAL1
RCMM_BITS LITERAL1
+R_LT0541_HTA_A LITERAL1
+R_LT0541_HTA_B LITERAL1
SAMSUNG LITERAL1
SAMSUNG36 LITERAL1
SAMSUNG_AC LITERAL1
@@ -958,6 +998,7 @@ SANYO LITERAL1
SANYO_LC7461 LITERAL1
SANYO_LC7461_BITS LITERAL1
SANYO_SA8650B_BITS LITERAL1
+SEND_AIRWELL LITERAL1
SEND_AIWA_RC_T501 LITERAL1
SEND_AMCOR LITERAL1
SEND_ARGO LITERAL1
@@ -970,6 +1011,7 @@ SEND_DAIKIN160 LITERAL1
SEND_DAIKIN176 LITERAL1
SEND_DAIKIN2 LITERAL1
SEND_DAIKIN216 LITERAL1
+SEND_DAIKIN64 LITERAL1
SEND_DENON LITERAL1
SEND_DISH LITERAL1
SEND_ELECTRA_AC LITERAL1
@@ -984,6 +1026,7 @@ SEND_HAIER_AC_YRW02 LITERAL1
SEND_HITACHI_AC LITERAL1
SEND_HITACHI_AC1 LITERAL1
SEND_HITACHI_AC2 LITERAL1
+SEND_HITACHI_AC3 LITERAL1
SEND_HITACHI_AC424 LITERAL1
SEND_INAX LITERAL1
SEND_JVC LITERAL1
@@ -1020,6 +1063,7 @@ SEND_SHARP LITERAL1
SEND_SHARP_AC LITERAL1
SEND_SHERWOOD LITERAL1
SEND_SONY LITERAL1
+SEND_SYMPHONY LITERAL1
SEND_TCL112AC LITERAL1
SEND_TECO LITERAL1
SEND_TOSHIBA_AC LITERAL1
@@ -1037,6 +1081,7 @@ SONY_12_BITS LITERAL1
SONY_15_BITS LITERAL1
SONY_20_BITS LITERAL1
SONY_38K LITERAL1
+SYMPHONY LITERAL1
TCL112AC LITERAL1
TECO LITERAL1
TIMEOUT_MS LITERAL1
@@ -1076,6 +1121,13 @@ k3DStr LITERAL1
k6thSenseStr LITERAL1
k8CHeatStr LITERAL1
kAirFlowStr LITERAL1
+kAirwellBits LITERAL1
+kAirwellFooterMark LITERAL1
+kAirwellHalfClockPeriod LITERAL1
+kAirwellHdrMark LITERAL1
+kAirwellHdrSpace LITERAL1
+kAirwellMinRepeats LITERAL1
+kAirwellOverhead LITERAL1
kAiwaRcT501Bits LITERAL1
kAiwaRcT501MinRepeats LITERAL1
kAiwaRcT501PostBits LITERAL1
@@ -1498,6 +1550,53 @@ kDaikin2SwingVLow LITERAL1
kDaikin2SwingVSwing LITERAL1
kDaikin2Tolerance LITERAL1
kDaikin2ZeroSpace LITERAL1
+kDaikin64BitMark LITERAL1
+kDaikin64Bits LITERAL1
+kDaikin64ChecksumOffset LITERAL1
+kDaikin64ChecksumSize LITERAL1
+kDaikin64ClockHoursSize LITERAL1
+kDaikin64ClockMinsSize LITERAL1
+kDaikin64ClockOffset LITERAL1
+kDaikin64ClockSize LITERAL1
+kDaikin64Cool LITERAL1
+kDaikin64DefaultRepeat LITERAL1
+kDaikin64Dry LITERAL1
+kDaikin64Fan LITERAL1
+kDaikin64FanAuto LITERAL1
+kDaikin64FanHigh LITERAL1
+kDaikin64FanLow LITERAL1
+kDaikin64FanMed LITERAL1
+kDaikin64FanOffset LITERAL1
+kDaikin64FanQuiet LITERAL1
+kDaikin64FanSize LITERAL1
+kDaikin64FanTurbo LITERAL1
+kDaikin64Freq LITERAL1
+kDaikin64Gap LITERAL1
+kDaikin64HdrMark LITERAL1
+kDaikin64HdrSpace LITERAL1
+kDaikin64KnownGoodState LITERAL1
+kDaikin64LdrMark LITERAL1
+kDaikin64LdrSpace LITERAL1
+kDaikin64MaxTemp LITERAL1
+kDaikin64MinTemp LITERAL1
+kDaikin64ModeOffset LITERAL1
+kDaikin64ModeSize LITERAL1
+kDaikin64OffTimeEnableBit LITERAL1
+kDaikin64OffTimeHalfHourBit LITERAL1
+kDaikin64OffTimeOffset LITERAL1
+kDaikin64OffTimeSize LITERAL1
+kDaikin64OnTimeEnableBit LITERAL1
+kDaikin64OnTimeHalfHourBit LITERAL1
+kDaikin64OnTimeOffset LITERAL1
+kDaikin64OnTimeSize LITERAL1
+kDaikin64OneSpace LITERAL1
+kDaikin64Overhead LITERAL1
+kDaikin64PowerToggleBit LITERAL1
+kDaikin64SleepBit LITERAL1
+kDaikin64SwingVBit LITERAL1
+kDaikin64TempOffset LITERAL1
+kDaikin64TempSize LITERAL1
+kDaikin64ZeroSpace LITERAL1
kDaikinAuto LITERAL1
kDaikinBeepLoud LITERAL1
kDaikinBeepOff LITERAL1
@@ -1955,12 +2054,67 @@ kHighNibble LITERAL1
kHighStr LITERAL1
kHighest LITERAL1
kHighestStr LITERAL1
+kHitachiAc1Auto LITERAL1
kHitachiAc1Bits LITERAL1
+kHitachiAc1ChecksumStartByte LITERAL1
+kHitachiAc1Cool LITERAL1
+kHitachiAc1Dry LITERAL1
+kHitachiAc1Fan LITERAL1
+kHitachiAc1FanAuto LITERAL1
+kHitachiAc1FanByte LITERAL1
+kHitachiAc1FanHigh LITERAL1
+kHitachiAc1FanLow LITERAL1
+kHitachiAc1FanMed LITERAL1
+kHitachiAc1FanOffset LITERAL1
+kHitachiAc1FanSize LITERAL1
kHitachiAc1HdrMark LITERAL1
kHitachiAc1HdrSpace LITERAL1
+kHitachiAc1Heat LITERAL1
+kHitachiAc1ModeByte LITERAL1
+kHitachiAc1ModeOffset LITERAL1
+kHitachiAc1ModeSize LITERAL1
+kHitachiAc1ModelByte LITERAL1
+kHitachiAc1ModelOffset LITERAL1
+kHitachiAc1ModelSize LITERAL1
+kHitachiAc1Model_A LITERAL1
+kHitachiAc1Model_B LITERAL1
+kHitachiAc1OffTimerHighByte LITERAL1
+kHitachiAc1OffTimerLowByte LITERAL1
+kHitachiAc1OnTimerHighByte LITERAL1
+kHitachiAc1OnTimerLowByte LITERAL1
+kHitachiAc1PowerByte LITERAL1
+kHitachiAc1PowerOffset LITERAL1
+kHitachiAc1PowerToggleOffset LITERAL1
+kHitachiAc1Sleep1 LITERAL1
+kHitachiAc1Sleep2 LITERAL1
+kHitachiAc1Sleep3 LITERAL1
+kHitachiAc1Sleep4 LITERAL1
+kHitachiAc1SleepByte LITERAL1
+kHitachiAc1SleepOff LITERAL1
+kHitachiAc1SleepOffset LITERAL1
+kHitachiAc1SleepSize LITERAL1
kHitachiAc1StateLength LITERAL1
+kHitachiAc1SwingByte LITERAL1
+kHitachiAc1SwingHOffset LITERAL1
+kHitachiAc1SwingToggleOffset LITERAL1
+kHitachiAc1SwingVOffset LITERAL1
+kHitachiAc1TempAuto LITERAL1
+kHitachiAc1TempByte LITERAL1
+kHitachiAc1TempDelta LITERAL1
+kHitachiAc1TempOffset LITERAL1
+kHitachiAc1TempSize LITERAL1
+kHitachiAc1TimerSize LITERAL1
kHitachiAc2Bits LITERAL1
kHitachiAc2StateLength LITERAL1
+kHitachiAc3BitMark LITERAL1
+kHitachiAc3Bits LITERAL1
+kHitachiAc3HdrMark LITERAL1
+kHitachiAc3HdrSpace LITERAL1
+kHitachiAc3MinBits LITERAL1
+kHitachiAc3MinStateLength LITERAL1
+kHitachiAc3OneSpace LITERAL1
+kHitachiAc3StateLength LITERAL1
+kHitachiAc3ZeroSpace LITERAL1
kHitachiAc424BitMark LITERAL1
kHitachiAc424Bits LITERAL1
kHitachiAc424ButtonByte LITERAL1
@@ -2709,6 +2863,7 @@ kPioneerZeroSpaceTicks LITERAL1
kPowerStr LITERAL1
kPowerToggleStr LITERAL1
kPowerfulStr LITERAL1
+kPreviousPowerStr LITERAL1
kProntoDataOffset LITERAL1
kProntoFreqFactor LITERAL1
kProntoFreqOffset LITERAL1
@@ -2770,12 +2925,14 @@ kRightMaxStr LITERAL1
kRightStr LITERAL1
kRoomStr LITERAL1
kSamsung36Bits LITERAL1
-kSamsungACSectionLength LITERAL1
kSamsungAcAuto LITERAL1
kSamsungAcAutoTemp LITERAL1
kSamsungAcBeepOffset LITERAL1
kSamsungAcBitMark LITERAL1
kSamsungAcBits LITERAL1
+kSamsungAcBreezeOffset LITERAL1
+kSamsungAcBreezeOn LITERAL1
+kSamsungAcBreezeSize LITERAL1
kSamsungAcClean10Offset LITERAL1
kSamsungAcClean11Offset LITERAL1
kSamsungAcCool LITERAL1
@@ -2806,11 +2963,13 @@ kSamsungAcPower6Offset LITERAL1
kSamsungAcPower6Size LITERAL1
kSamsungAcPowerSection LITERAL1
kSamsungAcPowerful10Offset LITERAL1
+kSamsungAcPowerful10On LITERAL1
kSamsungAcPowerful10Size LITERAL1
kSamsungAcPowerfulMask8 LITERAL1
kSamsungAcQuiet1Offset LITERAL1
kSamsungAcQuiet5Offset LITERAL1
kSamsungAcSectionGap LITERAL1
+kSamsungAcSectionLength LITERAL1
kSamsungAcSectionMark LITERAL1
kSamsungAcSectionSpace LITERAL1
kSamsungAcSections LITERAL1
@@ -2864,14 +3023,17 @@ kSensorStr LITERAL1
kSensorTempStr LITERAL1
kSetStr LITERAL1
kSharpAcAuto LITERAL1
-kSharpAcBitFanManualOffset LITERAL1
kSharpAcBitMark LITERAL1
-kSharpAcBitModeNonAutoOffset LITERAL1
kSharpAcBitPowerOffset LITERAL1
-kSharpAcBitTempManualOffset LITERAL1
+kSharpAcBitPreviousPowerOffset LITERAL1
kSharpAcBits LITERAL1
+kSharpAcButtonFan LITERAL1
+kSharpAcButtonOffset LITERAL1
+kSharpAcButtonPowerMode LITERAL1
+kSharpAcButtonSize LITERAL1
+kSharpAcButtonTemp LITERAL1
+kSharpAcByteButton LITERAL1
kSharpAcByteFan LITERAL1
-kSharpAcByteManual LITERAL1
kSharpAcByteMode LITERAL1
kSharpAcBytePower LITERAL1
kSharpAcByteTemp LITERAL1
@@ -2952,6 +3114,14 @@ kSwingStr LITERAL1
kSwingVModeStr LITERAL1
kSwingVStr LITERAL1
kSwingVToggleStr LITERAL1
+kSymphonyBits LITERAL1
+kSymphonyDefaultRepeat LITERAL1
+kSymphonyFooterGap LITERAL1
+kSymphonyFooterMark LITERAL1
+kSymphonyOneMark LITERAL1
+kSymphonyOneSpace LITERAL1
+kSymphonyZeroMark LITERAL1
+kSymphonyZeroSpace LITERAL1
kTcl112AcAuto LITERAL1
kTcl112AcBitEconoOffset LITERAL1
kTcl112AcBitHealthOffset LITERAL1
diff --git a/lib/IRremoteESP8266-2.7.4/library.json b/lib/IRremoteESP8266-2.7.6/library.json
similarity index 97%
rename from lib/IRremoteESP8266-2.7.4/library.json
rename to lib/IRremoteESP8266-2.7.6/library.json
index f135c19e7..c2780ac6c 100644
--- a/lib/IRremoteESP8266-2.7.4/library.json
+++ b/lib/IRremoteESP8266-2.7.6/library.json
@@ -1,6 +1,6 @@
{
"name": "IRremoteESP8266",
- "version": "2.7.4",
+ "version": "2.7.6",
"keywords": "infrared, ir, remote, esp8266, esp32",
"description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)",
"repository":
diff --git a/lib/IRremoteESP8266-2.7.4/library.properties b/lib/IRremoteESP8266-2.7.6/library.properties
similarity index 97%
rename from lib/IRremoteESP8266-2.7.4/library.properties
rename to lib/IRremoteESP8266-2.7.6/library.properties
index e98cd3f3b..b67edbce0 100644
--- a/lib/IRremoteESP8266-2.7.4/library.properties
+++ b/lib/IRremoteESP8266-2.7.6/library.properties
@@ -1,5 +1,5 @@
name=IRremoteESP8266
-version=2.7.4
+version=2.7.6
author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff
maintainer=David Conran, Mark Szabo, Sebastien Warin, Roi Dayan, Massimiliano Pinto
sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32)
diff --git a/lib/IRremoteESP8266-2.7.6/platformio.ini b/lib/IRremoteESP8266-2.7.6/platformio.ini
new file mode 100644
index 000000000..67dbeb606
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/platformio.ini
@@ -0,0 +1,21 @@
+[platformio]
+# Default to building IRrecvDumpV2 if not in a specific example directory.
+src_dir = examples/IRrecvDumpV2
+
+[env]
+lib_extra_dirs = .
+lib_ldf_mode = deep+
+lib_ignore = examples
+framework = arduino
+platform = espressif8266
+build_flags = ; -D_IR_LOCALE_=en-AU
+
+[env:nodemcuv2]
+board = nodemcuv2
+
+[env:d1_mini]
+board = d1_mini
+
+[env:esp32dev]
+platform = espressif32
+board = esp32dev
diff --git a/lib/IRremoteESP8266-2.7.4/pylintrc b/lib/IRremoteESP8266-2.7.6/pylintrc
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/pylintrc
rename to lib/IRremoteESP8266-2.7.6/pylintrc
diff --git a/lib/IRremoteESP8266-2.7.4/src/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.6/src/CPPLINT.cfg
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/CPPLINT.cfg
rename to lib/IRremoteESP8266-2.7.6/src/CPPLINT.cfg
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRac.cpp b/lib/IRremoteESP8266-2.7.6/src/IRac.cpp
similarity index 94%
rename from lib/IRremoteESP8266-2.7.4/src/IRac.cpp
rename to lib/IRremoteESP8266-2.7.6/src/IRac.cpp
index d3be30b80..abf450df9 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRac.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/IRac.cpp
@@ -123,6 +123,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
#if SEND_DAIKIN216
case decode_type_t::DAIKIN216:
#endif
+#if SEND_DAIKIN64
+ case decode_type_t::DAIKIN64:
+#endif
#if SEND_ELECTRA_AC
case decode_type_t::ELECTRA_AC:
#endif
@@ -144,6 +147,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
#if SEND_HITACHI_AC
case decode_type_t::HITACHI_AC:
#endif
+#if SEND_HITACHI_AC1
+ case decode_type_t::HITACHI_AC1:
+#endif
#if SEND_HITACHI_AC424
case decode_type_t::HITACHI_AC424:
#endif
@@ -461,6 +467,27 @@ void IRac::daikin216(IRDaikin216 *ac,
}
#endif // SEND_DAIKIN216
+#if SEND_DAIKIN64
+void IRac::daikin64(IRDaikin64 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const bool quiet, const bool turbo,
+ const int16_t sleep, const int16_t clock) {
+ ac->begin();
+ ac->setPowerToggle(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setTurbo(turbo);
+ ac->setQuiet(quiet);
+ ac->setSleep(sleep >= 0);
+ ac->setClock(clock);
+ ac->send();
+}
+#endif // SEND_DAIKIN64
+
#if SEND_ELECTRA_AC
void IRac::electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode,
@@ -674,6 +701,37 @@ void IRac::hitachi(IRHitachiAc *ac,
}
#endif // SEND_HITACHI_AC
+#if SEND_HITACHI_AC1
+void IRac::hitachi1(IRHitachiAc1 *ac, const hitachi_ac1_remote_model_t model,
+ const bool on, const bool power_toggle,
+ const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool swing_toggle, const int16_t sleep) {
+ ac->begin();
+ ac->setModel(model);
+ ac->setPower(on);
+ ac->setPowerToggle(power_toggle);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingV(swingv != stdAc::swingv_t::kOff);
+ ac->setSwingH(swingh != stdAc::swingh_t::kOff);
+ ac->setSwingToggle(swing_toggle);
+ ac->setSleep((sleep >= 0) ? kHitachiAc1Sleep2 : kHitachiAc1SleepOff);
+ // No Sleep setting available.
+ // No Swing(H) setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_HITACHI_AC1
+
#if SEND_HITACHI_AC424
void IRac::hitachi424(IRHitachiAc424 *ac,
const bool on, const stdAc::opmode_t mode,
@@ -999,10 +1057,11 @@ void IRac::samsung(IRSamsungAc *ac,
#if SEND_SHARP_AC
void IRac::sharp(IRSharpAc *ac,
- const bool on, const stdAc::opmode_t mode,
+ const bool on, const bool prev_power,
+ const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan) {
ac->begin();
- ac->setPower(on);
+ ac->setPower(on, prev_power);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
ac->setFan(ac->convertFan(fan));
@@ -1233,6 +1292,7 @@ stdAc::state_t IRac::handleToggles(const stdAc::state_t desired,
else
result.swingv = stdAc::swingv_t::kOff; // No change, so no toggle.
break;
+ case decode_type_t::DAIKIN64:
case decode_type_t::WHIRLPOOL_AC:
result.power = desired.power ^ prev->power;
break;
@@ -1390,6 +1450,15 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
break;
}
#endif // SEND_DAIKIN216
+#if SEND_DAIKIN64
+ case DAIKIN64:
+ {
+ IRDaikin64 ac(_pin, _inverted, _modulation);
+ daikin64(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
+ send.quiet, send.turbo, send.sleep, send.clock);
+ break;
+ }
+#endif // SEND_DAIKIN64
#if SEND_ELECTRA_AC
case ELECTRA_AC:
{
@@ -1457,6 +1526,23 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
break;
}
#endif // SEND_HITACHI_AC
+#if SEND_HITACHI_AC1
+ case HITACHI_AC1:
+ {
+ IRHitachiAc1 ac(_pin, _inverted, _modulation);
+ bool power_toggle = false;
+ bool swing_toggle = false;
+ if (prev != NULL) {
+ power_toggle = (send.power != prev->power);
+ swing_toggle = (send.swingv != prev->swingv) ||
+ (send.swingh != prev->swingh);
+ }
+ hitachi1(&ac, (hitachi_ac1_remote_model_t)send.model, send.power,
+ power_toggle, send.mode, degC, send.fanspeed, send.swingv,
+ send.swingh, swing_toggle, send.sleep);
+ break;
+ }
+#endif // SEND_HITACHI_AC1
#if SEND_HITACHI_AC424
case HITACHI_AC424:
{
@@ -1572,7 +1658,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case SHARP_AC:
{
IRSharpAc ac(_pin, _inverted, _modulation);
- sharp(&ac, send.power, send.mode, degC, send.fanspeed);
+ bool prev_power = !send.power;
+ if (prev != NULL) prev_power = prev->power;
+ sharp(&ac, send.power, prev_power, send.mode, degC, send.fanspeed);
break;
}
#endif // SEND_SHARP_AC
@@ -1796,6 +1884,11 @@ int16_t IRac::strToModel(const char *str, const int16_t def) {
return gree_ac_remote_model_t::YAW1F;
} else if (!strcasecmp(str, "YBOFB")) {
return gree_ac_remote_model_t::YBOFB;
+ // HitachiAc1 models
+ } else if (!strcasecmp(str, "R-LT0541-HTA-A")) {
+ return hitachi_ac1_remote_model_t::R_LT0541_HTA_A;
+ } else if (!strcasecmp(str, "R-LT0541-HTA-B")) {
+ return hitachi_ac1_remote_model_t::R_LT0541_HTA_B;
// Fujitsu A/C models
} else if (!strcasecmp(str, "ARRAH2E")) {
return fujitsu_ac_remote_model_t::ARRAH2E;
@@ -2008,6 +2101,13 @@ namespace IRAcUtils {
return ac.toString();
}
#endif // DECODE_DAIKIN216
+#if DECODE_DAIKIN64
+ case decode_type_t::DAIKIN64: {
+ IRDaikin64 ac(kGpioUnused);
+ ac.setRaw(result->value); // Daikin64 uses value instead of state.
+ return ac.toString();
+ }
+#endif // DECODE_DAIKIN216
#if DECODE_ELECTRA_AC
case decode_type_t::ELECTRA_AC: {
IRElectraAc ac(0);
@@ -2157,6 +2257,13 @@ namespace IRAcUtils {
return ac.toString();
}
#endif // DECODE_HITACHI_AC
+#if DECODE_HITACHI_AC1
+ case decode_type_t::HITACHI_AC1: {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setRaw(result->state);
+ return ac.toString();
+ }
+#endif // DECODE_HITACHI_AC1
#if DECODE_HITACHI_AC424
case decode_type_t::HITACHI_AC424: {
IRHitachiAc424 ac(0);
@@ -2305,6 +2412,14 @@ namespace IRAcUtils {
break;
}
#endif // DECODE_DAIKIN216
+#if DECODE_DAIKIN64
+ case decode_type_t::DAIKIN64: {
+ IRDaikin64 ac(kGpioUnused);
+ ac.setRaw(decode->value); // Uses value instead of state.
+ *result = ac.toCommon(prev);
+ break;
+ }
+#endif // DECODE_DAIKIN64
#if DECODE_ELECTRA_AC
case decode_type_t::ELECTRA_AC: {
IRElectraAc ac(kGpioUnused);
@@ -2361,6 +2476,14 @@ namespace IRAcUtils {
break;
}
#endif // (DECODE_HITACHI_AC || DECODE_HITACHI_AC2)
+#if DECODE_HITACHI_AC1
+ case decode_type_t::HITACHI_AC1: {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setRaw(decode->state);
+ *result = ac.toCommon();
+ break;
+ }
+#endif // DECODE_HITACHI_AC1
#if DECODE_HITACHI_AC424
case decode_type_t::HITACHI_AC424: {
IRHitachiAc424 ac(kGpioUnused);
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRac.h b/lib/IRremoteESP8266-2.7.6/src/IRac.h
similarity index 94%
rename from lib/IRremoteESP8266-2.7.4/src/IRac.h
rename to lib/IRremoteESP8266-2.7.6/src/IRac.h
index f38865e50..02faba36a 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRac.h
+++ b/lib/IRremoteESP8266-2.7.6/src/IRac.h
@@ -166,6 +166,14 @@ void daikin216(IRDaikin216 *ac,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo);
#endif // SEND_DAIKIN216
+#if SEND_DAIKIN64
+ void daikin64(IRDaikin64 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const bool quiet, const bool turbo,
+ const int16_t sleep = -1, const int16_t clock = -1);
+#endif // SEND_DAIKIN64
#if SEND_ELECTRA_AC
void electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode,
@@ -219,6 +227,14 @@ void electra(IRElectraAc *ac,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
#endif // SEND_HITACHI_AC
+#if SEND_HITACHI_AC1
+ void hitachi1(IRHitachiAc1 *ac, const hitachi_ac1_remote_model_t model,
+ const bool on, const bool power_toggle,
+ const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool swing_toggle, const int16_t sleep = -1);
+#endif // SEND_HITACHI_AC1
#if SEND_HITACHI_AC424
void hitachi424(IRHitachiAc424 *ac,
const bool on, const stdAc::opmode_t mode,
@@ -308,7 +324,7 @@ void electra(IRElectraAc *ac,
#endif // SEND_SAMSUNG_AC
#if SEND_SHARP_AC
void sharp(IRSharpAc *ac,
- const bool on, const stdAc::opmode_t mode,
+ const bool on, const bool prev_power, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan);
#endif // SEND_SHARP_AC
#if SEND_TCL112AC
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRrecv.cpp b/lib/IRremoteESP8266-2.7.6/src/IRrecv.cpp
similarity index 86%
rename from lib/IRremoteESP8266-2.7.4/src/IRrecv.cpp
rename to lib/IRremoteESP8266-2.7.6/src/IRrecv.cpp
index e629fc218..f59c1248c 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRrecv.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/IRrecv.cpp
@@ -641,10 +641,28 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
if (decodeHaierACYRW02(results, offset)) return true;
#endif
#if DECODE_HITACHI_AC424
- // HitachiAc424 should be checked before HitachiAC & HitachiAC2
+ // HitachiAc424 should be checked before HitachiAC, HitachiAC2,
+ // & HitachiAC184
DPRINTLN("Attempting Hitachi AC 424 decode");
if (decodeHitachiAc424(results, offset, kHitachiAc424Bits)) return true;
-#endif // DECODE_HITACHI_AC2
+#endif // DECODE_HITACHI_AC424
+#if DECODE_MITSUBISHI136
+ // Needs to happen before HitachiAc3 decode.
+ DPRINTLN("Attempting Mitsubishi136 decode");
+ if (decodeMitsubishi136(results, offset)) return true;
+#endif // DECODE_MITSUBISHI136
+#if DECODE_HITACHI_AC3
+ // HitachiAc3 should be checked before HitachiAC & HitachiAC2
+ // Attempt normal before the short version.
+ DPRINTLN("Attempting Hitachi AC3 decode");
+ // Order these in decreasing bit size, as it is more optimal.
+ if (decodeHitachiAc3(results, offset, kHitachiAc3Bits) ||
+ decodeHitachiAc3(results, offset, kHitachiAc3Bits - 4 * 8) ||
+ decodeHitachiAc3(results, offset, kHitachiAc3Bits - 6 * 8) ||
+ decodeHitachiAc3(results, offset, kHitachiAc3MinBits + 2 * 8) ||
+ decodeHitachiAc3(results, offset, kHitachiAc3MinBits))
+ return true;
+#endif // DECODE_HITACHI_AC3
#if DECODE_HITACHI_AC2
// HitachiAC2 should be checked before HitachiAC
DPRINTLN("Attempting Hitachi AC2 decode");
@@ -759,12 +777,20 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Daikin152 decode");
if (decodeDaikin152(results, offset)) return true;
#endif // DECODE_DAIKIN152
-#if DECODE_MITSUBISHI136
- DPRINTLN("Attempting Mitsubishi136 decode");
- if (decodeMitsubishi136(results, offset)) return true;
-#endif // DECODE_MITSUBISHI136
- }
+#if DECODE_SYMPHONY
+ DPRINTLN("Attempting Symphony decode");
+ if (decodeSymphony(results, offset)) return true;
+#endif // DECODE_SYMPHONY
+#if DECODE_DAIKIN64
+ DPRINTLN("Attempting Daikin64 decode");
+ if (decodeDaikin64(results, offset)) return true;
+#endif // DECODE_DAIKIN64
+#if DECODE_AIRWELL
+ DPRINTLN("Attempting Airwell decode");
+ if (decodeAirwell(results, offset)) return true;
+#endif // DECODE_AIRWELL
// Typically new protocols are added above this line.
+ }
#if DECODE_HASH
// decodeHash returns a hash on any input.
// Thus, it needs to be last in the list.
@@ -1270,4 +1296,166 @@ uint16_t IRrecv::matchGeneric(volatile uint16_t *data_ptr,
zeromark, zerospace, footermark, footerspace, atleast,
tolerance, excess, MSBfirst);
}
+
+// Match & decode a Manchester Code <= 64bit IR message.
+// The data is stored at result_ptr.
+// Values of 0 for hdrmark, hdrspace, footermark, or footerspace mean skip
+// that requirement.
+//
+// Args:
+// data_ptr: A pointer to where we are at in the capture buffer.
+// NOTE: It is assumed to be pointing to a "Mark", not a "Space".
+// result_ptr: A pointer to where to start storing the bits we decoded.
+// remaining: The size of the capture buffer are remaining.
+// nbits: Nr. of data bits we expect.
+// hdrmark: Nr. of uSeconds for the expected header mark signal.
+// hdrspace: Nr. of uSeconds for the expected header space signal.
+// half_period: Nr. of uSeconds for half the clock's period. (1/2 wavelength)
+// footermark: Nr. of uSeconds for the expected footer mark signal.
+// footerspace: Nr. of uSeconds for the expected footer space/gap signal.
+// atleast: Is the match on the footerspace a matchAtLeast or matchSpace?
+// tolerance: Percentage error margin to allow. (Def: kUseDefTol)
+// excess: Nr. of useconds. (Def: kMarkExcess)
+// MSBfirst: Bit order to save the data in. (Def: true)
+// GEThomas: Use G.E. Thomas (true/default) or IEEE 802.3 (false) convention?
+// Returns:
+// A uint16_t: If successful, how many buffer entries were used. Otherwise 0.
+//
+// Ref:
+// https://en.wikipedia.org/wiki/Manchester_code
+// http://ww1.microchip.com/downloads/en/AppNotes/Atmel-9164-Manchester-Coding-Basics_Application-Note.pdf
+uint16_t IRrecv::matchManchester(volatile const uint16_t *data_ptr,
+ uint64_t *result_ptr,
+ const uint16_t remaining,
+ const uint16_t nbits,
+ const uint16_t hdrmark,
+ const uint32_t hdrspace,
+ const uint16_t half_period,
+ const uint16_t footermark,
+ const uint32_t footerspace,
+ const bool atleast,
+ const uint8_t tolerance,
+ const int16_t excess,
+ const bool MSBfirst,
+ const bool GEThomas) {
+ uint16_t offset = 0;
+ uint64_t data = 0;
+ uint16_t nr_of_half_periods = GEThomas;
+ // 2 per bit, and 4 extra for the timing sync.
+ uint16_t expected_half_periods = 2 * nbits + 4;
+ bool currentBit = false;
+
+ // Calculate how much remaining buffer is required.
+ // Shortest case. Longest case is 2 * nbits.
+ uint16_t min_remaining = nbits + 2;
+
+ if (hdrmark) min_remaining++;
+ if (hdrspace) min_remaining++;
+ if (footermark) min_remaining++;
+ // Don't need to extend for footerspace because it could be the end of message
+
+ // Check if there is enough capture buffer to possibly have the message.
+ if (remaining < min_remaining) return 0; // Nope, so abort.
+
+ // Header
+ if (hdrmark && !matchMark(*(data_ptr + offset++), hdrmark, tolerance, excess))
+ return 0;
+ // Manchester Code always has a guaranteed 2x half_period (T2) at the start
+ // of the data section. e.g. a sync header. If it is a GEThomas-style, then
+ // it is space(T);mark(2xT);space(T), thus we need to check for that space
+ // plus any requested "header" space.
+ if ((hdrspace || GEThomas) &&
+ !matchSpace(*(data_ptr + offset++),
+ hdrspace + ((GEThomas) ? half_period : 0), tolerance, excess))
+ return 0;
+
+ // Data
+ // Loop until we find a 'long' pulse. This is the timing sync per protocol.
+ while ((offset < remaining) && (nr_of_half_periods < expected_half_periods) &&
+ !match(*(data_ptr + offset), half_period * 2, tolerance, excess)) {
+ // Was it not a short pulse?
+ if (!match(*(data_ptr + offset), half_period, tolerance, excess))
+ return 0;
+ nr_of_half_periods++;
+ offset++;
+ }
+
+ // Data (cont.)
+
+ // We are now pointing to the first 'long' pulse.
+ // Loop through the buffer till we run out of buffer, or nr of half periods.
+ while (offset < remaining && nr_of_half_periods < expected_half_periods) {
+ // Only if there is enough half_periods left for a long pulse &
+ // Is it a 'long' pulse?
+ if (nr_of_half_periods < expected_half_periods - 1 &&
+ match(*(data_ptr + offset), half_period * 2, tolerance, excess)) {
+ // Yes, so invert the value we will append.
+ currentBit = !currentBit;
+ nr_of_half_periods += 2; // A 'long' pulse is two half periods.
+ offset++;
+ // Append the bit value.
+ data <<= 1;
+ data |= currentBit;
+ } else if (match(*(data_ptr + offset), half_period, tolerance, excess)) {
+ // or is it part of a 'short' pulse pair?
+ nr_of_half_periods++;
+ offset++;
+ // Look for the second half of the 'short' pulse pair.
+ // Do we have enough buffer or nr of half periods?
+ if (offset < remaining && nr_of_half_periods < expected_half_periods) {
+ // We do, so look for it.
+ if (match(*(data_ptr + offset), half_period, tolerance, excess)) {
+ // Found it!
+ nr_of_half_periods++;
+ // No change of the polarity of the bit we will append.
+ // Append the bit value.
+ data <<= 1;
+ data |= currentBit;
+ offset++;
+ } else {
+ // It's not what we expected.
+ return 0;
+ }
+ }
+ } else if (nr_of_half_periods == expected_half_periods - 1 &&
+ matchAtLeast(*(data_ptr + offset), half_period, tolerance,
+ excess)) {
+ // Special case when we are at the end of the expected nr of periods.
+ // i.e. The pulse could be merged with the footer.
+ nr_of_half_periods++;
+ break;
+ } else {
+ // It's neither, so abort.
+ return 0;
+ }
+ }
+ // Did we collect the expected amount of data?
+ if (nr_of_half_periods < expected_half_periods) return 0;
+
+ // Footer
+ if (footermark &&
+ !(matchMark(*(data_ptr + offset), footermark + half_period,
+ tolerance, excess) ||
+ matchMark(*(data_ptr + offset), footermark,
+ tolerance, excess)))
+ return 0;
+ offset++;
+ // If we have something still to match & haven't reached the end of the buffer
+ if (footerspace && offset < remaining) {
+ if (atleast) {
+ if (!matchAtLeast(*(data_ptr + offset), footerspace, tolerance, excess))
+ return 0;
+ } else {
+ if (!matchSpace(*(data_ptr + offset), footerspace, tolerance, excess))
+ return 0;
+ }
+ offset++;
+ }
+
+ // Clean up and process the data.
+ if (!MSBfirst) data = reverseBits(data, nbits);
+ // Trim the data to size to remove timing sync.
+ *result_ptr = GETBITS64(data, 0, nbits);
+ return offset;
+}
// End of IRrecv class -------------------
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRrecv.h b/lib/IRremoteESP8266-2.7.6/src/IRrecv.h
similarity index 93%
rename from lib/IRremoteESP8266-2.7.4/src/IRrecv.h
rename to lib/IRremoteESP8266-2.7.6/src/IRrecv.h
index 60559981c..aeea5b32d 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRrecv.h
+++ b/lib/IRremoteESP8266-2.7.6/src/IRrecv.h
@@ -221,6 +221,20 @@ class IRrecv {
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true);
+ uint16_t matchManchester(volatile const uint16_t *data_ptr,
+ uint64_t *result_ptr,
+ const uint16_t remaining,
+ const uint16_t nbits,
+ const uint16_t hdrmark,
+ const uint32_t hdrspace,
+ const uint16_t clock_period,
+ const uint16_t footermark,
+ const uint32_t footerspace,
+ const bool atleast = false,
+ const uint8_t tolerance = kUseDefTol,
+ const int16_t excess = kMarkExcess,
+ const bool MSBfirst = true,
+ const bool GEThomas = true);
void crudeNoiseFilter(decode_results *results, const uint16_t floor = 0);
bool decodeHash(decode_results *results);
#if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || SEND_SANYO)
@@ -393,6 +407,11 @@ class IRrecv {
const uint16_t nbits = kDaikinBits,
const bool strict = true);
#endif
+#if DECODE_DAIKIN64
+ bool decodeDaikin64(decode_results *results, uint16_t offset = kStartOffset,
+ const uint16_t nbits = kDaikin64Bits,
+ const bool strict = true);
+#endif // DECODE_DAIKIN64
#if DECODE_DAIKIN128
bool decodeDaikin128(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kDaikin128Bits,
@@ -485,6 +504,12 @@ class IRrecv {
const uint16_t nbits = kHitachiAc1Bits,
const bool strict = true);
#endif
+#if DECODE_HITACHI_AC3
+ bool decodeHitachiAc3(decode_results *results,
+ uint16_t offset = kStartOffset,
+ const uint16_t nbits = kHitachiAc3Bits,
+ const bool strict = true);
+#endif // DECODE_HITACHI_AC3
#if DECODE_HITACHI_AC424
bool decodeHitachiAc424(decode_results *results,
uint16_t offset = kStartOffset,
@@ -558,6 +583,16 @@ class IRrecv {
const uint16_t nbits = kEpsonBits,
const bool strict = true);
#endif // DECODE_EPSON
+#if DECODE_SYMPHONY
+ bool decodeSymphony(decode_results *results, uint16_t offset = kStartOffset,
+ const uint16_t nbits = kSymphonyBits,
+ const bool strict = true);
+#endif // DECODE_SYMPHONY
+#if DECODE_AIRWELL
+ bool decodeAirwell(decode_results *results, uint16_t offset = kStartOffset,
+ const uint16_t nbits = kAirwellBits,
+ const bool strict = true);
+#endif // DECODE_AIRWELL
};
#endif // IRRECV_H_
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.7.6/src/IRremoteESP8266.h
similarity index 95%
rename from lib/IRremoteESP8266-2.7.4/src/IRremoteESP8266.h
rename to lib/IRremoteESP8266-2.7.6/src/IRremoteESP8266.h
index a048e23fc..2bf906697 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRremoteESP8266.h
+++ b/lib/IRremoteESP8266-2.7.6/src/IRremoteESP8266.h
@@ -52,7 +52,7 @@
#endif // UNIT_TEST
// Library Version
-#define _IRREMOTEESP8266_VERSION_ "2.7.4"
+#define _IRREMOTEESP8266_VERSION_ "2.7.6"
// Set the language & locale for the library. See the `locale` dir for options.
#ifndef _IR_LOCALE_
@@ -411,6 +411,20 @@
#define SEND_HITACHI_AC2 _IR_ENABLE_DEFAULT_
#endif // SEND_HITACHI_AC2
+#ifndef DECODE_HITACHI_AC3
+#define DECODE_HITACHI_AC3 _IR_ENABLE_DEFAULT_
+#endif // DECODE_HITACHI_AC3
+#ifndef SEND_HITACHI_AC3
+#define SEND_HITACHI_AC3 _IR_ENABLE_DEFAULT_
+#endif // SEND_HITACHI_AC3
+
+#ifndef DECODE_HITACHI_AC424
+#define DECODE_HITACHI_AC424 _IR_ENABLE_DEFAULT_
+#endif // DECODE_HITACHI_AC424
+#ifndef SEND_HITACHI_AC424
+#define SEND_HITACHI_AC424 _IR_ENABLE_DEFAULT_
+#endif // SEND_HITACHI_AC424
+
#ifndef DECODE_GICABLE
#define DECODE_GICABLE _IR_ENABLE_DEFAULT_
#endif // DECODE_GICABLE
@@ -558,13 +572,6 @@
#define SEND_DAIKIN152 _IR_ENABLE_DEFAULT_
#endif // SEND_DAIKIN152
-#ifndef DECODE_HITACHI_AC424
-#define DECODE_HITACHI_AC424 _IR_ENABLE_DEFAULT_
-#endif // DECODE_HITACHI_AC424
-#ifndef SEND_HITACHI_AC424
-#define SEND_HITACHI_AC424 _IR_ENABLE_DEFAULT_
-#endif // SEND_HITACHI_AC424
-
#ifndef DECODE_EPSON
#define DECODE_EPSON _IR_ENABLE_DEFAULT_
#endif // DECODE_EPSON
@@ -572,6 +579,27 @@
#define SEND_EPSON _IR_ENABLE_DEFAULT_
#endif // SEND_EPSON
+#ifndef DECODE_SYMPHONY
+#define DECODE_SYMPHONY _IR_ENABLE_DEFAULT_
+#endif // DECODE_SYMPHONY
+#ifndef SEND_SYMPHONY
+#define SEND_SYMPHONY _IR_ENABLE_DEFAULT_
+#endif // SEND_SYMPHONY
+
+#ifndef DECODE_DAIKIN64
+#define DECODE_DAIKIN64 _IR_ENABLE_DEFAULT_
+#endif // DECODE_DAIKIN64
+#ifndef SEND_DAIKIN64
+#define SEND_DAIKIN64 _IR_ENABLE_DEFAULT_
+#endif // SEND_DAIKIN64
+
+#ifndef DECODE_AIRWELL
+#define DECODE_AIRWELL _IR_ENABLE_DEFAULT_
+#endif // DECODE_AIRWELL
+#ifndef SEND_AIRWELL
+#define SEND_AIRWELL _IR_ENABLE_DEFAULT_
+#endif // SEND_AIRWELL
+
#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
@@ -582,7 +610,7 @@
DECODE_DAIKIN216 || DECODE_SHARP_AC || DECODE_DAIKIN160 || \
DECODE_NEOCLIMA || DECODE_DAIKIN176 || DECODE_DAIKIN128 || \
DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \
- DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424)
+ DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3)
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
#else
#define DECODE_AC false // We don't need that infrastructure.
@@ -695,14 +723,20 @@ enum decode_type_t {
HITACHI_AC424,
SONY_38K,
EPSON, // 75
+ SYMPHONY,
+ HITACHI_AC3,
+ DAIKIN64,
+ AIRWELL,
// Add new entries before this one, and update it to point to the last entry.
- kLastDecodeType = EPSON,
+ kLastDecodeType = AIRWELL,
};
// Message lengths & required repeat values
const uint16_t kNoRepeat = 0;
const uint16_t kSingleRepeat = 1;
+const uint16_t kAirwellBits = 32;
+const uint16_t kAirwellMinRepeats = 2;
const uint16_t kAiwaRcT501Bits = 15;
const uint16_t kAiwaRcT501MinRepeats = kSingleRepeat;
const uint16_t kAlokaBits = 32;
@@ -724,6 +758,8 @@ const uint16_t kDaikinDefaultRepeat = kNoRepeat;
const uint16_t kDaikin2StateLength = 39;
const uint16_t kDaikin2Bits = kDaikin2StateLength * 8;
const uint16_t kDaikin2DefaultRepeat = kNoRepeat;
+const uint16_t kDaikin64Bits = 64;
+const uint16_t kDaikin64DefaultRepeat = kNoRepeat;
const uint16_t kDaikin160StateLength = 20;
const uint16_t kDaikin160Bits = kDaikin160StateLength * 8;
const uint16_t kDaikin160DefaultRepeat = kNoRepeat;
@@ -774,6 +810,10 @@ const uint16_t kHitachiAc1StateLength = 13;
const uint16_t kHitachiAc1Bits = kHitachiAc1StateLength * 8;
const uint16_t kHitachiAc2StateLength = 53;
const uint16_t kHitachiAc2Bits = kHitachiAc2StateLength * 8;
+const uint16_t kHitachiAc3StateLength = 27;
+const uint16_t kHitachiAc3Bits = kHitachiAc3StateLength * 8;
+const uint16_t kHitachiAc3MinStateLength = 15;
+const uint16_t kHitachiAc3MinBits = kHitachiAc3MinStateLength * 8;
const uint16_t kHitachiAc424StateLength = 53;
const uint16_t kHitachiAc424Bits = kHitachiAc424StateLength * 8;
const uint16_t kInaxBits = 24;
@@ -857,6 +897,8 @@ const uint16_t kSony15Bits = 15;
const uint16_t kSony20Bits = 20;
const uint16_t kSonyMinBits = 12;
const uint16_t kSonyMinRepeat = 2;
+const uint16_t kSymphonyBits = 11;
+const uint16_t kSymphonyDefaultRepeat = kSingleRepeat;
const uint16_t kTcl112AcStateLength = 14;
const uint16_t kTcl112AcBits = kTcl112AcStateLength * 8;
const uint16_t kTcl112AcDefaultRepeat = kNoRepeat;
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRsend.cpp b/lib/IRremoteESP8266-2.7.6/src/IRsend.cpp
similarity index 86%
rename from lib/IRremoteESP8266-2.7.4/src/IRsend.cpp
rename to lib/IRremoteESP8266-2.7.6/src/IRsend.cpp
index 8bc12949b..bb5f55407 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRsend.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/IRsend.cpp
@@ -462,6 +462,105 @@ void IRsend::sendGeneric(const uint16_t headermark, const uint32_t headerspace,
}
}
+// Generic method for sending Manchester code data.
+// Will send leading or trailing 0's if the nbits is larger than the number
+// of bits in data.
+//
+// Args:
+// half_period: Nr. of uSeconds for half the clock's period. (1/2 wavelength)
+// data: The data to be transmitted.
+// nbits: Nr. of bits of data to be sent.
+// MSBfirst: Flag for bit transmission order. Defaults to MSB->LSB order.
+// GEThomas: Use G.E. Thomas (true/default) or IEEE 802.3 (false).
+void IRsend::sendManchesterData(const uint16_t half_period,
+ const uint64_t data,
+ const uint16_t nbits, const bool MSBfirst,
+ const bool GEThomas) {
+ if (nbits == 0) return; // Nothing to send.
+ uint16_t bits = nbits;
+ uint64_t copy = (GEThomas) ? data : ~data;
+
+ if (MSBfirst) { // Send the MSB first.
+ // Send 0's until we get down to a bit size we can actually manage.
+ if (bits > (sizeof(data) * 8)) {
+ sendManchesterData(half_period, 0ULL, bits - sizeof(data) * 8, MSBfirst,
+ GEThomas);
+ bits = sizeof(data) * 8;
+ }
+ // Send the supplied data.
+ for (uint64_t mask = 1ULL << (bits - 1); mask; mask >>= 1)
+ if (copy & mask) {
+ mark(half_period);
+ space(half_period);
+ } else {
+ space(half_period);
+ mark(half_period);
+ }
+ } else { // Send the Least Significant Bit (LSB) first / MSB last.
+ for (bits = 0; bits < nbits; bits++, copy >>= 1)
+ if (copy & 1) {
+ mark(half_period);
+ space(half_period);
+ } else {
+ space(half_period);
+ mark(half_period);
+ }
+ }
+}
+
+// Generic method for sending Manchester code messages.
+// Will send leading or trailing 0's if the nbits is larger than the number
+// of bits in data.
+//
+// Args:
+// headermark: Nr. of usecs for the led to be pulsed for the header mark.
+// A value of 0 means no header mark.
+// headerspace: Nr. of usecs for the led to be off after the header mark.
+// A value of 0 means no header space.
+// half_period: Nr. of uSeconds for half the clock's period. (1/2 wavelength)
+// footermark: Nr. of usecs for the led to be pulsed for the footer mark.
+// A value of 0 means no footer mark.
+// gap: Min. nr. of usecs for the led to be off after the footer mark.
+// This is effectively the absolute minimum gap between messages.
+// data: The data to be transmitted.
+// nbits: Nr. of bits of data to be sent.
+// frequency: The frequency we want to modulate at.
+// Assumes < 1000 means kHz otherwise it is in Hz.
+// Most common value is 38000 or 38, for 38kHz.
+// MSBfirst: Flag for bit transmission order. Defaults to MSB->LSB order.
+// repeat: Nr. of extra times the message will be sent.
+// e.g. 0 = 1 message sent, 1 = 1 initial + 1 repeat = 2 messages
+// dutycycle: Percentage duty cycle of the LED.
+// e.g. 25 = 25% = 1/4 on, 3/4 off.
+// If you are not sure, try 50 percent.
+// GEThomas: Use G.E. Thomas (true/default) or IEEE 802.3 (false).
+void IRsend::sendManchester(const uint16_t headermark,
+ const uint32_t headerspace,
+ const uint16_t half_period,
+ const uint16_t footermark, const uint32_t gap,
+ const uint64_t data, const uint16_t nbits,
+ const uint16_t frequency, const bool MSBfirst,
+ const uint16_t repeat, const uint8_t dutycycle,
+ const bool GEThomas) {
+ // Setup
+ enableIROut(frequency, dutycycle);
+
+ // We always send a message, even for repeat=0, hence '<= repeat'.
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Header
+ if (headermark) mark(headermark);
+ if (headerspace) space(headerspace);
+ // Data Marker/sync
+ // This guarantees a double width half_period. i.e. a Period or T2.
+ sendManchesterData(half_period, 0b01, 2, true, GEThomas);
+ // Data
+ sendManchesterData(half_period, data, nbits, MSBfirst, GEThomas);
+ // Footer
+ if (footermark) mark(footermark);
+ if (gap) space(gap);
+ }
+}
+
#if SEND_RAW
// Send a raw IRremote message.
//
@@ -509,17 +608,20 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) {
case MITSUBISHI2:
case MITSUBISHI_AC:
case SHERWOOD:
+ case SYMPHONY:
case TOSHIBA_AC:
return kSingleRepeat;
// Special
+ case AIRWELL:
+ return kAirwellMinRepeats;
case DISH:
return kDishMinRepeat;
+ case EPSON:
+ return kEpsonMinRepeat;
case SONY:
return kSonyMinRepeat;
case SONY_38K:
return kSonyMinRepeat + 1;
- case EPSON:
- return kEpsonMinRepeat;
default:
return kNoRepeat;
}
@@ -532,6 +634,8 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) {
// int16_t: The number of bits.
uint16_t IRsend::defaultBits(const decode_type_t protocol) {
switch (protocol) {
+ case SYMPHONY:
+ return 11;
case RC5:
return 12;
case LASERTAG:
@@ -560,6 +664,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
case LG:
case LG2:
return 28;
+ case AIRWELL:
case CARRIER_AC:
case EPSON:
case NEC:
@@ -601,6 +706,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kDaikin2Bits;
case DAIKIN216:
return kDaikin216Bits;
+ case DAIKIN64:
+ return kDaikin64Bits;
case ELECTRA_AC:
return kElectraAcBits;
case GREE:
@@ -615,6 +722,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kHitachiAc1Bits;
case HITACHI_AC2:
return kHitachiAc2Bits;
+ case HITACHI_AC3:
+ return kHitachiAc3Bits;
case HITACHI_AC424:
return kHitachiAc424Bits;
case KELVINATOR:
@@ -666,6 +775,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
const uint16_t nbits, const uint16_t repeat) {
uint16_t min_repeat = std::max(IRsend::minRepeats(type), repeat);
switch (type) {
+#if SEND_AIRWELL
+ case AIRWELL:
+ sendAirwell(data, nbits, min_repeat);
+ break;
+#endif
#if SEND_AIWA_RC_T501
case AIWA_RC_T501:
sendAiwaRCT501(data, nbits, min_repeat);
@@ -681,6 +795,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendCOOLIX(data, nbits, min_repeat);
break;
#endif
+#if SEND_DAIKIN64
+ case DAIKIN64:
+ sendDaikin64(data, nbits, min_repeat);
+ break;
+#endif
#if SEND_DENON
case DENON:
sendDenon(data, nbits, min_repeat);
@@ -834,6 +953,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendSony38(data, nbits, min_repeat);
break;
#endif
+#if SEND_SYMPHONY
+ case SYMPHONY:
+ sendSymphony(data, nbits, min_repeat);
+ break;
+#endif
#if SEND_TECO
case TECO:
sendTeco(data, nbits, min_repeat);
@@ -951,6 +1075,11 @@ bool IRsend::send(const decode_type_t type, const unsigned char *state,
sendHitachiAC2(state, nbytes);
break;
#endif // SEND_HITACHI_AC2
+#if SEND_HITACHI_AC3
+ case HITACHI_AC3:
+ sendHitachiAc3(state, nbytes);
+ break;
+#endif // SEND_HITACHI_AC3
#if SEND_HITACHI_AC424
case HITACHI_AC424:
sendHitachiAc424(state, nbytes);
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRsend.h b/lib/IRremoteESP8266-2.7.6/src/IRsend.h
similarity index 92%
rename from lib/IRremoteESP8266-2.7.4/src/IRsend.h
rename to lib/IRremoteESP8266-2.7.6/src/IRsend.h
index 902f22010..8d5e6a862 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRsend.h
+++ b/lib/IRremoteESP8266-2.7.6/src/IRsend.h
@@ -126,6 +126,11 @@ enum gree_ac_remote_model_t {
YBOFB, // (2) Green, YBOFB2, YAPOF3
};
+enum hitachi_ac1_remote_model_t {
+ R_LT0541_HTA_A = 1, // (1) R-LT0541-HTA Remote in "A" setting. (Default)
+ R_LT0541_HTA_B, // (2) R-LT0541-HTA Remote in "B" setting.
+};
+
enum panasonic_ac_remote_model_t {
kPanasonicUnknown = 0,
kPanasonicLke = 1,
@@ -162,6 +167,17 @@ class IRsend {
void sendData(uint16_t onemark, uint32_t onespace, uint16_t zeromark,
uint32_t zerospace, uint64_t data, uint16_t nbits,
bool MSBfirst = true);
+ void sendManchesterData(const uint16_t half_period, const uint64_t data,
+ const uint16_t nbits, const bool MSBfirst = true,
+ const bool GEThomas = true);
+ void sendManchester(const uint16_t headermark, const uint32_t headerspace,
+ const uint16_t half_period, const uint16_t footermark,
+ const uint32_t gap, const uint64_t data,
+ const uint16_t nbits, const uint16_t frequency = 38,
+ const bool MSBfirst = true,
+ const uint16_t repeat = kNoRepeat,
+ const uint8_t dutycycle = kDutyDefault,
+ const bool GEThomas = true);
void sendGeneric(const uint16_t headermark, const uint32_t headerspace,
const uint16_t onemark, const uint32_t onespace,
const uint16_t zeromark, const uint32_t zerospace,
@@ -362,6 +378,10 @@ class IRsend {
const uint16_t nbytes = kDaikinStateLength,
const uint16_t repeat = kDaikinDefaultRepeat);
#endif
+#if SEND_DAIKIN64
+ void sendDaikin64(const uint64_t data, const uint16_t nbits = kDaikin64Bits,
+ const uint16_t repeat = kDaikin64DefaultRepeat);
+#endif // SEND_DAIKIN64
#if SEND_DAIKIN128
void sendDaikin128(const unsigned char data[],
const uint16_t nbytes = kDaikin128StateLength,
@@ -471,6 +491,12 @@ class IRsend {
const uint16_t nbytes = kHitachiAc2StateLength,
const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif
+#if SEND_HITACHI_AC3
+ void sendHitachiAc3(const unsigned char data[],
+ const uint16_t nbytes, // No default as there as so many
+ // different sizes
+ const uint16_t repeat = kHitachiAcDefaultRepeat);
+#endif // SEND_HITACHI_AC3
#if SEND_HITACHI_AC424
void sendHitachiAc424(const unsigned char data[],
const uint16_t nbytes = kHitachiAc424StateLength,
@@ -539,6 +565,14 @@ class IRsend {
void sendEpson(uint64_t data, uint16_t nbits = kEpsonBits,
uint16_t repeat = kEpsonMinRepeat);
#endif
+#if SEND_SYMPHONY
+ void sendSymphony(uint64_t data, uint16_t nbits = kSymphonyBits,
+ uint16_t repeat = kSymphonyDefaultRepeat);
+#endif
+#if SEND_AIRWELL
+ void sendAirwell(uint64_t data, uint16_t nbits = kAirwellBits,
+ uint16_t repeat = kAirwellMinRepeats);
+#endif
protected:
#ifdef UNIT_TEST
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRtext.cpp b/lib/IRremoteESP8266-2.7.6/src/IRtext.cpp
similarity index 75%
rename from lib/IRremoteESP8266-2.7.4/src/IRtext.cpp
rename to lib/IRremoteESP8266-2.7.6/src/IRtext.cpp
index 82f728191..cb9ccd722 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRtext.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/IRtext.cpp
@@ -130,6 +130,7 @@ const PROGMEM char* kEyeAutoStr = D_STR_EYEAUTO;
const PROGMEM char* kLightToggleStr = D_STR_LIGHTTOGGLE;
const PROGMEM char* kOutsideQuietStr = D_STR_OUTSIDEQUIET;
const PROGMEM char* kPowerToggleStr = D_STR_POWERTOGGLE;
+const PROGMEM char* kPreviousPowerStr = D_STR_PREVIOUSPOWER;
const PROGMEM char* kSensorTempStr = D_STR_SENSORTEMP;
const PROGMEM char* kSleepTimerStr = D_STR_SLEEP_TIMER;
const PROGMEM char* kSwingVModeStr = D_STR_SWINGVMODE;
@@ -162,3 +163,88 @@ const PROGMEM char* kFalseStr = D_STR_FALSE;
const PROGMEM char* kRepeatStr = D_STR_REPEAT;
const PROGMEM char* kCodeStr = D_STR_CODE;
const PROGMEM char* kBitsStr = D_STR_BITS;
+
+// Protocol Names
+// Needs to be in decode_type_t order.
+const PROGMEM char *kAllProtocolNamesStr =
+ D_STR_UNUSED "\x0"
+ D_STR_RC5 "\x0"
+ D_STR_RC6 "\x0"
+ D_STR_NEC "\x0"
+ D_STR_SONY "\x0"
+ D_STR_PANASONIC "\x0"
+ D_STR_JVC "\x0"
+ D_STR_SAMSUNG "\x0"
+ D_STR_WHYNTER "\x0"
+ D_STR_AIWA_RC_T501 "\x0"
+ D_STR_LG "\x0"
+ D_STR_SANYO "\x0"
+ D_STR_MITSUBISHI "\x0"
+ D_STR_DISH "\x0"
+ D_STR_SHARP "\x0"
+ D_STR_COOLIX "\x0"
+ D_STR_DAIKIN "\x0"
+ D_STR_DENON "\x0"
+ D_STR_KELVINATOR "\x0"
+ D_STR_SHERWOOD "\x0"
+ D_STR_MITSUBISHI_AC "\x0"
+ D_STR_RCMM "\x0"
+ D_STR_SANYO_LC7461 "\x0"
+ D_STR_RC5X "\x0"
+ D_STR_GREE "\x0"
+ D_STR_PRONTO "\x0"
+ D_STR_NEC_LIKE "\x0"
+ D_STR_ARGO "\x0"
+ D_STR_TROTEC "\x0"
+ D_STR_NIKAI "\x0"
+ D_STR_RAW "\x0"
+ D_STR_GLOBALCACHE "\x0"
+ D_STR_TOSHIBA_AC "\x0"
+ D_STR_FUJITSU_AC "\x0"
+ D_STR_MIDEA "\x0"
+ D_STR_MAGIQUEST "\x0"
+ D_STR_LASERTAG "\x0"
+ D_STR_CARRIER_AC "\x0"
+ D_STR_HAIER_AC "\x0"
+ D_STR_MITSUBISHI2 "\x0"
+ D_STR_HITACHI_AC "\x0"
+ D_STR_HITACHI_AC1 "\x0"
+ D_STR_HITACHI_AC2 "\x0"
+ D_STR_GICABLE "\x0"
+ D_STR_HAIER_AC_YRW02 "\x0"
+ D_STR_WHIRLPOOL_AC "\x0"
+ D_STR_SAMSUNG_AC "\x0"
+ D_STR_LUTRON "\x0"
+ D_STR_ELECTRA_AC "\x0"
+ D_STR_PANASONIC_AC "\x0"
+ D_STR_PIONEER "\x0"
+ D_STR_LG2 "\x0"
+ D_STR_MWM "\x0"
+ D_STR_DAIKIN2 "\x0"
+ D_STR_VESTEL_AC "\x0"
+ D_STR_TECO "\x0"
+ D_STR_SAMSUNG36 "\x0"
+ D_STR_TCL112AC "\x0"
+ D_STR_LEGOPF "\x0"
+ D_STR_MITSUBISHI_HEAVY_88 "\x0"
+ D_STR_MITSUBISHI_HEAVY_152 "\x0"
+ D_STR_DAIKIN216 "\x0"
+ D_STR_SHARP_AC "\x0"
+ D_STR_GOODWEATHER "\x0"
+ D_STR_INAX "\x0"
+ D_STR_DAIKIN160 "\x0"
+ D_STR_NEOCLIMA "\x0"
+ D_STR_DAIKIN176 "\x0"
+ D_STR_DAIKIN128 "\x0"
+ D_STR_AMCOR "\x0"
+ D_STR_DAIKIN152 "\x0"
+ D_STR_MITSUBISHI136 "\x0"
+ D_STR_MITSUBISHI112 "\x0"
+ D_STR_HITACHI_AC424 "\x0"
+ D_STR_SONY_38K "\x0"
+ D_STR_EPSON "\x0"
+ D_STR_SYMPHONY "\x0"
+ D_STR_HITACHI_AC3 "\x0"
+ D_STR_DAIKIN64 "\x0"
+ D_STR_AIRWELL "\x0"
+ "\x0"; // This string requires double null termination.
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRtext.h b/lib/IRremoteESP8266-2.7.6/src/IRtext.h
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/IRtext.h
rename to lib/IRremoteESP8266-2.7.6/src/IRtext.h
index 522b528bc..cbce59747 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRtext.h
+++ b/lib/IRremoteESP8266-2.7.6/src/IRtext.h
@@ -17,6 +17,7 @@ extern const char* k3DStr;
extern const char* k6thSenseStr;
extern const char* k8CHeatStr;
extern const char* kAirFlowStr;
+extern const char *kAllProtocolNamesStr;
extern const char* kAutomaticStr;
extern const char* kAutoStr;
extern const char* kBeepStr;
@@ -104,6 +105,7 @@ extern const char* kOutsideStr;
extern const char* kPowerfulStr;
extern const char* kPowerStr;
extern const char* kPowerToggleStr;
+extern const char* kPreviousPowerStr;
extern const char* kProtocolStr;
extern const char* kPurifyStr;
extern const char* kQuietStr;
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRtimer.cpp b/lib/IRremoteESP8266-2.7.6/src/IRtimer.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/IRtimer.cpp
rename to lib/IRremoteESP8266-2.7.6/src/IRtimer.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRtimer.h b/lib/IRremoteESP8266-2.7.6/src/IRtimer.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/IRtimer.h
rename to lib/IRremoteESP8266-2.7.6/src/IRtimer.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRutils.cpp b/lib/IRremoteESP8266-2.7.6/src/IRutils.cpp
similarity index 72%
rename from lib/IRremoteESP8266-2.7.4/src/IRutils.cpp
rename to lib/IRremoteESP8266-2.7.6/src/IRutils.cpp
index 230b24809..39d9973ed 100644
--- a/lib/IRremoteESP8266-2.7.4/src/IRutils.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/IRutils.cpp
@@ -91,161 +91,14 @@ void serialPrintUint64(uint64_t input, uint8_t base) {
// Returns:
// A decode_type_t enum.
decode_type_t strToDecodeType(const char * const str) {
- if (!strcasecmp(str, kUnknownStr))
- return decode_type_t::UNKNOWN;
- else if (!strcasecmp(str, "UNUSED"))
- return decode_type_t::UNUSED;
- else if (!strcasecmp(str, "AIWA_RC_T501"))
- return decode_type_t::AIWA_RC_T501;
- else if (!strcasecmp(str, "AMCOR"))
- return decode_type_t::AMCOR;
- else if (!strcasecmp(str, "ARGO"))
- return decode_type_t::ARGO;
- else if (!strcasecmp(str, "CARRIER_AC"))
- return decode_type_t::CARRIER_AC;
- else if (!strcasecmp(str, "COOLIX"))
- return decode_type_t::COOLIX;
- else if (!strcasecmp(str, "DAIKIN"))
- return decode_type_t::DAIKIN;
- else if (!strcasecmp(str, "DAIKIN128"))
- return decode_type_t::DAIKIN128;
- else if (!strcasecmp(str, "DAIKIN152"))
- return decode_type_t::DAIKIN152;
- else if (!strcasecmp(str, "DAIKIN160"))
- return decode_type_t::DAIKIN160;
- else if (!strcasecmp(str, "DAIKIN176"))
- return decode_type_t::DAIKIN176;
- else if (!strcasecmp(str, "DAIKIN2"))
- return decode_type_t::DAIKIN2;
- else if (!strcasecmp(str, "DAIKIN216"))
- return decode_type_t::DAIKIN216;
- else if (!strcasecmp(str, "DENON"))
- return decode_type_t::DENON;
- else if (!strcasecmp(str, "DISH"))
- return decode_type_t::DISH;
- else if (!strcasecmp(str, "ELECTRA_AC"))
- return decode_type_t::ELECTRA_AC;
- else if (!strcasecmp(str, "EPSON"))
- return decode_type_t::EPSON;
- else if (!strcasecmp(str, "FUJITSU_AC"))
- return decode_type_t::FUJITSU_AC;
- else if (!strcasecmp(str, "GICABLE"))
- return decode_type_t::GICABLE;
- else if (!strcasecmp(str, "GLOBALCACHE"))
- return decode_type_t::GLOBALCACHE;
- else if (!strcasecmp(str, "GOODWEATHER"))
- return decode_type_t::GOODWEATHER;
- else if (!strcasecmp(str, "GREE"))
- return decode_type_t::GREE;
- else if (!strcasecmp(str, "HAIER_AC"))
- return decode_type_t::HAIER_AC;
- else if (!strcasecmp(str, "HAIER_AC_YRW02"))
- return decode_type_t::HAIER_AC_YRW02;
- else if (!strcasecmp(str, "HITACHI_AC"))
- return decode_type_t::HITACHI_AC;
- else if (!strcasecmp(str, "HITACHI_AC1"))
- return decode_type_t::HITACHI_AC1;
- else if (!strcasecmp(str, "HITACHI_AC2"))
- return decode_type_t::HITACHI_AC2;
- else if (!strcasecmp(str, "HITACHI_AC424"))
- return decode_type_t::HITACHI_AC424;
- else if (!strcasecmp(str, "INAX"))
- return decode_type_t::INAX;
- else if (!strcasecmp(str, "JVC"))
- return decode_type_t::JVC;
- else if (!strcasecmp(str, "KELVINATOR"))
- return decode_type_t::KELVINATOR;
- else if (!strcasecmp(str, "LEGOPF"))
- return decode_type_t::LEGOPF;
- else if (!strcasecmp(str, "LG"))
- return decode_type_t::LG;
- else if (!strcasecmp(str, "LG2"))
- return decode_type_t::LG2;
- else if (!strcasecmp(str, "LASERTAG"))
- return decode_type_t::LASERTAG;
- else if (!strcasecmp(str, "LUTRON"))
- return decode_type_t::LUTRON;
- else if (!strcasecmp(str, "MAGIQUEST"))
- return decode_type_t::MAGIQUEST;
- else if (!strcasecmp(str, "MIDEA"))
- return decode_type_t::MIDEA;
- else if (!strcasecmp(str, "MITSUBISHI"))
- return decode_type_t::MITSUBISHI;
- else if (!strcasecmp(str, "MITSUBISHI2"))
- return decode_type_t::MITSUBISHI2;
- else if (!strcasecmp(str, "MITSUBISHI_AC"))
- return decode_type_t::MITSUBISHI_AC;
- else if (!strcasecmp(str, "MITSUBISHI136"))
- return decode_type_t::MITSUBISHI136;
- else if (!strcasecmp(str, "MITSUBISHI112"))
- return decode_type_t::MITSUBISHI112;
- else if (!strcasecmp(str, "MITSUBISHI_HEAVY_88"))
- return decode_type_t::MITSUBISHI_HEAVY_88;
- else if (!strcasecmp(str, "MITSUBISHI_HEAVY_152"))
- return decode_type_t::MITSUBISHI_HEAVY_152;
- else if (!strcasecmp(str, "MWM"))
- return decode_type_t::MWM;
- else if (!strcasecmp(str, "NEOCLIMA"))
- return decode_type_t::NEOCLIMA;
- else if (!strcasecmp(str, "NEC"))
- return decode_type_t::NEC;
- else if (!strcasecmp(str, "NEC_LIKE") ||
- !strcasecmp(str, "NEC (NON-STRICT)"))
- return decode_type_t::NEC_LIKE;
- else if (!strcasecmp(str, "NIKAI"))
- return decode_type_t::NIKAI;
- else if (!strcasecmp(str, "PANASONIC"))
- return decode_type_t::PANASONIC;
- else if (!strcasecmp(str, "PANASONIC_AC"))
- return decode_type_t::PANASONIC_AC;
- else if (!strcasecmp(str, "PIONEER"))
- return decode_type_t::PIONEER;
- else if (!strcasecmp(str, "PRONTO"))
- return decode_type_t::PRONTO;
- else if (!strcasecmp(str, "RAW"))
- return decode_type_t::RAW;
- else if (!strcasecmp(str, "RC5"))
- return decode_type_t::RC5;
- else if (!strcasecmp(str, "RC5X"))
- return decode_type_t::RC5X;
- else if (!strcasecmp(str, "RC6"))
- return decode_type_t::RC6;
- else if (!strcasecmp(str, "RCMM"))
- return decode_type_t::RCMM;
- else if (!strcasecmp(str, "SAMSUNG"))
- return decode_type_t::SAMSUNG;
- else if (!strcasecmp(str, "SAMSUNG36"))
- return decode_type_t::SAMSUNG36;
- else if (!strcasecmp(str, "SAMSUNG_AC"))
- return decode_type_t::SAMSUNG_AC;
- else if (!strcasecmp(str, "SANYO"))
- return decode_type_t::SANYO;
- else if (!strcasecmp(str, "SANYO_LC7461"))
- return decode_type_t::SANYO_LC7461;
- else if (!strcasecmp(str, "SHARP"))
- return decode_type_t::SHARP;
- else if (!strcasecmp(str, "SHARP_AC"))
- return decode_type_t::SHARP_AC;
- else if (!strcasecmp(str, "SHERWOOD"))
- return decode_type_t::SHERWOOD;
- else if (!strcasecmp(str, "SONY"))
- return decode_type_t::SONY;
- else if (!strcasecmp(str, "SONY_38K"))
- return decode_type_t::SONY_38K;
- else if (!strcasecmp(str, "TCL112AC"))
- return decode_type_t::TCL112AC;
- else if (!strcasecmp(str, "TECO"))
- return decode_type_t::TECO;
- else if (!strcasecmp(str, "TOSHIBA_AC"))
- return decode_type_t::TOSHIBA_AC;
- else if (!strcasecmp(str, "TROTEC"))
- return decode_type_t::TROTEC;
- else if (!strcasecmp(str, "VESTEL_AC"))
- return decode_type_t::VESTEL_AC;
- else if (!strcasecmp(str, "WHIRLPOOL_AC"))
- return decode_type_t::WHIRLPOOL_AC;
- else if (!strcasecmp(str, "WHYNTER"))
- return decode_type_t::WHYNTER;
+ const char *ptr = kAllProtocolNamesStr;
+ uint16_t length = strlen(ptr);
+ for (uint16_t i = 0; length; i++) {
+ if (!strcasecmp(str, ptr)) return (decode_type_t)i;
+ ptr += length + 1;
+ length = strlen(ptr);
+ }
+
// Handle integer values of the type by converting to a string and back again.
decode_type_t result = strToDecodeType(
typeToString((decode_type_t)atoi(str)).c_str());
@@ -263,239 +116,17 @@ decode_type_t strToDecodeType(const char * const str) {
// A string containing the protocol name.
String typeToString(const decode_type_t protocol, const bool isRepeat) {
String result = "";
- switch (protocol) {
- case UNUSED:
- result = F("UNUSED");
- break;
- case AIWA_RC_T501:
- result = F("AIWA_RC_T501");
- break;
- case AMCOR:
- result = F("AMCOR");
- break;
- case ARGO:
- result = F("ARGO");
- break;
- case CARRIER_AC:
- result = F("CARRIER_AC");
- break;
- case COOLIX:
- result = F("COOLIX");
- break;
- case DAIKIN:
- result = F("DAIKIN");
- break;
- case DAIKIN128:
- result = F("DAIKIN128");
- break;
- case DAIKIN152:
- result = F("DAIKIN152");
- break;
- case DAIKIN160:
- result = F("DAIKIN160");
- break;
- case DAIKIN176:
- result = F("DAIKIN176");
- break;
- case DAIKIN2:
- result = F("DAIKIN2");
- break;
- case DAIKIN216:
- result = F("DAIKIN216");
- break;
- case DENON:
- result = F("DENON");
- break;
- case DISH:
- result = F("DISH");
- break;
- case ELECTRA_AC:
- result = F("ELECTRA_AC");
- break;
- case EPSON:
- result = F("EPSON");
- break;
- case FUJITSU_AC:
- result = F("FUJITSU_AC");
- break;
- case GICABLE:
- result = F("GICABLE");
- break;
- case GLOBALCACHE:
- result = F("GLOBALCACHE");
- break;
- case GOODWEATHER:
- result = F("GOODWEATHER");
- break;
- case GREE:
- result = F("GREE");
- break;
- case HAIER_AC:
- result = F("HAIER_AC");
- break;
- case HAIER_AC_YRW02:
- result = F("HAIER_AC_YRW02");
- break;
- case HITACHI_AC:
- result = F("HITACHI_AC");
- break;
- case HITACHI_AC1:
- result = F("HITACHI_AC1");
- break;
- case HITACHI_AC2:
- result = F("HITACHI_AC2");
- break;
- case HITACHI_AC424:
- result = F("HITACHI_AC424");
- break;
- case INAX:
- result = F("INAX");
- break;
- case JVC:
- result = F("JVC");
- break;
- case KELVINATOR:
- result = F("KELVINATOR");
- break;
- case LEGOPF:
- result = F("LEGOPF");
- break;
- case LG:
- result = F("LG");
- break;
- case LG2:
- result = F("LG2");
- break;
- case LASERTAG:
- result = F("LASERTAG");
- break;
- case LUTRON:
- result = F("LUTRON");
- break;
- case MAGIQUEST:
- result = F("MAGIQUEST");
- break;
- case MIDEA:
- result = F("MIDEA");
- break;
- case MITSUBISHI:
- result = F("MITSUBISHI");
- break;
- case MITSUBISHI2:
- result = F("MITSUBISHI2");
- break;
- case MITSUBISHI_AC:
- result = F("MITSUBISHI_AC");
- break;
- case MITSUBISHI136:
- result = F("MITSUBISHI136");
- break;
- case MITSUBISHI112:
- result = F("MITSUBISHI112");
- break;
- case MITSUBISHI_HEAVY_88:
- result = F("MITSUBISHI_HEAVY_88");
- break;
- case MITSUBISHI_HEAVY_152:
- result = F("MITSUBISHI_HEAVY_152");
- break;
- case MWM:
- result = F("MWM");
- break;
- case NEOCLIMA:
- result = F("NEOCLIMA");
- break;
- case NEC:
- result = F("NEC");
- break;
- case NEC_LIKE:
- result = F("NEC (non-strict)");
- break;
- case NIKAI:
- result = F("NIKAI");
- break;
- case PANASONIC:
- result = F("PANASONIC");
- break;
- case PANASONIC_AC:
- result = F("PANASONIC_AC");
- break;
- case PIONEER:
- result = F("PIONEER");
- break;
- case PRONTO:
- result = F("PRONTO");
- break;
- case RAW:
- result = F("RAW");
- break;
- case RC5:
- result = F("RC5");
- break;
- case RC5X:
- result = F("RC5X");
- break;
- case RC6:
- result = F("RC6");
- break;
- case RCMM:
- result = F("RCMM");
- break;
- case SAMSUNG:
- result = F("SAMSUNG");
- break;
- case SAMSUNG36:
- result = F("SAMSUNG36");
- break;
- case SAMSUNG_AC:
- result = F("SAMSUNG_AC");
- break;
- case SANYO:
- result = F("SANYO");
- break;
- case SANYO_LC7461:
- result = F("SANYO_LC7461");
- break;
- case SHARP:
- result = F("SHARP");
- break;
- case SHARP_AC:
- result = F("SHARP_AC");
- break;
- case SHERWOOD:
- result = F("SHERWOOD");
- break;
- case SONY:
- result = F("SONY");
- break;
- case SONY_38K:
- result = F("SONY_38K");
- break;
- case TCL112AC:
- result = F("TCL112AC");
- break;
- case TECO:
- result = F("TECO");
- break;
- case TOSHIBA_AC:
- result = F("TOSHIBA_AC");
- break;
- case TROTEC:
- result = F("TROTEC");
- break;
- case VESTEL_AC:
- result = F("VESTEL_AC");
- break;
- case WHIRLPOOL_AC:
- result = F("WHIRLPOOL_AC");
- break;
- case WHYNTER:
- result = F("WHYNTER");
- break;
- case UNKNOWN:
- default:
- result = kUnknownStr;
- break;
+ const char *ptr = kAllProtocolNamesStr;
+ if (protocol > kLastDecodeType || protocol == decode_type_t::UNKNOWN) {
+ result = kUnknownStr;
+ } else {
+ for (uint16_t i = 0; i <= protocol && strlen(ptr); i++) {
+ if (i == protocol) {
+ result = ptr;
+ break;
+ }
+ ptr += strlen(ptr) + 1;
+ }
}
if (isRepeat) {
result += kSpaceLBraceStr;
@@ -525,6 +156,7 @@ bool hasACState(const decode_type_t protocol) {
case HITACHI_AC:
case HITACHI_AC1:
case HITACHI_AC2:
+ case HITACHI_AC3:
case HITACHI_AC424:
case KELVINATOR:
case MITSUBISHI136:
@@ -851,6 +483,15 @@ namespace irutils {
default: return kUnknownStr;
}
break;
+ case decode_type_t::HITACHI_AC1:
+ switch (model) {
+ case hitachi_ac1_remote_model_t::R_LT0541_HTA_A:
+ return F("R-LT0541-HTA-A");
+ case hitachi_ac1_remote_model_t::R_LT0541_HTA_B:
+ return F("R-LT0541-HTA-B");
+ default: return kUnknownStr;
+ }
+ break;
case decode_type_t::LG:
case decode_type_t::LG2:
switch (model) {
diff --git a/lib/IRremoteESP8266-2.7.4/src/IRutils.h b/lib/IRremoteESP8266-2.7.6/src/IRutils.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/IRutils.h
rename to lib/IRremoteESP8266-2.7.6/src/IRutils.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/i18n.h b/lib/IRremoteESP8266-2.7.6/src/i18n.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/i18n.h
rename to lib/IRremoteESP8266-2.7.6/src/i18n.h
diff --git a/lib/IRremoteESP8266-2.7.6/src/ir_Airwell.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Airwell.cpp
new file mode 100644
index 000000000..5eb103b84
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Airwell.cpp
@@ -0,0 +1,83 @@
+// Copyright 2020 David Conran
+
+#include "IRrecv.h"
+#include "IRsend.h"
+
+// Airwell "Manchester code" based protocol.
+// Some other Airwell products use the COOLIX protocol.
+//
+// Supports:
+// Brand: Airwell, Model: RC08W remote
+
+const uint8_t kAirwellOverhead = 4;
+const uint16_t kAirwellHalfClockPeriod = 950; // uSeconds
+const uint16_t kAirwellHdrMark = 3 * kAirwellHalfClockPeriod; // uSeconds
+const uint16_t kAirwellHdrSpace = 4 * kAirwellHalfClockPeriod; // uSeconds
+const uint16_t kAirwellFooterMark = 5 * kAirwellHalfClockPeriod; // uSeconds
+
+#if SEND_AIRWELL
+// Send an Airwell Manchester Code formatted message.
+//
+// Args:
+// data: The message to be sent.
+// nbits: The number of bits of the message to be sent.
+// Typically kAirwellBits.
+// repeat: The number of times the command is to be repeated.
+//
+// Status: BETA / Appears to be working.
+//
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1069
+void IRsend::sendAirwell(uint64_t data, uint16_t nbits, uint16_t repeat) {
+ // Header + Data
+ sendManchester(kAirwellHdrMark, kAirwellHdrMark, kAirwellHalfClockPeriod,
+ 0, 0, data, nbits, 38000, true, repeat);
+ // Footer
+ mark(kAirwellHdrMark + kAirwellHalfClockPeriod);
+ space(kDefaultMessageGap); // A guess.
+}
+#endif
+
+#if DECODE_AIRWELL
+// Decode the supplied Airwell "Manchester code" message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// offset: The starting index to use when attempting to decode the raw data.
+// Typically/Defaults to kStartOffset.
+// nbits: The number of data bits to expect. Typically kAirwellBits.
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: BETA / Appears to be working.
+//
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1069
+bool IRrecv::decodeAirwell(decode_results *results, uint16_t offset,
+ const uint16_t nbits, const bool strict) {
+ if (results->rawlen < nbits + kAirwellOverhead - offset)
+ return false; // Too short a message to match.
+
+ // Compliance
+ if (strict && nbits != kAirwellBits)
+ return false; // Doesn't match our protocol defn.
+
+ // Header #1 + Data #1 + Footer #1 (There are total of 3 sections)
+ uint16_t used = matchManchester(results->rawbuf + offset, &results->value,
+ results->rawlen - offset, nbits,
+ kAirwellHdrMark, kAirwellHdrMark,
+ kAirwellHalfClockPeriod,
+ kAirwellHdrMark, kAirwellHdrSpace,
+ true);
+ if (used == 0) return false;
+ offset += used;
+
+ // Success
+ results->decode_type = decode_type_t::AIRWELL;
+ results->bits = nbits;
+ results->address = 0;
+ results->command = 0;
+ return true;
+}
+#endif
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Aiwa.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Aiwa.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Aiwa.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Aiwa.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Amcor.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Amcor.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Amcor.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Amcor.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Amcor.h b/lib/IRremoteESP8266-2.7.6/src/ir_Amcor.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Amcor.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Amcor.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Argo.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Argo.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Argo.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Argo.cpp
index 11e8336e3..0c4656cb5 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Argo.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Argo.cpp
@@ -38,7 +38,7 @@ using irutils::setBits;
// Args:
// data: An array of kArgoStateLength bytes containing the IR command.
//
-// Status: ALPHA / Untested.
+// Status: BETA / Probably works.
void IRsend::sendArgo(const unsigned char data[], const uint16_t nbytes,
const uint16_t repeat) {
@@ -385,7 +385,7 @@ String IRArgoAC::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: ALPHA / Probably doesn't work.
+// Status: BETA / Probably works.
//
// Note:
// This decoder is based soley off sendArgo(). We have no actual captures
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Argo.h b/lib/IRremoteESP8266-2.7.6/src/ir_Argo.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Argo.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Argo.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Carrier.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Carrier.cpp
similarity index 97%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Carrier.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Carrier.cpp
index 7b2b00d58..293711a03 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Carrier.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Carrier.cpp
@@ -30,7 +30,7 @@ const uint16_t kCarrierAcGap = 20000;
// nbits: The bit size of the message being sent. typically kCarrierAcBits.
// repeat: The number of times the message is to be repeated.
//
-// Status: BETA / Appears to work on real devices.
+// Status: STABLE / Work on real devices.
//
void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) {
for (uint16_t r = 0; r <= repeat; r++) {
@@ -61,7 +61,7 @@ void IRsend::sendCarrierAC(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: ALPHA / Untested.
+// Status: BETA / Probably works.
//
bool IRrecv::decodeCarrierAC(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Coolix.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Coolix.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Coolix.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Coolix.cpp
index a8d98301c..65535442a 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Coolix.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Coolix.cpp
@@ -586,7 +586,7 @@ String IRCoolixAC::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Probably working.
+// Status: STABLE / Known Working.
bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
// The protocol sends the data normal + inverted, alternating on
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Coolix.h b/lib/IRremoteESP8266-2.7.6/src/ir_Coolix.h
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Coolix.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Coolix.h
index c2fb2034d..6f7778416 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Coolix.h
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Coolix.h
@@ -23,6 +23,7 @@
// Brand: Midea, Model: MS12FU-10HRDN1-QRD0GW(B) A/C
// Brand: Midea, Model: MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
// Brand: Tokio, Model: AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote
+// Brand: Airwell, Model: RC08B remote
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/484
// Kudos:
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Daikin.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Daikin.cpp
similarity index 88%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Daikin.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Daikin.cpp
index 4941fe977..c18e77569 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Daikin.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Daikin.cpp
@@ -593,7 +593,7 @@ bool IRrecv::decodeDaikin(decode_results *results, uint16_t offset,
// Args:
// data: An array of kDaikin2StateLength bytes containing the IR command.
//
-// Status: BETA/Appears to work.
+// Status: STABLE / Expected to work.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/582
@@ -1219,7 +1219,7 @@ String IRDaikin2::toString(void) {
// - Daikin FTXZ25NV1B, FTXZ35NV1B, FTXZ50NV1B Aircon
// - Daikin ARC477A1 remote
//
-// Status: BETA / Work as expected.
+// Status: STABLE / Works as expected.
//
// Ref:
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
@@ -1565,7 +1565,7 @@ String IRDaikin216::toString(void) {
// Supported devices:
// - Daikin ARC433B69 remote.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/689
@@ -2283,7 +2283,7 @@ String IRDaikin176::toString(void) {
// Supported devices:
// - Daikin BRC4C153 remote.
//
-// Status: BETA / Probably works.
+// Status: STABLE / Expected to work.
//
bool IRrecv::decodeDaikin176(decode_results *results, uint16_t offset,
@@ -3187,3 +3187,420 @@ String IRDaikin152::toString(void) {
result += addBoolToString(getComfort(), kComfortStr);
return result;
}
+
+#if SEND_DAIKIN64
+// Send a Daikin 64 bit A/C message.
+//
+// Args:
+// data: A uint64_t containing the IR command/code.
+//
+// Supported devices:
+// - Daikin FFN-C.
+//
+// Status: Beta / Probably Working.
+//
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1064
+void IRsend::sendDaikin64(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ enableIROut(kDaikin64Freq);
+ for (uint16_t r = 0; r <= repeat; r++) {
+ for (uint8_t i = 0; i < 2; i++) {
+ // Leader
+ mark(kDaikin64LdrMark);
+ space(kDaikin64LdrSpace);
+ }
+ // Header + Data + Footer #1
+ sendGeneric(kDaikin64HdrMark, kDaikin64HdrSpace,
+ kDaikin64BitMark, kDaikin64OneSpace,
+ kDaikin64BitMark, kDaikin64ZeroSpace,
+ kDaikin64BitMark, kDaikin64Gap,
+ data, nbits, kDaikin64Freq, false, 0, 50);
+ // Footer #2
+ mark(kDaikin64HdrMark);
+ space(kDefaultMessageGap); // A guess of the gap between messages.
+ }
+}
+#endif // SEND_DAIKIN64
+
+#if DECODE_DAIKIN64
+// Decode the supplied Daikin 64 bit A/C message.
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// offset: The starting index to use when attempting to decode the raw data.
+// Typically/Defaults to kStartOffset.
+// nbits: Nr. of bits to expect in the data portion. (kDaikin64Bits)
+// strict: Flag to indicate if we strictly adhere to the specification.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Supported devices:
+// - Daikin FFN-C.
+//
+// Status: Beta / Probably Working.
+//
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1064
+bool IRrecv::decodeDaikin64(decode_results *results, uint16_t offset,
+ const uint16_t nbits, const bool strict) {
+ if (results->rawlen < 2 * nbits + kDaikin64Overhead - offset)
+ return false; // Too short a message to match.
+ // Compliance
+ if (strict && nbits != kDaikin64Bits)
+ return false;
+
+ // Leader
+ for (uint8_t i = 0; i < 2; i++) {
+ if (!matchMark(results->rawbuf[offset++], kDaikin64LdrMark))
+ return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikin64LdrSpace))
+ return false;
+ }
+ // Header + Data + Footer #1
+ uint16_t used = matchGeneric(results->rawbuf + offset, &results->value,
+ results->rawlen - offset, nbits,
+ kDaikin64HdrMark, kDaikin64HdrSpace,
+ kDaikin64BitMark, kDaikin64OneSpace,
+ kDaikin64BitMark, kDaikin64ZeroSpace,
+ kDaikin64BitMark, kDaikin64Gap,
+ false, _tolerance, kMarkExcess, false);
+ if (used == 0) return false;
+ offset += used;
+ // Footer #2
+ if (!matchMark(results->rawbuf[offset++], kDaikin64HdrMark))
+ return false;
+
+ // Compliance
+ if (strict && !IRDaikin64::validChecksum(results->value)) return false;
+ // Success
+ results->decode_type = decode_type_t::DAIKIN64;
+ results->bits = nbits;
+ results->command = 0;
+ results->address = 0;
+ return true;
+}
+#endif // DAIKIN64
+
+// Class for handling Daikin 64 bit / 19 byte A/C messages.
+//
+// Code by crankyoldgit.
+//
+// Supported Remotes: Daikin ARC480A5 remote
+//
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/873
+// https://github.com/ToniA/arduino-heatpumpir/blob/master/DaikinHeatpumpARC480A14IR.cpp
+// https://github.com/ToniA/arduino-heatpumpir/blob/master/DaikinHeatpumpARC480A14IR.h
+IRDaikin64::IRDaikin64(const uint16_t pin, const bool inverted,
+ const bool use_modulation)
+ : _irsend(pin, inverted, use_modulation) { stateReset(); }
+
+void IRDaikin64::begin(void) { _irsend.begin(); }
+
+#if SEND_DAIKIN64
+void IRDaikin64::send(const uint16_t repeat) {
+ _irsend.sendDaikin64(getRaw(), kDaikin64Bits, repeat);
+}
+#endif // SEND_DAIKIN64
+
+// Calc the checksum for a given state.
+// Args:
+// state: The value to calc the checksum of.
+// Returns:
+// A 4-bit checksum stored in a uint_8.
+uint8_t IRDaikin64::calcChecksum(const uint64_t state) {
+ uint64_t data = GETBITS64(state, 0, kDaikin64ChecksumOffset);
+ uint8_t result = 0;
+ for (; data; data >>= 4) // Add each nibble together.
+ result += GETBITS64(data, 0, 4);
+ return result & 0xF;
+}
+
+// Verify the checksum is valid for a given state.
+// Args:
+// state: The array to verify the checksum of.
+// length: The size of the state.
+// Returns:
+// A boolean.
+bool IRDaikin64::validChecksum(const uint64_t state) {
+ // Validate the checksum of the given state.
+ return (GETBITS64(state, kDaikin64ChecksumOffset,
+ kDaikin64ChecksumSize) == calcChecksum(state));
+}
+
+// Calculate and set the checksum values for the internal state.
+void IRDaikin64::checksum(void) {
+ setBits(&remote_state, kDaikin64ChecksumOffset, kDaikin64ChecksumSize,
+ calcChecksum(remote_state));
+}
+
+void IRDaikin64::stateReset(void) {
+ remote_state = kDaikin64KnownGoodState;
+}
+
+uint64_t IRDaikin64::getRaw(void) {
+ checksum(); // Ensure correct settings before sending.
+ return remote_state;
+}
+
+void IRDaikin64::setRaw(const uint64_t new_state) { remote_state = new_state; }
+
+void IRDaikin64::setPowerToggle(const bool on) {
+ setBit(&remote_state, kDaikin64PowerToggleBit, on);
+}
+
+bool IRDaikin64::getPowerToggle(void) {
+ return GETBIT64(remote_state, kDaikin64PowerToggleBit);
+}
+
+// Set the temp in deg C
+void IRDaikin64::setTemp(const uint8_t temp) {
+ uint8_t degrees = std::max(temp, kDaikin64MinTemp);
+ degrees = std::min(degrees, kDaikin64MaxTemp);
+ setBits(&remote_state, kDaikin64TempOffset,
+ kDaikin64TempSize, uint8ToBcd(degrees));
+}
+
+uint8_t IRDaikin64::getTemp(void) {
+ return bcdToUint8(GETBITS64(remote_state, kDaikin64TempOffset,
+ kDaikin64TempSize));
+}
+
+uint8_t IRDaikin64::getMode(void) {
+ return GETBITS64(remote_state, kDaikin64ModeOffset, kDaikin64ModeSize);
+}
+
+void IRDaikin64::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kDaikin64Fan:
+ case kDaikin64Dry:
+ case kDaikin64Cool:
+ break;
+ default:
+ this->setMode(kDaikin64Cool);
+ return;
+ }
+ setBits(&remote_state, kDaikin64ModeOffset, kDaikin64ModeSize, mode);
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRDaikin64::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kDry: return kDaikin64Dry;
+ case stdAc::opmode_t::kFan: return kDaikin64Fan;
+ default: return kDaikinCool;
+ }
+}
+
+// Convert a native mode to it's common equivalent.
+stdAc::opmode_t IRDaikin64::toCommonMode(const uint8_t mode) {
+ switch (mode) {
+ case kDaikin64Cool: return stdAc::opmode_t::kCool;
+ case kDaikin64Dry: return stdAc::opmode_t::kDry;
+ case kDaikin64Fan: return stdAc::opmode_t::kFan;
+ default: return stdAc::opmode_t::kAuto;
+ }
+}
+
+uint8_t IRDaikin64::getFan(void) {
+ return GETBITS64(remote_state, kDaikin64FanOffset, kDaikin64FanSize);
+}
+
+void IRDaikin64::setFan(const uint8_t speed) {
+ switch (speed) {
+ case kDaikin64FanQuiet:
+ case kDaikin64FanTurbo:
+ case kDaikin64FanAuto:
+ case kDaikin64FanHigh:
+ case kDaikin64FanMed:
+ case kDaikin64FanLow:
+ setBits(&remote_state, kDaikin64FanOffset, kDaikin64FanSize, speed);
+ break;
+ default:
+ this->setFan(kDaikin64FanAuto);
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikin64::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin: return kDaikin64FanQuiet;
+ case stdAc::fanspeed_t::kLow: return kDaikin64FanLow;
+ case stdAc::fanspeed_t::kMedium: return kDaikin64FanMed;
+ case stdAc::fanspeed_t::kHigh: return kDaikin64FanHigh;
+ case stdAc::fanspeed_t::kMax: return kDaikin64FanTurbo;
+ default: return kDaikin64FanAuto;
+ }
+}
+
+// Convert a native fan speed to it's common equivalent.
+stdAc::fanspeed_t IRDaikin64::toCommonFanSpeed(const uint8_t speed) {
+ switch (speed) {
+ case kDaikin64FanTurbo: return stdAc::fanspeed_t::kMax;
+ case kDaikin64FanHigh: return stdAc::fanspeed_t::kHigh;
+ case kDaikin64FanMed: return stdAc::fanspeed_t::kMedium;
+ case kDaikin64FanLow: return stdAc::fanspeed_t::kLow;
+ case kDaikinFanQuiet: return stdAc::fanspeed_t::kMin;
+ default: return stdAc::fanspeed_t::kAuto;
+ }
+}
+
+bool IRDaikin64::getTurbo(void) {
+ return getFan() == kDaikin64FanTurbo;
+}
+
+void IRDaikin64::setTurbo(const bool on) {
+ if (on) {
+ setFan(kDaikin64FanTurbo);
+ } else {
+ if (getFan() == kDaikin64FanTurbo) setFan(kDaikin64FanAuto);
+ }
+}
+
+bool IRDaikin64::getQuiet(void) {
+ return getFan() == kDaikin64FanQuiet;
+}
+
+void IRDaikin64::setQuiet(const bool on) {
+ if (on) {
+ setFan(kDaikin64FanQuiet);
+ } else {
+ if (getFan() == kDaikin64FanQuiet) setFan(kDaikin64FanAuto);
+ }
+}
+
+void IRDaikin64::setSwingVertical(const bool on) {
+ setBit(&remote_state, kDaikin64SwingVBit, on);
+}
+
+bool IRDaikin64::getSwingVertical(void) {
+ return GETBIT64(remote_state, kDaikin64SwingVBit);
+}
+
+void IRDaikin64::setSleep(const bool on) {
+ setBit(&remote_state, kDaikin64SleepBit, on);
+}
+
+bool IRDaikin64::getSleep(void) {
+ return GETBIT64(remote_state, kDaikin64SleepBit);
+}
+
+void IRDaikin64::setClock(const uint16_t mins_since_midnight) {
+ uint16_t mins = mins_since_midnight;
+ if (mins_since_midnight >= 24 * 60) mins = 0; // Bounds check.
+ setBits(&remote_state, kDaikin64ClockOffset, kDaikin64ClockMinsSize,
+ uint8ToBcd(mins % 60)); // Mins
+ setBits(&remote_state, kDaikin64ClockOffset + kDaikin64ClockMinsSize,
+ kDaikin64ClockHoursSize, uint8ToBcd(mins / 60)); // Hours
+}
+
+uint16_t IRDaikin64::getClock(void) {
+ return bcdToUint8(GETBITS64(remote_state,
+ kDaikin64ClockOffset + kDaikin64ClockMinsSize,
+ kDaikin64ClockHoursSize)) * 60 +
+ bcdToUint8(GETBITS64(remote_state, kDaikin64ClockOffset,
+ kDaikin64ClockMinsSize));
+}
+
+void IRDaikin64::setOnTimeEnabled(const bool on) {
+ setBit(&remote_state, kDaikin64OnTimeEnableBit, on);
+}
+
+bool IRDaikin64::getOnTimeEnabled(void) {
+ return GETBIT64(remote_state, kDaikin64OnTimeEnableBit);
+}
+
+uint16_t IRDaikin64::getOnTime(void) {
+ return bcdToUint8(GETBITS64(remote_state, kDaikin64OnTimeOffset,
+ kDaikin64OnTimeSize)) * 60 +
+ (GETBIT64(remote_state, kDaikin64OnTimeHalfHourBit) ? 30 : 0);
+}
+
+void IRDaikin64::setOnTime(const uint16_t mins_since_midnight) {
+ uint16_t halfhours = mins_since_midnight / 30;
+ if (mins_since_midnight >= 24 * 60) halfhours = 0; // Bounds check.
+ setBits(&remote_state, kDaikin64OnTimeOffset, kDaikin64OnTimeSize,
+ uint8ToBcd(halfhours / 2)); // Hours
+ // Half Hour
+ setBit(&remote_state, kDaikin64OnTimeHalfHourBit, halfhours % 2);
+}
+
+void IRDaikin64::setOffTimeEnabled(const bool on) {
+ setBit(&remote_state, kDaikin64OffTimeEnableBit, on);
+}
+
+bool IRDaikin64::getOffTimeEnabled(void) {
+ return GETBIT64(remote_state, kDaikin64OffTimeEnableBit);
+}
+
+uint16_t IRDaikin64::getOffTime(void) {
+ return bcdToUint8(GETBITS64(remote_state, kDaikin64OffTimeOffset,
+ kDaikin64OffTimeSize)) * 60 +
+ (GETBIT64(remote_state, kDaikin64OffTimeHalfHourBit) ? 30 : 0);
+}
+
+void IRDaikin64::setOffTime(const uint16_t mins_since_midnight) {
+ uint16_t halfhours = mins_since_midnight / 30;
+ if (mins_since_midnight >= 24 * 60) halfhours = 0; // Bounds check.
+ setBits(&remote_state, kDaikin64OffTimeOffset, kDaikin64OffTimeSize,
+ uint8ToBcd(halfhours / 2)); // Hours
+ // Half Hour
+ setBit(&remote_state, kDaikin64OffTimeHalfHourBit, halfhours % 2);
+}
+
+// Convert the internal state into a human readable string.
+String IRDaikin64::toString(void) {
+ String result = "";
+ result.reserve(120); // Reserve some heap for the string to reduce fragging.
+ result += addBoolToString(getPowerToggle(), kPowerToggleStr, false);
+ result += addModeToString(getMode(), 0xFF, kDaikin64Cool,
+ 0xFF, kDaikin64Dry, kDaikin64Fan);
+ result += addTempToString(getTemp());
+ if (!getTurbo()) {
+ result += addFanToString(getFan(), kDaikin64FanHigh, kDaikin64FanLow,
+ kDaikin64FanAuto, kDaikin64FanQuiet,
+ kDaikin64FanMed);
+ } else {
+ result += addIntToString(getFan(), kFanStr);
+ result += kSpaceLBraceStr;
+ result += kTurboStr;
+ result += ')';
+ }
+ result += addBoolToString(getTurbo(), kTurboStr);
+ result += addBoolToString(getQuiet(), kQuietStr);
+ result += addBoolToString(getSwingVertical(), kSwingVStr);
+ result += addBoolToString(getSleep(), kSleepStr);
+ result += addLabeledString(minsToString(getClock()), kClockStr);
+ result += addLabeledString(getOnTimeEnabled()
+ ? minsToString(getOnTime()) : kOffStr,
+ kOnTimerStr);
+ result += addLabeledString(getOffTimeEnabled()
+ ? minsToString(getOffTime()) : kOffStr,
+ kOffTimerStr);
+ return result;
+}
+
+// Convert the A/C state to it's common equivalent.
+stdAc::state_t IRDaikin64::toCommon(const stdAc::state_t *prev) {
+ stdAc::state_t result;
+ if (prev != NULL) result = *prev;
+ result.protocol = decode_type_t::DAIKIN64;
+ result.model = -1; // No models used.
+ result.power ^= getPowerToggle();
+ result.mode = toCommonMode(getMode());
+ result.celsius = true;
+ result.degrees = getTemp();
+ result.fanspeed = toCommonFanSpeed(getFan());
+ result.swingv = getSwingVertical() ? stdAc::swingv_t::kAuto
+ : stdAc::swingv_t::kOff;
+ result.turbo = getTurbo();
+ result.quiet = getQuiet();
+ result.sleep = getSleep() ? 0 : -1;
+ result.clock = getClock();
+ // Not supported.
+ result.swingh = stdAc::swingh_t::kOff;
+ result.clean = false;
+ result.filter = false;
+ result.beep = false;
+ result.econo = false;
+ result.light = false;
+ return result;
+}
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Daikin.h b/lib/IRremoteESP8266-2.7.6/src/ir_Daikin.h
similarity index 87%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Daikin.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Daikin.h
index 42039b07b..3630aa77b 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Daikin.h
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Daikin.h
@@ -17,6 +17,8 @@
// Brand: Daikin, Model: FTXB09AXVJU A/C (DAIKIN128)
// Brand: Daikin, Model: BRC52B63 remote (DAIKIN128)
// Brand: Daikin, Model: ARC480A5 remote (DAIKIN152)
+// Brand: Daikin, Model: FFN-C/FCN-F Series A/C (DAIKIN64)
+// Brand: Daikin, Model: DGS01 remote (DAIKIN64)
#ifndef IR_DAIKIN_H_
#define IR_DAIKIN_H_
@@ -430,6 +432,56 @@ const uint8_t kDaikin152ComfortOffset = 1; // Mask 0b00000010
const uint8_t kDaikin152SensorByte = kDaikin152EconoByte; // Mask 0b00001000
const uint8_t kDaikin152SensorOffset = 3; // Mask 0b00001000
+const uint16_t kDaikin64HdrMark = kDaikin128HdrMark;
+const uint16_t kDaikin64BitMark = kDaikin128BitMark;
+const uint16_t kDaikin64HdrSpace = kDaikin128HdrSpace;
+const uint16_t kDaikin64OneSpace = kDaikin128OneSpace;
+const uint16_t kDaikin64ZeroSpace = kDaikin128ZeroSpace;
+const uint16_t kDaikin64LdrMark = kDaikin128LeaderMark;
+const uint16_t kDaikin64Gap = kDaikin128Gap;
+const uint16_t kDaikin64LdrSpace = kDaikin128LeaderSpace;
+const uint16_t kDaikin64Freq = kDaikin128Freq; // Hz.
+const uint16_t kDaikin64Overhead = 9;
+
+const uint64_t kDaikin64KnownGoodState = 0x7C16161607204216;
+const uint8_t kDaikin64ModeOffset = 8;
+const uint8_t kDaikin64ModeSize = 4; // Mask 0b111100000000
+const uint8_t kDaikin64Dry = 0b001;
+const uint8_t kDaikin64Cool = 0b010;
+const uint8_t kDaikin64Fan = 0b100;
+const uint8_t kDaikin64FanOffset = kDaikin64ModeOffset + kDaikin64ModeSize;
+const uint8_t kDaikin64FanSize = 4; // Mask 0b1111000000000000
+const uint8_t kDaikin64FanAuto = 0b0001;
+const uint8_t kDaikin64FanLow = 0b1000;
+const uint8_t kDaikin64FanMed = 0b0100;
+const uint8_t kDaikin64FanHigh = 0b0010;
+const uint8_t kDaikin64FanQuiet = 0b1001;
+const uint8_t kDaikin64FanTurbo = 0b0011;
+const uint8_t kDaikin64ClockOffset = kDaikin64FanOffset + kDaikin64FanSize;
+const uint8_t kDaikin64ClockMinsSize = 8;
+const uint8_t kDaikin64ClockHoursSize = 8;
+const uint8_t kDaikin64ClockSize = kDaikin64ClockMinsSize +
+ kDaikin64ClockHoursSize; // Mask 0b1111111111111111 << 15
+const uint8_t kDaikin64OnTimeOffset = kDaikin64ClockOffset +
+ kDaikin64ClockSize;
+const uint8_t kDaikin64OnTimeSize = 6;
+const uint8_t kDaikin64OnTimeHalfHourBit = kDaikin64OnTimeOffset +
+ kDaikin64OnTimeSize;
+const uint8_t kDaikin64OnTimeEnableBit = kDaikin64OnTimeHalfHourBit + 1;
+const uint8_t kDaikin64OffTimeOffset = kDaikin64OnTimeEnableBit + 1;
+const uint8_t kDaikin64OffTimeSize = 6;
+const uint8_t kDaikin64OffTimeHalfHourBit = kDaikin64OffTimeOffset +
+ kDaikin64OffTimeSize;
+const uint8_t kDaikin64OffTimeEnableBit = kDaikin64OffTimeHalfHourBit + 1;
+const uint8_t kDaikin64TempOffset = 48;
+const uint8_t kDaikin64TempSize = 8; // Mask 0b11111111 << 47
+const uint8_t kDaikin64MinTemp = 16; // Celsius
+const uint8_t kDaikin64MaxTemp = 30; // Celsius
+const uint8_t kDaikin64SwingVBit = 56;
+const uint8_t kDaikin64SleepBit = kDaikin64SwingVBit + 1;
+const uint8_t kDaikin64PowerToggleBit = 59;
+const uint8_t kDaikin64ChecksumOffset = 60;
+const uint8_t kDaikin64ChecksumSize = 4; // Mask 0b1111 << 59
// Legacy defines.
#define DAIKIN_COOL kDaikinCool
@@ -881,4 +933,63 @@ class IRDaikin152 {
void stateReset();
void checksum();
};
+
+// Class to emulate a Daikin DGS01 remote.
+class IRDaikin64 {
+ public:
+ explicit IRDaikin64(const uint16_t pin, const bool inverted = false,
+ const bool use_modulation = true);
+
+#if SEND_DAIKIN64
+ void send(const uint16_t repeat = kDaikin64DefaultRepeat);
+ uint8_t calibrate(void) { return _irsend.calibrate(); }
+#endif // SEND_DAIKIN64
+ void begin();
+ uint64_t getRaw();
+ void setRaw(const uint64_t new_state);
+ static uint8_t calcChecksum(const uint64_t state);
+ static bool validChecksum(const uint64_t state);
+ void setPowerToggle(const bool on);
+ bool getPowerToggle(void);
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp();
+ void setFan(const uint8_t fan);
+ uint8_t getFan(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setSleep(const bool on);
+ bool getSleep(void);
+ bool getQuiet(void);
+ void setQuiet(const bool on);
+ bool getTurbo(void);
+ void setTurbo(const bool on);
+ void setClock(const uint16_t mins_since_midnight);
+ uint16_t getClock(void);
+ void setOnTimeEnabled(const bool on);
+ bool getOnTimeEnabled(void);
+ void setOnTime(const uint16_t mins_since_midnight);
+ uint16_t getOnTime(void);
+ void setOffTimeEnabled(const bool on);
+ bool getOffTimeEnabled(void);
+ void setOffTime(const uint16_t mins_since_midnight);
+ uint16_t getOffTime(void);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static stdAc::opmode_t toCommonMode(const uint8_t mode);
+ static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
+ stdAc::state_t toCommon(const stdAc::state_t *prev = NULL);
+ String toString(void);
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint64_t remote_state;
+ void stateReset();
+ void checksum();
+};
#endif // IR_DAIKIN_H_
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Denon.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Denon.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Denon.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Denon.cpp
index bd4940714..6dd4cd839 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Denon.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Denon.cpp
@@ -40,7 +40,7 @@ const uint64_t kDenonManufacturer = 0x2A4CULL;
// nbits: Nr. of bits of data to be sent. Typically kDenonBits.
// repeat: Nr. of additional times the message is to be sent.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
//
// Notes:
// Some Denon devices use a Kaseikyo/Panasonic 48-bit format
@@ -71,7 +71,7 @@ void IRsend::sendDenon(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Should work fine.
+// Status: STABLE / Should work fine.
//
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Dish.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Dish.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Dish.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Dish.cpp
index 834ceda04..291201ed6 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Dish.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Dish.cpp
@@ -37,7 +37,7 @@ const uint16_t kDishRptSpace = kDishRptSpaceTicks * kDishTick;
// nbits: The bit size of the command being sent.
// repeat: The number of times you want the command to be repeated.
//
-// Status: BETA / Previously working.
+// Status: STABLE / Working.
//
// Note:
// Dishplayer is a different protocol.
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Electra.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Electra.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Electra.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Electra.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Electra.h b/lib/IRremoteESP8266-2.7.6/src/ir_Electra.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Electra.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Electra.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Epson.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Epson.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Epson.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Epson.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Fujitsu.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Fujitsu.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Fujitsu.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Fujitsu.h b/lib/IRremoteESP8266-2.7.6/src/ir_Fujitsu.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Fujitsu.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Fujitsu.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_GICable.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_GICable.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_GICable.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_GICable.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_GlobalCache.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_GlobalCache.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_GlobalCache.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Goodweather.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Goodweather.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Goodweather.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Goodweather.cpp
index 8b7e0b76e..97a4a9277 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Goodweather.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Goodweather.cpp
@@ -34,7 +34,7 @@ using irutils::setBits;
// nbits: Nr. of bits of data in the message. (Default is kGoodweatherBits)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: ALPHA / Untested.
+// Status: BETA / Needs testing on real device.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/697
@@ -377,7 +377,7 @@ String IRGoodweatherAc::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: ALPHA / Untested.
+// Status: BETA / Probably works.
bool IRrecv::decodeGoodweather(decode_results* results, uint16_t offset,
const uint16_t nbits,
const bool strict) {
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Goodweather.h b/lib/IRremoteESP8266-2.7.6/src/ir_Goodweather.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Goodweather.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Goodweather.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Gree.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Gree.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Gree.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Gree.cpp
index 735e3b88c..81062d650 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Gree.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Gree.cpp
@@ -50,7 +50,7 @@ using irutils::setBits;
// nbytes: Nr. of bytes of data in the array. (>=kGreeStateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: ALPHA / Untested.
+// Status: STABLE / Working.
//
// Ref:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp
@@ -84,7 +84,7 @@ void IRsend::sendGree(const unsigned char data[], const uint16_t nbytes,
// nbits: Nr. of bits of data in the message. (Default is kGreeBits)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: ALPHA / Untested.
+// Status: STABLE / Working.
//
// Ref:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Gree.h b/lib/IRremoteESP8266-2.7.6/src/ir_Gree.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Gree.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Gree.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Haier.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Haier.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Haier.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Haier.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Haier.h b/lib/IRremoteESP8266-2.7.6/src/ir_Haier.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Haier.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Haier.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Hitachi.cpp
similarity index 60%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Hitachi.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Hitachi.cpp
index 02489d010..01cc49d28 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Hitachi.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Hitachi.cpp
@@ -37,12 +37,22 @@ const uint16_t kHitachiAc424BitMark = 463;
const uint16_t kHitachiAc424OneSpace = 1208;
const uint16_t kHitachiAc424ZeroSpace = 372;
+// Support for HitachiAc3 protocol
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1060
+const uint16_t kHitachiAc3HdrMark = 3400; // Header
+const uint16_t kHitachiAc3HdrSpace = 1660; // Header
+const uint16_t kHitachiAc3BitMark = 460;
+const uint16_t kHitachiAc3OneSpace = 1250;
+const uint16_t kHitachiAc3ZeroSpace = 410;
+
using irutils::addBoolToString;
using irutils::addIntToString;
using irutils::addLabeledString;
using irutils::addModeToString;
+using irutils::addModelToString;
using irutils::addFanToString;
using irutils::addTempToString;
+using irutils::minsToString;
using irutils::setBit;
using irutils::setBits;
@@ -54,7 +64,7 @@ using irutils::setBits;
// nbytes: Nr. of bytes of data in the array. (>=kHitachiAcStateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: ALPHA / Untested.
+// Status: STABLE / Working.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/417
@@ -80,7 +90,7 @@ void IRsend::sendHitachiAC(const unsigned char data[], const uint16_t nbytes,
// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc1StateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: BETA / Appears to work.
+// Status: STABLE / Confirmed Working.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/453
@@ -107,7 +117,7 @@ void IRsend::sendHitachiAC1(const unsigned char data[], const uint16_t nbytes,
// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc2StateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: BETA / Appears to work.
+// Status: STABLE / Expected to work.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/417
@@ -354,6 +364,358 @@ String IRHitachiAc::toString(void) {
return result;
}
+// Class for handling the remote control on a Hitachi 13 byte A/C message.
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1056
+
+IRHitachiAc1::IRHitachiAc1(const uint16_t pin, const bool inverted,
+ const bool use_modulation)
+ : _irsend(pin, inverted, use_modulation) { stateReset(); }
+
+void IRHitachiAc1::stateReset(void) {
+ for (uint8_t i = 0; i < kHitachiAc1StateLength; i++) remote_state[i] = 0x00;
+ // Copy in a known good state.
+ remote_state[0] = 0xB2;
+ remote_state[1] = 0xAE;
+ remote_state[2] = 0x4D;
+ remote_state[3] = 0x91;
+ remote_state[4] = 0xF0;
+ remote_state[5] = 0xE1;
+ remote_state[6] = 0xA4;
+ remote_state[11] = 0x61;
+ remote_state[12] = 0x24;
+}
+
+void IRHitachiAc1::begin(void) { _irsend.begin(); }
+
+uint8_t IRHitachiAc1::calcChecksum(const uint8_t state[],
+ const uint16_t length) {
+ uint8_t sum = 0;
+ for (uint16_t i = kHitachiAc1ChecksumStartByte; i < length - 1; i++) {
+ sum += reverseBits(GETBITS8(state[i], kLowNibble, kNibbleSize),
+ kNibbleSize);
+ sum += reverseBits(GETBITS8(state[i], kHighNibble, kNibbleSize),
+ kNibbleSize);
+ }
+ return reverseBits(sum, 8);
+}
+
+void IRHitachiAc1::checksum(const uint16_t length) {
+ remote_state[length - 1] = calcChecksum(remote_state, length);
+}
+
+bool IRHitachiAc1::validChecksum(const uint8_t state[], const uint16_t length) {
+ if (length < 2) return true; // Assume true for lengths that are too short.
+ return (state[length - 1] == calcChecksum(state, length));
+}
+
+uint8_t *IRHitachiAc1::getRaw(void) {
+ checksum();
+ return remote_state;
+}
+
+void IRHitachiAc1::setRaw(const uint8_t new_code[], const uint16_t length) {
+ memcpy(remote_state, new_code, std::min(length, kHitachiAc1StateLength));
+}
+
+#if SEND_HITACHI_AC
+void IRHitachiAc1::send(const uint16_t repeat) {
+ _irsend.sendHitachiAC1(getRaw(), kHitachiAc1StateLength, repeat);
+ // Clear the toggle bits as we have actioned them by sending them.
+ setPowerToggle(false);
+ setSwingToggle(false);
+}
+#endif // SEND_HITACHI_AC
+
+hitachi_ac1_remote_model_t IRHitachiAc1::getModel(void) {
+ switch (GETBITS8(remote_state[kHitachiAc1ModelByte], kHitachiAc1ModelOffset,
+ kHitachiAc1ModelSize)) {
+ case kHitachiAc1Model_B: return hitachi_ac1_remote_model_t::R_LT0541_HTA_B;
+ default: return hitachi_ac1_remote_model_t::R_LT0541_HTA_A;
+ }
+}
+
+void IRHitachiAc1::setModel(const hitachi_ac1_remote_model_t model) {
+ uint8_t value = 0;
+ switch (model) {
+ case hitachi_ac1_remote_model_t::R_LT0541_HTA_B:
+ value = kHitachiAc1Model_B;
+ break;
+ default:
+ value = kHitachiAc1Model_A; // i.e. 'A' mode.
+ }
+ setBits(&remote_state[kHitachiAc1ModelByte], kHitachiAc1ModelOffset,
+ kHitachiAc1ModelSize, value);
+}
+
+bool IRHitachiAc1::getPower(void) {
+ return GETBIT8(remote_state[kHitachiAc1PowerByte], kHitachiAc1PowerOffset);
+}
+
+void IRHitachiAc1::setPower(const bool on) {
+ // If the power changes, set the power toggle bit.
+ if (on != getPower()) setPowerToggle(true);
+ setBit(&remote_state[kHitachiAc1PowerByte], kHitachiAc1PowerOffset, on);
+}
+
+bool IRHitachiAc1::getPowerToggle(void) {
+ return GETBIT8(remote_state[kHitachiAc1PowerByte],
+ kHitachiAc1PowerToggleOffset);
+}
+
+void IRHitachiAc1::setPowerToggle(const bool on) {
+ setBit(&remote_state[kHitachiAc1PowerByte], kHitachiAc1PowerToggleOffset, on);
+}
+
+void IRHitachiAc1::on(void) { setPower(true); }
+
+void IRHitachiAc1::off(void) { setPower(false); }
+
+uint8_t IRHitachiAc1::getMode(void) {
+ return GETBITS8(remote_state[kHitachiAc1ModeByte], kHitachiAc1ModeOffset,
+ kHitachiAc1ModeSize);
+}
+
+void IRHitachiAc1::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kHitachiAc1Auto:
+ setTemp(kHitachiAc1TempAuto);
+ // FALL THRU
+ case kHitachiAc1Fan:
+ case kHitachiAc1Heat:
+ case kHitachiAc1Cool:
+ case kHitachiAc1Dry:
+ setBits(&remote_state[kHitachiAc1ModeByte], kHitachiAc1ModeOffset,
+ kHitachiAc1ModeSize, mode);
+ setSleep(getSleep()); // Correct the sleep mode if required.
+ setFan(getFan()); // Correct the fan speed if required.
+ break;
+ default: setMode(kHitachiAc1Auto);
+ }
+ switch (mode) {
+ case kHitachiAc1Fan:
+ case kHitachiAc1Heat:
+ // Auto fan speed not available in these modes, change if needed.
+ if (getFan() == kHitachiAc1FanAuto) setFan(kHitachiAc1FanLow);
+ }
+}
+
+uint8_t IRHitachiAc1::getTemp(void) {
+ return reverseBits(GETBITS8(remote_state[kHitachiAc1TempByte],
+ kHitachiAc1TempOffset, kHitachiAc1TempSize),
+ kHitachiAc1TempSize) + kHitachiAc1TempDelta;
+}
+
+void IRHitachiAc1::setTemp(const uint8_t celsius) {
+ if (getMode() == kHitachiAc1Auto) return; // Can't change temp in Auto mode.
+ uint8_t temp = std::min(celsius, kHitachiAcMaxTemp);
+ temp = std::max(temp, kHitachiAcMinTemp);
+ temp -= kHitachiAc1TempDelta;
+ temp = reverseBits(temp, kHitachiAc1TempSize);
+ setBits(&remote_state[kHitachiAc1TempByte], kHitachiAc1TempOffset,
+ kHitachiAc1TempSize, temp);
+}
+
+uint8_t IRHitachiAc1::getFan(void) {
+ return GETBITS8(remote_state[kHitachiAc1FanByte], kHitachiAc1FanOffset,
+ kHitachiAc1FanSize);
+}
+
+void IRHitachiAc1::setFan(const uint8_t speed, const bool force) {
+ if (!force) {
+ switch (getMode()) {
+ case kHitachiAc1Dry:
+ setFan(kHitachiAc1FanLow, true); // Dry is locked to Low speed.
+ return;
+ case kHitachiAc1Auto:
+ setFan(kHitachiAc1FanAuto, true); // Auto is locked to Auto speed.
+ return;
+ }
+ }
+ switch (speed) {
+ case kHitachiAc1FanAuto:
+ switch (getMode()) {
+ case kHitachiAc1Heat:
+ case kHitachiAc1Fan: return; // Auto speed not allowed in these modes.
+ }
+ // FALL THRU
+ case kHitachiAc1FanHigh:
+ case kHitachiAc1FanMed:
+ case kHitachiAc1FanLow:
+ setBits(&remote_state[kHitachiAc1FanByte], kHitachiAc1FanOffset,
+ kHitachiAc1FanSize, speed);
+ break;
+ default: setFan(kHitachiAc1FanAuto);
+ }
+}
+
+bool IRHitachiAc1::getSwingToggle(void) {
+ return GETBIT8(remote_state[kHitachiAc1SwingByte],
+ kHitachiAc1SwingToggleOffset);
+}
+
+void IRHitachiAc1::setSwingToggle(const bool toggle) {
+ setBit(&remote_state[kHitachiAc1SwingByte], kHitachiAc1SwingToggleOffset,
+ toggle);
+}
+
+bool IRHitachiAc1::getSwingV(void) {
+ return GETBIT8(remote_state[kHitachiAc1SwingByte], kHitachiAc1SwingVOffset);
+}
+
+void IRHitachiAc1::setSwingV(const bool on) {
+ setBit(&remote_state[kHitachiAc1SwingByte], kHitachiAc1SwingVOffset, on);
+}
+
+bool IRHitachiAc1::getSwingH(void) {
+ return GETBIT8(remote_state[kHitachiAc1SwingByte], kHitachiAc1SwingHOffset);
+}
+
+void IRHitachiAc1::setSwingH(const bool on) {
+ setBit(&remote_state[kHitachiAc1SwingByte], kHitachiAc1SwingHOffset, on);
+}
+
+uint8_t IRHitachiAc1::getSleep(void) {
+ return GETBITS8(remote_state[kHitachiAc1SleepByte], kHitachiAc1SleepOffset,
+ kHitachiAc1SleepSize);
+}
+
+void IRHitachiAc1::setSleep(const uint8_t mode) {
+ // Sleep modes only available in Auto & Cool modes, otherwise it's off.
+ switch (getMode()) {
+ case kHitachiAc1Auto:
+ case kHitachiAc1Cool:
+ setBits(&remote_state[kHitachiAc1SleepByte], kHitachiAc1SleepOffset,
+ kHitachiAc1SleepSize, std::min(mode, kHitachiAc1Sleep4));
+ break;
+ default:
+ setBits(&remote_state[kHitachiAc1SleepByte], kHitachiAc1SleepOffset,
+ kHitachiAc1SleepSize, kHitachiAc1SleepOff);
+ }
+}
+
+void IRHitachiAc1::setOnTimer(const uint16_t mins) {
+ const uint16_t mins_lsb = reverseBits(mins, kHitachiAc1TimerSize);
+ remote_state[kHitachiAc1OnTimerLowByte] = GETBITS16(mins_lsb, 8, 8);
+ remote_state[kHitachiAc1OnTimerHighByte] = GETBITS16(mins_lsb, 0, 8);
+}
+
+uint16_t IRHitachiAc1::getOnTimer(void) {
+ return reverseBits(
+ (remote_state[kHitachiAc1OnTimerLowByte] << 8) |
+ remote_state[kHitachiAc1OnTimerHighByte], kHitachiAc1TimerSize);
+}
+
+void IRHitachiAc1::setOffTimer(const uint16_t mins) {
+ const uint16_t mins_lsb = reverseBits(mins, kHitachiAc1TimerSize);
+ remote_state[kHitachiAc1OffTimerLowByte] = GETBITS16(mins_lsb, 8, 8);
+ remote_state[kHitachiAc1OffTimerHighByte] = GETBITS16(mins_lsb, 0, 8);
+}
+
+uint16_t IRHitachiAc1::getOffTimer(void) {
+ return reverseBits(
+ (remote_state[kHitachiAc1OffTimerLowByte] << 8) |
+ remote_state[kHitachiAc1OffTimerHighByte], kHitachiAc1TimerSize);
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHitachiAc1::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool: return kHitachiAc1Cool;
+ case stdAc::opmode_t::kHeat: return kHitachiAc1Heat;
+ case stdAc::opmode_t::kDry: return kHitachiAc1Dry;
+ case stdAc::opmode_t::kFan: return kHitachiAc1Fan;
+ default: return kHitachiAc1Auto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHitachiAc1::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow: return kHitachiAc1FanLow;
+ case stdAc::fanspeed_t::kMedium: return kHitachiAc1FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax: return kHitachiAc1FanHigh;
+ default: return kHitachiAc1FanAuto;
+ }
+}
+
+// Convert a native mode to it's common equivalent.
+stdAc::opmode_t IRHitachiAc1::toCommonMode(const uint8_t mode) {
+ switch (mode) {
+ case kHitachiAc1Cool: return stdAc::opmode_t::kCool;
+ case kHitachiAc1Heat: return stdAc::opmode_t::kHeat;
+ case kHitachiAc1Dry: return stdAc::opmode_t::kDry;
+ case kHitachiAc1Fan: return stdAc::opmode_t::kFan;
+ default: return stdAc::opmode_t::kAuto;
+ }
+}
+
+// Convert a native fan speed to it's common equivalent.
+stdAc::fanspeed_t IRHitachiAc1::toCommonFanSpeed(const uint8_t speed) {
+ switch (speed) {
+ case kHitachiAc1FanHigh: return stdAc::fanspeed_t::kMax;
+ case kHitachiAc1FanMed: return stdAc::fanspeed_t::kMedium;
+ case kHitachiAc1FanLow: return stdAc::fanspeed_t::kLow;
+ default: return stdAc::fanspeed_t::kAuto;
+ }
+}
+
+// Convert the A/C state to it's common equivalent.
+stdAc::state_t IRHitachiAc1::toCommon(void) {
+ stdAc::state_t result;
+ result.protocol = decode_type_t::HITACHI_AC1;
+ result.model = this->getModel();
+ result.power = this->getPower();
+ result.mode = this->toCommonMode(this->getMode());
+ result.celsius = true;
+ result.degrees = this->getTemp();
+ result.fanspeed = this->toCommonFanSpeed(this->getFan());
+ result.swingv = this->getSwingV() ? stdAc::swingv_t::kAuto :
+ stdAc::swingv_t::kOff;
+ result.swingh = this->getSwingH() ? stdAc::swingh_t::kAuto :
+ stdAc::swingh_t::kOff;
+ result.sleep = this->getSleep() ? 0 : -1;
+ // Not supported.
+ result.quiet = false;
+ result.turbo = false;
+ result.clean = false;
+ result.econo = false;
+ result.filter = false;
+ result.light = false;
+ result.beep = false;
+ result.clock = -1;
+ return result;
+}
+
+// Convert the internal state into a human readable string.
+String IRHitachiAc1::toString(void) {
+ String result = "";
+ result.reserve(170); // Reserve some heap for the string to reduce fragging.
+ result += addModelToString(decode_type_t::HITACHI_AC1, getModel(), false);
+ result += addBoolToString(getPower(), kPowerStr);
+ result += addBoolToString(getPowerToggle(), kPowerToggleStr);
+ result += addModeToString(getMode(), kHitachiAc1Auto, kHitachiAc1Cool,
+ kHitachiAc1Heat, kHitachiAc1Dry, kHitachiAc1Fan);
+ result += addTempToString(getTemp());
+ result += addFanToString(getFan(), kHitachiAc1FanHigh, kHitachiAc1FanLow,
+ kHitachiAc1FanAuto, kHitachiAc1FanAuto,
+ kHitachiAc1FanMed);
+ result += addBoolToString(getSwingToggle(), kSwingVToggleStr);
+ result += addBoolToString(getSwingV(), kSwingVStr);
+ result += addBoolToString(getSwingH(), kSwingHStr);
+ result += addLabeledString(getSleep() ? uint64ToString(getSleep()) : kOffStr,
+ kSleepStr);
+ result += addLabeledString(getOnTimer() ? minsToString(getOnTimer())
+ : kOffStr,
+ kOnTimerStr);
+ result += addLabeledString(getOffTimer() ? minsToString(getOffTimer())
+ : kOffStr,
+ kOffTimerStr);
+ return result;
+}
+
#if (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2)
// Decode the supplied Hitachi A/C message.
//
@@ -367,7 +729,7 @@ String IRHitachiAc::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Probably works.
+// Status: STABLE / Expected to work.
//
// Supported devices:
// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA
@@ -412,6 +774,9 @@ bool IRrecv::decodeHitachiAC(decode_results *results, uint16_t offset,
if (nbits / 8 == kHitachiAcStateLength &&
!IRHitachiAc::validChecksum(results->state, kHitachiAcStateLength))
return false;
+ if (nbits / 8 == kHitachiAc1StateLength &&
+ !IRHitachiAc1::validChecksum(results->state, kHitachiAc1StateLength))
+ return false;
}
// Success
@@ -800,3 +1165,142 @@ String IRHitachiAc424::toString(void) {
result += ')';
return result;
}
+
+
+#if SEND_HITACHI_AC3
+// Send HITACHI_AC3 messages
+//
+// Note: This protocol is almost exactly the same as HitachiAC424 except this
+// variant has subtle timing differences.
+// There are five(5) typical sizes:
+// * kHitachiAc3MinStateLength (Cancel Timer)
+// * kHitachiAc3MinStateLength + 2 (Change Temp)
+// * kHitachiAc3StateLength - 6 (Change Mode)
+// * kHitachiAc3StateLength- 4 (Normal)
+// * kHitachiAc3StateLength (Set Timer)
+//
+// Args:
+// data: An array of bytes containing the IR command.
+// It is assumed to be in LSBF order for this code.
+// nbytes: Nr. of bytes of data in the array.
+// repeat: Nr. of times the message is to be repeated.
+//
+// Status: STABLE / Working fine.
+void IRsend::sendHitachiAc3(const uint8_t data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ // Header + Data + Footer
+ sendGeneric(kHitachiAc3HdrMark, kHitachiAc3HdrSpace,
+ kHitachiAc3BitMark, kHitachiAc3OneSpace,
+ kHitachiAc3BitMark, kHitachiAc3ZeroSpace,
+ kHitachiAc3BitMark, kHitachiAcMinGap,
+ data, nbytes, // Bytes
+ kHitachiAcFreq, false, repeat, kDutyDefault);
+}
+#endif // SEND_HITACHI_AC3
+
+
+// Class for handling the remote control on a Hitachi_AC3 53 A/C message
+IRHitachiAc3::IRHitachiAc3(const uint16_t pin, const bool inverted,
+ const bool use_modulation)
+ : _irsend(pin, inverted, use_modulation) { stateReset(); }
+
+// Reset to auto fan, cooling, 23° Celcius
+void IRHitachiAc3::stateReset(void) {
+ for (uint8_t i = 0; i < kHitachiAc3StateLength; i++)
+ remote_state[i] = 0x00;
+ remote_state[0] = 0x01;
+ remote_state[1] = 0x10;
+ remote_state[3] = 0x40;
+ remote_state[5] = 0xFF;
+ remote_state[7] = 0xE8;
+ remote_state[9] = 0x89;
+ remote_state[11] = 0x0B;
+ remote_state[13] = 0x3F;
+ remote_state[15] = 0x15;
+ remote_state[21] = 0x4B;
+ remote_state[23] = 0x18;
+ setInvertedStates();
+}
+
+void IRHitachiAc3::setInvertedStates(const uint16_t length) {
+ for (uint8_t i = 3; i < length - 1; i += 2)
+ remote_state[i + 1] = ~remote_state[i];
+}
+
+bool IRHitachiAc3::hasInvertedStates(const uint8_t state[],
+ const uint16_t length) {
+ for (uint8_t i = 3; i < length - 1; i += 2)
+ if ((state[i + 1] ^ state[i]) != 0xFF) return false;
+ return true;
+}
+
+void IRHitachiAc3::begin(void) { _irsend.begin(); }
+
+uint8_t *IRHitachiAc3::getRaw(void) {
+ setInvertedStates();
+ return remote_state;
+}
+
+void IRHitachiAc3::setRaw(const uint8_t new_code[], const uint16_t length) {
+ memcpy(remote_state, new_code, std::min(length, kHitachiAc3StateLength));
+}
+
+#if DECODE_HITACHI_AC3
+// Decode the supplied HitachiAc3 A/C message.
+//
+// Note: This protocol is almost exactly the same as HitachiAC424 except this
+// variant has subtle timing differences and multiple lengths.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// offset: The starting index to use when attempting to decode the raw data.
+// Typically/Defaults to kStartOffset.
+// nbits: The number of data bits to expect. Typically kHitachiAc3Bits.
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: STABLE / Works fine.
+//
+// Supported devices:
+// Hitachi PC-LH3B
+//
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1060
+bool IRrecv::decodeHitachiAc3(decode_results *results, uint16_t offset,
+ const uint16_t nbits,
+ const bool strict) {
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1 + offset)
+ return false; // Too short a message to match.
+ if (strict) {
+ // Check the requested bit length.
+ switch (nbits) {
+ case kHitachiAc3MinBits: // Cancel Timer (Min Size)
+ case kHitachiAc3MinBits + 2 * 8: // Change Temp
+ case kHitachiAc3Bits - 6 * 8: // Change Mode
+ case kHitachiAc3Bits - 4 * 8: // Normal
+ case kHitachiAc3Bits: // Set Temp (Max Size)
+ break;
+ default: return false;
+ }
+ }
+
+ // Header + Data + Footer
+ if (!matchGeneric(results->rawbuf + offset, results->state,
+ results->rawlen - offset, nbits,
+ kHitachiAc3HdrMark, kHitachiAc3HdrSpace,
+ kHitachiAc3BitMark, kHitachiAc3OneSpace,
+ kHitachiAc3BitMark, kHitachiAc3ZeroSpace,
+ kHitachiAc3BitMark, kHitachiAcMinGap, true,
+ kUseDefTol, 0, false))
+ return false; // We failed to find any data.
+
+ // Compliance
+ if (strict && !IRHitachiAc3::hasInvertedStates(results->state, nbits / 8))
+ return false;
+ // Success
+ results->decode_type = decode_type_t::HITACHI_AC3;
+ results->bits = nbits;
+ return true;
+}
+#endif // DECODE_HITACHI_AC3
diff --git a/lib/IRremoteESP8266-2.7.6/src/ir_Hitachi.h b/lib/IRremoteESP8266-2.7.6/src/ir_Hitachi.h
new file mode 100644
index 000000000..0db3552ff
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Hitachi.h
@@ -0,0 +1,330 @@
+// Hitachi A/C
+//
+// Copyright 2018-2020 David Conran
+
+// Supports:
+// Brand: Hitachi, Model: RAS-35THA6 remote
+// Brand: Hitachi, Model: LT0541-HTA remote
+// Brand: Hitachi, Model: Series VI A/C (Circa 2007)
+// Brand: Hitachi, Model: RAR-8P2 remote
+// Brand: Hitachi, Model: RAS-AJ25H A/C
+// Brand: Hitachi, Model: PC-LH3B (HITACHI_AC3)
+// Brand: Hitachi, Model: KAZE-312KSDP A/C (HITACHI_AC1)
+// Brand: Hitachi, Model: R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1)
+
+#ifndef IR_HITACHI_H_
+#define IR_HITACHI_H_
+
+#define __STDC_LIMIT_MACROS
+#include
+#ifndef UNIT_TEST
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Constants
+const uint16_t kHitachiAcFreq = 38000; // Hz.
+const uint8_t kHitachiAcAuto = 2;
+const uint8_t kHitachiAcHeat = 3;
+const uint8_t kHitachiAcCool = 4;
+const uint8_t kHitachiAcDry = 5;
+const uint8_t kHitachiAcFan = 0xC;
+const uint8_t kHitachiAcFanAuto = 1;
+const uint8_t kHitachiAcFanLow = 2;
+const uint8_t kHitachiAcFanMed = 3;
+const uint8_t kHitachiAcFanHigh = 5;
+const uint8_t kHitachiAcMinTemp = 16; // 16C
+const uint8_t kHitachiAcMaxTemp = 32; // 32C
+const uint8_t kHitachiAcAutoTemp = 23; // 23C
+const uint8_t kHitachiAcPowerOffset = 0;
+const uint8_t kHitachiAcSwingOffset = 7;
+
+// HitachiAc424
+// Byte[11]
+const uint8_t kHitachiAc424ButtonByte = 11;
+const uint8_t kHitachiAc424ButtonPowerMode = 0x13;
+const uint8_t kHitachiAc424ButtonFan = 0x42;
+const uint8_t kHitachiAc424ButtonTempDown = 0x43;
+const uint8_t kHitachiAc424ButtonTempUp = 0x44;
+const uint8_t kHitachiAc424ButtonSwingV = 0x81;
+
+// Byte[13]
+const uint8_t kHitachiAc424TempByte = 13;
+const uint8_t kHitachiAc424TempOffset = 2;
+const uint8_t kHitachiAc424TempSize = 6;
+const uint8_t kHitachiAc424MinTemp = 16; // 16C
+const uint8_t kHitachiAc424MaxTemp = 32; // 32C
+const uint8_t kHitachiAc424FanTemp = 27; // 27C
+
+// Byte[25]
+const uint8_t kHitachiAc424ModeByte = 25;
+const uint8_t kHitachiAc424Fan = 1;
+const uint8_t kHitachiAc424Cool = 3;
+const uint8_t kHitachiAc424Dry = 5;
+const uint8_t kHitachiAc424Heat = 6;
+const uint8_t kHitachiAc424FanByte = kHitachiAc424ModeByte;
+const uint8_t kHitachiAc424FanMin = 1;
+const uint8_t kHitachiAc424FanLow = 2;
+const uint8_t kHitachiAc424FanMedium = 3;
+const uint8_t kHitachiAc424FanHigh = 4;
+const uint8_t kHitachiAc424FanAuto = 5;
+const uint8_t kHitachiAc424FanMax = 6;
+const uint8_t kHitachiAc424FanMaxDry = 2;
+// Byte[27]
+const uint8_t kHitachiAc424PowerByte = 27;
+const uint8_t kHitachiAc424PowerOn = 0xF1;
+const uint8_t kHitachiAc424PowerOff = 0xE1;
+
+// HitachiAc1
+// Byte[3] (Model)
+const uint8_t kHitachiAc1ModelByte = 3;
+const uint8_t kHitachiAc1ModelOffset = 6; // Mask 0b11000000
+const uint8_t kHitachiAc1Model_A = 0b10;
+const uint8_t kHitachiAc1Model_B = 0b01;
+const uint8_t kHitachiAc1ModelSize = 2;
+
+// Byte[5] (Mode & Fan)
+const uint8_t kHitachiAc1ModeByte = 5;
+const uint8_t kHitachiAc1ModeOffset = 4;
+const uint8_t kHitachiAc1ModeSize = 4; // Mask 0b11110000
+const uint8_t kHitachiAc1Dry = 0b0010; // 2
+const uint8_t kHitachiAc1Fan = 0b0100; // 4
+const uint8_t kHitachiAc1Cool = 0b0110; // 6
+const uint8_t kHitachiAc1Heat = 0b1001; // 9
+const uint8_t kHitachiAc1Auto = 0b1110; // 14
+const uint8_t kHitachiAc1FanByte = kHitachiAc1ModeByte;
+const uint8_t kHitachiAc1FanOffset = 0;
+const uint8_t kHitachiAc1FanSize = 4; // Mask 0b0001111
+const uint8_t kHitachiAc1FanAuto = 1; // 0b0001
+const uint8_t kHitachiAc1FanHigh = 2; // 0b0010
+const uint8_t kHitachiAc1FanMed = 4; // 0b0100
+const uint8_t kHitachiAc1FanLow = 8; // 0b1000
+// Byte[6] (Temperature)
+// Note: Temp is stored in LSB order.
+const uint8_t kHitachiAc1TempByte = 6;
+const uint8_t kHitachiAc1TempOffset = 2;
+const uint8_t kHitachiAc1TempSize = 5; // Mask 0b01111100
+const uint8_t kHitachiAc1TempDelta = 7;
+const uint8_t kHitachiAc1TempAuto = 25; // Celsius
+// Note: Timers are nr. of minutes & stored in LSB order.
+// Byte[7-8] (Off Timer)
+const uint8_t kHitachiAc1TimerSize = 16; // Mask 0b1111111111111111
+const uint8_t kHitachiAc1OffTimerLowByte = 7;
+const uint8_t kHitachiAc1OffTimerHighByte = 8;
+// Byte[9-10] (On Timer)
+const uint8_t kHitachiAc1OnTimerLowByte = 9;
+const uint8_t kHitachiAc1OnTimerHighByte = 10;
+// Byte[11] (Power/Swing/Sleep)
+const uint8_t kHitachiAc1PowerByte = 11;
+const uint8_t kHitachiAc1PowerOffset = 5; // Mask 0b00100000
+const uint8_t kHitachiAc1PowerToggleOffset = 4; // Mask 0b00010000
+const uint8_t kHitachiAc1SwingByte = kHitachiAc1PowerByte;
+const uint8_t kHitachiAc1SwingHOffset = 7; // Mask 0b10000000
+const uint8_t kHitachiAc1SwingVOffset = 6; // Mask 0b01000000
+const uint8_t kHitachiAc1SwingToggleOffset = 0; // Mask 0b00000001
+const uint8_t kHitachiAc1SleepByte = kHitachiAc1PowerByte;
+const uint8_t kHitachiAc1SleepOffset = 1; // Mask 0b00001110
+const uint8_t kHitachiAc1SleepSize = 3; // Mask 0b00001110
+const uint8_t kHitachiAc1SleepOff = 0b000;
+const uint8_t kHitachiAc1Sleep1 = 0b001;
+const uint8_t kHitachiAc1Sleep2 = 0b010;
+const uint8_t kHitachiAc1Sleep3 = 0b011;
+const uint8_t kHitachiAc1Sleep4 = 0b100;
+// Byte[12] (Checksum)
+const uint8_t kHitachiAc1ChecksumStartByte = 5;
+
+
+// Classes
+class IRHitachiAc {
+ public:
+ explicit IRHitachiAc(const uint16_t pin, const bool inverted = false,
+ const bool use_modulation = true);
+
+ void stateReset(void);
+#if SEND_HITACHI_AC
+ void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
+ uint8_t calibrate(void) { return _irsend.calibrate(); }
+#endif // SEND_HITACHI_AC
+ void begin(void);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp(void);
+ void setFan(const uint8_t speed);
+ uint8_t getFan(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kHitachiAcStateLength);
+ static bool validChecksum(const uint8_t state[],
+ const uint16_t length = kHitachiAcStateLength);
+ static uint8_t calcChecksum(const uint8_t state[],
+ const uint16_t length = kHitachiAcStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static stdAc::opmode_t toCommonMode(const uint8_t mode);
+ static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
+ stdAc::state_t toCommon(void);
+ String toString(void);
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kHitachiAcStateLength];
+ void checksum(const uint16_t length = kHitachiAcStateLength);
+ uint8_t _previoustemp;
+};
+
+class IRHitachiAc1 {
+ public:
+ explicit IRHitachiAc1(const uint16_t pin, const bool inverted = false,
+ const bool use_modulation = true);
+
+ void stateReset(void);
+#if SEND_HITACHI_AC1
+ void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
+ uint8_t calibrate(void) { return _irsend.calibrate(); }
+#endif // SEND_HITACHI_AC1
+ void begin(void);
+ void on(void);
+ void off(void);
+ void setModel(const hitachi_ac1_remote_model_t model);
+ hitachi_ac1_remote_model_t getModel(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setPowerToggle(const bool on);
+ bool getPowerToggle(void);
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp(void);
+ void setFan(const uint8_t speed, const bool force = false);
+ uint8_t getFan(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ void setSwingToggle(const bool toggle);
+ bool getSwingToggle(void);
+ void setSwingV(const bool on);
+ bool getSwingV(void);
+ void setSwingH(const bool on);
+ bool getSwingH(void);
+ void setSleep(const uint8_t mode);
+ uint8_t getSleep(void);
+ void setOnTimer(const uint16_t mins);
+ uint16_t getOnTimer(void);
+ void setOffTimer(const uint16_t mins);
+ uint16_t getOffTimer(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kHitachiAc1StateLength);
+ static bool validChecksum(const uint8_t state[],
+ const uint16_t length = kHitachiAc1StateLength);
+ static uint8_t calcChecksum(const uint8_t state[],
+ const uint16_t length = kHitachiAc1StateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static stdAc::opmode_t toCommonMode(const uint8_t mode);
+ static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
+ stdAc::state_t toCommon(void);
+ String toString(void);
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kHitachiAc1StateLength];
+ void checksum(const uint16_t length = kHitachiAc1StateLength);
+};
+
+class IRHitachiAc424 {
+ public:
+ explicit IRHitachiAc424(const uint16_t pin, const bool inverted = false,
+ const bool use_modulation = true);
+
+ void stateReset(void);
+#if SEND_HITACHI_AC424
+ void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
+ uint8_t calibrate(void) { return _irsend.calibrate(); }
+#endif // SEND_HITACHI_AC424
+ void begin(void);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const uint8_t temp, bool setPrevious = true);
+ uint8_t getTemp(void);
+ void setFan(const uint8_t speed);
+ uint8_t getFan(void);
+ uint8_t getButton(void);
+ void setButton(const uint8_t button);
+ void setSwingVToggle(const bool on);
+ bool getSwingVToggle(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kHitachiAc424StateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static stdAc::opmode_t toCommonMode(const uint8_t mode);
+ static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
+ stdAc::state_t toCommon(void);
+ String toString(void);
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kHitachiAc424StateLength];
+ void setInvertedStates(void);
+ uint8_t _previoustemp;
+};
+
+class IRHitachiAc3 {
+ public:
+ explicit IRHitachiAc3(const uint16_t pin, const bool inverted = false,
+ const bool use_modulation = true);
+
+ void stateReset(void);
+#if SEND_HITACHI_AC3
+ void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
+ uint8_t calibrate(void) { return _irsend.calibrate(); }
+#endif // SEND_HITACHI_AC3
+ void begin(void);
+ uint8_t getMode(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kHitachiAc3StateLength);
+ static bool hasInvertedStates(const uint8_t state[], const uint16_t length);
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kHitachiAc3StateLength];
+ void setInvertedStates(const uint16_t length = kHitachiAc3StateLength);
+};
+
+#endif // IR_HITACHI_H_
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Inax.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Inax.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Inax.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Inax.cpp
index 9822e750b..b57742a12 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Inax.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Inax.cpp
@@ -31,7 +31,7 @@ const uint16_t kInaxMinGap = 40000;
// nbits: The bit size of the message being sent. typically kInaxBits.
// repeat: The number of times the message is to be repeated.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Working.
//
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/706
void IRsend::sendInax(const uint64_t data, const uint16_t nbits,
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_JVC.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_JVC.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_JVC.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_JVC.cpp
index 128efdf08..7e1e5de27 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_JVC.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_JVC.cpp
@@ -78,7 +78,7 @@ void IRsend::sendJVC(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// A raw JVC message.
//
-// Status: BETA / Should work fine.
+// Status: STABLE / Works fine.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/jvc.php
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Kelvinator.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Kelvinator.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Kelvinator.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Kelvinator.h b/lib/IRremoteESP8266-2.7.6/src/ir_Kelvinator.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Kelvinator.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Kelvinator.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_LG.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_LG.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_LG.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_LG.cpp
index b30dba082..1024548ca 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_LG.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_LG.cpp
@@ -157,7 +157,7 @@ void IRsend::sendLG2(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// A raw 28-bit LG message code suitable for sendLG() etc.
//
-// Status: BETA / Should work.
+// Status: STABLE / Works.
//
// Notes:
// e.g. Sequence of bits = address + command + checksum.
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_LG.h b/lib/IRremoteESP8266-2.7.6/src/ir_LG.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_LG.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_LG.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Lasertag.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Lasertag.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Lasertag.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Lasertag.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Lego.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Lego.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Lego.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Lego.cpp
index 502352218..b2d2f2d0e 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Lego.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Lego.cpp
@@ -74,7 +74,7 @@ void IRsend::sendLegoPf(const uint64_t data, const uint16_t nbits,
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Appears to work.
+// Status: STABLE / Appears to work.
bool IRrecv::decodeLegoPf(decode_results* results, uint16_t offset,
const uint16_t nbits, const bool strict) {
// Check if can possibly be a valid LEGO message.
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Lutron.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Lutron.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Lutron.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Lutron.cpp
index 094932e5d..8ea4f0b3a 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Lutron.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Lutron.cpp
@@ -65,7 +65,7 @@ void IRsend::sendLutron(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: ALPHA / Untested.
+// Status: STABLE / Working.
//
// Notes:
//
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_MWM.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_MWM.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_MWM.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_MWM.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Magiquest.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Magiquest.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Magiquest.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Magiquest.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Magiquest.h b/lib/IRremoteESP8266-2.7.6/src/ir_Magiquest.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Magiquest.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Magiquest.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Midea.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Midea.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Midea.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Midea.h b/lib/IRremoteESP8266-2.7.6/src/ir_Midea.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Midea.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Midea.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Mitsubishi.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Mitsubishi.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Mitsubishi.cpp
index 68098f40a..b8d62e109 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Mitsubishi.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Mitsubishi.cpp
@@ -107,7 +107,7 @@ using irutils::setBits;
// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits.
// repeat: Nr. of additional times the message is to be sent.
//
-// Status: ALPHA / untested.
+// Status: STABLE / Working.
//
// Notes:
// This protocol appears to have no header.
@@ -134,7 +134,7 @@ void IRsend::sendMitsubishi(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / previously working.
+// Status: STABLE / Working.
//
// Notes:
// This protocol appears to have no header.
@@ -174,7 +174,7 @@ bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t offset,
// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits.
// repeat: Nr. of additional times the message is to be sent.
//
-// Status: ALPHA / untested.
+// Status: BETA / Probably works.
//
// Notes:
// Based on a Mitsubishi HC3000 projector's remote.
@@ -214,7 +214,7 @@ void IRsend::sendMitsubishi2(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Works with simulated data.
+// Status: STABLE / Works.
//
// Notes:
// Hardware supported:
@@ -270,7 +270,7 @@ bool IRrecv::decodeMitsubishi2(decode_results *results, uint16_t offset,
// repeat: Nr. of times the message is to be repeated.
// (Default = kMitsubishiACMinRepeat).
//
-// Status: BETA / Appears to be working.
+// Status: STABLE / Working.
//
void IRsend::sendMitsubishiAC(const unsigned char data[], const uint16_t nbytes,
const uint16_t repeat) {
@@ -296,7 +296,7 @@ void IRsend::sendMitsubishiAC(const unsigned char data[], const uint16_t nbytes,
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: ALPHA / Under development
+// Status: BETA / Probably works
//
// Ref:
// https://www.analysir.com/blog/2015/01/06/reverse-engineering-mitsubishi-ac-infrared-protocol/
@@ -804,7 +804,7 @@ String IRMitsubishiAC::toString(void) {
// repeat: Nr. of times the message is to be repeated.
// (Default = kMitsubishi136MinRepeat).
//
-// Status: ALPHA / Probably working. Needs to be tested against a real device.
+// Status: BETA / Probably working. Needs to be tested against a real device.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/888
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.7.6/src/ir_Mitsubishi.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Mitsubishi.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Mitsubishi.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_MitsubishiHeavy.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_MitsubishiHeavy.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_MitsubishiHeavy.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_MitsubishiHeavy.h b/lib/IRremoteESP8266-2.7.6/src/ir_MitsubishiHeavy.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_MitsubishiHeavy.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_MitsubishiHeavy.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_NEC.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_NEC.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_NEC.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_NEC.cpp
index 2f870f58c..9145f5c24 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_NEC.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_NEC.cpp
@@ -44,7 +44,7 @@ void IRsend::sendNEC(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// A raw 32-bit NEC message.
//
-// Status: BETA / Expected to work.
+// Status: STABLE / Expected to work.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_NEC.h b/lib/IRremoteESP8266-2.7.6/src/ir_NEC.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_NEC.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_NEC.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Neoclima.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Neoclima.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Neoclima.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Neoclima.cpp
index 0e410ca67..8c93ef26f 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Neoclima.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Neoclima.cpp
@@ -470,7 +470,7 @@ String IRNeoclimaAc::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Known working
+// Status: STABLE / Known working
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/764
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Neoclima.h b/lib/IRremoteESP8266-2.7.6/src/ir_Neoclima.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Neoclima.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Neoclima.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Nikai.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Nikai.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Nikai.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Nikai.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Panasonic.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Panasonic.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Panasonic.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Panasonic.cpp
index bf472de88..d8b627c9f 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Panasonic.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Panasonic.cpp
@@ -82,7 +82,7 @@ using irutils::setBits;
// nbits: The number of bits of the message to be sent. (kPanasonicBits).
// repeat: The number of times the command is to be repeated.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
//
// Note:
// This protocol is a modified version of Kaseikyo.
@@ -121,7 +121,7 @@ void IRsend::sendPanasonic(const uint16_t address, const uint32_t data,
// Returns:
// A raw uint64_t Panasonic message.
//
-// Status: BETA / Should be working..
+// Status: STABLE / Should be working..
//
// Note:
// Panasonic 48-bit protocol is a modified version of Kaseikyo.
@@ -149,7 +149,7 @@ uint64_t IRsend::encodePanasonic(const uint16_t manufacturer,
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
// Note:
// Panasonic 48-bit protocol is a modified version of Kaseikyo.
// Ref:
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Panasonic.h b/lib/IRremoteESP8266-2.7.6/src/ir_Panasonic.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Panasonic.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Panasonic.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Pioneer.cpp
similarity index 97%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Pioneer.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Pioneer.cpp
index 85343a117..08bbf3c06 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Pioneer.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Pioneer.cpp
@@ -41,7 +41,7 @@ const uint32_t kPioneerMinGap = kPioneerMinGapTicks * kPioneerTick;
// Typically kPioneerBits.
// repeat: The number of times the command is to be repeated.
//
-// Status: BETA / Expected to be working.
+// Status: STABLE / Expected to be working.
//
// Ref:
// http://adrian-kingston.com/IRFormatPioneer.htm
@@ -75,7 +75,7 @@ void IRsend::sendPioneer(const uint64_t data, const uint16_t nbits,
// Returns:
// A raw 64-bit Pioneer message code.
//
-// Status: BETA / Expected to work.
+// Status: STABLE / Expected to work.
//
// Note:
// Address & Command can be take from a decode result OR from the spreadsheets
@@ -103,7 +103,7 @@ uint64_t IRsend::encodePioneer(const uint16_t address, const uint16_t command) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Should be working. (Self decodes & real examples)
+// Status: STABLE / Should be working. (Self decodes & real examples)
//
bool IRrecv::decodePioneer(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Pronto.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Pronto.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Pronto.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Pronto.cpp
index a408afed5..6b7a779de 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Pronto.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Pronto.cpp
@@ -21,7 +21,7 @@ const uint16_t kProntoDataOffset = 4;
// len: Nr. of entries in the data[] array.
// repeat: Nr. of times to repeat the message.
//
-// Status: ALPHA / Not tested in the real world.
+// Status: STABLE / Known working.
//
// Note:
// Pronto codes are typically represented in hexadecimal.
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_RC5_RC6.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_RC5_RC6.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_RC5_RC6.cpp
index ce69aaa3a..370100f9e 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_RC5_RC6.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_RC5_RC6.cpp
@@ -184,7 +184,7 @@ uint64_t IRsend::toggleRC5(uint64_t data) { return data ^ kRc5ToggleMask; }
// Returns:
// A data message suitable for use in sendRC6() with the toggle bit flipped.
//
-// Status: BETA / Should work fine.
+// Status: STABLE / Should work fine.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc6.php
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_RCMM.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_RCMM.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/ir_RCMM.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_RCMM.cpp
index a2542e467..ea0e05e9d 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_RCMM.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_RCMM.cpp
@@ -45,7 +45,7 @@ const uint16_t kRcmmExcess = 50;
// nbits: The number of bits of data to send. (Typically 12, 24, or 32[Nokia])
// repeat: The nr. of times the message should be sent.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rcmm.php
@@ -102,7 +102,7 @@ void IRsend::sendRCMM(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rcmm.php
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Samsung.cpp
similarity index 93%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Samsung.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Samsung.cpp
index a31e76953..78b36e146 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Samsung.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Samsung.cpp
@@ -72,7 +72,7 @@ using irutils::setBits;
// nbits: The bit size of the message being sent. typically kSamsungBits.
// repeat: The number of times the message is to be repeated.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
//
// Ref: http://elektrolab.wz.cz/katalog/samsung_protocol.pdf
void IRsend::sendSAMSUNG(const uint64_t data, const uint16_t nbits,
@@ -92,7 +92,7 @@ void IRsend::sendSAMSUNG(const uint64_t data, const uint16_t nbits,
// Returns:
// A raw 32-bit Samsung message suitable for sendSAMSUNG().
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
uint32_t IRsend::encodeSAMSUNG(const uint8_t customer, const uint8_t command) {
uint8_t revcustomer = reverseBits(customer, sizeof(customer) * 8);
uint8_t revcommand = reverseBits(command, sizeof(command) * 8);
@@ -271,7 +271,7 @@ bool IRrecv::decodeSamsung36(decode_results *results, uint16_t offset,
// https://github.com/crankyoldgit/IRremoteESP8266/issues/505
void IRsend::sendSamsungAC(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
- if (nbytes < kSamsungAcStateLength && nbytes % kSamsungACSectionLength)
+ if (nbytes < kSamsungAcStateLength && nbytes % kSamsungAcSectionLength)
return; // Not an appropriate number of bytes to send a proper message.
enableIROut(38);
@@ -281,11 +281,11 @@ void IRsend::sendSamsungAC(const uint8_t data[], const uint16_t nbytes,
space(kSamsungAcHdrSpace);
// Send in 7 byte sections.
for (uint16_t offset = 0; offset < nbytes;
- offset += kSamsungACSectionLength) {
+ offset += kSamsungAcSectionLength) {
sendGeneric(kSamsungAcSectionMark, kSamsungAcSectionSpace,
kSamsungAcBitMark, kSamsungAcOneSpace, kSamsungAcBitMark,
kSamsungAcZeroSpace, kSamsungAcBitMark, kSamsungAcSectionGap,
- data + offset, kSamsungACSectionLength, // 7 bytes == 56 bits
+ data + offset, kSamsungAcSectionLength, // 7 bytes == 56 bits
38000, false, 0, 50); // Send in LSBF order
}
// Complete made up guess at inter-message gap.
@@ -379,10 +379,10 @@ void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) {
0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Copy/convert the internal state to an extended state.
- for (uint16_t i = 0; i < kSamsungACSectionLength; i++)
+ for (uint16_t i = 0; i < kSamsungAcSectionLength; i++)
extended_state[i] = remote_state[i];
- for (uint16_t i = kSamsungACSectionLength; i < kSamsungAcStateLength; i++)
- extended_state[i + kSamsungACSectionLength] = remote_state[i];
+ for (uint16_t i = kSamsungAcSectionLength; i < kSamsungAcStateLength; i++)
+ extended_state[i + kSamsungAcSectionLength] = remote_state[i];
// extended_state[8] seems special. This is a guess on how to calculate it.
extended_state[8] = (extended_state[1] & 0x9F) | 0x40;
// Send it.
@@ -425,7 +425,7 @@ void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) {
// Shrink the extended state into a normal state.
if (length > kSamsungAcStateLength) {
for (uint8_t i = kSamsungAcStateLength; i < length; i++)
- remote_state[i - kSamsungACSectionLength] = remote_state[i];
+ remote_state[i - kSamsungAcSectionLength] = remote_state[i];
}
}
@@ -550,14 +550,15 @@ void IRSamsungAc::setQuiet(const bool on) {
bool IRSamsungAc::getPowerful(void) {
return !(remote_state[8] & kSamsungAcPowerfulMask8) &&
- GETBITS8(remote_state[10], kSamsungAcPowerful10Offset,
- kSamsungAcPowerful10Offset) &&
+ (GETBITS8(remote_state[10], kSamsungAcPowerful10Offset,
+ kSamsungAcPowerful10Size) == kSamsungAcPowerful10On) &&
(this->getFan() == kSamsungAcFanTurbo);
}
void IRSamsungAc::setPowerful(const bool on) {
+ uint8_t off_value = this->getBreeze() ? kSamsungAcBreezeOn : 0b000;
setBits(&remote_state[10], kSamsungAcPowerful10Offset,
- kSamsungAcPowerful10Offset, on ? 0b11: 0b00);
+ kSamsungAcPowerful10Size, on ? kSamsungAcPowerful10On : off_value);
if (on) {
remote_state[8] &= ~kSamsungAcPowerfulMask8; // Bit needs to be cleared.
// Powerful mode sets fan speed to Turbo.
@@ -570,6 +571,26 @@ void IRSamsungAc::setPowerful(const bool on) {
}
}
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
+// Are the vanes closed over the fan outlet, to stop direct wind? Aka. WindFree
+bool IRSamsungAc::getBreeze(void) {
+ return (GETBITS8(remote_state[10], kSamsungAcBreezeOffset,
+ kSamsungAcBreezeSize) == kSamsungAcBreezeOn) &&
+ (this->getFan() == kSamsungAcFanAuto && !getSwing());
+}
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
+// Closes the vanes over the fan outlet, to stop direct wind. Aka. WindFree
+void IRSamsungAc::setBreeze(const bool on) {
+ uint8_t off_value = this->getPowerful() ? kSamsungAcPowerful10On : 0b000;
+ setBits(&remote_state[10], kSamsungAcBreezeOffset,
+ kSamsungAcBreezeSize, on ? kSamsungAcBreezeOn : off_value);
+ if (on) {
+ this->setFan(kSamsungAcFanAuto);
+ this->setSwing(false);
+ }
+}
+
bool IRSamsungAc::getDisplay(void) {
return GETBIT8(remote_state[10], kSamsungAcDisplayOffset);
}
@@ -695,6 +716,7 @@ String IRSamsungAc::toString(void) {
result += addBoolToString(getClean(), kCleanStr);
result += addBoolToString(getQuiet(), kQuietStr);
result += addBoolToString(getPowerful(), kPowerfulStr);
+ result += addBoolToString(getBreeze(), kBreezeStr);
result += addBoolToString(getDisplay(), kLightStr);
result += addBoolToString(getIon(), kIonStr);
return result;
@@ -726,17 +748,17 @@ bool IRrecv::decodeSamsungAC(decode_results *results, uint16_t offset,
if (!matchMark(results->rawbuf[offset++], kSamsungAcBitMark)) return false;
if (!matchSpace(results->rawbuf[offset++], kSamsungAcHdrSpace)) return false;
// Section(s)
- for (uint16_t pos = 0; pos <= (nbits / 8) - kSamsungACSectionLength;
- pos += kSamsungACSectionLength) {
+ for (uint16_t pos = 0; pos <= (nbits / 8) - kSamsungAcSectionLength;
+ pos += kSamsungAcSectionLength) {
uint16_t used;
// Section Header + Section Data (7 bytes) + Section Footer
used = matchGeneric(results->rawbuf + offset, results->state + pos,
- results->rawlen - offset, kSamsungACSectionLength * 8,
+ results->rawlen - offset, kSamsungAcSectionLength * 8,
kSamsungAcSectionMark, kSamsungAcSectionSpace,
kSamsungAcBitMark, kSamsungAcOneSpace,
kSamsungAcBitMark, kSamsungAcZeroSpace,
kSamsungAcBitMark, kSamsungAcSectionGap,
- pos + kSamsungACSectionLength >= nbits / 8,
+ pos + kSamsungAcSectionLength >= nbits / 8,
_tolerance, 0, false);
if (used == 0) return false;
offset += used;
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Samsung.h b/lib/IRremoteESP8266-2.7.6/src/ir_Samsung.h
similarity index 70%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Samsung.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Samsung.h
index 52a781b65..31b5ea181 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Samsung.h
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Samsung.h
@@ -19,22 +19,59 @@
// Supports:
// Brand: Samsung, Model: UA55H6300 TV
// Brand: Samsung, Model: DB63-03556X003 remote
+// Brand: Samsung, Model: DB93-16761C remote
// Brand: Samsung, Model: IEC-R03 remote
// Brand: Samsung, Model: AR09FSSDAWKNFA A/C
// Brand: Samsung, Model: AR12KSFPEWQNET A/C
// Brand: Samsung, Model: AR12HSSDBWKNEU A/C
+// Brand: Samsung, Model: AR12NXCXAWKXEU A/C
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/505
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
// Constants
+// Byte[1]
+// Checksum 0b11110000 ???
+const uint8_t kSamsungAcPower1Offset = 5; // Mask 0b00100000
+const uint8_t kSamsungAcQuiet1Offset = 4; // Mask 0b00010000
+// Byte[5]
+const uint8_t kSamsungAcQuiet5Offset = 5;
+// Byte[6]
+const uint8_t kSamsungAcPower6Offset = 4; // Mask 0b00110000
+const uint8_t kSamsungAcPower6Size = 2; // Bits
+// Byte[8]
+// Checksum 0b11110000 ???
+const uint8_t kSamsungAcPowerfulMask8 = 0b01010000;
+// Byte[9]
+const uint8_t kSamsungAcSwingOffset = 4; // Mask 0b01110000
+const uint8_t kSamsungAcSwingSize = 3; // Bits
+const uint8_t kSamsungAcSwingMove = 0b010;
+const uint8_t kSamsungAcSwingStop = 0b111;
+// Byte[10]
+const uint8_t kSamsungAcPowerful10Offset = 1; // Mask 0b00001110
+const uint8_t kSamsungAcPowerful10Size = 3; // Mask 0b00001110
+const uint8_t kSamsungAcPowerful10On = 0b011;
+// Breeze (aka. WindFree)
+const uint8_t kSamsungAcBreezeOffset = kSamsungAcPowerful10Offset;
+const uint8_t kSamsungAcBreezeSize = kSamsungAcPowerful10Size;
+const uint8_t kSamsungAcBreezeOn = 0b101;
+const uint8_t kSamsungAcDisplayOffset = 4; // Mask 0b00010000
+const uint8_t kSamsungAcClean10Offset = 7; // Mask 0b10000000
+// Byte[11]
+const uint8_t kSamsungAcIonOffset = 0; // Mask 0b00000001
+const uint8_t kSamsungAcClean11Offset = 1; // Mask 0b00000010
+const uint8_t kSamsungAcMinTemp = 16; // C Mask 0b11110000
+const uint8_t kSamsungAcMaxTemp = 30; // C Mask 0b11110000
+const uint8_t kSamsungAcAutoTemp = 25; // C Mask 0b11110000
+// Byte[12]
+const uint8_t kSamsungAcModeOffset = 4; // Mask 0b01110000
const uint8_t kSamsungAcAuto = 0;
const uint8_t kSamsungAcCool = 1;
const uint8_t kSamsungAcDry = 2;
const uint8_t kSamsungAcFan = 3;
const uint8_t kSamsungAcHeat = 4;
-const uint8_t kSamsungAcModeOffset = 4; // Mask 0b01110000
-const uint8_t kSamsungAcFanOffest = 1; // Mask 0b00001110
+const uint8_t kSamsungAcFanOffest = 1; // Mask 0b00001110
const uint8_t kSamsungAcFanSize = 3; // Bits
const uint8_t kSamsungAcFanAuto = 0;
const uint8_t kSamsungAcFanLow = 2;
@@ -42,28 +79,10 @@ const uint8_t kSamsungAcFanMed = 4;
const uint8_t kSamsungAcFanHigh = 5;
const uint8_t kSamsungAcFanAuto2 = 6;
const uint8_t kSamsungAcFanTurbo = 7;
-const uint8_t kSamsungAcMinTemp = 16; // 16C
-const uint8_t kSamsungAcMaxTemp = 30; // 30C
-const uint8_t kSamsungAcAutoTemp = 25; // 25C
-const uint8_t kSamsungAcPower1Offset = 5;
-const uint8_t kSamsungAcPower6Offset = 4; // Mask 0b00110000
-const uint8_t kSamsungAcPower6Size = 2; // Bits
-const uint8_t kSamsungAcSwingOffset = 4; // Mask 0b01110000
-const uint8_t kSamsungAcSwingSize = 3; // Bits
-const uint8_t kSamsungAcSwingMove = 0b010;
-const uint8_t kSamsungAcSwingStop = 0b111;
-const uint8_t kSamsungAcBeepOffset = 1;
-const uint8_t kSamsungAcClean10Offset = 7;
-const uint8_t kSamsungAcClean11Offset = 1; // 0b00000010
-const uint8_t kSamsungAcQuiet1Offset = 4;
-const uint8_t kSamsungAcQuiet5Offset = 5;
-const uint8_t kSamsungAcPowerfulMask8 = 0b01010000;
-const uint8_t kSamsungAcPowerful10Offset = 1; // Mask 0b00000110
-const uint8_t kSamsungAcPowerful10Size = 1; // Mask 0b00000110
-const uint8_t kSamsungAcDisplayOffset = 4; // Mask 0b00010000
-const uint8_t kSamsungAcIonOffset = 0; // Mask 0b00000001
+// Byte[13]
+const uint8_t kSamsungAcBeepOffset = 1; // Mask 0b00000010
-const uint16_t kSamsungACSectionLength = 7;
+const uint16_t kSamsungAcSectionLength = 7;
const uint64_t kSamsungAcPowerSection = 0x1D20F00000000;
// Classes
@@ -103,7 +122,8 @@ class IRSamsungAc {
bool getQuiet(void);
void setPowerful(const bool on);
bool getPowerful(void);
-
+ void setBreeze(const bool on);
+ bool getBreeze(void);
void setDisplay(const bool on);
bool getDisplay(void);
void setIon(const bool on);
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Sanyo.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Sanyo.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Sanyo.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Sharp.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Sharp.cpp
similarity index 93%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Sharp.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Sharp.cpp
index f28ca0f4d..363271012 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Sharp.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Sharp.cpp
@@ -16,6 +16,7 @@
// Equipment it seems compatible with:
// * Sharp LC-52D62U
+// * Sharp AH-AxSAY A/C (Remote CRMC-A907 JBEZ)
// *
//
@@ -56,7 +57,7 @@ using irutils::setBits;
// nbits: Nr. of bits of data to be sent. Typically kSharpBits.
// repeat: Nr. of additional times the message is to be sent.
//
-// Status: BETA / Previously working fine.
+// Status: STABLE / Working fine.
//
// Notes:
// This procedure handles the inversion of bits required per protocol.
@@ -102,7 +103,7 @@ void IRsend::sendSharpRaw(const uint64_t data, const uint16_t nbits,
// Returns:
// An uint32_t containing the raw Sharp message for sendSharpRaw().
//
-// Status: BETA / Should work okay.
+// Status: STABLE / Works okay.
//
// Notes:
// Assumes the standard Sharp bit sizes.
@@ -334,18 +335,51 @@ void IRSharpAc::setRaw(const uint8_t new_code[], const uint16_t length) {
memcpy(remote, new_code, std::min(length, kSharpAcStateLength));
}
+void IRSharpAc::setPreviousPower(const bool on) {
+ setBit(&remote[kSharpAcBytePower], kSharpAcBitPreviousPowerOffset, on);
+}
+
+bool IRSharpAc::getPreviousPower(void) {
+ return GETBIT8(remote[kSharpAcBytePower], kSharpAcBitPreviousPowerOffset);
+}
+
void IRSharpAc::on(void) { setPower(true); }
void IRSharpAc::off(void) { setPower(false); }
void IRSharpAc::setPower(const bool on) {
+ setPreviousPower(getPower());
setBit(&remote[kSharpAcBytePower], kSharpAcBitPowerOffset, on);
+ setButton(kSharpAcButtonPowerMode);
+}
+
+void IRSharpAc::setPower(const bool on, const bool prev) {
+ setPower(on);
+ setPreviousPower(prev);
}
bool IRSharpAc::getPower(void) {
return GETBIT8(remote[kSharpAcBytePower], kSharpAcBitPowerOffset);
}
+void IRSharpAc::setButton(const uint8_t button) {
+ switch (button) {
+ case kSharpAcButtonPowerMode:
+ case kSharpAcButtonTemp:
+ case kSharpAcButtonFan:
+ setBits(&remote[kSharpAcByteButton], kSharpAcButtonOffset,
+ kSharpAcButtonSize, button);
+ break;
+ default:
+ setButton(kSharpAcButtonPowerMode);
+ }
+}
+
+uint8_t IRSharpAc::getButton(void) {
+ return GETBITS8(remote[kSharpAcByteButton], kSharpAcButtonOffset,
+ kSharpAcButtonSize);
+}
+
// Set the temp in deg C
void IRSharpAc::setTemp(const uint8_t temp) {
switch (this->getMode()) {
@@ -353,16 +387,15 @@ void IRSharpAc::setTemp(const uint8_t temp) {
case kSharpAcAuto:
case kSharpAcDry:
remote[kSharpAcByteTemp] = 0;
- remote[kSharpAcByteManual] = 0; // When in Dry/Auto this byte is 0.
return;
default:
remote[kSharpAcByteTemp] = 0xC0;
- setBit(&remote[kSharpAcByteManual], kSharpAcBitTempManualOffset);
}
uint8_t degrees = std::max(temp, kSharpAcMinTemp);
degrees = std::min(degrees, kSharpAcMaxTemp);
setBits(&remote[kSharpAcByteTemp], kLowNibble, kNibbleSize,
degrees - kSharpAcMinTemp);
+ setButton(kSharpAcButtonTemp);
}
uint8_t IRSharpAc::getTemp(void) {
@@ -375,11 +408,10 @@ uint8_t IRSharpAc::getMode(void) {
}
void IRSharpAc::setMode(const uint8_t mode) {
- setBit(&remote[kSharpAcBytePower], kSharpAcBitModeNonAutoOffset,
- mode != kSharpAcAuto);
switch (mode) {
case kSharpAcAuto:
case kSharpAcDry:
+ this->setFan(2); // When Dry or Auto, Fan always 2(Auto)
this->setTemp(0); // Dry/Auto have no temp setting.
// FALLTHRU
case kSharpAcCool:
@@ -389,6 +421,7 @@ void IRSharpAc::setMode(const uint8_t mode) {
default:
this->setMode(kSharpAcAuto);
}
+ setButton(kSharpAcButtonPowerMode);
}
// Set the speed of the fan
@@ -399,14 +432,13 @@ void IRSharpAc::setFan(const uint8_t speed) {
case kSharpAcFanMed:
case kSharpAcFanHigh:
case kSharpAcFanMax:
- setBit(&remote[kSharpAcByteManual], kSharpAcBitFanManualOffset,
- speed != kSharpAcFanAuto);
setBits(&remote[kSharpAcByteFan], kSharpAcFanOffset, kSharpAcFanSize,
speed);
break;
default:
this->setFan(kSharpAcFanAuto);
}
+ setButton(kSharpAcButtonFan);
}
uint8_t IRSharpAc::getFan(void) {
@@ -485,8 +517,9 @@ stdAc::state_t IRSharpAc::toCommon(void) {
// Convert the internal state into a human readable string.
String IRSharpAc::toString(void) {
String result = "";
- result.reserve(60); // Reserve some heap for the string to reduce fragging.
+ result.reserve(80); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), kPowerStr, false);
+ result += addBoolToString(getPreviousPower(), kPreviousPowerStr);
result += addModeToString(getMode(), kSharpAcAuto, kSharpAcCool, kSharpAcHeat,
kSharpAcDry, kSharpAcAuto);
result += addTempToString(getTemp());
@@ -506,7 +539,7 @@ String IRSharpAc::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Known working.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/638
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Sharp.h b/lib/IRremoteESP8266-2.7.6/src/ir_Sharp.h
similarity index 81%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Sharp.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Sharp.h
index e1c81c3a2..03d27d44f 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Sharp.h
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Sharp.h
@@ -3,6 +3,7 @@
// Supports:
// Brand: Sharp, Model: LC-52D62U TV
// Brand: Sharp, Model: AY-ZP40KR A/C
+// Brand: Sharp, Model: AH-AxSAY A/C
#ifndef IR_SHARP_H_
#define IR_SHARP_H_
@@ -38,17 +39,19 @@ const uint8_t kSharpAcFanHigh = 0b101; // 5 (FAN3)
const uint8_t kSharpAcFanMax = 0b111; // 7 (FAN4)
const uint8_t kSharpAcByteTemp = 4;
const uint8_t kSharpAcBytePower = 5;
-const uint8_t kSharpAcBitPowerOffset = 4;
-const uint8_t kSharpAcBitModeNonAutoOffset = 5; // 0b00100000
+const uint8_t kSharpAcBitPowerOffset = 4; // 0b000x0000
+const uint8_t kSharpAcBitPreviousPowerOffset = 5; // 0b00x00000
const uint8_t kSharpAcByteMode = 6;
const uint8_t kSharpAcModeSize = 2; // Mask 0b00000011;
const uint8_t kSharpAcByteFan = kSharpAcByteMode;
const uint8_t kSharpAcFanOffset = 4; // Mask 0b01110000
const uint8_t kSharpAcFanSize = 3; // Nr. of Bits
-const uint8_t kSharpAcByteManual = 10;
-const uint8_t kSharpAcBitFanManualOffset = 0; // 0b00000001
-const uint8_t kSharpAcBitTempManualOffset = 2; // 0b00000100
-
+const uint8_t kSharpAcByteButton = 10;
+const uint8_t kSharpAcButtonOffset = 0;
+const uint8_t kSharpAcButtonSize = 3; // Mask 0b00000xxx
+const uint8_t kSharpAcButtonPowerMode = 0b000; // 0
+const uint8_t kSharpAcButtonTemp = 0b100; // 4
+const uint8_t kSharpAcButtonFan = 0b101; // 5
class IRSharpAc {
public:
@@ -63,13 +66,18 @@ class IRSharpAc {
void on(void);
void off(void);
void setPower(const bool on);
+ void setPower(const bool on, const bool prev);
bool getPower(void);
+ void setPreviousPower(const bool on);
+ bool getPreviousPower(void);
void setTemp(const uint8_t temp);
uint8_t getTemp(void);
void setFan(const uint8_t fan);
uint8_t getFan(void);
void setMode(const uint8_t mode);
uint8_t getMode(void);
+ void setButton(const uint8_t button);
+ uint8_t getButton(void);
uint8_t* getRaw(void);
void setRaw(const uint8_t new_code[],
const uint16_t length = kSharpAcStateLength);
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Sherwood.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Sherwood.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Sherwood.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Sherwood.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Sony.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Sony.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Sony.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Sony.cpp
index c346eb293..9ff0c50cc 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Sony.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Sony.cpp
@@ -106,7 +106,7 @@ void IRsend::_sendSony(uint64_t data, uint16_t nbits, uint16_t repeat,
// Returns:
// A sendSony compatible data message.
//
-// Status: BETA / Should be working.
+// Status: STABLE / Should be working.
uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command, uint16_t address,
uint16_t extended) {
uint32_t result = 0;
@@ -141,7 +141,7 @@ uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command, uint16_t address,
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Should be working. strict mode is ALPHA / Untested.
+// Status: STABLE / Should be working. strict mode is ALPHA / Untested.
//
// Notes:
// SONY protocol, SIRC (Serial Infra-Red Control) can be 12,15,20 bits long.
diff --git a/lib/IRremoteESP8266-2.7.6/src/ir_Symphony.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Symphony.cpp
new file mode 100644
index 000000000..f0194fdb8
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Symphony.cpp
@@ -0,0 +1,87 @@
+// Copyright 2020 David Conran
+
+// Send & decode support for Symphony added by David Conran
+
+// Supports:
+// Brand: Symphony, Model: Air Cooler 3Di
+
+#include
+#include "IRrecv.h"
+#include "IRsend.h"
+#include "IRtimer.h"
+#include "IRutils.h"
+
+// Constants
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1057
+const uint16_t kSymphonyZeroMark = 1250;
+const uint16_t kSymphonyZeroSpace = 400;
+const uint16_t kSymphonyOneMark = kSymphonyZeroSpace;
+const uint16_t kSymphonyOneSpace = kSymphonyZeroMark;
+const uint16_t kSymphonyFooterMark = kSymphonyOneMark;
+const uint32_t kSymphonyFooterGap = 8000;
+
+#if SEND_SYMPHONY
+// Send a Symphony packet.
+//
+// Args:
+// data: The data we want to send. MSB first.
+// nbits: The number of bits of data to send. (Typically 12, 24, or 32[Nokia])
+// repeat: The nr. of times the message should be sent.
+//
+// Status: STABLE / Should be working.
+//
+// Ref:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1057
+void IRsend::sendSymphony(uint64_t data, uint16_t nbits, uint16_t repeat) {
+ sendGeneric(0, 0,
+ kSymphonyOneMark, kSymphonyOneSpace,
+ kSymphonyZeroMark, kSymphonyZeroSpace,
+ kSymphonyFooterMark, kSymphonyFooterGap,
+ data, nbits, 38000, true, repeat, kDutyDefault);
+}
+#endif // SEND_SYMPHONY
+
+#if DECODE_SYMPHONY
+// Decode a Symphony packet if possible.
+// Places successful decode information in the results pointer.
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// offset: The starting index to use when attempting to decode the raw data.
+// Typically/Defaults to kStartOffset.
+// nbits: Nr. of bits to expect in the data portion. Typically kSymphonyBits
+// strict: Flag to indicate if we strictly adhere to the specification.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: STABLE / Should be working.
+//
+// Ref:
+//
+bool IRrecv::decodeSymphony(decode_results *results, uint16_t offset,
+ const uint16_t nbits, const bool strict) {
+ uint64_t data = 0;
+
+ if (results->rawlen < 2 * nbits + kFooter + offset - 1)
+ return false; // Not enough entries to ever be SYMPHONY.
+ // Compliance
+ if (strict && nbits != kSymphonyBits) return false;
+
+ if (!matchGeneric(results->rawbuf + offset, &data, results->rawlen - offset,
+ nbits,
+ 0, 0, // No Header
+ kSymphonyOneMark, kSymphonyOneSpace,
+ kSymphonyZeroMark, kSymphonyZeroSpace,
+ kSymphonyFooterMark, kSymphonyFooterGap, true,
+ _tolerance, 0))
+ return false;
+
+ // Success
+ results->value = data;
+ results->decode_type = decode_type_t::SYMPHONY;
+ results->bits = nbits;
+ results->address = 0;
+ results->command = 0;
+ return true;
+}
+#endif // DECODE_SYMPHONY
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Tcl.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Tcl.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Tcl.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Tcl.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Tcl.h b/lib/IRremoteESP8266-2.7.6/src/ir_Tcl.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Tcl.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Tcl.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Teco.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Teco.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Teco.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Teco.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Teco.h b/lib/IRremoteESP8266-2.7.6/src/ir_Teco.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Teco.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Teco.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Toshiba.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Toshiba.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Toshiba.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.7.6/src/ir_Toshiba.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Toshiba.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Toshiba.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Trotec.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Trotec.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Trotec.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Trotec.cpp
index 563564d36..d8b87e034 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Trotec.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Trotec.cpp
@@ -245,7 +245,7 @@ String IRTrotecESP::toString(void) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Probably works. Untested on real devices.
+// Status: STABLE / Works. Untested on real devices.
//
// Ref:
bool IRrecv::decodeTrotec(decode_results *results, uint16_t offset,
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Trotec.h b/lib/IRremoteESP8266-2.7.6/src/ir_Trotec.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Trotec.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Trotec.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Vestel.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Vestel.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Vestel.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Vestel.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Vestel.h b/lib/IRremoteESP8266-2.7.6/src/ir_Vestel.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Vestel.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Vestel.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Whirlpool.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Whirlpool.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Whirlpool.cpp
index e1ca2e6db..3ba781c4c 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Whirlpool.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Whirlpool.cpp
@@ -56,7 +56,7 @@ using irutils::setBits;
// nbytes: Nr. of bytes of data in the array. (>=kWhirlpoolAcStateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: ALPHA / Untested.
+// Status: BETA / Probably works.
//
// Ref:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/509
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Whirlpool.h b/lib/IRremoteESP8266-2.7.6/src/ir_Whirlpool.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Whirlpool.h
rename to lib/IRremoteESP8266-2.7.6/src/ir_Whirlpool.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/ir_Whynter.cpp b/lib/IRremoteESP8266-2.7.6/src/ir_Whynter.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/ir_Whynter.cpp
rename to lib/IRremoteESP8266-2.7.6/src/ir_Whynter.cpp
index 118eb7559..92bad25ce 100644
--- a/lib/IRremoteESP8266-2.7.4/src/ir_Whynter.cpp
+++ b/lib/IRremoteESP8266-2.7.6/src/ir_Whynter.cpp
@@ -76,7 +76,7 @@ void IRsend::sendWhynter(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA Strict mode is ALPHA.
+// Status: STABLE / Working. Strict mode is ALPHA.
//
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Whynter.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/README.md b/lib/IRremoteESP8266-2.7.6/src/locale/README.md
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/README.md
rename to lib/IRremoteESP8266-2.7.6/src/locale/README.md
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/de-CH.h b/lib/IRremoteESP8266-2.7.6/src/locale/de-CH.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/de-CH.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/de-CH.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/de-DE.h b/lib/IRremoteESP8266-2.7.6/src/locale/de-DE.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/de-DE.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/de-DE.h
diff --git a/lib/IRremoteESP8266-2.7.6/src/locale/defaults.h b/lib/IRremoteESP8266-2.7.6/src/locale/defaults.h
new file mode 100644
index 000000000..f96595616
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/src/locale/defaults.h
@@ -0,0 +1,719 @@
+// Copyright 2019 - David Conran (@crankyoldgit)
+// The default text to use throughout the library.
+// The library will use this text if no locale (_IR_LOCALE_) is set or if
+// the locale doesn't define particular values.
+// If they are defined, this file should NOT override them.
+//
+// This file should contain a #define for every translateable/locale dependant
+// string used by the library. Language specific files don't have to include
+// everything.
+//
+// NOTE: ASCII/UTF-8 characters only. Unicode is NOT supported.
+//
+// The defaults are English (AU) / en-AU. Australia (AU) is pretty much the same
+// as English (UK) for this libraries use case.
+#ifndef LOCALE_DEFAULTS_H_
+#define LOCALE_DEFAULTS_H_
+
+#ifndef D_STR_UNKNOWN
+#define D_STR_UNKNOWN "UNKNOWN"
+#endif // D_STR_UNKNOWN
+#ifndef D_STR_PROTOCOL
+#define D_STR_PROTOCOL "Protocol"
+#endif // D_STR_PROTOCOL
+#ifndef D_STR_POWER
+#define D_STR_POWER "Power"
+#endif // D_STR_POWER
+#ifndef D_STR_PREVIOUS
+#define D_STR_PREVIOUS "Previous"
+#endif // D_STR_PREVIOUS
+#ifndef D_STR_ON
+#define D_STR_ON "On"
+#endif // D_STR_ON
+#ifndef D_STR_OFF
+#define D_STR_OFF "Off"
+#endif // D_STR_OFF
+#ifndef D_STR_MODE
+#define D_STR_MODE "Mode"
+#endif // D_STR_MODE
+#ifndef D_STR_TOGGLE
+#define D_STR_TOGGLE "Toggle"
+#endif // D_STR_TOGGLE
+#ifndef D_STR_TURBO
+#define D_STR_TURBO "Turbo"
+#endif // D_STR_TURBO
+#ifndef D_STR_SUPER
+#define D_STR_SUPER "Super"
+#endif // D_STR_SUPER
+#ifndef D_STR_SLEEP
+#define D_STR_SLEEP "Sleep"
+#endif // D_STR_SLEEP
+#ifndef D_STR_LIGHT
+#define D_STR_LIGHT "Light"
+#endif // D_STR_LIGHT
+#ifndef D_STR_POWERFUL
+#define D_STR_POWERFUL "Powerful"
+#endif // D_STR_POWERFUL
+#ifndef D_STR_QUIET
+#define D_STR_QUIET "Quiet"
+#endif // D_STR_QUIET
+#ifndef D_STR_ECONO
+#define D_STR_ECONO "Econo"
+#endif // D_STR_ECONO
+#ifndef D_STR_SWING
+#define D_STR_SWING "Swing"
+#endif // D_STR_SWING
+#ifndef D_STR_SWINGH
+#define D_STR_SWINGH D_STR_SWING"(H)" // Set `D_STR_SWING` first!
+#endif // D_STR_SWINGH
+#ifndef D_STR_SWINGV
+#define D_STR_SWINGV D_STR_SWING"(V)" // Set `D_STR_SWING` first!
+#endif // D_STR_SWINGV
+#ifndef D_STR_BEEP
+#define D_STR_BEEP "Beep"
+#endif // D_STR_BEEP
+#ifndef D_STR_MOULD
+#define D_STR_MOULD "Mould"
+#endif // D_STR_MOULD
+#ifndef D_STR_CLEAN
+#define D_STR_CLEAN "Clean"
+#endif // D_STR_CLEAN
+#ifndef D_STR_PURIFY
+#define D_STR_PURIFY "Purify"
+#endif // D_STR_PURIFY
+#ifndef D_STR_TIMER
+#define D_STR_TIMER "Timer"
+#endif // D_STR_TIMER
+#ifndef D_STR_ONTIMER
+#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER // Set `D_STR_ON` first!
+#endif // D_STR_ONTIMER
+#ifndef D_STR_OFFTIMER
+#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER // Set `D_STR_OFF` first!
+#endif // D_STR_OFFTIMER
+#ifndef D_STR_CLOCK
+#define D_STR_CLOCK "Clock"
+#endif // D_STR_CLOCK
+#ifndef D_STR_COMMAND
+#define D_STR_COMMAND "Command"
+#endif // D_STR_COMMAND
+#ifndef D_STR_XFAN
+#define D_STR_XFAN "XFan"
+#endif // D_STR_XFAN
+#ifndef D_STR_HEALTH
+#define D_STR_HEALTH "Health"
+#endif // D_STR_HEALTH
+#ifndef D_STR_MODEL
+#define D_STR_MODEL "Model"
+#endif // D_STR_MODEL
+#ifndef D_STR_TEMP
+#define D_STR_TEMP "Temp"
+#endif // D_STR_TEMP
+#ifndef D_STR_IFEEL
+#define D_STR_IFEEL "IFeel"
+#endif // D_STR_IFEEL
+#ifndef D_STR_HUMID
+#define D_STR_HUMID "Humid"
+#endif // D_STR_HUMID
+#ifndef D_STR_SAVE
+#define D_STR_SAVE "Save"
+#endif // D_STR_SAVE
+#ifndef D_STR_EYE
+#define D_STR_EYE "Eye"
+#endif // D_STR_EYE
+#ifndef D_STR_FOLLOW
+#define D_STR_FOLLOW "Follow"
+#endif // D_STR_FOLLOW
+#ifndef D_STR_ION
+#define D_STR_ION "Ion"
+#endif // D_STR_ION
+#ifndef D_STR_FRESH
+#define D_STR_FRESH "Fresh"
+#endif // D_STR_FRESH
+#ifndef D_STR_HOLD
+#define D_STR_HOLD "Hold"
+#endif // D_STR_HOLD
+#ifndef D_STR_8C_HEAT
+#define D_STR_8C_HEAT "8C " D_STR_HEAT // Set `D_STR_HEAT` first!
+#endif // D_STR_8C_HEAT
+#ifndef D_STR_BUTTON
+#define D_STR_BUTTON "Button"
+#endif // D_STR_BUTTON
+#ifndef D_STR_NIGHT
+#define D_STR_NIGHT "Night"
+#endif // D_STR_NIGHT
+#ifndef D_STR_SILENT
+#define D_STR_SILENT "Silent"
+#endif // D_STR_SILENT
+#ifndef D_STR_FILTER
+#define D_STR_FILTER "Filter"
+#endif // D_STR_FILTER
+#ifndef D_STR_3D
+#define D_STR_3D "3D"
+#endif // D_STR_3D
+#ifndef D_STR_CELSIUS
+#define D_STR_CELSIUS "Celsius"
+#endif // D_STR_CELSIUS
+#ifndef D_STR_UP
+#define D_STR_UP "Up"
+#endif // D_STR_UP
+#ifndef D_STR_TEMPUP
+#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP // Set `D_STR_TEMP` first!
+#endif // D_STR_TEMPUP
+#ifndef D_STR_DOWN
+#define D_STR_DOWN "Down"
+#endif // D_STR_DOWN
+#ifndef D_STR_TEMPDOWN
+#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN // Set `D_STR_TEMP` first!
+#endif // D_STR_TEMPDOWN
+#ifndef D_STR_CHANGE
+#define D_STR_CHANGE "Change"
+#endif // D_STR_CHANGE
+#ifndef D_STR_START
+#define D_STR_START "Start"
+#endif // D_STR_START
+#ifndef D_STR_STOP
+#define D_STR_STOP "Stop"
+#endif // D_STR_STOP
+#ifndef D_STR_MOVE
+#define D_STR_MOVE "Move"
+#endif // D_STR_MOVE
+#ifndef D_STR_SET
+#define D_STR_SET "Set"
+#endif // D_STR_SET
+#ifndef D_STR_CANCEL
+#define D_STR_CANCEL "Cancel"
+#endif // D_STR_CANCEL
+#ifndef D_STR_COMFORT
+#define D_STR_COMFORT "Comfort"
+#endif // D_STR_COMFORT
+#ifndef D_STR_SENSOR
+#define D_STR_SENSOR "Sensor"
+#endif // D_STR_SENSOR
+#ifndef D_STR_WEEKLY
+#define D_STR_WEEKLY "Weekly"
+#endif // D_STR_WEEKLY
+#ifndef D_STR_WEEKLYTIMER
+#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER // Needs `D_STR_WEEKLY`!
+#endif // D_STR_WEEKLYTIMER
+#ifndef D_STR_WIFI
+#define D_STR_WIFI "WiFi"
+#endif // D_STR_WIFI
+#ifndef D_STR_LAST
+#define D_STR_LAST "Last"
+#endif // D_STR_LAST
+#ifndef D_STR_FAST
+#define D_STR_FAST "Fast"
+#endif // D_STR_FAST
+#ifndef D_STR_SLOW
+#define D_STR_SLOW "Slow"
+#endif // D_STR_SLOW
+#ifndef D_STR_AIRFLOW
+#define D_STR_AIRFLOW "Air Flow"
+#endif // D_STR_AIRFLOW
+#ifndef D_STR_STEP
+#define D_STR_STEP "Step"
+#endif // D_STR_STEP
+#ifndef D_STR_NA
+#define D_STR_NA "N/A"
+#endif // D_STR_NA
+#ifndef D_STR_OUTSIDE
+#define D_STR_OUTSIDE "Outside"
+#endif // D_STR_OUTSIDE
+#ifndef D_STR_LOUD
+#define D_STR_LOUD "Loud"
+#endif // D_STR_LOUD
+#ifndef D_STR_UPPER
+#define D_STR_UPPER "Upper"
+#endif // D_STR_UPPER
+#ifndef D_STR_LOWER
+#define D_STR_LOWER "Lower"
+#endif // D_STR_LOWER
+#ifndef D_STR_BREEZE
+#define D_STR_BREEZE "Breeze"
+#endif // D_STR_BREEZE
+#ifndef D_STR_CIRCULATE
+#define D_STR_CIRCULATE "Circulate"
+#endif // D_STR_CIRCULATE
+#ifndef D_STR_CEILING
+#define D_STR_CEILING "Ceiling"
+#endif // D_STR_CEILING
+#ifndef D_STR_WALL
+#define D_STR_WALL "Wall"
+#endif // D_STR_WALL
+#ifndef D_STR_ROOM
+#define D_STR_ROOM "Room"
+#endif // D_STR_ROOM
+#ifndef D_STR_6THSENSE
+#define D_STR_6THSENSE "6th Sense"
+#endif // D_STR_6THSENSE
+#ifndef D_STR_ZONEFOLLOW
+#define D_STR_ZONEFOLLOW "Zone Follow"
+#endif // D_STR_ZONEFOLLOW
+#ifndef D_STR_FIXED
+#define D_STR_FIXED "Fixed"
+#endif // D_STR_FIXED
+
+#ifndef D_STR_AUTO
+#define D_STR_AUTO "Auto"
+#endif // D_STR_AUTO
+#ifndef D_STR_AUTOMATIC
+#define D_STR_AUTOMATIC "Automatic"
+#endif // D_STR_AUTOMATIC
+#ifndef D_STR_MANUAL
+#define D_STR_MANUAL "Manual"
+#endif // D_STR_MANUAL
+#ifndef D_STR_COOL
+#define D_STR_COOL "Cool"
+#endif // D_STR_COOL
+#ifndef D_STR_HEAT
+#define D_STR_HEAT "Heat"
+#endif // D_STR_HEAT
+#ifndef D_STR_FAN
+#define D_STR_FAN "Fan"
+#endif // D_STR_FAN
+#ifndef D_STR_FANONLY
+#define D_STR_FANONLY "fan_only"
+#endif // D_STR_FANONLY
+#ifndef D_STR_DRY
+#define D_STR_DRY "Dry"
+#endif // D_STR_DRY
+
+#ifndef D_STR_MAX
+#define D_STR_MAX "Max"
+#endif // D_STR_MAX
+#ifndef D_STR_MAXIMUM
+#define D_STR_MAXIMUM "Maximum"
+#endif // D_STR_MAXIMUM
+#ifndef D_STR_MIN
+#define D_STR_MIN "Min"
+#endif // D_STR_MIN
+#ifndef D_STR_MINIMUM
+#define D_STR_MINIMUM "Minimum"
+#endif // D_STR_MINIMUM
+#ifndef D_STR_MED
+#define D_STR_MED "Med"
+#endif // D_STR_MED
+#ifndef D_STR_MEDIUM
+#define D_STR_MEDIUM "Medium"
+#endif // D_STR_MEDIUM
+
+#ifndef D_STR_HIGHEST
+#define D_STR_HIGHEST "Highest"
+#endif // D_STR_HIGHEST
+#ifndef D_STR_HIGH
+#define D_STR_HIGH "High"
+#endif // D_STR_HIGH
+#ifndef D_STR_HI
+#define D_STR_HI "Hi"
+#endif // D_STR_HI
+#ifndef D_STR_MID
+#define D_STR_MID "Mid"
+#endif // D_STR_MID
+#ifndef D_STR_MIDDLE
+#define D_STR_MIDDLE "Middle"
+#endif // D_STR_MIDDLE
+#ifndef D_STR_LOW
+#define D_STR_LOW "Low"
+#endif // D_STR_LOW
+#ifndef D_STR_LO
+#define D_STR_LO "Lo"
+#endif // D_STR_LO
+#ifndef D_STR_LOWEST
+#define D_STR_LOWEST "Lowest"
+#endif // D_STR_LOWEST
+#ifndef D_STR_RIGHT
+#define D_STR_RIGHT "Right"
+#endif // D_STR_RIGHT
+#ifndef D_STR_MAXRIGHT
+#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT // Set `D_STR_MAX` first!
+#endif // D_STR_MAXRIGHT
+#ifndef D_STR_RIGHTMAX_NOSPACE
+#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` first!
+#endif // D_STR_RIGHTMAX_NOSPACE
+#ifndef D_STR_LEFT
+#define D_STR_LEFT "Left"
+#endif // D_STR_LEFT
+#ifndef D_STR_MAXLEFT
+#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT // Set `D_STR_MAX` first!
+#endif // D_STR_MAXLEFT
+#ifndef D_STR_LEFTMAX_NOSPACE
+#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` first!
+#endif // D_STR_LEFTMAX_NOSPACE
+#ifndef D_STR_WIDE
+#define D_STR_WIDE "Wide"
+#endif // D_STR_WIDE
+#ifndef D_STR_CENTRE
+#define D_STR_CENTRE "Centre"
+#endif // D_STR_CENTRE
+#ifndef D_STR_TOP
+#define D_STR_TOP "Top"
+#endif // D_STR_TOP
+#ifndef D_STR_BOTTOM
+#define D_STR_BOTTOM "Bottom"
+#endif // D_STR_BOTTOM
+
+// Compound words/phrases/descriptions from pre-defined words.
+// Note: Obviously these need to be defined *after* their component words.
+#ifndef D_STR_EYEAUTO
+#define D_STR_EYEAUTO D_STR_EYE " " D_STR_AUTO
+#endif // D_STR_EYEAUTO
+#ifndef D_STR_LIGHTTOGGLE
+#define D_STR_LIGHTTOGGLE D_STR_LIGHT " " D_STR_TOGGLE
+#endif // D_STR_LIGHTTOGGLE
+#ifndef D_STR_OUTSIDEQUIET
+#define D_STR_OUTSIDEQUIET D_STR_OUTSIDE " " D_STR_QUIET
+#endif // D_STR_OUTSIDEQUIET
+#ifndef D_STR_POWERTOGGLE
+#define D_STR_POWERTOGGLE D_STR_POWER " " D_STR_TOGGLE
+#endif // D_STR_POWERTOGGLE
+#ifndef D_STR_PREVIOUSPOWER
+#define D_STR_PREVIOUSPOWER D_STR_PREVIOUS " " D_STR_POWER
+#endif // D_STR_PREVIOUSPOWER
+#ifndef D_STR_SENSORTEMP
+#define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP
+#endif // D_STR_SENSORTEMP
+#ifndef D_STR_SLEEP_TIMER
+#define D_STR_SLEEP_TIMER D_STR_SLEEP " " D_STR_TIMER
+#endif // D_STR_SLEEP_TIMER
+#ifndef D_STR_SWINGVMODE
+#define D_STR_SWINGVMODE D_STR_SWINGV " " D_STR_MODE
+#endif // D_STR_SWINGVMODE
+#ifndef D_STR_SWINGVTOGGLE
+#define D_STR_SWINGVTOGGLE D_STR_SWINGV " " D_STR_TOGGLE
+#endif // D_STR_SWINGVTOGGLE
+
+// Separators
+#ifndef D_CHR_TIME_SEP
+#define D_CHR_TIME_SEP ':'
+#endif // D_CHR_TIME_SEP
+#ifndef D_STR_SPACELBRACE
+#define D_STR_SPACELBRACE " ("
+#endif // D_STR_SPACELBRACE
+#ifndef D_STR_COMMASPACE
+#define D_STR_COMMASPACE ", "
+#endif // D_STR_COMMASPACE
+#ifndef D_STR_COLONSPACE
+#define D_STR_COLONSPACE ": "
+#endif // D_STR_COLONSPACE
+
+#ifndef D_STR_DAY
+#define D_STR_DAY "Day"
+#endif // D_STR_DAY
+#ifndef D_STR_DAYS
+#define D_STR_DAYS D_STR_DAY "s"
+#endif // D_STR_DAYS
+#ifndef D_STR_HOUR
+#define D_STR_HOUR "Hour"
+#endif // D_STR_HOUR
+#ifndef D_STR_HOURS
+#define D_STR_HOURS D_STR_HOUR "s"
+#endif // D_STR_HOURS
+#ifndef D_STR_MINUTE
+#define D_STR_MINUTE "Minute"
+#endif // D_STR_MINUTE
+#ifndef D_STR_MINUTES
+#define D_STR_MINUTES D_STR_MINUTE "s"
+#endif // D_STR_MINUTES
+#ifndef D_STR_SECOND
+#define D_STR_SECOND "Second"
+#endif // D_STR_SECOND
+#ifndef D_STR_SECONDS
+#define D_STR_SECONDS D_STR_SECOND "s"
+#endif // D_STR_SECONDS
+#ifndef D_STR_NOW
+#define D_STR_NOW "Now"
+#endif // D_STR_NOW
+#ifndef D_STR_THREELETTERDAYS
+#define D_STR_THREELETTERDAYS "SunMonTueWedThuFriSat"
+#endif // D_STR_THREELETTERDAYS
+
+#ifndef D_STR_YES
+#define D_STR_YES "Yes"
+#endif // D_STR_YES
+#ifndef D_STR_NO
+#define D_STR_NO "No"
+#endif // D_STR_NO
+#ifndef D_STR_TRUE
+#define D_STR_TRUE "True"
+#endif // D_STR_TRUE
+#ifndef D_STR_FALSE
+#define D_STR_FALSE "False"
+#endif // D_STR_FALSE
+
+#ifndef D_STR_REPEAT
+#define D_STR_REPEAT "Repeat"
+#endif // D_STR_REPEAT
+#ifndef D_STR_CODE
+#define D_STR_CODE "Code"
+#endif // D_STR_CODE
+#ifndef D_STR_BITS
+#define D_STR_BITS "Bits"
+#endif // D_STR_BITS
+
+// Protocols Names
+#ifndef D_STR_AIRWELL
+#define D_STR_AIRWELL "AIRWELL"
+#endif // D_STR_AIRWELL
+#ifndef D_STR_AIWA_RC_T501
+#define D_STR_AIWA_RC_T501 "AIWA_RC_T501"
+#endif // D_STR_AIWA_RC_T501
+#ifndef D_STR_AMCOR
+#define D_STR_AMCOR "AMCOR"
+#endif // D_STR_AMCOR
+#ifndef D_STR_ARGO
+#define D_STR_ARGO "ARGO"
+#endif // D_STR_ARGO
+#ifndef D_STR_CARRIER_AC
+#define D_STR_CARRIER_AC "CARRIER_AC"
+#endif // D_STR_CARRIER_AC
+#ifndef D_STR_COOLIX
+#define D_STR_COOLIX "COOLIX"
+#endif // D_STR_COOLIX
+#ifndef D_STR_DAIKIN
+#define D_STR_DAIKIN "DAIKIN"
+#endif // D_STR_DAIKIN
+#ifndef D_STR_DAIKIN128
+#define D_STR_DAIKIN128 "DAIKIN128"
+#endif // D_STR_DAIKIN128
+#ifndef D_STR_DAIKIN152
+#define D_STR_DAIKIN152 "DAIKIN152"
+#endif // D_STR_DAIKIN152
+#ifndef D_STR_DAIKIN160
+#define D_STR_DAIKIN160 "DAIKIN160"
+#endif // D_STR_DAIKIN160
+#ifndef D_STR_DAIKIN176
+#define D_STR_DAIKIN176 "DAIKIN176"
+#endif // D_STR_DAIKIN176
+#ifndef D_STR_DAIKIN2
+#define D_STR_DAIKIN2 "DAIKIN2"
+#endif // D_STR_DAIKIN2
+#ifndef D_STR_DAIKIN216
+#define D_STR_DAIKIN216 "DAIKIN216"
+#endif // D_STR_DAIKIN216
+#ifndef D_STR_DAIKIN64
+#define D_STR_DAIKIN64 "DAIKIN64"
+#endif // D_STR_DAIKIN64
+#ifndef D_STR_DENON
+#define D_STR_DENON "DENON"
+#endif // D_STR_DENON
+#ifndef D_STR_DISH
+#define D_STR_DISH "DISH"
+#endif // D_STR_DISH
+#ifndef D_STR_ELECTRA_AC
+#define D_STR_ELECTRA_AC "ELECTRA_AC"
+#endif // D_STR_ELECTRA_AC
+#ifndef D_STR_EPSON
+#define D_STR_EPSON "EPSON"
+#endif // D_STR_EPSON
+#ifndef D_STR_FUJITSU_AC
+#define D_STR_FUJITSU_AC "FUJITSU_AC"
+#endif // D_STR_FUJITSU_AC
+#ifndef D_STR_GICABLE
+#define D_STR_GICABLE "GICABLE"
+#endif // D_STR_GICABLE
+#ifndef D_STR_GLOBALCACHE
+#define D_STR_GLOBALCACHE "GLOBALCACHE"
+#endif // D_STR_GLOBALCACHE
+#ifndef D_STR_GOODWEATHER
+#define D_STR_GOODWEATHER "GOODWEATHER"
+#endif // D_STR_GOODWEATHER
+#ifndef D_STR_GREE
+#define D_STR_GREE "GREE"
+#endif // D_STR_GREE
+#ifndef D_STR_HAIER_AC
+#define D_STR_HAIER_AC "HAIER_AC"
+#endif // D_STR_HAIER_AC
+#ifndef D_STR_HAIER_AC_YRW02
+#define D_STR_HAIER_AC_YRW02 "HAIER_AC_YRW02"
+#endif // D_STR_HAIER_AC_YRW02
+#ifndef D_STR_HITACHI_AC
+#define D_STR_HITACHI_AC "HITACHI_AC"
+#endif // D_STR_HITACHI_AC
+#ifndef D_STR_HITACHI_AC1
+#define D_STR_HITACHI_AC1 "HITACHI_AC1"
+#endif // D_STR_HITACHI_AC1
+#ifndef D_STR_HITACHI_AC2
+#define D_STR_HITACHI_AC2 "HITACHI_AC2"
+#endif // D_STR_HITACHI_AC2
+#ifndef D_STR_HITACHI_AC3
+#define D_STR_HITACHI_AC3 "HITACHI_AC3"
+#endif // D_STR_HITACHI_AC3
+#ifndef D_STR_HITACHI_AC424
+#define D_STR_HITACHI_AC424 "HITACHI_AC424"
+#endif // D_STR_HITACHI_AC424
+#ifndef D_STR_INAX
+#define D_STR_INAX "INAX"
+#endif // D_STR_INAX
+#ifndef D_STR_JVC
+#define D_STR_JVC "JVC"
+#endif // D_STR_JVC
+#ifndef D_STR_KELVINATOR
+#define D_STR_KELVINATOR "KELVINATOR"
+#endif // D_STR_KELVINATOR
+#ifndef D_STR_LASERTAG
+#define D_STR_LASERTAG "LASERTAG"
+#endif // D_STR_LASERTAG
+#ifndef D_STR_LEGOPF
+#define D_STR_LEGOPF "LEGOPF"
+#endif // D_STR_LEGOPF
+#ifndef D_STR_LG
+#define D_STR_LG "LG"
+#endif // D_STR_LG
+#ifndef D_STR_LG2
+#define D_STR_LG2 "LG2"
+#endif // D_STR_LG2
+#ifndef D_STR_LUTRON
+#define D_STR_LUTRON "LUTRON"
+#endif // D_STR_LUTRON
+#ifndef D_STR_MAGIQUEST
+#define D_STR_MAGIQUEST "MAGIQUEST"
+#endif // D_STR_MAGIQUEST
+#ifndef D_STR_MIDEA
+#define D_STR_MIDEA "MIDEA"
+#endif // D_STR_MIDEA
+#ifndef D_STR_MITSUBISHI
+#define D_STR_MITSUBISHI "MITSUBISHI"
+#endif // D_STR_MITSUBISHI
+#ifndef D_STR_MITSUBISHI112
+#define D_STR_MITSUBISHI112 "MITSUBISHI112"
+#endif // D_STR_MITSUBISHI112
+#ifndef D_STR_MITSUBISHI136
+#define D_STR_MITSUBISHI136 "MITSUBISHI136"
+#endif // D_STR_MITSUBISHI136
+#ifndef D_STR_MITSUBISHI2
+#define D_STR_MITSUBISHI2 "MITSUBISHI2"
+#endif // D_STR_MITSUBISHI2
+#ifndef D_STR_MITSUBISHI_AC
+#define D_STR_MITSUBISHI_AC "MITSUBISHI_AC"
+#endif // D_STR_MITSUBISHI_AC
+#ifndef D_STR_MITSUBISHI_HEAVY_152
+#define D_STR_MITSUBISHI_HEAVY_152 "MITSUBISHI_HEAVY_152"
+#endif // D_STR_MITSUBISHI_HEAVY_152
+#ifndef D_STR_MITSUBISHI_HEAVY_88
+#define D_STR_MITSUBISHI_HEAVY_88 "MITSUBISHI_HEAVY_88"
+#endif // D_STR_MITSUBISHI_HEAVY_88
+#ifndef D_STR_MWM
+#define D_STR_MWM "MWM"
+#endif // D_STR_MWM
+#ifndef D_STR_NEC
+#define D_STR_NEC "NEC"
+#endif // D_STR_NEC
+#ifndef D_STR_NEC_LIKE
+#define D_STR_NEC_LIKE D_STR_NEC "_LIKE"
+#endif // D_STR_NEC_LIKE
+#ifndef D_STR_NEC_NON_STRICT
+#define D_STR_NEC_NON_STRICT D_STR_NEC " (NON-STRICT)"
+#endif // D_STR_NEC_NON_STRICT
+#ifndef D_STR_NEOCLIMA
+#define D_STR_NEOCLIMA "NEOCLIMA"
+#endif // D_STR_NEOCLIMA
+#ifndef D_STR_NIKAI
+#define D_STR_NIKAI "NIKAI"
+#endif // D_STR_NIKAI
+#ifndef D_STR_PANASONIC
+#define D_STR_PANASONIC "PANASONIC"
+#endif // D_STR_PANASONIC
+#ifndef D_STR_PANASONIC_AC
+#define D_STR_PANASONIC_AC "PANASONIC_AC"
+#endif // D_STR_PANASONIC_AC
+#ifndef D_STR_PIONEER
+#define D_STR_PIONEER "PIONEER"
+#endif // D_STR_PIONEER
+#ifndef D_STR_PRONTO
+#define D_STR_PRONTO "PRONTO"
+#endif // D_STR_PRONTO
+#ifndef D_STR_RAW
+#define D_STR_RAW "RAW"
+#endif // D_STR_RAW
+#ifndef D_STR_RC5
+#define D_STR_RC5 "RC5"
+#endif // D_STR_RC5
+#ifndef D_STR_RC5X
+#define D_STR_RC5X "RC5X"
+#endif // D_STR_RC5X
+#ifndef D_STR_RC6
+#define D_STR_RC6 "RC6"
+#endif // D_STR_RC6
+#ifndef D_STR_RCMM
+#define D_STR_RCMM "RCMM"
+#endif // D_STR_RCMM
+#ifndef D_STR_SAMSUNG
+#define D_STR_SAMSUNG "SAMSUNG"
+#endif // D_STR_SAMSUNG
+#ifndef D_STR_SAMSUNG36
+#define D_STR_SAMSUNG36 "SAMSUNG36"
+#endif // D_STR_SAMSUNG36
+#ifndef D_STR_SAMSUNG_AC
+#define D_STR_SAMSUNG_AC "SAMSUNG_AC"
+#endif // D_STR_SAMSUNG_AC
+#ifndef D_STR_SANYO
+#define D_STR_SANYO "SANYO"
+#endif // D_STR_SANYO
+#ifndef D_STR_SANYO_LC7461
+#define D_STR_SANYO_LC7461 "SANYO_LC7461"
+#endif // D_STR_SANYO_LC7461
+#ifndef D_STR_SHARP
+#define D_STR_SHARP "SHARP"
+#endif // D_STR_SHARP
+#ifndef D_STR_SHARP_AC
+#define D_STR_SHARP_AC "SHARP_AC"
+#endif // D_STR_SHARP_AC
+#ifndef D_STR_SHERWOOD
+#define D_STR_SHERWOOD "SHERWOOD"
+#endif // D_STR_SHERWOOD
+#ifndef D_STR_SONY
+#define D_STR_SONY "SONY"
+#endif // D_STR_SONY
+#ifndef D_STR_SONY_38K
+#define D_STR_SONY_38K "SONY_38K"
+#endif // D_STR_SONY_38K
+#ifndef D_STR_SYMPHONY
+#define D_STR_SYMPHONY "SYMPHONY"
+#endif // D_STR_SYMPHONY
+#ifndef D_STR_TCL112AC
+#define D_STR_TCL112AC "TCL112AC"
+#endif // D_STR_TCL112AC
+#ifndef D_STR_TECO
+#define D_STR_TECO "TECO"
+#endif // D_STR_TECO
+#ifndef D_STR_TOSHIBA_AC
+#define D_STR_TOSHIBA_AC "TOSHIBA_AC"
+#endif // D_STR_TOSHIBA_AC
+#ifndef D_STR_TROTEC
+#define D_STR_TROTEC "TROTEC"
+#endif // D_STR_TROTEC
+#ifndef D_STR_UNUSED
+#define D_STR_UNUSED "UNUSED"
+#endif // D_STR_UNUSED
+#ifndef D_STR_VESTEL_AC
+#define D_STR_VESTEL_AC "VESTEL_AC"
+#endif // D_STR_VESTEL_AC
+#ifndef D_STR_WHIRLPOOL_AC
+#define D_STR_WHIRLPOOL_AC "WHIRLPOOL_AC"
+#endif // D_STR_WHIRLPOOL_AC
+#ifndef D_STR_WHYNTER
+#define D_STR_WHYNTER "WHYNTER"
+#endif // D_STR_WHYNTER
+
+// IRrecvDumpV2
+#ifndef D_STR_TIMESTAMP
+#define D_STR_TIMESTAMP "Timestamp"
+#endif // D_STR_TIMESTAMP
+#ifndef D_STR_LIBRARY
+#define D_STR_LIBRARY "Library"
+#endif // D_STR_LIBRARY
+#ifndef D_STR_MESGDESC
+#define D_STR_MESGDESC "Mesg Desc."
+#endif // D_STR_MESGDESC
+#ifndef D_STR_IRRECVDUMP_STARTUP
+#define D_STR_IRRECVDUMP_STARTUP \
+ "IRrecvDumpV2 is now running and waiting for IR input on Pin %d"
+#endif // D_STR_IRRECVDUMP_STARTUP
+#ifndef D_WARN_BUFFERFULL
+#define D_WARN_BUFFERFULL \
+ "WARNING: IR code is too big for buffer (>= %d). " \
+ "This result shouldn't be trusted until this is resolved. " \
+ "Edit & increase `kCaptureBufferSize`."
+#endif // D_WARN_BUFFERFULL
+
+#endif // LOCALE_DEFAULTS_H_
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/en-AU.h b/lib/IRremoteESP8266-2.7.6/src/locale/en-AU.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/en-AU.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/en-AU.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/en-IE.h b/lib/IRremoteESP8266-2.7.6/src/locale/en-IE.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/en-IE.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/en-IE.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/en-UK.h b/lib/IRremoteESP8266-2.7.6/src/locale/en-UK.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/en-UK.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/en-UK.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/en-US.h b/lib/IRremoteESP8266-2.7.6/src/locale/en-US.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/src/locale/en-US.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/en-US.h
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/es-ES.h b/lib/IRremoteESP8266-2.7.6/src/locale/es-ES.h
similarity index 97%
rename from lib/IRremoteESP8266-2.7.4/src/locale/es-ES.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/es-ES.h
index 821186141..52f22333d 100644
--- a/lib/IRremoteESP8266-2.7.4/src/locale/es-ES.h
+++ b/lib/IRremoteESP8266-2.7.6/src/locale/es-ES.h
@@ -7,6 +7,8 @@
#define D_STR_UNKNOWN "DESCONOCIDO"
#define D_STR_PROTOCOL "Protocolo"
#define D_STR_POWER "Poder"
+#define D_STR_PREVIOUS "Anterior"
+#define D_STR_PREVIOUSPOWER D_STR_POWER " " D_STR_PREVIOUS
#define D_STR_ON "Encendido"
#define D_STR_OFF "Apagado"
#define D_STR_MODE "Modo"
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/fr-FR.h b/lib/IRremoteESP8266-2.7.6/src/locale/fr-FR.h
similarity index 97%
rename from lib/IRremoteESP8266-2.7.4/src/locale/fr-FR.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/fr-FR.h
index 5ab10cb62..0eae39e2e 100644
--- a/lib/IRremoteESP8266-2.7.4/src/locale/fr-FR.h
+++ b/lib/IRremoteESP8266-2.7.6/src/locale/fr-FR.h
@@ -10,6 +10,8 @@
#define D_STR_SLEEP "Pause"
#define D_STR_LIGHT "Lumière"
#define D_STR_POWERFUL "Puissance"
+#define D_STR_PREVIOUS "Precedente"
+#define D_STR_PREVIOUSPOWER D_STR_POWER " " D_STR_PREVIOUS
#define D_STR_QUIET "Silence"
#define D_STR_ECONO "Economie"
#define D_STR_BEEP "Bip"
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/it-IT.h b/lib/IRremoteESP8266-2.7.6/src/locale/it-IT.h
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/src/locale/it-IT.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/it-IT.h
index b078a7319..b04a129d2 100644
--- a/lib/IRremoteESP8266-2.7.4/src/locale/it-IT.h
+++ b/lib/IRremoteESP8266-2.7.6/src/locale/it-IT.h
@@ -8,6 +8,8 @@
#define D_STR_UNKNOWN "SCONOSCIUTO"
#define D_STR_PROTOCOL "Protocollo"
#define D_STR_POWER "Accensione"
+#define D_STR_PREVIOUS "Precedente"
+#define D_STR_PREVIOUSPOWER D_STR_POWER " " D_STR_PREVIOUS
#define D_STR_ON "Acceso"
#define D_STR_OFF "Spento"
#define D_STR_MODE "Modalità"
diff --git a/lib/IRremoteESP8266-2.7.4/src/locale/defaults.h b/lib/IRremoteESP8266-2.7.6/src/locale/zh-CN.h
similarity index 67%
rename from lib/IRremoteESP8266-2.7.4/src/locale/defaults.h
rename to lib/IRremoteESP8266-2.7.6/src/locale/zh-CN.h
index 20e38082a..bcb30392c 100644
--- a/lib/IRremoteESP8266-2.7.4/src/locale/defaults.h
+++ b/lib/IRremoteESP8266-2.7.6/src/locale/zh-CN.h
@@ -1,64 +1,56 @@
-// Copyright 2019 - David Conran (@crankyoldgit)
-// The default text to use throughout the library.
-// The library will use this text if no locale (_IR_LOCALE_) is set or if
-// the locale doesn't define particular values.
-// If they are defined, this file should NOT override them.
-//
-// This file should contain a #define for every translateable/locale dependant
-// string used by the library. Language specific files don't have to include
-// everything.
-//
-// NOTE: ASCII/UTF-8 characters only. Unicode is NOT supported.
-//
-// The defaults are English (AU) / en-AU. Australia (AU) is pretty much the same
-// as English (UK) for this libraries use case.
-#ifndef LOCALE_DEFAULTS_H_
-#define LOCALE_DEFAULTS_H_
+// Copyright 2020 - MiaoYi (@Caffreyfans)
+// Locale/language file for China / Simplified.
+// This file will override the default values located in `defaults.h`.
+#ifndef LOCALE_ZH_CN_H_
+#define LOCALE_ZH_CN_H_
#ifndef D_STR_UNKNOWN
-#define D_STR_UNKNOWN "UNKNOWN"
+#define D_STR_UNKNOWN "未知"
#endif // D_STR_UNKNOWN
#ifndef D_STR_PROTOCOL
-#define D_STR_PROTOCOL "Protocol"
+#define D_STR_PROTOCOL "协议"
#endif // D_STR_PROTOCOL
#ifndef D_STR_POWER
-#define D_STR_POWER "Power"
+#define D_STR_POWER "电源"
#endif // D_STR_POWER
+#ifndef D_STR_PREVIOUS
+#define D_STR_PREVIOUS "以前"
+#endif // D_STR_PREVIOUS
#ifndef D_STR_ON
-#define D_STR_ON "On"
+#define D_STR_ON "开"
#endif // D_STR_ON
#ifndef D_STR_OFF
-#define D_STR_OFF "Off"
+#define D_STR_OFF "关"
#endif // D_STR_OFF
#ifndef D_STR_MODE
-#define D_STR_MODE "Mode"
+#define D_STR_MODE "模式"
#endif // D_STR_MODE
#ifndef D_STR_TOGGLE
-#define D_STR_TOGGLE "Toggle"
+#define D_STR_TOGGLE "切换"
#endif // D_STR_TOGGLE
#ifndef D_STR_TURBO
-#define D_STR_TURBO "Turbo"
+#define D_STR_TURBO "强力"
#endif // D_STR_TURBO
#ifndef D_STR_SUPER
-#define D_STR_SUPER "Super"
+#define D_STR_SUPER "超级"
#endif // D_STR_SUPER
#ifndef D_STR_SLEEP
-#define D_STR_SLEEP "Sleep"
+#define D_STR_SLEEP "睡眠"
#endif // D_STR_SLEEP
#ifndef D_STR_LIGHT
-#define D_STR_LIGHT "Light"
+#define D_STR_LIGHT "灯光"
#endif // D_STR_LIGHT
#ifndef D_STR_POWERFUL
-#define D_STR_POWERFUL "Powerful"
+#define D_STR_POWERFUL "强劲模式"
#endif // D_STR_POWERFUL
#ifndef D_STR_QUIET
-#define D_STR_QUIET "Quiet"
+#define D_STR_QUIET "安静"
#endif // D_STR_QUIET
#ifndef D_STR_ECONO
-#define D_STR_ECONO "Econo"
+#define D_STR_ECONO "经济"
#endif // D_STR_ECONO
#ifndef D_STR_SWING
-#define D_STR_SWING "Swing"
+#define D_STR_SWING "扫风"
#endif // D_STR_SWING
#ifndef D_STR_SWINGH
#define D_STR_SWINGH D_STR_SWING"(H)" // Set `D_STR_SWING` first!
@@ -67,19 +59,19 @@
#define D_STR_SWINGV D_STR_SWING"(V)" // Set `D_STR_SWING` first!
#endif // D_STR_SWINGV
#ifndef D_STR_BEEP
-#define D_STR_BEEP "Beep"
+#define D_STR_BEEP "蜂鸣"
#endif // D_STR_BEEP
#ifndef D_STR_MOULD
-#define D_STR_MOULD "Mould"
+#define D_STR_MOULD "模子"
#endif // D_STR_MOULD
#ifndef D_STR_CLEAN
-#define D_STR_CLEAN "Clean"
+#define D_STR_CLEAN "清洁"
#endif // D_STR_CLEAN
#ifndef D_STR_PURIFY
-#define D_STR_PURIFY "Purify"
+#define D_STR_PURIFY "净化"
#endif // D_STR_PURIFY
#ifndef D_STR_TIMER
-#define D_STR_TIMER "Timer"
+#define D_STR_TIMER "计时器"
#endif // D_STR_TIMER
#ifndef D_STR_ONTIMER
#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER // Set `D_STR_ON` first!
@@ -88,106 +80,106 @@
#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER // Set `D_STR_OFF` first!
#endif // D_STR_OFFTIMER
#ifndef D_STR_CLOCK
-#define D_STR_CLOCK "Clock"
+#define D_STR_CLOCK "时钟"
#endif // D_STR_CLOCK
#ifndef D_STR_COMMAND
-#define D_STR_COMMAND "Command"
+#define D_STR_COMMAND "命令"
#endif // D_STR_COMMAND
#ifndef D_STR_XFAN
#define D_STR_XFAN "XFan"
#endif // D_STR_XFAN
#ifndef D_STR_HEALTH
-#define D_STR_HEALTH "Health"
+#define D_STR_HEALTH "健康"
#endif // D_STR_HEALTH
#ifndef D_STR_MODEL
-#define D_STR_MODEL "Model"
+#define D_STR_MODEL "模式"
#endif // D_STR_MODEL
#ifndef D_STR_TEMP
-#define D_STR_TEMP "Temp"
+#define D_STR_TEMP "温度"
#endif // D_STR_TEMP
#ifndef D_STR_IFEEL
#define D_STR_IFEEL "IFeel"
#endif // D_STR_IFEEL
#ifndef D_STR_HUMID
-#define D_STR_HUMID "Humid"
+#define D_STR_HUMID "湿度"
#endif // D_STR_HUMID
#ifndef D_STR_SAVE
-#define D_STR_SAVE "Save"
+#define D_STR_SAVE "保存"
#endif // D_STR_SAVE
#ifndef D_STR_EYE
-#define D_STR_EYE "Eye"
+#define D_STR_EYE "眼"
#endif // D_STR_EYE
#ifndef D_STR_FOLLOW
-#define D_STR_FOLLOW "Follow"
+#define D_STR_FOLLOW "跟随"
#endif // D_STR_FOLLOW
#ifndef D_STR_ION
#define D_STR_ION "Ion"
#endif // D_STR_ION
#ifndef D_STR_FRESH
-#define D_STR_FRESH "Fresh"
+#define D_STR_FRESH "刷新"
#endif // D_STR_FRESH
#ifndef D_STR_HOLD
-#define D_STR_HOLD "Hold"
+#define D_STR_HOLD "保持"
#endif // D_STR_HOLD
#ifndef D_STR_8C_HEAT
#define D_STR_8C_HEAT "8C " D_STR_HEAT // Set `D_STR_HEAT` first!
#endif // D_STR_8C_HEAT
#ifndef D_STR_BUTTON
-#define D_STR_BUTTON "Button"
+#define D_STR_BUTTON "按钮"
#endif // D_STR_BUTTON
#ifndef D_STR_NIGHT
-#define D_STR_NIGHT "Night"
+#define D_STR_NIGHT "夜间"
#endif // D_STR_NIGHT
#ifndef D_STR_SILENT
-#define D_STR_SILENT "Silent"
+#define D_STR_SILENT "安静"
#endif // D_STR_SILENT
#ifndef D_STR_FILTER
-#define D_STR_FILTER "Filter"
+#define D_STR_FILTER "过滤"
#endif // D_STR_FILTER
#ifndef D_STR_3D
#define D_STR_3D "3D"
#endif // D_STR_3D
#ifndef D_STR_CELSIUS
-#define D_STR_CELSIUS "Celsius"
+#define D_STR_CELSIUS "摄氏度"
#endif // D_STR_CELSIUS
#ifndef D_STR_UP
-#define D_STR_UP "Up"
+#define D_STR_UP "上"
#endif // D_STR_UP
#ifndef D_STR_TEMPUP
#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP // Set `D_STR_TEMP` first!
#endif // D_STR_TEMPUP
#ifndef D_STR_DOWN
-#define D_STR_DOWN "Down"
+#define D_STR_DOWN "下"
#endif // D_STR_DOWN
#ifndef D_STR_TEMPDOWN
#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN // Set `D_STR_TEMP` first!
#endif // D_STR_TEMPDOWN
#ifndef D_STR_CHANGE
-#define D_STR_CHANGE "Change"
+#define D_STR_CHANGE "改变"
#endif // D_STR_CHANGE
#ifndef D_STR_START
-#define D_STR_START "Start"
+#define D_STR_START "开始"
#endif // D_STR_START
#ifndef D_STR_STOP
-#define D_STR_STOP "Stop"
+#define D_STR_STOP "结束"
#endif // D_STR_STOP
#ifndef D_STR_MOVE
-#define D_STR_MOVE "Move"
+#define D_STR_MOVE "移动"
#endif // D_STR_MOVE
#ifndef D_STR_SET
-#define D_STR_SET "Set"
+#define D_STR_SET "设置"
#endif // D_STR_SET
#ifndef D_STR_CANCEL
-#define D_STR_CANCEL "Cancel"
+#define D_STR_CANCEL "取消"
#endif // D_STR_CANCEL
#ifndef D_STR_COMFORT
-#define D_STR_COMFORT "Comfort"
+#define D_STR_COMFORT "舒适"
#endif // D_STR_COMFORT
#ifndef D_STR_SENSOR
-#define D_STR_SENSOR "Sensor"
+#define D_STR_SENSOR "传感器"
#endif // D_STR_SENSOR
#ifndef D_STR_WEEKLY
-#define D_STR_WEEKLY "Weekly"
+#define D_STR_WEEKLY "每周"
#endif // D_STR_WEEKLY
#ifndef D_STR_WEEKLYTIMER
#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER // Needs `D_STR_WEEKLY`!
@@ -196,130 +188,130 @@
#define D_STR_WIFI "WiFi"
#endif // D_STR_WIFI
#ifndef D_STR_LAST
-#define D_STR_LAST "Last"
+#define D_STR_LAST "最近"
#endif // D_STR_LAST
#ifndef D_STR_FAST
-#define D_STR_FAST "Fast"
+#define D_STR_FAST "快"
#endif // D_STR_FAST
#ifndef D_STR_SLOW
-#define D_STR_SLOW "Slow"
+#define D_STR_SLOW "慢"
#endif // D_STR_SLOW
#ifndef D_STR_AIRFLOW
-#define D_STR_AIRFLOW "Air Flow"
+#define D_STR_AIRFLOW "空气流动"
#endif // D_STR_AIRFLOW
#ifndef D_STR_STEP
-#define D_STR_STEP "Step"
+#define D_STR_STEP "步"
#endif // D_STR_STEP
#ifndef D_STR_NA
-#define D_STR_NA "N/A"
+#define D_STR_NA "不适用"
#endif // D_STR_NA
#ifndef D_STR_OUTSIDE
-#define D_STR_OUTSIDE "Outside"
+#define D_STR_OUTSIDE "室外"
#endif // D_STR_OUTSIDE
#ifndef D_STR_LOUD
-#define D_STR_LOUD "Loud"
+#define D_STR_LOUD "大声"
#endif // D_STR_LOUD
#ifndef D_STR_UPPER
-#define D_STR_UPPER "Upper"
+#define D_STR_UPPER "更高"
#endif // D_STR_UPPER
#ifndef D_STR_LOWER
-#define D_STR_LOWER "Lower"
+#define D_STR_LOWER "更低"
#endif // D_STR_LOWER
#ifndef D_STR_BREEZE
-#define D_STR_BREEZE "Breeze"
+#define D_STR_BREEZE "微风"
#endif // D_STR_BREEZE
#ifndef D_STR_CIRCULATE
-#define D_STR_CIRCULATE "Circulate"
+#define D_STR_CIRCULATE "流通"
#endif // D_STR_CIRCULATE
#ifndef D_STR_CEILING
-#define D_STR_CEILING "Ceiling"
+#define D_STR_CEILING "天花板"
#endif // D_STR_CEILING
#ifndef D_STR_WALL
-#define D_STR_WALL "Wall"
+#define D_STR_WALL "墙"
#endif // D_STR_WALL
#ifndef D_STR_ROOM
-#define D_STR_ROOM "Room"
+#define D_STR_ROOM "房间"
#endif // D_STR_ROOM
#ifndef D_STR_6THSENSE
-#define D_STR_6THSENSE "6th Sense"
+#define D_STR_6THSENSE "第六感"
#endif // D_STR_6THSENSE
#ifndef D_STR_ZONEFOLLOW
-#define D_STR_ZONEFOLLOW "Zone Follow"
+#define D_STR_ZONEFOLLOW "区域跟随"
#endif // D_STR_ZONEFOLLOW
#ifndef D_STR_FIXED
-#define D_STR_FIXED "Fixed"
+#define D_STR_FIXED "固定"
#endif // D_STR_FIXED
#ifndef D_STR_AUTO
-#define D_STR_AUTO "Auto"
+#define D_STR_AUTO "自动"
#endif // D_STR_AUTO
#ifndef D_STR_AUTOMATIC
-#define D_STR_AUTOMATIC "Automatic"
+#define D_STR_AUTOMATIC "自动的"
#endif // D_STR_AUTOMATIC
#ifndef D_STR_MANUAL
-#define D_STR_MANUAL "Manual"
+#define D_STR_MANUAL "手动"
#endif // D_STR_MANUAL
#ifndef D_STR_COOL
-#define D_STR_COOL "Cool"
+#define D_STR_COOL "制冷"
#endif // D_STR_COOL
#ifndef D_STR_HEAT
-#define D_STR_HEAT "Heat"
+#define D_STR_HEAT "加热"
#endif // D_STR_HEAT
#ifndef D_STR_FAN
-#define D_STR_FAN "Fan"
+#define D_STR_FAN "风扇"
#endif // D_STR_FAN
#ifndef D_STR_FANONLY
-#define D_STR_FANONLY "fan_only"
+#define D_STR_FANONLY "仅风扇"
#endif // D_STR_FANONLY
#ifndef D_STR_DRY
-#define D_STR_DRY "Dry"
+#define D_STR_DRY "干燥"
#endif // D_STR_DRY
#ifndef D_STR_MAX
-#define D_STR_MAX "Max"
+#define D_STR_MAX "最大"
#endif // D_STR_MAX
#ifndef D_STR_MAXIMUM
-#define D_STR_MAXIMUM "Maximum"
+#define D_STR_MAXIMUM "最小"
#endif // D_STR_MAXIMUM
#ifndef D_STR_MIN
-#define D_STR_MIN "Min"
+#define D_STR_MIN "最低"
#endif // D_STR_MIN
#ifndef D_STR_MINIMUM
-#define D_STR_MINIMUM "Minimum"
+#define D_STR_MINIMUM "最低"
#endif // D_STR_MINIMUM
#ifndef D_STR_MED
-#define D_STR_MED "Med"
+#define D_STR_MED "中"
#endif // D_STR_MED
#ifndef D_STR_MEDIUM
-#define D_STR_MEDIUM "Medium"
+#define D_STR_MEDIUM "中"
#endif // D_STR_MEDIUM
#ifndef D_STR_HIGHEST
-#define D_STR_HIGHEST "Highest"
+#define D_STR_HIGHEST "最高"
#endif // D_STR_HIGHEST
#ifndef D_STR_HIGH
-#define D_STR_HIGH "High"
+#define D_STR_HIGH "高"
#endif // D_STR_HIGH
#ifndef D_STR_HI
-#define D_STR_HI "Hi"
+#define D_STR_HI "嗨"
#endif // D_STR_HI
#ifndef D_STR_MID
-#define D_STR_MID "Mid"
+#define D_STR_MID "中"
#endif // D_STR_MID
#ifndef D_STR_MIDDLE
-#define D_STR_MIDDLE "Middle"
+#define D_STR_MIDDLE "居中"
#endif // D_STR_MIDDLE
#ifndef D_STR_LOW
-#define D_STR_LOW "Low"
+#define D_STR_LOW "低"
#endif // D_STR_LOW
#ifndef D_STR_LO
-#define D_STR_LO "Lo"
+#define D_STR_LO "低"
#endif // D_STR_LO
#ifndef D_STR_LOWEST
-#define D_STR_LOWEST "Lowest"
+#define D_STR_LOWEST "最低"
#endif // D_STR_LOWEST
#ifndef D_STR_RIGHT
-#define D_STR_RIGHT "Right"
+#define D_STR_RIGHT "右"
#endif // D_STR_RIGHT
#ifndef D_STR_MAXRIGHT
#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT // Set `D_STR_MAX` first!
@@ -328,7 +320,7 @@
#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` first!
#endif // D_STR_RIGHTMAX_NOSPACE
#ifndef D_STR_LEFT
-#define D_STR_LEFT "Left"
+#define D_STR_LEFT "左"
#endif // D_STR_LEFT
#ifndef D_STR_MAXLEFT
#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT // Set `D_STR_MAX` first!
@@ -337,16 +329,16 @@
#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` first!
#endif // D_STR_LEFTMAX_NOSPACE
#ifndef D_STR_WIDE
-#define D_STR_WIDE "Wide"
+#define D_STR_WIDE "扫风"
#endif // D_STR_WIDE
#ifndef D_STR_CENTRE
-#define D_STR_CENTRE "Centre"
+#define D_STR_CENTRE "中间"
#endif // D_STR_CENTRE
#ifndef D_STR_TOP
-#define D_STR_TOP "Top"
+#define D_STR_TOP "上部"
#endif // D_STR_TOP
#ifndef D_STR_BOTTOM
-#define D_STR_BOTTOM "Bottom"
+#define D_STR_BOTTOM "底部"
#endif // D_STR_BOTTOM
// Compound words/phrases/descriptions from pre-defined words.
@@ -363,6 +355,9 @@
#ifndef D_STR_POWERTOGGLE
#define D_STR_POWERTOGGLE D_STR_POWER " " D_STR_TOGGLE
#endif // D_STR_POWERTOGGLE
+#ifndef D_STR_PREVIOUSPOWER
+#define D_STR_PREVIOUSPOWER D_STR_PREVIOUS " " D_STR_POWER
+#endif // D_STR_PREVIOUSPOWER
#ifndef D_STR_SENSORTEMP
#define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP
#endif // D_STR_SENSORTEMP
@@ -391,78 +386,80 @@
#endif // D_STR_COLONSPACE
#ifndef D_STR_DAY
-#define D_STR_DAY "Day"
+#define D_STR_DAY "天"
#endif // D_STR_DAY
#ifndef D_STR_DAYS
#define D_STR_DAYS D_STR_DAY "s"
#endif // D_STR_DAYS
#ifndef D_STR_HOUR
-#define D_STR_HOUR "Hour"
+#define D_STR_HOUR "时"
#endif // D_STR_HOUR
#ifndef D_STR_HOURS
#define D_STR_HOURS D_STR_HOUR "s"
#endif // D_STR_HOURS
#ifndef D_STR_MINUTE
-#define D_STR_MINUTE "Minute"
+#define D_STR_MINUTE "分"
#endif // D_STR_MINUTE
#ifndef D_STR_MINUTES
#define D_STR_MINUTES D_STR_MINUTE "s"
#endif // D_STR_MINUTES
#ifndef D_STR_SECOND
-#define D_STR_SECOND "Second"
+#define D_STR_SECOND "秒"
#endif // D_STR_SECOND
#ifndef D_STR_SECONDS
#define D_STR_SECONDS D_STR_SECOND "s"
#endif // D_STR_SECONDS
#ifndef D_STR_NOW
-#define D_STR_NOW "Now"
+#define D_STR_NOW "现在"
#endif // D_STR_NOW
+/* This is not three letter days. Disabled.
#ifndef D_STR_THREELETTERDAYS
-#define D_STR_THREELETTERDAYS "SunMonTueWedThuFriSat"
+#define D_STR_THREELETTERDAYS "周一至周末"
#endif // D_STR_THREELETTERDAYS
+*/
#ifndef D_STR_YES
-#define D_STR_YES "Yes"
+#define D_STR_YES "是"
#endif // D_STR_YES
#ifndef D_STR_NO
-#define D_STR_NO "No"
+#define D_STR_NO "否"
#endif // D_STR_NO
#ifndef D_STR_TRUE
-#define D_STR_TRUE "True"
+#define D_STR_TRUE "正确"
#endif // D_STR_TRUE
#ifndef D_STR_FALSE
-#define D_STR_FALSE "False"
+#define D_STR_FALSE "错误"
#endif // D_STR_FALSE
#ifndef D_STR_REPEAT
-#define D_STR_REPEAT "Repeat"
+#define D_STR_REPEAT "重复"
#endif // D_STR_REPEAT
#ifndef D_STR_CODE
-#define D_STR_CODE "Code"
+#define D_STR_CODE "代码"
#endif // D_STR_CODE
#ifndef D_STR_BITS
-#define D_STR_BITS "Bits"
+#define D_STR_BITS "位"
#endif // D_STR_BITS
// IRrecvDumpV2
#ifndef D_STR_TIMESTAMP
-#define D_STR_TIMESTAMP "Timestamp"
+#define D_STR_TIMESTAMP "时间戳记"
#endif // D_STR_TIMESTAMP
#ifndef D_STR_LIBRARY
-#define D_STR_LIBRARY "Library"
+#define D_STR_LIBRARY "库文件"
#endif // D_STR_LIBRARY
#ifndef D_STR_MESGDESC
-#define D_STR_MESGDESC "Mesg Desc."
+#define D_STR_MESGDESC "等等信息"
#endif // D_STR_MESGDESC
#ifndef D_STR_IRRECVDUMP_STARTUP
#define D_STR_IRRECVDUMP_STARTUP \
- "IRrecvDumpV2 is now running and waiting for IR input on Pin %d"
+ "IRrecvDumpV2 运行当中,等待红外信息输入位于引脚 %d"
#endif // D_STR_IRRECVDUMP_STARTUP
#ifndef D_WARN_BUFFERFULL
#define D_WARN_BUFFERFULL \
- "WARNING: IR code is too big for buffer (>= %d). " \
- "This result shouldn't be trusted until this is resolved. " \
- "Edit & increase `kCaptureBufferSize`."
+ "警告: 红外编码数组过大(>= %d). " \
+ "在解决此问题之前,不应信任此结果. " \
+ "编辑并增加 `kCaptureBufferSize` 变量."
#endif // D_WARN_BUFFERFULL
-#endif // LOCALE_DEFAULTS_H_
+#endif // LOCALE_ZH_CN_H_
diff --git a/lib/IRremoteESP8266-2.7.4/test/IRac_test.cpp b/lib/IRremoteESP8266-2.7.6/test/IRac_test.cpp
similarity index 90%
rename from lib/IRremoteESP8266-2.7.4/test/IRac_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/IRac_test.cpp
index c8c231621..8ddf98b59 100644
--- a/lib/IRremoteESP8266-2.7.4/test/IRac_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/IRac_test.cpp
@@ -54,6 +54,8 @@ TEST(TestIRac, Amcor) {
ASSERT_EQ(AMCOR, ac._irsend.capture.decode_type);
ASSERT_EQ(kAmcorBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Argo) {
@@ -103,6 +105,8 @@ TEST(TestIRac, Coolix) {
ASSERT_EQ(COOLIX, ac._irsend.capture.decode_type);
ASSERT_EQ(kCoolixBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
// Confirm we are sending with a repeat of 1. i.e. two messages.
EXPECT_EQ(
"f38000d50" // 38kHz Frequency and 50% duty-cycle.
@@ -165,6 +169,8 @@ TEST(TestIRac, Daikin) {
ASSERT_EQ(DAIKIN, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikinBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Daikin128) {
@@ -196,6 +202,8 @@ TEST(TestIRac, Daikin128) {
ASSERT_EQ(DAIKIN128, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikin128Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Daikin152) {
@@ -222,6 +230,8 @@ TEST(TestIRac, Daikin152) {
ASSERT_EQ(DAIKIN152, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikin152Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Daikin160) {
@@ -245,6 +255,8 @@ TEST(TestIRac, Daikin160) {
ASSERT_EQ(DAIKIN160, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikin160Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Daikin176) {
@@ -267,6 +279,8 @@ TEST(TestIRac, Daikin176) {
ASSERT_EQ(DAIKIN176, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikin176Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Daikin2) {
@@ -303,6 +317,8 @@ TEST(TestIRac, Daikin2) {
ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikin2Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Daikin216) {
@@ -329,6 +345,36 @@ TEST(TestIRac, Daikin216) {
ASSERT_EQ(DAIKIN216, ac._irsend.capture.decode_type);
ASSERT_EQ(kDaikin216Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
+}
+
+TEST(TestIRac, Daikin64) {
+ IRDaikin64 ac(kGpioUnused);
+ IRac irac(kGpioUnused);
+ IRrecv capture(kGpioUnused);
+ char expected[] =
+ "Power Toggle: On, Mode: 2 (Cool), Temp: 27C, Fan: 8 (Low), "
+ "Turbo: Off, Quiet: Off, Swing(V): On, Sleep: On, "
+ "Clock: 17:59, On Timer: Off, Off Timer: Off";
+
+ ac.begin();
+ irac.daikin64(&ac,
+ true, // Power (Toggle)
+ stdAc::opmode_t::kCool, // Mode
+ 27, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan Speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ false, // Quiet
+ false, // Turbo
+ 360, // Sleep
+ 17 * 60 + 59); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(DAIKIN64, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin64Bits, ac._irsend.capture.bits);
+ ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
}
TEST(TestIRac, Electra) {
@@ -392,6 +438,8 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kFujitsuAcBits - 8, ac._irsend.capture.bits);
ASSERT_EQ(ardb1_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
irac.fujitsu(&ac,
@@ -413,6 +461,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
ASSERT_EQ(arrah2e_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
irac.fujitsu(&ac,
fujitsu_ac_remote_model_t::ARRY4, // Model
@@ -433,6 +482,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
ASSERT_EQ(arry4_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Goodweather) {
@@ -459,6 +509,8 @@ TEST(TestIRac, Goodweather) {
ASSERT_EQ(GOODWEATHER, ac._irsend.capture.decode_type);
ASSERT_EQ(kGoodweatherBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Gree) {
@@ -489,6 +541,8 @@ TEST(TestIRac, Gree) {
ASSERT_EQ(GREE, ac._irsend.capture.decode_type);
ASSERT_EQ(kGreeBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Haier) {
@@ -516,6 +570,8 @@ TEST(TestIRac, Haier) {
ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kHaierACBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
@@ -544,6 +600,8 @@ TEST(TestIRac, HaierYrwo2) {
ASSERT_EQ(HAIER_AC_YRW02, ac._irsend.capture.decode_type);
ASSERT_EQ(kHaierACYRW02Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Hitachi) {
@@ -569,6 +627,40 @@ TEST(TestIRac, Hitachi) {
ASSERT_EQ(HITACHI_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kHitachiAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
+}
+
+TEST(TestIRac, Hitachi1) {
+ IRHitachiAc1 ac(kGpioUnused);
+ IRac irac(kGpioUnused);
+ IRrecv capture(kGpioUnused);
+ char expected[] =
+ "Model: 1 (R-LT0541-HTA-A), Power: On, Power Toggle: Off, "
+ "Mode: 6 (Cool), Temp: 19C, Fan: 4 (Medium), "
+ "Swing(V) Toggle: On, Swing(V): On, Swing(H): On, Sleep: 2, "
+ "On Timer: Off, Off Timer: Off";
+
+ ac.begin();
+ irac.hitachi1(&ac,
+ hitachi_ac1_remote_model_t::R_LT0541_HTA_A, // Model
+ true, // Power
+ false, // Power Toggle
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Vertical swing
+ stdAc::swingh_t::kLeft, // Horizontal swing
+ true, // Swing toggle
+ 5 * 60 + 37); // Sleep
+
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HITACHI_AC1, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAc1Bits, ac._irsend.capture.bits);
+ ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Hitachi424) {
@@ -596,6 +688,8 @@ TEST(TestIRac, Hitachi424) {
ASSERT_EQ(HITACHI_AC424, ac._irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
irac.hitachi424(&ac,
@@ -611,6 +705,7 @@ TEST(TestIRac, Hitachi424) {
ASSERT_EQ(HITACHI_AC424, ac._irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected_swingv, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Kelvinator) {
@@ -642,6 +737,8 @@ TEST(TestIRac, Kelvinator) {
ASSERT_EQ(KELVINATOR, ac._irsend.capture.decode_type);
ASSERT_EQ(kKelvinatorBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, LG) {
@@ -666,6 +763,8 @@ TEST(TestIRac, LG) {
ASSERT_EQ(LG, ac._irsend.capture.decode_type);
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Midea) {
@@ -692,6 +791,8 @@ TEST(TestIRac, Midea) {
ASSERT_EQ(MIDEA, ac._irsend.capture.decode_type);
ASSERT_EQ(kMideaBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Mitsubishi) {
@@ -719,6 +820,8 @@ TEST(TestIRac, Mitsubishi) {
ASSERT_EQ(MITSUBISHI_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kMitsubishiACBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Mitsubishi136) {
@@ -743,6 +846,8 @@ TEST(TestIRac, Mitsubishi136) {
ASSERT_EQ(MITSUBISHI136, ac._irsend.capture.decode_type);
ASSERT_EQ(kMitsubishi136Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, MitsubishiHeavy88) {
@@ -771,6 +876,8 @@ TEST(TestIRac, MitsubishiHeavy88) {
ASSERT_EQ(MITSUBISHI_HEAVY_88, ac._irsend.capture.decode_type);
ASSERT_EQ(kMitsubishiHeavy88Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, MitsubishiHeavy152) {
@@ -802,6 +909,8 @@ TEST(TestIRac, MitsubishiHeavy152) {
ASSERT_EQ(MITSUBISHI_HEAVY_152, ac._irsend.capture.decode_type);
ASSERT_EQ(kMitsubishiHeavy152Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Neoclima) {
@@ -832,6 +941,8 @@ TEST(TestIRac, Neoclima) {
ASSERT_EQ(decode_type_t::NEOCLIMA, ac._irsend.capture.decode_type);
ASSERT_EQ(kNeoclimaBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Panasonic) {
@@ -862,6 +973,8 @@ TEST(TestIRac, Panasonic) {
ASSERT_EQ(PANASONIC_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_nke, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
char expected_dke[] =
"Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (High), "
@@ -887,6 +1000,7 @@ TEST(TestIRac, Panasonic) {
ASSERT_EQ(PANASONIC_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_dke, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Samsung) {
@@ -895,7 +1009,8 @@ TEST(TestIRac, Samsung) {
IRrecv capture(0);
char expected[] =
"Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), Swing: On, "
- "Beep: On, Clean: On, Quiet: On, Powerful: Off, Light: On, Ion: Off";
+ "Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off";
ac.begin();
irac.samsung(&ac,
@@ -918,6 +1033,8 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kSamsungAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
irac.samsung(&ac,
@@ -943,8 +1060,10 @@ TEST(TestIRac, Samsung) {
// desired state.
char expected_on[] =
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off";
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off";
ASSERT_EQ(expected_on, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Sharp) {
@@ -952,11 +1071,13 @@ TEST(TestIRac, Sharp) {
IRac irac(0);
IRrecv capture(0);
char expected[] =
- "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium)";
+ "Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 3 (Medium)";
ac.begin();
irac.sharp(&ac,
true, // Power
+ true, // Previous Power
stdAc::opmode_t::kCool, // Mode
28, // Celsius
stdAc::fanspeed_t::kMedium); // Fan speed
@@ -966,6 +1087,8 @@ TEST(TestIRac, Sharp) {
ASSERT_EQ(SHARP_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kSharpAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Tcl112) {
@@ -994,6 +1117,8 @@ TEST(TestIRac, Tcl112) {
ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Teco) {
@@ -1019,6 +1144,8 @@ TEST(TestIRac, Teco) {
ASSERT_EQ(TECO, ac._irsend.capture.decode_type);
ASSERT_EQ(kTecoBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Toshiba) {
@@ -1039,6 +1166,8 @@ TEST(TestIRac, Toshiba) {
ASSERT_EQ(TOSHIBA_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kToshibaACBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Trotec) {
@@ -1066,6 +1195,8 @@ TEST(TestIRac, Trotec) {
ASSERT_EQ(TROTEC, ac._irsend.capture.decode_type);
ASSERT_EQ(kTrotecBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, Vestel) {
@@ -1093,6 +1224,8 @@ TEST(TestIRac, Vestel) {
ASSERT_EQ(VESTEL_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
char expected_clocks[] =
@@ -1117,6 +1250,7 @@ TEST(TestIRac, Vestel) {
ASSERT_EQ(VESTEL_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_clocks, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
// Now check it sends both messages during normal operation when the
// clock is set.
@@ -1183,6 +1317,8 @@ TEST(TestIRac, Whirlpool) {
ASSERT_EQ(WHIRLPOOL_AC, ac._irsend.capture.decode_type);
ASSERT_EQ(kWhirlpoolAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRac, cmpStates) {
@@ -1577,6 +1713,8 @@ TEST(TestIRac, Issue1001) {
"On Timer: Off, Off Timer: Off, Sleep: Off, Super: Off, "
"Command: 1 (Power)",
IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
// Now check if the mode is set to "Off" instead of just change to power off.
// i.e. How Home Assistant expects things to work.
@@ -1606,6 +1744,7 @@ TEST(TestIRac, Issue1001) {
"On Timer: Off, Off Timer: Off, Sleep: Off, Super: Off, "
"Command: 1 (Power)",
IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
// Check power switching in Daikin2 common a/c handling when from an IR message.
diff --git a/lib/IRremoteESP8266-2.7.4/test/IRrecv_test.cpp b/lib/IRremoteESP8266-2.7.6/test/IRrecv_test.cpp
similarity index 91%
rename from lib/IRremoteESP8266-2.7.4/test/IRrecv_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/IRrecv_test.cpp
index fa025a2cb..e66866be1 100644
--- a/lib/IRremoteESP8266-2.7.4/test/IRrecv_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/IRrecv_test.cpp
@@ -1589,3 +1589,107 @@ TEST(TestCrudeNoiseFilter, NoiseAtEndOfSample) {
"uint64_t data = 0x20DFC03F;\n",
resultToSourceCode(&irsend.capture));
}
+
+TEST(TestManchesterCode, matchManchester) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+
+ const uint16_t rawData[163] = {
+ 2860, 3862,
+ 1924, 1952, 1926, 1952, 956, 984, 1924, 1028, 952, 958, 980, 956, 982,
+ 1882, 1016, 950, 1958, 1920, 1948, 1004, 954, 956, 984, 956, 952, 984,
+ 974, 966, 974, 964, 974, 1888, 1010, 960, 1948, 1002, 946, 962, 978,
+ 962, 976, 960, 948, 992, 978, 1886, 982, 984, 1924, 1954, 952, 986,
+ 3892, 3862,
+ 1924, 1954, 1924, 1954, 984, 952, 1956, 996, 954, 990, 948, 958, 980,
+ 1882, 1016, 952, 1958, 1920, 1956, 994, 944, 962, 986, 956, 972, 962,
+ 976, 962, 978, 964, 952, 1908, 1010, 960, 1948, 1002, 946, 960, 978,
+ 962, 946, 990, 978, 960, 978, 1888, 1008, 954, 1952, 1928, 982, 956,
+ 3920, 3830,
+ 1946, 1934, 1954, 1922, 976, 962, 1946, 1006, 922, 990, 948, 988, 950,
+ 1910, 1008, 964, 1922, 1952, 1924, 1030, 920, 984, 954, 986, 952, 986,
+ 952, 984, 954, 986, 952, 1910, 1010, 960, 1928, 1024, 944, 996, 924,
+ 984, 954, 988, 950, 984, 954, 1910, 1008, 960, 1920, 1958, 980, 958,
+ 4800};
+ irsend.sendRaw(rawData, 163, 38);
+ irsend.makeDecodeResult();
+
+ uint16_t offset = 1;
+ uint64_t result = 0;
+ uint16_t nbits = 32;
+ EXPECT_EQ(56, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 2860, 3800, 1000, 0, 3800));
+ EXPECT_EQ(0x4F2FE7E4, result);
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 55, 38); // Send just the bare minimum.
+ irsend.makeDecodeResult();
+
+ EXPECT_EQ(55, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 2860, 3800, 1000, 0, 3800));
+ EXPECT_EQ(0x4F2FE7E4, result);
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 52, 38); // Now, just too short.
+ irsend.makeDecodeResult();
+
+ EXPECT_EQ(0, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 2860, 3800, 1000, 0, 0));
+}
+
+TEST(TestManchesterCode, ManchesterLoopBackGEThomasTest) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ uint16_t offset = 1;
+ uint64_t result = 0;
+ uint16_t nbits = 32;
+ irsend.begin();
+ irsend.reset();
+ irsend.sendManchester(5000, 7000, 1000, 0, 10000, 0x12345678, nbits);
+ irsend.makeDecodeResult();
+ EXPECT_EQ(52, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 5000, 7000, 1000, 0, 10000, true,
+ kUseDefTol, kMarkExcess, true, true));
+ EXPECT_EQ(0x12345678, result);
+
+ irsend.reset();
+ irsend.sendManchester(5000, 7000, 1000, 0, 10000, 0x87654321, nbits);
+ irsend.makeDecodeResult();
+ EXPECT_EQ(52, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 5000, 7000, 1000, 0, 10000, true,
+ kUseDefTol, kMarkExcess, true, true));
+ EXPECT_EQ(0x87654321, result);
+}
+
+TEST(TestManchesterCode, ManchesterLoopBackIEEE802_3Test) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ uint16_t offset = 1;
+ uint64_t result = 0;
+ uint16_t nbits = 32;
+ irsend.begin();
+ irsend.reset();
+ irsend.sendManchester(5000, 7000, 1000, 0, 10000, 0x12345678, nbits, 38000,
+ true, kNoRepeat, kDutyDefault, false);
+ irsend.makeDecodeResult();
+ EXPECT_EQ(52, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 5000, 7000, 1000, 0, 10000, true,
+ kUseDefTol, kMarkExcess, true, false));
+ EXPECT_EQ(0x12345678, result);
+
+ irsend.reset();
+ irsend.sendManchester(5000, 7000, 1000, 0, 10000, 0x87654321, nbits, 38000,
+ true, kNoRepeat, kDutyDefault, false);
+ irsend.makeDecodeResult();
+ EXPECT_EQ(54, irrecv.matchManchester(irsend.capture.rawbuf + offset, &result,
+ irsend.capture.rawlen - offset, nbits,
+ 5000, 7000, 1000, 0, 10000, true,
+ kUseDefTol, kMarkExcess, true, false));
+ EXPECT_EQ(0x87654321, result);
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/IRrecv_test.h b/lib/IRremoteESP8266-2.7.6/test/IRrecv_test.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/IRrecv_test.h
rename to lib/IRremoteESP8266-2.7.6/test/IRrecv_test.h
diff --git a/lib/IRremoteESP8266-2.7.4/test/IRsend_test.cpp b/lib/IRremoteESP8266-2.7.6/test/IRsend_test.cpp
similarity index 89%
rename from lib/IRremoteESP8266-2.7.4/test/IRsend_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/IRsend_test.cpp
index f2e280504..2f39e323d 100644
--- a/lib/IRremoteESP8266-2.7.4/test/IRsend_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/IRsend_test.cpp
@@ -786,3 +786,80 @@ TEST(TestSend, defaultBits) {
}
}
}
+
+// Tests sendManchester().
+
+// Test sending zero bits.
+TEST(TestSendManchester, SendZeroBits) {
+ IRsendTest irsend(0);
+ irsend.begin();
+ irsend.sendManchester(0, 0, 1, 0, 0, 0b1, 0);
+ EXPECT_EQ("f36000d25m0f38000d50s1m2s1", irsend.outputStr());
+ irsend.sendManchester(1, 2, 100, 3, 4, 0b1, 0);
+ EXPECT_EQ("f38000d50m1s102m200s100m3s4", irsend.outputStr());
+}
+
+// Test sending zero and one.
+TEST(TestSendManchester, SendSingleBit) {
+ IRsendTest irsend(0);
+ irsend.begin();
+ irsend.sendManchester(1000, 2000, 100, 3000, 4000, 0b0, 1);
+ EXPECT_EQ("f38000d50m1000s2100m200s200m3100s4000", irsend.outputStr());
+ irsend.sendManchester(1000, 2000, 100, 3000, 4000, 0b0, 1, 38, true,
+ kNoRepeat, kDutyDefault, false);
+ EXPECT_EQ("f38000d50m1000s2000m100s200m200s100m3000s4000",
+ irsend.outputStr());
+}
+
+// Test sending bit order.
+TEST(TestSendManchester, TestingBitSendOrder) {
+ IRsendTest irsend(0);
+ irsend.begin();
+ irsend.sendManchester(1000, 2000, 100, 3000, 0, 0b10, 2);
+ EXPECT_EQ("f38000d50m1000s2100m200s100m100s200m3100", irsend.outputStr());
+ irsend.sendManchester(1000, 2000, 100, 3000, 0, 0b10, 2, 38, false);
+ EXPECT_EQ("f38000d50m1000s2100m200s200m200s100m3000", irsend.outputStr());
+ irsend.sendManchester(1000, 2000, 100, 3000, 0, 0b0001, 4, 38, true);
+ EXPECT_EQ("f38000d50m1000s2100m200s200m100s100m100s100m200s100m3000",
+ irsend.outputStr());
+ irsend.sendManchester(1000, 2000, 100, 3000, 0, 0b0001, 4, 38, false);
+ EXPECT_EQ("f38000d50m1000s2100m200s100m100s200m100s100m100s100m3100",
+ irsend.outputStr());
+}
+
+// Test sending typical data.
+TEST(TestSendManchester, SendTypicalData) {
+ IRsendTest irsend(0);
+ irsend.begin();
+ // Example from https://en.wikipedia.org/wiki/Manchester_code diagram
+ irsend.sendManchester(0, 0, 100, 0, 0, 0b10100111001, 11, 38, true);
+ EXPECT_EQ(
+ "f38000d50"
+ "m0s100m200s100"
+ "m100s200m200s200m100s100m200s100m100s100m100s200m100s100m200s100",
+ irsend.outputStr());
+ irsend.sendManchester(100, 200, 1, 300, 0, 0x1234567890ABCDEF, 64, 38, true);
+ EXPECT_EQ(
+ "f38000d50"
+ "m100s201"
+ "m2s2m1s1m1s1m2s2m1s1m2s2m1s1m1s1m2s1m1s2m2s2m1s1m1s1m2s2m2s2m2s1m1s2m1s1"
+ "m2s1m1s1m1s1m1s2m1s1m1s1m2s2m1s1m2s2m1s1m1s1m1s1m2s2m2s2m2s2m2s1m1s1m1s1"
+ "m1s2m1s1m2s1m1s2m2s1m1s1m1s1m1s2m2s1m1s1m1s1m1s1m300",
+ irsend.outputStr());
+}
+
+// Test sending more than expected bits.
+TEST(TestSendManchester, SendOverLargeData) {
+ IRsendTest irsend(0);
+ irsend.begin();
+ irsend.sendManchester(100, 200, 1, 300, 0, 0xFFFFFFFFFFFFFFFF, 70, 38, true);
+ EXPECT_EQ(
+ "f38000d50"
+ "m100s201"
+ "m2s2m1s1m1s1m1s1m1s1m1s1m2s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1"
+ "m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1"
+ "m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1"
+ "m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1m1s1"
+ "m300",
+ irsend.outputStr());
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/IRsend_test.h b/lib/IRremoteESP8266-2.7.6/test/IRsend_test.h
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/IRsend_test.h
rename to lib/IRremoteESP8266-2.7.6/test/IRsend_test.h
diff --git a/lib/IRremoteESP8266-2.7.4/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.7.6/test/IRutils_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/IRutils_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/IRutils_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/Makefile b/lib/IRremoteESP8266-2.7.6/test/Makefile
similarity index 96%
rename from lib/IRremoteESP8266-2.7.4/test/Makefile
rename to lib/IRremoteESP8266-2.7.6/test/Makefile
index 7b1a4b379..dc0574a1d 100644
--- a/lib/IRremoteESP8266-2.7.4/test/Makefile
+++ b/lib/IRremoteESP8266-2.7.6/test/Makefile
@@ -39,7 +39,8 @@ TESTS = IRutils_test IRsend_test ir_NEC_test ir_GlobalCache_test \
ir_Whirlpool_test ir_Lutron_test ir_Electra_test ir_Pioneer_test \
ir_MWM_test ir_Vestel_test ir_Teco_test ir_Tcl_test ir_Lego_test IRac_test \
ir_MitsubishiHeavy_test ir_Trotec_test ir_Argo_test ir_Goodweather_test \
- ir_Inax_test ir_Neoclima_test ir_Amcor_test ir_Epson_test
+ ir_Inax_test ir_Neoclima_test ir_Amcor_test ir_Epson_test ir_Symphony_test \
+ ir_Airwell_test
# All Google Test headers. Usually you shouldn't change this
# definition.
@@ -85,7 +86,7 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_Hitachi.o ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o \
ir_Pioneer.o ir_MWM.o ir_Vestel.o ir_Teco.o ir_Tcl.o ir_Lego.o ir_Argo.o \
ir_Trotec.o ir_MitsubishiHeavy.o ir_Goodweather.o ir_Inax.o ir_Neoclima.o \
- ir_Amcor.o ir_Epson.o
+ ir_Amcor.o ir_Epson.o ir_Symphony.o ir_Airwell.o
# All the IR Protocol header files.
PROTOCOLS_H = $(USER_DIR)/ir_Amcor.h \
@@ -632,3 +633,21 @@ ir_Epson_test.o : ir_Epson_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
ir_Epson_test : $(COMMON_OBJ) ir_Epson_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Symphony.o : $(USER_DIR)/ir_Symphony.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Symphony.cpp
+
+ir_Symphony_test.o : ir_Symphony_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Symphony_test.cpp
+
+ir_Symphony_test : $(COMMON_OBJ) ir_Symphony_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Airwell.o : $(USER_DIR)/ir_Airwell.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Airwell.cpp
+
+ir_Airwell_test.o : ir_Airwell_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Airwell_test.cpp
+
+ir_Airwell_test : $(COMMON_OBJ) ir_Airwell_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
diff --git a/lib/IRremoteESP8266-2.7.6/test/ir_Airwell_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Airwell_test.cpp
new file mode 100644
index 000000000..b58bceced
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Airwell_test.cpp
@@ -0,0 +1,216 @@
+// Copyright 2020 David Conran
+
+#include "IRac.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for decodeAirwell().
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1069
+// Data from:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1069#issuecomment-604293514
+TEST(TestDecodeAirwell, RealExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ // ON / OFF / 25 degrees heat
+ const uint16_t rawData_1[163] = {
+ 2860, 3862,
+ 1924, 1952, 1926, 1952, 956, 984, 1924, 1028, 952, 958, 980, 956, 982,
+ 1882, 1016, 950, 1958, 1920, 1948, 1004, 954, 956, 984, 956, 952, 984,
+ 974, 966, 974, 964, 974, 1888, 1010, 960, 1948, 1002, 946, 962, 978,
+ 962, 976, 960, 948, 992, 978, 1886, 982, 984, 1924, 1954, 952, 986,
+ 3892, 3862,
+ 1924, 1954, 1924, 1954, 984, 952, 1956, 996, 954, 990, 948, 958, 980,
+ 1882, 1016, 952, 1958, 1920, 1956, 994, 944, 962, 986, 956, 972, 962,
+ 976, 962, 978, 964, 952, 1908, 1010, 960, 1948, 1002, 946, 960, 978,
+ 962, 946, 990, 978, 960, 978, 1888, 1008, 954, 1952, 1928, 982, 956,
+ 3920, 3830,
+ 1946, 1934, 1954, 1922, 976, 962, 1946, 1006, 922, 990, 948, 988, 950,
+ 1910, 1008, 964, 1922, 1952, 1924, 1030, 920, 984, 954, 986, 952, 986,
+ 952, 984, 954, 986, 952, 1910, 1010, 960, 1928, 1024, 944, 996, 924,
+ 984, 954, 988, 950, 984, 954, 1910, 1008, 960, 1920, 1958, 980, 958,
+ 4800}; // UNKNOWN 565E2BB3
+ irsend.begin();
+ irsend.reset();
+ irsend.sendRaw(rawData_1, 163, 38);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ ASSERT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0x4F2FE7E4, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+
+ const uint16_t rawData_2[175] = {
+ 2862, 3892,
+ 1894, 1060, 890, 1944, 952, 1014, 922, 1016, 1892, 1062, 886,
+ 1020, 928, 1042, 896, 1938, 960, 1008, 920, 1020, 928, 1010, 928, 1012,
+ 1896, 1056, 892, 1016, 922, 1020, 918, 1018, 920, 1018, 920, 1946, 950,
+ 1014, 1894, 1062, 896, 1010, 928, 1010, 928, 1014, 924, 1014, 922, 1938,
+ 960, 1012, 1896, 1984, 922, 1014,
+ 3862, 3894,
+ 1892, 1062, 896, 1936, 950, 1020, 928, 1008, 1898, 1056, 892, 1016, 952,
+ 984, 954, 1910, 956, 1012, 924, 1014, 924, 1014, 922, 1014, 1892, 1060,
+ 916, 992, 926, 1010, 928, 1014, 954, 982, 944, 1918, 958, 1010, 1896,
+ 1058, 922, 986, 952, 988, 920, 1018, 950, 986, 952, 1914, 954, 1014,
+ 1892, 1986, 922, 1016,
+ 3860, 3896,
+ 1898, 1054, 924, 1908, 958, 1012, 926, 1012, 1896, 1056, 942, 966, 952,
+ 988, 950, 1910, 956, 1016, 922, 1016, 952, 988, 950, 986, 1922, 1032,
+ 916, 990, 948, 960, 988, 984, 944, 960, 978, 1918, 978, 990, 1896, 1054,
+ 924, 982, 946, 994, 954, 984, 954, 988, 950, 1910, 956, 1012, 1896, 1984,
+ 922, 1018, 4768}; // UNKNOWN 1002DCC8
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendRaw(rawData_2, 175, 38);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ ASSERT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0x8F07E7E4, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+}
+
+TEST(TestDecodeAirwell, SyntheticExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+ irsend.reset();
+ irsend.sendAirwell(0xB0D0181B);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ EXPECT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0xB0D0181B, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+
+ EXPECT_EQ(
+ "f38000d50"
+ "m2850s3800"
+ "m1900s950m950s1900m1900s950m950s1900m950s950m950s950m950s950"
+ "m1900s950m950s1900m1900s1900m950s950m950s950m950s950m950s950"
+ "m950s950m950s950m1900s950m950s1900m950s950m950s950m950s950"
+ "m950s950m950s950m1900s950m950s1900m1900s950m950s950"
+ "m2850s3800"
+ "m1900s950m950s1900m1900s950m950s1900m950s950m950s950m950s950"
+ "m1900s950m950s1900m1900s1900m950s950m950s950m950s950m950s950"
+ "m950s950m950s950m1900s950m950s1900m950s950m950s950m950s950"
+ "m950s950m950s950m1900s950m950s1900m1900s950m950s950"
+ "m2850s3800"
+ "m1900s950m950s1900m1900s950m950s1900m950s950m950s950m950s950"
+ "m1900s950m950s1900m1900s1900m950s950m950s950m950s950m950s950"
+ "m950s950m950s950m1900s950m950s1900m950s950m950s950m950s950"
+ "m950s950m950s950m1900s950m950s1900m1900s950m950s950"
+ "m3800s100000",
+ irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendAirwell(0x4F2FE7E4);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ EXPECT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0x4F2FE7E4, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+ EXPECT_EQ(
+ "f38000d50"
+ "m2850s3800"
+ "m1900s1900m1900s1900m950s950m1900s950m950s950m950s950m950"
+ "s1900m950s950m1900s1900m1900s950m950s950m950s950m950s950"
+ "m950s950m950s950m950s1900m950s950m1900s950m950s950m950"
+ "s950m950s950m950s950m950s1900m950s950m1900s1900m950s950"
+ "m3800s3800"
+ "m1900s1900m1900s1900m950s950m1900s950m950s950m950s950m950"
+ "s1900m950s950m1900s1900m1900s950m950s950m950s950m950s950"
+ "m950s950m950s950m950s1900m950s950m1900s950m950s950m950"
+ "s950m950s950m950s950m950s1900m950s950m1900s1900m950s950"
+ "m3800s3800"
+ "m1900s1900m1900s1900m950s950m1900s950m950s950m950s950m950"
+ "s1900m950s950m1900s1900m1900s950m950s950m950s950m950s950"
+ "m950s950m950s950m950s1900m950s950m1900s950m950s950m950"
+ "s950m950s950m950s950m950s1900m950s950m1900s1900m950s950"
+ "m4750s100000",
+ irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendAirwell(0x70F8181B);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ EXPECT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0x70F8181B, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+}
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1069
+// Data from:
+// https://github.com/crankyoldgit/IRremoteESP8266/issues/1069#issuecomment-607659677
+TEST(TestDecodeAirwell, RealExample2) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ // "When I change from 22° to 23° :"
+ const uint16_t rawData[175] = {
+ 2890, 2918,
+ 924, 1006, 946, 1886, 1986, 1922, 978, 958, 1952, 1000, 952, 956, 974,
+ 964, 976, 1884, 1016, 952, 1948, 1006, 944, 962, 980, 958, 982, 958, 952,
+ 982, 978, 960, 980, 956, 986, 956, 974, 1888, 1014, 954, 1948, 1002, 948,
+ 960, 980, 960, 950, 986, 1006, 962, 980, 1854, 1036, 932, 1948, 1928, 984,
+ 954,
+ 3918, 2920,
+ 922, 1008, 942, 1888, 1984, 1926, 984, 950, 1952, 1000, 952, 956, 984,
+ 956, 954, 1908, 1014, 952, 1948, 1002, 948, 960, 950, 986, 984, 956, 954,
+ 984, 956, 984, 946, 992, 948, 992, 948, 1910, 1012, 958, 1954, 996, 922,
+ 984, 956, 986, 956, 980, 950, 988, 954, 1910, 1010, 956, 1946, 1932, 978,
+ 962,
+ 3922, 2914,
+ 918, 1010, 920, 1912, 1980, 1928, 982, 956, 1944, 1006, 924, 982, 958,
+ 982, 948, 1912, 1008, 958, 1952, 1000, 920, 988, 952, 982, 958, 984, 958,
+ 978, 952, 986, 986, 952, 958, 984, 946, 1912, 1010, 962, 1948, 1004, 926,
+ 980, 950, 988, 952, 984, 956, 982, 948, 1916, 1016, 952, 1950, 1926, 984,
+ 952, 4830}; // UNKNOWN 8E34167B
+ irsend.begin();
+ irsend.reset();
+ irsend.sendRaw(rawData, 175, 38);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ ASSERT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0xB0C0181B, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+
+ // Resend it as a synthetic to see if it decodes to the same value.
+ irsend.reset();
+ irsend.sendAirwell(0xB0C0181B);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(decode_type_t::AIRWELL, irsend.capture.decode_type);
+ ASSERT_EQ(kAirwellBits, irsend.capture.bits);
+ EXPECT_EQ(0xB0C0181B, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+}
+
+TEST(TestUtils, Housekeeping) {
+ ASSERT_EQ("AIRWELL", typeToString(decode_type_t::AIRWELL));
+ ASSERT_EQ(decode_type_t::AIRWELL, strToDecodeType("AIRWELL"));
+ ASSERT_FALSE(hasACState(decode_type_t::AIRWELL));
+ ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::AIRWELL));
+ ASSERT_EQ(kAirwellBits, IRsend::defaultBits(decode_type_t::AIRWELL));
+ ASSERT_EQ(kAirwellMinRepeats, IRsend::minRepeats(decode_type_t::AIRWELL));
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Aiwa_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Aiwa_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Aiwa_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Amcor_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Amcor_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Amcor_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Amcor_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Argo_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Argo_test.cpp
similarity index 95%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Argo_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Argo_test.cpp
index d5a5d17ad..3ab890adc 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Argo_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Argo_test.cpp
@@ -1,5 +1,6 @@
// Copyright 2019 David Conran
#include "ir_Argo.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -105,6 +106,12 @@ TEST(TestDecodeArgo, SyntheticDecode) {
EXPECT_EQ(decode_type_t::ARGO, irsend.capture.decode_type);
EXPECT_EQ(kArgoBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (Cool), Fan: 0 (Auto), Temp: 20C, Room Temp: 21C, "
+ "Max: On, IFeel: On, Night: On",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Carrier_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Carrier_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Carrier_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Coolix_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Coolix_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Coolix_test.cpp
index 20a46c7b4..45d53a12f 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Coolix_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Coolix_test.cpp
@@ -773,6 +773,8 @@ TEST(TestCoolixACClass, Issue985) {
EXPECT_EQ(kCoolixBits, ac._irsend.capture.bits);
EXPECT_EQ(kCoolixOff, ac._irsend.capture.value);
EXPECT_EQ("Power: Off", IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
@@ -793,6 +795,7 @@ TEST(TestCoolixACClass, Issue985) {
EXPECT_EQ(
"Power: On, Mode: 0 (Cool), Fan: 5 (Auto), Temp: 20C, Zone Follow: Off, "
"Sensor Temp: Off", IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac._irsend.reset();
@@ -808,6 +811,7 @@ TEST(TestCoolixACClass, Issue985) {
EXPECT_EQ(kCoolixBits, ac._irsend.capture.bits);
EXPECT_EQ(kCoolixOff, ac._irsend.capture.value);
EXPECT_EQ("Power: Off", IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestCoolixACClass, PowerStateWithSetRaw) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Daikin_test.cpp
similarity index 92%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Daikin_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Daikin_test.cpp
index 60d39d9a3..e37c6b00a 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Daikin_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Daikin_test.cpp
@@ -1545,6 +1545,11 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ(decode_type_t::DAIKIN216, strToDecodeType("DAIKIN216"));
ASSERT_TRUE(hasACState(decode_type_t::DAIKIN216));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::DAIKIN216));
+
+ ASSERT_EQ("DAIKIN64", typeToString(decode_type_t::DAIKIN64));
+ ASSERT_EQ(decode_type_t::DAIKIN64, strToDecodeType("DAIKIN64"));
+ ASSERT_FALSE(hasACState(decode_type_t::DAIKIN64));
+ ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::DAIKIN64));
}
// https://github.com/crankyoldgit/IRremoteESP8266/issues/582#issuecomment-453863879
@@ -2581,6 +2586,8 @@ TEST(TestDecodeDaikin128, RealExample) {
"On Timer: Off, On Timer: 07:30, Off Timer: Off, Off Timer: 22:00, "
"Light Toggle: 0 (Off)",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t result, prev;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
}
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/827
@@ -2971,6 +2978,8 @@ TEST(TestDecodeDaikin152, RealExample) {
"Power: Off, Mode: 0 (Auto), Temp: 26C, Fan: 2 (UNKNOWN), Swing(V): Off, "
"Powerful: Off, Quiet: On, Econo: Off, Sensor: Off, Comfort: Off",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t result, prev;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
}
// https://github.com/crankyoldgit/IRremoteESP8266/issues/873
@@ -3006,6 +3015,8 @@ TEST(TestDecodeDaikin152, SyntheticExample) {
"Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 1 (Low), Swing(V): On, "
"Powerful: Off, Quiet: Off, Econo: Off, Sensor: Off, Comfort: Off",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t result, prev;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
}
TEST(TestDaikin2ClassNew, Issue908) {
@@ -3400,3 +3411,282 @@ TEST(TestDaikin2Class, Issue1035) {
ac.toString());
ASSERT_FALSE(ac.toCommon().power);
}
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1064
+// Data from:
+// https://docs.google.com/spreadsheets/d/1sxjLQCRLMFM1FQpttBXsye2JG5hHIe2BrKnKDuPV9Bw/edit#gid=726071135&range=A1
+TEST(TestDecodeDaikin64, RealExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ uint16_t rawData[137] = {
+ 9864, 9778, 9810, 9728, 4666, 2482, 384, 342, 390, 922, 386, 928, 388,
+ 348, 388, 920, 386, 348, 390, 342, 384, 330, 414, 342, 390, 922, 386, 348,
+ 390, 342, 382, 352, 384, 352, 382, 924, 386, 356, 382, 344, 384, 350, 388,
+ 346, 390, 342, 386, 348, 386, 928, 388, 348, 388, 354, 388, 888, 412, 928,
+ 390, 896, 416, 348, 386, 348, 388, 346, 388, 342, 384, 358, 388, 340, 384,
+ 926, 384, 932, 386, 346, 388, 922, 384, 350, 384, 348, 384, 358, 382, 338,
+ 394, 922, 388, 928, 386, 350, 384, 926, 390, 344, 388, 342, 386, 356, 388,
+ 338, 382, 928, 382, 932, 390, 344, 386, 924, 390, 344, 388, 314, 414, 356,
+ 384, 344, 386, 346, 390, 926, 386, 924, 388, 924, 388, 926, 386, 924, 388,
+ 350, 388, 20258, 4670};
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendRaw(rawData, 137, kDaikin64Freq);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(decode_type_t::DAIKIN64, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin64Bits, irsend.capture.bits);
+ EXPECT_EQ(0x7C16161607204216, irsend.capture.value);
+ EXPECT_EQ(
+ "Power Toggle: On, Mode: 2 (Cool), Temp: 16C, Fan: 4 (Medium), "
+ "Turbo: Off, Quiet: Off, Swing(V): Off, Sleep: Off, "
+ "Clock: 07:20, On Timer: Off, Off Timer: Off",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t result, prev;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
+}
+
+TEST(TestDecodeDaikin64, SyntheticExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendDaikin64(0x7C16161607204216);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(decode_type_t::DAIKIN64, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin64Bits, irsend.capture.bits);
+ EXPECT_EQ(0x7C16161607204216, irsend.capture.value);
+}
+
+TEST(TestDaikin64Class, ChecksumAndSetGetRaw) {
+ IRDaikin64 ac(kGpioUnused);
+
+ const uint64_t valid = 0x7C16161607204216;
+ const uint64_t invalid = 0x1C16161607204216;
+ ASSERT_NE(valid, invalid);
+ ASSERT_EQ(0x07, IRDaikin64::calcChecksum(valid));
+ ASSERT_TRUE(IRDaikin64::validChecksum(valid));
+ ASSERT_FALSE(IRDaikin64::validChecksum(invalid));
+ ac.setRaw(valid);
+ ASSERT_EQ(valid, ac.getRaw());
+ ac.setRaw(invalid);
+ ASSERT_EQ(valid, ac.getRaw());
+}
+
+TEST(TestDaikin64Class, Temperature) {
+ IRDaikin64 ac(0);
+ ac.begin();
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikin64MinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikin64MaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikin64MinTemp);
+ EXPECT_EQ(kDaikin64MinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikin64MaxTemp);
+ EXPECT_EQ(kDaikin64MaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikin64MinTemp - 1);
+ EXPECT_EQ(kDaikin64MinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikin64MaxTemp + 1);
+ EXPECT_EQ(kDaikin64MaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikin64MinTemp + 1);
+ EXPECT_EQ(kDaikin64MinTemp + 1, ac.getTemp());
+
+ ac.setTemp(21);
+ EXPECT_EQ(21, ac.getTemp());
+
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+
+ ac.setTemp(29);
+ EXPECT_EQ(29, ac.getTemp());
+
+ // Ref: https://docs.google.com/spreadsheets/d/1sxjLQCRLMFM1FQpttBXsye2JG5hHIe2BrKnKDuPV9Bw/edit#gid=1521758824&range=R2:AG2
+ const uint64_t deg16 = 0x8C16105500001216;
+ ac.setRaw(deg16);
+ EXPECT_EQ(16, ac.getTemp());
+}
+
+TEST(TestDaikin64Class, OperatingMode) {
+ IRDaikin64 ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikin64Cool);
+ EXPECT_EQ(kDaikin64Cool, ac.getMode());
+
+ ac.setMode(kDaikin64Fan);
+ EXPECT_EQ(kDaikin64Fan, ac.getMode());
+
+ ac.setMode(kDaikin64Dry);
+ EXPECT_EQ(kDaikin64Dry, ac.getMode());
+
+ ac.setMode(kDaikin64Fan + 1);
+ EXPECT_EQ(kDaikin64Cool, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kDaikin64Cool, ac.getMode());
+
+ // Ref: https://docs.google.com/spreadsheets/d/1sxjLQCRLMFM1FQpttBXsye2JG5hHIe2BrKnKDuPV9Bw/edit#gid=1521758824&range=R2:AG2
+ const uint64_t cool = 0x8C16105500001216;
+ ac.setMode(kDaikin64Dry);
+ ac.setRaw(cool);
+ EXPECT_EQ(kDaikin64Cool, ac.getMode());
+}
+
+TEST(TestDaikin64Class, PowerToggle) {
+ IRDaikin64 ac(0);
+ ac.begin();
+
+ ac.setPowerToggle(true);
+ EXPECT_TRUE(ac.getPowerToggle());
+ ac.setPowerToggle(false);
+ EXPECT_FALSE(ac.getPowerToggle());
+ ac.setPowerToggle(true);
+ EXPECT_TRUE(ac.getPowerToggle());
+}
+
+TEST(TestDaikin64Class, FanSpeed) {
+ IRDaikin64 ac(kGpioUnused);
+ ac.begin();
+
+ // Unexpected value should default to Auto.
+ ac.setFan(0);
+ EXPECT_EQ(kDaikin64FanAuto, ac.getFan());
+ ac.setFan(255);
+ EXPECT_EQ(kDaikin64FanAuto, ac.getFan());
+ ac.setFan(5);
+ EXPECT_EQ(kDaikin64FanAuto, ac.getFan());
+
+ ac.setFan(kDaikin64FanHigh);
+ EXPECT_EQ(kDaikin64FanHigh, ac.getFan());
+
+ // Beyond Quiet should default to Auto.
+ ac.setFan(kDaikin64FanQuiet + 1);
+ EXPECT_EQ(kDaikin64FanAuto, ac.getFan());
+
+ ac.setFan(kDaikin64FanMed);
+ EXPECT_EQ(kDaikin64FanMed, ac.getFan());
+
+ ac.setFan(kDaikin64FanLow);
+ EXPECT_EQ(kDaikin64FanLow, ac.getFan());
+
+ ac.setFan(kDaikin64FanTurbo);
+ EXPECT_EQ(kDaikin64FanTurbo, ac.getFan());
+
+ ac.setFan(kDaikin64FanAuto);
+ EXPECT_EQ(kDaikin64FanAuto, ac.getFan());
+
+ ac.setFan(kDaikin64FanQuiet);
+ EXPECT_EQ(kDaikin64FanQuiet, ac.getFan());
+}
+
+TEST(TestDaikin64Class, Turbo) {
+ IRDaikin64 ac(kGpioUnused);
+ ac.begin();
+ ac.setFan(kDaikin64FanAuto);
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+ EXPECT_EQ(kDaikin64FanTurbo, ac.getFan());
+ ac.setTurbo(false);
+ EXPECT_NE(kDaikin64FanTurbo, ac.getFan());
+ EXPECT_FALSE(ac.getTurbo());
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestDaikin64Class, Quiet) {
+ IRDaikin64 ac(kGpioUnused);
+ ac.begin();
+ ac.setFan(kDaikin64FanAuto);
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+ EXPECT_EQ(kDaikin64FanQuiet, ac.getFan());
+ ac.setQuiet(false);
+ EXPECT_NE(kDaikin64FanQuiet, ac.getFan());
+ EXPECT_FALSE(ac.getQuiet());
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+}
+
+TEST(TestDaikin64Class, Sleep) {
+ IRDaikin64 ac(kGpioUnused);
+ ac.begin();
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+ ac.setSleep(false);
+ EXPECT_FALSE(ac.getSleep());
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+}
+
+TEST(TestDaikin64Class, SwingVertical) {
+ IRDaikin64 ac(kGpioUnused);
+ ac.begin();
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingVertical());
+ ac.setSwingVertical(false);
+ EXPECT_FALSE(ac.getSwingVertical());
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingVertical());
+}
+
+TEST(TestDaikin64Class, Clock) {
+ IRDaikin64 ac(kGpioUnused);
+ ac.begin();
+
+ ac.setClock(0);
+ EXPECT_EQ(0, ac.getClock());
+ ac.setClock(23 * 60 + 59);
+ EXPECT_EQ(23 * 60 + 59, ac.getClock());
+ ac.setClock(23 * 60 + 59 + 1);
+ EXPECT_EQ(0, ac.getClock());
+ ac.setClock(24 * 60 + 99);
+ EXPECT_EQ(0, ac.getClock());
+}
+
+// Test human readable output.
+TEST(TestDaikin64Class, HumanReadable) {
+ IRDaikin64 ac(kGpioUnused);
+ EXPECT_EQ(
+ "Power Toggle: On, Mode: 2 (Cool), Temp: 16C, Fan: 4 (Medium), "
+ "Turbo: Off, Quiet: Off, Swing(V): Off, Sleep: Off, "
+ "Clock: 07:20, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.setPowerToggle(false);
+ ac.setMode(kDaikin64Fan);
+ ac.setTemp(30);
+ ac.setFan(kDaikin64FanAuto);
+ ac.setSwingVertical(true);
+ EXPECT_EQ(
+ "Power Toggle: Off, Mode: 4 (Fan), Temp: 30C, Fan: 1 (Auto), "
+ "Turbo: Off, Quiet: Off, Swing(V): On, Sleep: Off, "
+ "Clock: 07:20, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.setTurbo(true);
+ ac.setOffTimeEnabled(true);
+ ac.setOffTime(23 * 60 + 30);
+ EXPECT_EQ(
+ "Power Toggle: Off, Mode: 4 (Fan), Temp: 30C, Fan: 3 (Turbo), "
+ "Turbo: On, Quiet: Off, Swing(V): On, Sleep: Off, "
+ "Clock: 07:20, On Timer: Off, Off Timer: 23:30",
+ ac.toString());
+ ac.setQuiet(true);
+ ac.setSleep(true);
+ ac.setClock(12 * 60 + 31);
+ ac.setOnTimeEnabled(true);
+ ac.setOnTime(8 * 60 + 59);
+ ac.setOffTimeEnabled(false);
+ EXPECT_EQ(
+ "Power Toggle: Off, Mode: 4 (Fan), Temp: 30C, Fan: 9 (Quiet), "
+ "Turbo: Off, Quiet: On, Swing(V): On, Sleep: On, "
+ "Clock: 12:31, On Timer: 08:30, Off Timer: Off",
+ ac.toString());
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Denon_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Denon_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Denon_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Denon_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Dish_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Dish_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Dish_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Dish_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Electra_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Electra_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Electra_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Electra_test.cpp
index b49482433..1fddf537b 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Electra_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Electra_test.cpp
@@ -103,6 +103,8 @@ TEST(TestDecodeElectraAC, RealExampleDecode) {
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestIRElectraAcClass, Power) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Epson_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Epson_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Epson_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Epson_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Fujitsu_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Fujitsu_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Fujitsu_test.cpp
index 2aead1e13..aa8d2d941 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Fujitsu_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Fujitsu_test.cpp
@@ -1,5 +1,5 @@
// Copyright 2017 Jonny Graham, David Conran
-
+#include "IRac.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
@@ -316,6 +316,12 @@ TEST(TestDecodeFujitsuAC, SyntheticShortMessages) {
ASSERT_EQ(kFujitsuAcMinBits + 8, irsend.capture.bits);
uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02, 0xFD};
EXPECT_STATE_EQ(expected_arrah2e, irsend.capture.state, irsend.capture.bits);
+ EXPECT_EQ(
+ "Model: 1 (ARRAH2E), Power: Off, Mode: 0 (Auto), Temp: 16C, "
+ "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
irsend.reset();
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_GICable_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_GICable_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_GICable_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_GICable_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_GlobalCache_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_GlobalCache_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_GlobalCache_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Goodweather_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Goodweather_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Goodweather_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Goodweather_test.cpp
index 6345d2398..be07b9d09 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Goodweather_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Goodweather_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2019 David Conran
#include "ir_Goodweather.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -276,11 +277,12 @@ uint16_t rawData_FAD2BE31[197] = {
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
- ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 22C, Fan: 3 (Low), Turbo: -, Light: -, "
"Sleep: -, Swing: 1 (Slow), Command: 4 (Swing)",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Gree_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Gree_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Gree_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Gree_test.cpp
index 6c8672c77..a824cd10a 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Gree_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Gree_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 David Conran
#include "ir_Gree.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRremoteESP8266.h"
@@ -576,7 +577,9 @@ TEST(TestDecodeGree, NormalRealExample) {
"Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 26C, Fan: 1 (Low), "
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
"Swing(V) Mode: Manual, Swing(V): 2 (UNKNOWN), Timer: Off",
- irgree.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestGreeClass, toCommon) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Haier_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Haier_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Haier_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Haier_test.cpp
index ee55d2866..cdd2894df 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Haier_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Haier_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2018 David Conran
#include "ir_Haier.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -818,13 +819,13 @@ TEST(TestDecodeHaierAC, RealExample1) {
EXPECT_FALSE(irsend.capture.repeat);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
- IRHaierAC haier(0);
- haier.setRaw(irsend.capture.state);
EXPECT_EQ(
"Command: 1 (On), Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), "
"Swing: 0 (Off), Sleep: Off, Health: Off, "
"Clock: 00:01, On Timer: Off, Off Timer: Off",
- haier.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Decode a "real" example message.
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Hitachi_test.cpp
similarity index 65%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Hitachi_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Hitachi_test.cpp
index 1f04ee8ee..aef8008ff 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Hitachi_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Hitachi_test.cpp
@@ -572,6 +572,12 @@ TEST(TestDecodeHitachiAC1, NormalRealExample) {
EXPECT_EQ(HITACHI_AC1, irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc1Bits, irsend.capture.bits);
EXPECT_STATE_EQ(hitachi_code, irsend.capture.state, kHitachiAc1Bits);
+ EXPECT_EQ(
+ "Model: 2 (R-LT0541-HTA-B), Power: Off, Power Toggle: On, "
+ "Mode: 6 (Cool), Temp: 23C, Fan: 1 (Auto), "
+ "Swing(V) Toggle: Off, Swing(V): Off, Swing(H): Off, Sleep: Off, "
+ "On Timer: Off, Off Timer: Off",
+ IRAcUtils::resultAcToString(&irsend.capture));
}
// Tests for sendHitachiAC2().
@@ -809,13 +815,18 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ("HITACHI_AC1", typeToString(decode_type_t::HITACHI_AC1));
ASSERT_EQ(decode_type_t::HITACHI_AC1, strToDecodeType("HITACHI_AC1"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC1));
- ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC1));
+ ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC1));
ASSERT_EQ("HITACHI_AC2", typeToString(decode_type_t::HITACHI_AC2));
ASSERT_EQ(decode_type_t::HITACHI_AC2, strToDecodeType("HITACHI_AC2"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC2));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC2));
+ ASSERT_EQ("HITACHI_AC3", typeToString(decode_type_t::HITACHI_AC3));
+ ASSERT_EQ(decode_type_t::HITACHI_AC3, strToDecodeType("HITACHI_AC3"));
+ ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC3));
+ ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC3));
+
ASSERT_EQ("HITACHI_AC424", typeToString(decode_type_t::HITACHI_AC424));
ASSERT_EQ(decode_type_t::HITACHI_AC424, strToDecodeType("HITACHI_AC424"));
ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC424));
@@ -915,6 +926,8 @@ TEST(TestDecodeHitachiAc424, RealExample) {
"Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 5 (Auto), "
"Swing(V) Toggle: Off, Button: 19 (Power/Mode)",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestDecodeHitachiAc424, SyntheticExample) {
@@ -1113,7 +1126,7 @@ TEST(TestIRHitachiAc424Class, HumanReadable) {
}
TEST(TestIRHitachiAc424Class, toCommon) {
- IRHitachiAc424 ac(0);
+ IRHitachiAc424 ac(kGpioUnused);
ac.setPower(true);
ac.setMode(kHitachiAc424Cool);
ac.setTemp(20);
@@ -1139,3 +1152,652 @@ TEST(TestIRHitachiAc424Class, toCommon) {
ASSERT_EQ(-1, ac.toCommon().sleep);
ASSERT_EQ(-1, ac.toCommon().clock);
}
+
+TEST(TestDecodeHitachiAc3, SyntheticExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ uint8_t expected[kHitachiAc3StateLength - 4] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE6, 0x19, 0x89, 0x76, 0x01,
+ 0xFE, 0x3F, 0xC0, 0x2F, 0xD0, 0x18, 0xE7, 0x00, 0xFF, 0xA0, 0x5F};
+
+ irsend.reset();
+ irsend.sendHitachiAc3(expected, kHitachiAc3StateLength - 4);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAc3Bits - 32, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+}
+
+// Decode a 'real' HitachiAc3 message.
+TEST(TestDecodeHitachiAc3, RealExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ uint8_t expected[kHitachiAc3StateLength - 4] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE6, 0x19, 0x89, 0x76, 0x01,
+ 0xFE, 0x3F, 0xC0, 0x2F, 0xD0, 0x18, 0xE7, 0x00, 0xFF, 0xA0, 0x5F};
+
+ // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1060#issuecomment-597519432
+ uint16_t rawData[371] = {
+ // Power Off
+ 3422, 1660, 464, 1264, 438, 426, 438, 402, 486, 426, 440, 402, 462, 402,
+ 488, 428, 438, 402, 460, 404, 488, 426, 440, 424, 436, 428, 462, 1240,
+ 466, 398, 462, 404, 486, 426, 438, 402, 464, 400, 490, 400, 464, 426, 438,
+ 402, 488, 428, 436, 428, 462, 376, 486, 404, 474, 416, 438, 400, 488, 402,
+ 462, 426, 438, 426, 458, 1246, 464, 426, 436, 1244, 488, 1266, 434, 1268,
+ 436, 1242, 486, 1242, 462, 1240, 464, 426, 462, 1266, 438, 1242, 462,
+ 1240, 514, 1214, 466, 1236, 462, 1266, 464, 1264, 438, 1266, 438, 1240,
+ 488, 400, 466, 424, 440, 402, 486, 404, 462, 402, 464, 402, 488, 426, 438,
+ 402, 462, 402, 488, 1264, 438, 1242, 460, 428, 462, 428, 436, 1264, 440,
+ 1240, 488, 1240, 464, 1240, 460, 402, 490, 424, 440, 1264, 438, 1242, 512,
+ 402, 438, 426, 466, 398, 464, 1266, 440, 400, 462, 402, 488, 1264, 438,
+ 402, 462, 402, 482, 432, 438, 1264, 436, 404, 488, 1240, 462, 1264, 438,
+ 402, 486, 1246, 456, 1266, 438, 1238, 488, 402, 462, 1240, 462, 402, 512,
+ 402, 438, 428, 438, 426, 462, 430, 434, 428, 438, 402, 512, 376, 462,
+ 1240, 464, 1264, 458, 1270, 436, 1242, 462, 1240, 486, 1242, 460, 1242,
+ 462, 1242, 486, 1240, 464, 1240, 464, 1238, 492, 1264, 436, 1266, 440,
+ 400, 488, 426, 436, 430, 434, 430, 460, 404, 462, 426, 438, 402, 488, 426,
+ 436, 1264, 466, 1238, 462, 1242, 462, 1266, 438, 1238, 490, 1264, 438,
+ 426, 438, 1240, 486, 406, 462, 402, 462, 400, 488, 428, 436, 426, 438,
+ 402, 484, 1268, 438, 426, 436, 1242, 488, 1266, 436, 402, 462, 402, 502,
+ 386, 464, 1240, 464, 1240, 488, 426, 438, 426, 438, 402, 488, 1240, 462,
+ 1266, 438, 1242, 486, 428, 440, 424, 438, 1266, 460, 1268, 438, 1264, 438,
+ 404, 486, 428, 438, 426, 438, 402, 490, 400, 462, 426, 436, 402, 490, 426,
+ 438, 1240, 462, 1268, 460, 1268, 434, 1266, 436, 1240, 514, 1238, 438,
+ 1240, 488, 1240, 460, 406, 464, 426, 436, 402, 488, 402, 462, 402, 462,
+ 1264, 462, 404, 462, 1266, 434, 1268, 464, 1264, 438, 1242, 464, 1238,
+ 488, 1266, 438, 402, 462, 1268, 458, 430, 410};
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 371, kHitachiAcFreq);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAc3Bits - 32, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+}
+
+TEST(TestDecodeHitachiAc3, SyntheticTempChangeExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint16_t expectedLength = kHitachiAc3MinStateLength + 2;
+ uint8_t expected[expectedLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE3, 0x1C, 0x89, 0x76, 0x08,
+ 0xF7, 0x3F, 0xC0, 0x15, 0xEA};
+
+ irsend.reset();
+ irsend.sendHitachiAc3(expected, expectedLength);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(expectedLength * 8, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+}
+
+// Decode a 'real' Temp Change HitachiAc3 message.
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1060#issuecomment-597592537
+TEST(TestDecodeHitachiAc3, RealTempChangeExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3MinStateLength + 2] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE3, 0x1C, 0x89, 0x76, 0x08,
+ 0xF7, 0x3F, 0xC0, 0x15, 0xEA};
+ const uint16_t expectedBits = kHitachiAc3MinBits + 2 * 8;
+
+ const uint16_t rawData[275] = {
+ // Change Temp
+ 3422, 1636, 490, 1242, 484, 380, 488, 400, 466, 426, 432, 406, 490, 400,
+ 464, 426, 462, 398, 466, 376, 492, 400, 458, 404, 490, 400, 466, 1262,
+ 434, 430, 464, 400, 490, 400, 458, 380, 490, 374, 490, 426, 432, 430, 464,
+ 400, 464, 426, 460, 402, 468, 372, 490, 400, 460, 404, 490, 374, 490, 400,
+ 484, 378, 490, 398, 464, 1240, 490, 398, 466, 1238, 464, 1266, 434, 1268,
+ 466, 1238, 466, 1240, 484, 1218, 490, 400, 460, 1246, 484, 1242, 466,
+ 1214, 488, 1240, 486, 1218, 490, 1214, 488, 1266, 434, 1242, 490, 1214,
+ 490, 424, 460, 404, 464, 374, 492, 424, 434, 430, 466, 400, 464, 426, 464,
+ 376, 492, 1236, 464, 1240, 488, 402, 466, 374, 490, 400, 458, 1244, 490,
+ 1238, 496, 1234, 436, 404, 488, 400, 464, 1240, 484, 1244, 464, 1238, 466,
+ 426, 434, 430, 466, 400, 464, 1264, 434, 406, 490, 374, 490, 1264, 458,
+ 404, 466, 400, 466, 424, 466, 1238, 464, 400, 466, 1238, 486, 1216, 490,
+ 400, 464, 1240, 486, 1240, 466, 1238, 460, 432, 432, 430, 468, 374, 488,
+ 426, 462, 1242, 464, 400, 466, 426, 434, 404, 490, 374, 490, 1240, 484,
+ 1244, 466, 1240, 462, 428, 436, 1242, 490, 1212, 490, 1264, 466, 1236,
+ 466, 1214, 490, 1240, 488, 1240, 466, 1236, 466, 1264, 434, 1268, 464,
+ 400, 494, 400, 430, 406, 488, 376, 488, 428, 432, 432, 462, 402, 462, 426,
+ 458, 1220, 488, 1214, 490, 1240, 484, 406, 466, 1212, 490, 426, 462, 1216,
+ 488, 400, 464, 402, 488, 402, 462, 374, 492, 1262, 460, 380, 488, 1240,
+ 464, 428, 462, 1214, 492, 1236, 462, 1216, 490};
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 275, kHitachiAcFreq);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(expectedBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, expectedBits);
+}
+
+// Decode a 'real' Cancel Timer HitachiAc3 message.
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1060#issuecomment-598631576
+TEST(TestDecodeHitachiAc3, RealCancelTimerExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3MinStateLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE2, 0x1D, 0x89, 0x76, 0x0D,
+ 0xF2, 0x3F, 0xC0};
+ const uint16_t expectedBits = kHitachiAc3MinBits;
+
+ const uint16_t rawData[243] = {
+ // Cancel Timer
+ 3368, 1688, 460, 1244, 456, 434, 458, 406, 456, 408, 480, 410, 458, 406,
+ 458, 406, 484, 406, 458, 406, 458, 432, 428, 464, 456, 380, 458, 1242,
+ 458, 432, 456, 406, 486, 378, 430, 458, 456, 408, 458, 406, 456, 434, 456,
+ 410, 454, 408, 454, 434, 460, 404, 458, 406, 454, 436, 456, 408, 458, 406,
+ 458, 432, 456, 434, 430, 1246, 484, 404, 484, 1218, 458, 1244, 484, 1244,
+ 460, 1244, 456, 1270, 430, 1274, 460, 404, 484, 1218, 486, 1244, 456,
+ 1244, 456, 1248, 454, 1272, 460, 1268, 432, 1246, 484, 1244, 458, 1244,
+ 462, 404, 456, 434, 458, 432, 432, 408, 456, 434, 460, 404, 460, 404, 484,
+ 406, 432, 432, 458, 1298, 402, 432, 460, 404, 460, 404, 482, 1244, 460,
+ 1270, 462, 1214, 456, 1272, 460, 404, 456, 1246, 486, 1244, 458, 1244,
+ 458, 406, 454, 460, 434, 404, 460, 1268, 430, 460, 432, 406, 458, 1244,
+ 456, 434, 458, 406, 456, 432, 460, 1268, 432, 406, 458, 1244, 484, 1272,
+ 432, 430, 432, 1298, 378, 1298, 458, 1244, 484, 406, 460, 1242, 458, 406,
+ 458, 1246, 456, 1272, 458, 406, 458, 432, 458, 404, 460, 404, 456, 408,
+ 484, 1272, 432, 432, 432, 406, 454, 1272, 458, 1246, 458, 1244, 484, 1268,
+ 436, 1242, 458, 1298, 402, 1274, 456, 1244, 458, 1244, 486, 1242, 458,
+ 408, 486, 378, 454, 460, 434, 406, 458, 406, 484, 406, 458, 406, 458, 408,
+ 452, 1302, 434, 1244, 430};
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 243, kHitachiAcFreq);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(expectedBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, expectedBits);
+}
+
+TEST(TestDecodeHitachiAc3, SyntheticCancelTimerExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3MinStateLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE2, 0x1D, 0x89, 0x76, 0x0D,
+ 0xF2, 0x3F, 0xC0};
+
+ irsend.reset();
+ irsend.sendHitachiAc3(expected, kHitachiAc3MinStateLength);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAc3MinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+}
+
+// Decode a 'real' Set Timer HitachiAc3 message.
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1060#issuecomment-598631576
+TEST(TestDecodeHitachiAc3, RealSetTimerExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3StateLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE8, 0x17, 0x89, 0x76, 0x0B,
+ 0xF4, 0x3F, 0xC0, 0x15, 0xEA, 0x00, 0xFF, 0x00, 0xFF, 0x4B, 0xB4, 0x18,
+ 0xE7, 0x00, 0xFF};
+ const uint16_t expectedBits = kHitachiAc3Bits;
+
+ const uint16_t rawData[435] = {
+ // Set Timer
+ 3364, 1668, 486, 1244, 458, 406, 456, 436, 430, 434, 430, 434, 456, 408,
+ 484, 432, 428, 432, 414, 450, 458, 432, 432, 432, 430, 436, 458, 1270,
+ 430, 408, 456, 408, 454, 462, 404, 460, 428, 408, 486, 404, 456, 408, 458,
+ 406, 484, 406, 456, 434, 432, 408, 484, 406, 454, 436, 404, 432, 486, 430,
+ 430, 408, 456, 432, 458, 1270, 406, 434, 456, 1246, 484, 1244, 456, 1274,
+ 432, 1244, 486, 1268, 432, 1244, 454, 412, 454, 1272, 430, 1272, 456,
+ 1274, 456, 1246, 456, 1244, 458, 1270, 458, 1246, 456, 1254, 450, 1246,
+ 484, 408, 456, 434, 430, 408, 486, 430, 404, 460, 430, 408, 486, 404, 458,
+ 406, 458, 406, 486, 404, 458, 432, 430, 1272, 456, 408, 458, 1244, 458,
+ 1244, 456, 1274, 456, 1246, 456, 1270, 460, 1250, 426, 460, 404, 1270,
+ 484, 432, 404, 462, 402, 460, 458, 1244, 456, 386, 452, 460, 458, 1244,
+ 458, 406, 458, 406, 486, 430, 416, 1260, 458, 406, 484, 1270, 406, 1296,
+ 430, 410, 482, 1246, 456, 1246, 456, 1246, 456, 434, 458, 1244, 456, 1272,
+ 458, 408, 458, 1244, 456, 410, 484, 404, 454, 410, 456, 408, 484, 406,
+ 458, 432, 430, 1246, 484, 406, 454, 1248, 458, 1244, 486, 1248, 428, 1270,
+ 456, 1266, 464, 1244, 458, 1246, 456, 1246, 484, 1270, 430, 1246, 456,
+ 434, 430, 460, 406, 432, 430, 432, 484, 432, 406, 432, 458, 406, 484, 432,
+ 432, 1266, 434, 1274, 430, 1298, 428, 408, 456, 1246, 486, 430, 432, 1270,
+ 404, 434, 484, 432, 430, 408, 456, 406, 460, 1268, 458, 408, 456, 1246,
+ 486, 406, 456, 1244, 456, 1248, 456, 1300, 430, 408, 456, 408, 484, 432,
+ 430, 434, 428, 434, 460, 430, 404, 434, 458, 406, 486, 1242, 458, 1270,
+ 430, 1246, 484, 1244, 456, 1270, 432, 1248, 484, 1244, 456, 1246, 456,
+ 408, 486, 404, 456, 408, 456, 432, 462, 430, 406, 458, 432, 432, 428,
+ 436, 456, 1246, 456, 1246, 484, 1244, 454, 1268, 438, 1244, 488, 1266,
+ 430, 1246, 458, 1244, 486, 1244, 430, 1298, 430, 434, 460, 1242, 458, 430,
+ 430, 408, 486, 1242, 456, 434, 404, 462, 456, 430, 432, 1246, 456, 408,
+ 486, 1270, 430, 1246, 460, 404, 482, 1246, 458, 406, 456, 408, 484, 404,
+ 458, 1270, 430, 1274, 458, 432, 430, 408, 456, 406, 486, 1244, 458, 1242,
+ 458, 1246, 484, 406, 458, 432, 430, 1246, 486, 1242, 456, 1272, 430, 434,
+ 458, 406, 458, 406, 458, 406, 486, 404, 458, 406, 458, 430, 430, 460, 430,
+ 1270, 430, 1248, 484, 1244, 456, 1244, 458, 1246, 484, 1244, 456, 1246,
+ 460, 1244, 458}; // UNKNOWN D3A5A0BA
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 435, kHitachiAcFreq);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(expectedBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, expectedBits);
+}
+
+TEST(TestDecodeHitachiAc3, SyntheticSetTimerExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3StateLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE8, 0x17, 0x89, 0x76, 0x0B,
+ 0xF4, 0x3F, 0xC0, 0x15, 0xEA, 0x00, 0xFF, 0x00, 0xFF, 0x4B, 0xB4, 0x18,
+ 0xE7, 0x00, 0xFF};
+
+ irsend.reset();
+ irsend.sendHitachiAc3(expected, kHitachiAc3StateLength);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAc3Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+}
+
+// Decode a 'real' Change Mode HitachiAc3 message.
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1060#issuecomment-598631576
+TEST(TestDecodeHitachiAc3, RealChangeModeExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3StateLength - 6] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE5, 0x1A, 0x89, 0x76, 0x04,
+ 0xFB, 0x3F, 0xC0, 0x1B, 0xE4, 0x14, 0xEB, 0x02, 0xFD};
+ const uint16_t expectedBits = kHitachiAc3Bits - 6 * 8;
+
+ const uint16_t rawData[339] = {
+ // Change Mode
+ 3364, 1666, 488, 1268, 404, 434, 454, 434, 460, 404, 458, 406, 458, 406,
+ 484, 432, 432, 430, 432, 408, 484, 406, 458, 432, 432, 406, 486, 1242,
+ 458, 430, 430, 408, 454, 436, 456, 408, 458, 406, 484, 432, 428, 434, 430,
+ 408, 484, 406, 458, 430, 432, 408, 484, 430, 430, 432, 432, 408, 482, 408,
+ 456, 408, 458, 432, 458, 1246, 458, 430, 430, 1246, 486, 1242, 458, 1270,
+ 432, 1246, 486, 1242, 458, 1268, 432, 434, 430, 1272, 456, 1246, 458,
+ 1270, 460, 1244, 458, 1246, 456, 1272, 460, 1242, 456, 1270, 434, 1246,
+ 486, 430, 430, 434, 432, 406, 484, 430, 432, 432, 430, 408, 484, 432, 432,
+ 432, 430, 1246, 484, 406, 458, 1246, 456, 408, 486, 404, 458, 1268, 434,
+ 1270, 430, 1274, 456, 408, 458, 1270, 460, 404, 458, 1244, 458, 1246, 486,
+ 430, 430, 432, 460, 378, 488, 1240, 460, 404, 458, 408, 486, 1242, 458,
+ 432, 430, 434, 460, 430, 432, 1246, 458, 406, 488, 1240, 430, 1272, 458,
+ 406, 486, 1242, 430, 1298, 430, 1274, 428, 432, 430, 436, 456, 408, 482,
+ 1248, 458, 406, 430, 462, 456, 404, 458, 432, 430, 408, 486, 1266, 436,
+ 1242, 458, 406, 486, 1242, 456, 1246, 458, 1244, 488, 1240, 458, 1244,
+ 458, 1272, 460, 1242, 456, 1246, 458, 1246, 486, 1242, 458, 1270, 432,
+ 406, 458, 458, 434, 430, 432, 406, 486, 406, 456, 408, 458, 432, 484, 406,
+ 430, 1272, 460, 1216, 486, 1242, 456, 1246, 458, 406, 486, 1268, 432,
+ 1244, 458, 406, 486, 404, 460, 432, 430, 406, 488, 402, 458, 1272, 428,
+ 434, 460, 404, 460, 1242, 458, 1246, 480, 1244, 462, 428, 432, 432, 460,
+ 1244, 458, 432, 430, 1246, 488, 402, 456, 408, 458, 406, 486, 1268, 432,
+ 1246, 460, 430, 460, 1244, 458, 406, 458, 1244, 486, 1242, 458, 1244, 458,
+ 432, 462, 1242, 456, 408, 456, 406, 486, 428, 434, 406, 458, 406, 456,
+ 434, 458, 1244, 460, 430, 462, 1240, 458, 1244, 460, 1244, 486, 1244, 458,
+ 1242, 488, 1214, 460}; // UNKNOWN C1EA1036
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 339, kHitachiAcFreq);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(expectedBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, expectedBits);
+}
+
+TEST(TestDecodeHitachiAc3, SyntheticChangeModeExample) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ const uint8_t expected[kHitachiAc3StateLength - 6] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE5, 0x1A, 0x89, 0x76, 0x04,
+ 0xFB, 0x3F, 0xC0, 0x1B, 0xE4, 0x14, 0xEB, 0x02, 0xFD};
+ const uint16_t expectedBits = kHitachiAc3Bits - 6 * 8;
+
+ irsend.reset();
+ irsend.sendHitachiAc3(expected, kHitachiAc3StateLength - 6);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(HITACHI_AC3, irsend.capture.decode_type);
+ ASSERT_EQ(expectedBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+}
+
+TEST(TestHitachiAc3Class, hasInvertedStates) {
+ const uint8_t good_state[kHitachiAc3StateLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE8, 0x17, 0x89, 0x76, 0x0B,
+ 0xF4, 0x3F, 0xC0, 0x15, 0xEA, 0x00, 0xFF, 0x00, 0xFF, 0x4B, 0xB4, 0x18,
+ 0xE7, 0x00, 0xFF};
+ // bad_state[kHitachiAc3MinStateLength + 1] has been modified to be different.
+ // i.e. Anything larger than kHitachiAc3MinStateLength should fail.
+ // kHitachiAc3MinStateLength or shorter should pass.
+ const uint8_t bad_state[kHitachiAc3StateLength] = {
+ 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xE8, 0x17, 0x89, 0x76, 0x0B,
+ 0xF4, 0x3F, 0xC0, 0x15, 0xE0, 0x00, 0xFF, 0x00, 0xFF, 0x4B, 0xB4, 0x18,
+ 0xE7, 0x00, 0xFF};
+
+ EXPECT_TRUE(IRHitachiAc3::hasInvertedStates(good_state,
+ kHitachiAc3StateLength));
+
+ for (uint8_t len = kHitachiAc3StateLength;
+ len > kHitachiAc3MinStateLength;
+ len -= 2) {
+ EXPECT_FALSE(IRHitachiAc3::hasInvertedStates(bad_state, len));
+ }
+ EXPECT_TRUE(IRHitachiAc3::hasInvertedStates(bad_state,
+ kHitachiAc3MinStateLength));
+ EXPECT_TRUE(IRHitachiAc3::hasInvertedStates(bad_state,
+ kHitachiAc3MinStateLength - 2));
+}
+
+// HitachiAc1 Class tests
+
+TEST(TestIRHitachiAc1Class, SetAndGetPower) {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.on();
+ ac.setPowerToggle(false);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.getPowerToggle());
+ ac.off();
+ EXPECT_FALSE(ac.getPower());
+ EXPECT_TRUE(ac.getPowerToggle());
+ ac.setPowerToggle(false);
+ EXPECT_FALSE(ac.getPowerToggle());
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_TRUE(ac.getPowerToggle());
+ ac.setPower(false);
+ EXPECT_FALSE(ac.getPower());
+ EXPECT_TRUE(ac.getPowerToggle());
+}
+
+TEST(TestIRHitachiAc1Class, SetAndGetTemp) {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setMode(kHitachiAc1Cool); // All temps possible in Cool mode.
+ ac.setTemp(26);
+ EXPECT_EQ(26, ac.getTemp());
+ ac.setTemp(kHitachiAcMinTemp);
+ EXPECT_EQ(kHitachiAcMinTemp, ac.getTemp());
+ ac.setTemp(kHitachiAcMinTemp - 1);
+ EXPECT_EQ(kHitachiAcMinTemp, ac.getTemp());
+ ac.setTemp(kHitachiAcMaxTemp);
+ EXPECT_EQ(kHitachiAcMaxTemp, ac.getTemp());
+ ac.setTemp(kHitachiAcMaxTemp + 1);
+ EXPECT_EQ(kHitachiAcMaxTemp, ac.getTemp());
+
+ // Can't change temp in Auto mode.
+ ac.setMode(kHitachiAc1Auto); // All temps possible in Cool mode.
+ EXPECT_EQ(kHitachiAc1TempAuto, ac.getTemp());
+ ac.setTemp(kHitachiAcMinTemp);
+ EXPECT_EQ(kHitachiAc1TempAuto, ac.getTemp());
+
+ // Ref: https://docs.google.com/spreadsheets/d/10eKpJEWJppUYktPRLCcAIwzfFXjtkOZNyn1reh5MFfU/edit#gid=0&range=B46
+ const uint8_t cool_31_auto[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0x61, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x68};
+ ac.setRaw(cool_31_auto);
+ EXPECT_EQ(31, ac.getTemp());
+}
+
+TEST(TestIRHitachiAc1Class, SetAndGetMode) {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setMode(kHitachiAc1Auto);
+ EXPECT_EQ(kHitachiAc1Auto, ac.getMode());
+ ac.setMode(kHitachiAc1Cool);
+ EXPECT_EQ(kHitachiAc1Cool, ac.getMode());
+ ac.setMode(kHitachiAc1Fan);
+ EXPECT_EQ(kHitachiAc1Fan, ac.getMode());
+ ac.setMode(kHitachiAc1Heat);
+ EXPECT_EQ(kHitachiAc1Heat, ac.getMode());
+ ac.setMode(kHitachiAc1Dry);
+ EXPECT_EQ(kHitachiAc1Dry, ac.getMode());
+ ac.setMode(0);
+ EXPECT_EQ(kHitachiAc1Auto, ac.getMode());
+ ac.setMode(255);
+ EXPECT_EQ(kHitachiAc1Auto, ac.getMode());
+}
+
+TEST(TestIRHitachiAc1Class, SetAndGetFan) {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setMode(kHitachiAc1Cool); // All speeds possible in Cool mode.
+ ac.setFan(kHitachiAc1FanAuto);
+ EXPECT_EQ(kHitachiAc1FanAuto, ac.getFan());
+ ac.setFan(kHitachiAc1FanLow);
+ EXPECT_EQ(kHitachiAc1FanLow, ac.getFan());
+ ac.setFan(kHitachiAc1FanHigh);
+ EXPECT_EQ(kHitachiAc1FanHigh, ac.getFan());
+ ac.setFan(kHitachiAc1FanMed);
+ EXPECT_EQ(kHitachiAc1FanMed, ac.getFan());
+
+ ac.setFan(255);
+ EXPECT_EQ(kHitachiAc1FanAuto, ac.getFan());
+ ac.setFan(0);
+ EXPECT_EQ(kHitachiAc1FanAuto, ac.getFan());
+
+ // Can't change speed in Auto mode. Locked to auto speed.
+ ac.setMode(kHitachiAc1Auto);
+ EXPECT_EQ(kHitachiAc1FanAuto, ac.getFan());
+ ac.setFan(kHitachiAc1FanLow);
+ EXPECT_EQ(kHitachiAc1FanAuto, ac.getFan());
+ // Can't change speed in Dry mode. Locked to low speed.
+ ac.setMode(kHitachiAc1Dry);
+ EXPECT_EQ(kHitachiAc1FanLow, ac.getFan());
+ ac.setFan(kHitachiAc1FanHigh);
+ EXPECT_EQ(kHitachiAc1FanLow, ac.getFan());
+}
+
+TEST(TestIRHitachiAc1Class, HumanReadable) {
+ IRHitachiAc1 ac(kGpioUnused);
+
+ // Ref: https://docs.google.com/spreadsheets/d/10eKpJEWJppUYktPRLCcAIwzfFXjtkOZNyn1reh5MFfU/edit#gid=0&range=A47:B47
+ const uint8_t cool_32_auto[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0x61, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x30,
+ 0x04};
+ ac.setRaw(cool_32_auto);
+ EXPECT_EQ(
+ "Model: 1 (R-LT0541-HTA-A), Power: On, Power Toggle: On, Mode: 6 (Cool), "
+ "Temp: 32C, Fan: 1 (Auto), Swing(V) Toggle: Off, "
+ "Swing(V): Off, Swing(H): Off, "
+ "Sleep: Off, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.setModel(hitachi_ac1_remote_model_t::R_LT0541_HTA_B);
+ ac.setSwingV(true);
+ ac.setSwingToggle(true);
+ ac.setSleep(kHitachiAc1Sleep2);
+ ac.setPowerToggle(false);
+ ac.setOnTimer(2 * 60 + 39);
+ ac.setOffTimer(10 * 60 + 17);
+ EXPECT_EQ(
+ "Model: 2 (R-LT0541-HTA-B), Power: On, Power Toggle: Off, "
+ "Mode: 6 (Cool), Temp: 32C, Fan: 1 (Auto), "
+ "Swing(V) Toggle: On, Swing(V): On, Swing(H): Off, Sleep: 2, "
+ "On Timer: 02:39, Off Timer: 10:17",
+ ac.toString());
+}
+
+TEST(TestIRHitachiAc1Class, Checksum) {
+ // Reverse Table: 2=4, B=D, A=5, E=7, 1=8, 3=C, 0=0, 6=6, 9=9, F=F
+ IRHitachiAc1 ac(kGpioUnused);
+ // Ref: https://docs.google.com/spreadsheets/d/10eKpJEWJppUYktPRLCcAIwzfFXjtkOZNyn1reh5MFfU/edit#gid=0&range=A47:B47
+ const uint8_t cool_32_auto[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0x61, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x30,
+ 0x04};
+ // Reversed: 4D, 75, B2, 89, 0F, 86, 33, 00, 00, 00, 00, 0C, 20
+ EXPECT_TRUE(ac.validChecksum(cool_32_auto));
+ EXPECT_EQ(0x04, ac.calcChecksum(cool_32_auto));
+
+ // Ref: https://docs.google.com/spreadsheets/d/10eKpJEWJppUYktPRLCcAIwzfFXjtkOZNyn1reh5MFfU/edit#gid=0&range=B46
+ const uint8_t cool_31_auto[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0x61, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x68};
+ // Reversed: 4D, 75, B2, 89, 0F, 86, 31, 00, 00, 00, 00, 04, 16
+ EXPECT_TRUE(ac.validChecksum(cool_31_auto));
+ EXPECT_EQ(0x68, ac.calcChecksum(cool_31_auto));
+
+ // Ref: https://docs.google.com/spreadsheets/d/10eKpJEWJppUYktPRLCcAIwzfFXjtkOZNyn1reh5MFfU/edit#gid=0&range=B13
+ const uint8_t auto_25_auto_swing_on[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0xE1, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x61,
+ 0x24};
+ // Reversed: 4D, 75, B2, 89, 0F, 87, 25, 00, 00, 00, 00, 86, 42
+ EXPECT_TRUE(ac.validChecksum(auto_25_auto_swing_on));
+ EXPECT_EQ(0x24, ac.calcChecksum(auto_25_auto_swing_on));
+ // Ref: https://docs.google.com/spreadsheets/d/10eKpJEWJppUYktPRLCcAIwzfFXjtkOZNyn1reh5MFfU/edit#gid=0&range=B45
+ const uint8_t cool_30_auto[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0x61, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0xC4};
+ EXPECT_TRUE(ac.validChecksum(cool_30_auto));
+ EXPECT_EQ(0xC4, ac.calcChecksum(cool_30_auto));
+}
+
+TEST(TestIRHitachiAc1Class, toCommon) {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setPower(true);
+ ac.setMode(kHitachiAc1Cool);
+ ac.setTemp(20);
+ ac.setFan(kHitachiAc1FanHigh);
+ ac.setSwingV(false);
+ ac.setSwingH(true);
+ ac.setModel(hitachi_ac1_remote_model_t::R_LT0541_HTA_B);
+ // Now test it.
+ ASSERT_EQ(decode_type_t::HITACHI_AC1, ac.toCommon().protocol);
+ ASSERT_EQ(2, ac.toCommon().model);
+ ASSERT_TRUE(ac.toCommon().power);
+ ASSERT_TRUE(ac.toCommon().celsius);
+ ASSERT_EQ(20, ac.toCommon().degrees);
+ ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode);
+ ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed);
+ ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv);
+ ASSERT_EQ(stdAc::swingh_t::kAuto, ac.toCommon().swingh);
+ // Unsupported.
+ ASSERT_FALSE(ac.toCommon().turbo);
+ ASSERT_FALSE(ac.toCommon().clean);
+ ASSERT_FALSE(ac.toCommon().light);
+ ASSERT_FALSE(ac.toCommon().quiet);
+ ASSERT_FALSE(ac.toCommon().econo);
+ ASSERT_FALSE(ac.toCommon().filter);
+ ASSERT_FALSE(ac.toCommon().beep);
+ ASSERT_EQ(-1, ac.toCommon().sleep);
+ ASSERT_EQ(-1, ac.toCommon().clock);
+}
+
+TEST(TestIRHitachiAc1Class, ReconstructKnownGood) {
+ IRHitachiAc1 ac(kGpioUnused);
+ const uint8_t known_good[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x51, 0xF0, 0x61, 0x84,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x98};
+ ac.stateReset();
+ ac.setPower(false);
+ ac.setPowerToggle(true);
+ ac.setMode(kHitachiAc1Cool);
+ ac.setTemp(23);
+ ac.setFan(kHitachiAc1FanAuto);
+ ac.setSwingV(false);
+ ac.setSwingH(false);
+ ac.setSwingToggle(false);
+ ac.setModel(hitachi_ac1_remote_model_t::R_LT0541_HTA_B);
+
+ EXPECT_STATE_EQ(known_good, ac.getRaw(), kHitachiAc1Bits);
+ EXPECT_EQ(
+ "Model: 2 (R-LT0541-HTA-B), Power: Off, Power Toggle: On, "
+ "Mode: 6 (Cool), Temp: 23C, Fan: 1 (Auto), "
+ "Swing(V) Toggle: Off, Swing(V): Off, Swing(H): Off, Sleep: Off, "
+ "On Timer: Off, Off Timer: Off",
+ ac.toString());
+}
+
+TEST(TestIRHitachiAc1Class, Swing) {
+ IRHitachiAc1 ac(kGpioUnused);
+ ac.setSwingV(false);
+ EXPECT_FALSE(ac.getSwingV());
+ ac.setSwingToggle(false);
+ EXPECT_FALSE(ac.getSwingToggle());
+
+ ac.setSwingV(true);
+ EXPECT_TRUE(ac.getSwingV());
+ EXPECT_FALSE(ac.getSwingToggle());
+ ac.setSwingToggle(true);
+ EXPECT_TRUE(ac.getSwingV());
+ EXPECT_TRUE(ac.getSwingToggle());
+
+ ac.setSwingV(false);
+ EXPECT_FALSE(ac.getSwingV());
+ ac.setSwingToggle(false);
+ EXPECT_FALSE(ac.getSwingToggle());
+
+ const uint8_t swing_on_with_toggle[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0xE1, 0xA4,
+ 0x00, 0x00, 0x00, 0x00, 0x61, 0x24};
+ ac.setRaw(swing_on_with_toggle);
+ EXPECT_TRUE(ac.getSwingV());
+ EXPECT_FALSE(ac.getSwingH());
+ EXPECT_TRUE(ac.getSwingToggle());
+ const uint8_t swing_off_with_toggle[kHitachiAc1StateLength] = {
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0xE1, 0xA4,
+ 0x00, 0x00, 0x00, 0x00, 0x21, 0x44};
+ ac.setRaw(swing_off_with_toggle);
+ EXPECT_FALSE(ac.getSwingV());
+ EXPECT_FALSE(ac.getSwingH());
+ EXPECT_TRUE(ac.getSwingToggle());
+ ac.setSwingToggle(true);
+ EXPECT_STATE_EQ(swing_off_with_toggle, ac.getRaw(), kHitachiAc1Bits);
+}
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1056#issuecomment-609374682
+TEST(TestIRHitachiAc1Class, FanSpeedInDryMode) {
+ IRHitachiAc1 ac(kGpioUnused);
+ // IRhvac {"Vendor":"HITACHI_AC1", "Power":"On","Mode":"dry","FanSpeed":"low"
+ // "Temp":22.5}
+ const uint8_t state[kHitachiAc1StateLength] = { // Code generated by Tasmota.
+ 0xB2, 0xAE, 0x4D, 0x91, 0xF0, 0x21, 0xF8,
+ 0x00, 0x00, 0x00, 0x00, 0x31, 0x0C};
+ ac.setRaw(state);
+ EXPECT_EQ(
+ "Model: 1 (R-LT0541-HTA-A), Power: On, Power Toggle: On, Mode: 2 (Dry), "
+ "Temp: 22C, Fan: 1 (Auto), "
+ "Swing(V) Toggle: On, Swing(V): Off, Swing(H): Off, Sleep: Off, "
+ "On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.stateReset();
+ // Build it via the build order in IRac::hitachi1()
+ ac.setModel(hitachi_ac1_remote_model_t::R_LT0541_HTA_A);
+ ac.setPower(true);
+ ac.setPowerToggle(true);
+ ac.setMode(kHitachiAc1Dry);
+ ac.setTemp(22.5);
+ ac.setFan(kHitachiAc1FanLow);
+ ac.setSwingV(false);
+ ac.setSwingH(false);
+ ac.setSwingToggle(true);
+ ac.setSleep(0);
+ EXPECT_EQ(
+ "Model: 1 (R-LT0541-HTA-A), Power: On, Power Toggle: On, Mode: 2 (Dry), "
+ "Temp: 22C, Fan: 8 (Low), "
+ "Swing(V) Toggle: On, Swing(V): Off, Swing(H): Off, Sleep: Off, "
+ "On Timer: Off, Off Timer: Off",
+ ac.toString());
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Inax_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Inax_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Inax_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Inax_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_JVC_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_JVC_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_JVC_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_JVC_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Kelvinator_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Kelvinator_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Kelvinator_test.cpp
index e01a585bd..73ad6581d 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Kelvinator_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Kelvinator_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 David Conran
#include "ir_Kelvinator.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRremoteESP8266.h"
@@ -519,6 +520,13 @@ TEST(TestDecodeKelvinator, NormalSynthetic) {
EXPECT_EQ(KELVINATOR, irsend.capture.decode_type);
ASSERT_EQ(kKelvinatorBits, irsend.capture.bits);
EXPECT_STATE_EQ(kelv_code, irsend.capture.state, kKelvinatorBits);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, "
+ "Quiet: Off, XFan: On, Ion: Off, Light: Off, "
+ "Swing(H): Off, Swing(V): Off",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestKelvinatorClass, toCommon) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_LG_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_LG_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_LG_test.cpp
index 703ea3c6c..3c04c902f 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_LG_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_LG_test.cpp
@@ -843,6 +843,8 @@ TEST(TestDecodeLG2, Issue1008) {
ASSERT_EQ(LG2, ac._irsend.capture.decode_type);
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
TEST(TestIRLgAcClass, DifferentModels) {
@@ -864,6 +866,8 @@ TEST(TestIRLgAcClass, DifferentModels) {
ASSERT_EQ(LG, ac._irsend.capture.decode_type); // Not "LG2"
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
ASSERT_EQ(expected1, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ac.setModel(lg_ac_remote_model_t::AKB75215403); // aka. 2
@@ -879,4 +883,5 @@ TEST(TestIRLgAcClass, DifferentModels) {
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG"
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
ASSERT_EQ(expected2, IRAcUtils::resultAcToString(&ac._irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Lasertag_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Lasertag_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Lasertag_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Lego_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Lego_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Lego_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Lego_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Lutron_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Lutron_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Lutron_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_MWM_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_MWM_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_MWM_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_MWM_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Magiquest_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Magiquest_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Magiquest_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Midea_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Midea_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Midea_test.cpp
index a43076fea..4c437a576 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Midea_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Midea_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 David Conran
#include "ir_Midea.h"
+#include "IRac.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
@@ -669,6 +670,12 @@ TEST(TestDecodeMidea, DecodeRealExample) {
EXPECT_EQ(MIDEA, irsend.capture.decode_type);
EXPECT_EQ(kMideaBits, irsend.capture.bits);
EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 18C/65F, Fan: 0 (Auto), "
+ "Sleep: Off, Swing(V) Toggle: Off",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestMideaACClass, toCommon) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_MitsubishiHeavy_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_MitsubishiHeavy_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/test/ir_MitsubishiHeavy_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_MitsubishiHeavy_test.cpp
index a8226feb8..d182fd941 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_MitsubishiHeavy_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_MitsubishiHeavy_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2019 David Conran
#include "ir_MitsubishiHeavy.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRremoteESP8266.h"
@@ -742,7 +743,9 @@ TEST(TestDecodeMitsubishiHeavy, ZmsRealExample) {
"Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), "
"Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, "
"Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Decode a Synthetic MitsubishiHeavy 152Bit message.
@@ -847,7 +850,9 @@ TEST(TestDecodeMitsubishiHeavy, ZjsSyntheticExample) {
"Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
"Swing(V): 0 (Off), Swing(H): 6 (Left Right), Turbo: Off, Econo: Off, "
"3D: Off, Clean: Off",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestMitsubishiHeavy152AcClass, toCommon) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Mitsubishi_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Mitsubishi_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Mitsubishi_test.cpp
index 4f759c046..8e1c1bf51 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Mitsubishi_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Mitsubishi_test.cpp
@@ -1230,6 +1230,8 @@ TEST(TestDecodeMitsubishi136, DecodeRealExample) {
"Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 3 (High), "
"Swing(V): 3 (Highest), Quiet: Off",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Self decode a synthetic example.
@@ -1719,6 +1721,8 @@ TEST(TestDecodeMitsubishi112, DecodeRealExample) {
"Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 2 (Quiet), "
"Swing(V): 7 (Auto), Swing(H): 12 (Auto), Quiet: On",
IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Self decode a synthetic example.
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_NEC_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_NEC_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_NEC_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_NEC_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Neoclima_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Neoclima_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Neoclima_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Neoclima_test.cpp
index c743e7ba5..b395ee8dd 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Neoclima_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Neoclima_test.cpp
@@ -2,6 +2,7 @@
#include "ir_Neoclima.h"
#include
+#include "IRac.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "IRrecv.h"
@@ -12,6 +13,7 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ("NEOCLIMA", typeToString(decode_type_t::NEOCLIMA));
ASSERT_EQ(decode_type_t::NEOCLIMA, strToDecodeType("NEOCLIMA"));
ASSERT_TRUE(hasACState(decode_type_t::NEOCLIMA));
+ ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::NEOCLIMA));
}
// Test sending typical data only.
@@ -83,7 +85,9 @@ TEST(TestDecodeNeoclima, RealExample) {
"Swing(V): Off, Swing(H): On, Sleep: Off, Turbo: Off, Hold: Off, "
"Ion: Off, Eye: Off, Light: Off, Follow: Off, 8C Heat: Off, Fresh: Off, "
"Button: 0 (Power)",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Self decode.
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Nikai_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Nikai_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Nikai_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Panasonic_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Panasonic_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Panasonic_test.cpp
index 7f022ed17..fbce6de4e 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Panasonic_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Panasonic_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2017, 2018 David Conran
#include "ir_Panasonic.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -889,14 +890,13 @@ TEST(TestDecodePanasonicAC, SyntheticExample) {
EXPECT_EQ(kPanasonicAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
EXPECT_FALSE(irsend.capture.repeat);
-
- IRPanasonicAc pana(0);
- pana.setRaw(irsend.capture.state);
EXPECT_EQ(
"Model: 4 (JKE), Power: Off, Mode: 3 (Cool), Temp: 25C, "
"Fan: 7 (Auto), Swing(V): 15 (Auto), Quiet: Off, "
"Powerful: Off, Clock: 00:00, On Timer: Off, Off Timer: Off",
- pana.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Tests for general utility functions.
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Pioneer_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Pioneer_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Pioneer_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Pronto_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Pronto_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Pronto_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_RC5_RC6_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_RC5_RC6_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_RC5_RC6_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_RCMM_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_RCMM_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_RCMM_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Samsung_test.cpp
similarity index 94%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Samsung_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Samsung_test.cpp
index c44572934..52165b780 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Samsung_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Samsung_test.cpp
@@ -1,7 +1,8 @@
-// Copyright 2017, 2018, 2019 David Conran
+// Copyright 2017-2020 David Conran
#include
#include "ir_Samsung.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -571,6 +572,13 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) {
EXPECT_FALSE(ac.getPowerful());
EXPECT_EQ(kSamsungAcFanAuto, ac.getFan());
+ // Breeze and Powerful/Turbo are mutually exclusive.
+ ac.setPowerful(true);
+ EXPECT_TRUE(ac.getPowerful());
+ ac.setBreeze(true);
+ EXPECT_TRUE(ac.getBreeze());
+ EXPECT_FALSE(ac.getPowerful());
+
// Actual powerful on & off states from:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/734#issuecomment-500120270
uint8_t on[kSamsungAcStateLength] = {
@@ -581,7 +589,8 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) {
EXPECT_EQ(kSamsungAcFanTurbo, ac.getFan());
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 7 (Turbo), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: On, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: On, Breeze: Off, "
+ "Light: On, Ion: Off",
ac.toString());
uint8_t off[kSamsungAcStateLength] = {
@@ -592,7 +601,8 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) {
EXPECT_NE(kSamsungAcFanTurbo, ac.getFan());
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
ac.toString());
}
@@ -658,7 +668,8 @@ TEST(TestIRSamsungAcClass, HumanReadable) {
IRSamsungAc samsung(0);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
samsung.setTemp(kSamsungAcMaxTemp);
samsung.setMode(kSamsungAcHeat);
@@ -669,24 +680,28 @@ TEST(TestIRSamsungAcClass, HumanReadable) {
samsung.setClean(true);
EXPECT_EQ(
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 5 (High), Swing: Off, "
- "Beep: On, Clean: On, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: On, Clean: On, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
samsung.setQuiet(true);
EXPECT_EQ(
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, "
- "Beep: On, Clean: On, Quiet: On, Powerful: Off, Light: On, Ion: Off",
+ "Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
samsung.setQuiet(false);
samsung.setPowerful(true);
EXPECT_EQ(
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, "
- "Beep: On, Clean: On, Quiet: Off, Powerful: On, Light: On, Ion: Off",
+ "Beep: On, Clean: On, Quiet: Off, Powerful: On, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
samsung.setIon(true);
samsung.setDisplay(false);
EXPECT_EQ(
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, "
- "Beep: On, Clean: On, Quiet: Off, Powerful: On, Light: Off, Ion: On",
+ "Beep: On, Clean: On, Quiet: Off, Powerful: On, Breeze: Off, "
+ "Light: Off, Ion: On",
samsung.toString());
}
@@ -790,7 +805,8 @@ TEST(TestDecodeSamsungAC, DecodeRealExample) {
samsung.setRaw(irsend.capture.state);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
}
@@ -839,7 +855,8 @@ TEST(TestDecodeSamsungAC, DecodeRealExample2) {
samsung.setRaw(irsend.capture.state);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
}
@@ -898,7 +915,8 @@ TEST(TestDecodeSamsungAC, DecodePowerOnSample) {
samsung.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
}
@@ -958,7 +976,8 @@ TEST(TestDecodeSamsungAC, DecodePowerOffSample) {
samsung.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength);
EXPECT_EQ(
"Power: Off, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
}
@@ -1005,7 +1024,8 @@ TEST(TestDecodeSamsungAC, DecodeHeatSample) {
samsung.setRaw(irsend.capture.state);
EXPECT_EQ(
"Power: On, Mode: 4 (Heat), Temp: 17C, Fan: 0 (Auto), Swing: On, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
}
@@ -1047,13 +1067,13 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) {
ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type);
EXPECT_EQ(kSamsungAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
-
- IRSamsungAc samsung(0);
- samsung.setRaw(irsend.capture.state);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
- samsung.toString());
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestDecodeSamsungAC, Issue604DecodeExtended) {
@@ -1110,7 +1130,8 @@ TEST(TestDecodeSamsungAC, Issue604DecodeExtended) {
samsung.setRaw(irsend.capture.state, irsend.capture.bits / 8);
EXPECT_EQ(
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
samsung.toString());
}
@@ -1307,7 +1328,7 @@ TEST(TestIRSamsungAcClass, Issue604SendPowerHack) {
"m586s100000";
std::string text = "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 4 (Med), "
"Swing: On, Beep: Off, Clean: Off, Quiet: Off, "
- "Powerful: Off, Light: On, Ion: Off";
+ "Powerful: Off, Breeze: Off, Light: On, Ion: Off";
// Don't do a setPower()/on()/off() as that will trigger the special message.
// So it should only be the normal "settings" message.
ac.setTemp(23);
@@ -1434,7 +1455,8 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) {
ac.setRaw(irsend.capture.state, irsend.capture.bits / 8);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
ac.toString());
// Make sure the ac class state is in something wildly different first.
@@ -1456,7 +1478,8 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) {
ac.setQuiet(true);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
ac.toString());
// Check it matches the known good/expected state.
EXPECT_STATE_EQ(expectedState, ac.getRaw(), kSamsungAcBits);
@@ -1506,6 +1529,52 @@ TEST(TestDecodeSamsungAC, Issue734PowerfulOff) {
ac.setRaw(irsend.capture.state, irsend.capture.bits / 8);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
- "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Light: On, Ion: Off",
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
+ ac.toString());
+}
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
+TEST(TestIRSamsungAcClass, SetAndGetBreeze) {
+ IRSamsungAc ac(kGpioUnused);
+ ac.setFan(kSamsungAcFanMed);
+ ac.setBreeze(false);
+ EXPECT_FALSE(ac.getBreeze());
+ EXPECT_EQ(kSamsungAcFanMed, ac.getFan());
+ ac.setBreeze(true);
+ EXPECT_TRUE(ac.getBreeze());
+ EXPECT_EQ(kSamsungAcFanAuto, ac.getFan()); // Breeze sets fan to auto.
+ ac.setBreeze(false);
+ EXPECT_FALSE(ac.getBreeze());
+ EXPECT_EQ(kSamsungAcFanAuto, ac.getFan());
+
+ // Breeze and Powerful/Turbo are mutually exclusive.
+ ac.setBreeze(true);
+ EXPECT_TRUE(ac.getBreeze());
+ ac.setPowerful(true);
+ EXPECT_FALSE(ac.getBreeze());
+
+ // Check against real messages.
+ // MODE FAN, 24C WINDFREE ON
+ const uint8_t on[14] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xB2, 0xFE, 0x7B, 0x80,
+ 0x31, 0xF0};
+ ac.setRaw(on);
+ ASSERT_TRUE(ac.getBreeze());
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: On, "
+ "Light: On, Ion: Off",
+ ac.toString());
+ // MODE FAN, 24C WINDFREE OFF, FAN = LOW
+ const uint8_t off[14] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xC2, 0xFE, 0x71, 0x80,
+ 0x35, 0xF0};
+ ac.setRaw(off);
+ ASSERT_FALSE(ac.getBreeze());
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 2 (Low), Swing: Off, "
+ "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
+ "Light: On, Ion: Off",
ac.toString());
}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Sanyo_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Sanyo_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Sanyo_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Sharp_test.cpp
similarity index 83%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Sharp_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Sharp_test.cpp
index e605e0d05..173c94f2a 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Sharp_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Sharp_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 David Conran
#include "ir_Sharp.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -407,12 +408,11 @@ TEST(TestDecodeSharpAc, RealExample) {
ASSERT_EQ(SHARP_AC, irsend.capture.decode_type);
ASSERT_EQ(kSharpAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
-
- IRSharpAc ac(0);
- ac.begin();
- ac.setRaw(irsend.capture.state);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto)",
- ac.toString());
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 27C, "
+ "Fan: 2 (Auto)",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// https://github.com/crankyoldgit/IRremoteESP8266/issues/638#issue-421064165
@@ -588,23 +588,25 @@ TEST(TestSharpAcClass, ReconstructKnownState) {
uint8_t on_auto_auto[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0,
0x01};
- ac.on();
- ac.setMode(kSharpAcAuto);
+ ac.setPower(true, false);
ac.setTemp(kSharpAcMinTemp);
ac.setFan(kSharpAcFanAuto);
+ ac.setMode(kSharpAcAuto);
EXPECT_STATE_EQ(on_auto_auto, ac.getRaw(), kSharpAcBits);
- EXPECT_EQ("Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto)",
+ EXPECT_EQ("Power: On, Previous Power: Off, Mode: 0 (Auto), Temp: 15C, "
+ "Fan: 2 (Auto)",
ac.toString());
uint8_t cool_auto_28[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
0x51};
ac.stateReset();
- ac.on();
+ ac.setPower(true, true);
ac.setMode(kSharpAcCool);
- ac.setTemp(28);
ac.setFan(kSharpAcFanAuto);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto)",
+ ac.setTemp(28);
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 2 (Auto)",
ac.toString());
EXPECT_STATE_EQ(cool_auto_28, ac.getRaw(), kSharpAcBits);
}
@@ -619,49 +621,56 @@ TEST(TestSharpAcClass, KnownStates) {
0x31};
ASSERT_TRUE(ac.validChecksum(off_auto_auto));
ac.setRaw(off_auto_auto);
- EXPECT_EQ("Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto)",
+ EXPECT_EQ("Power: Off, Previous Power: On, Mode: 0 (Auto), Temp: 15C, "
+ "Fan: 2 (Auto)",
ac.toString());
uint8_t on_auto_auto[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0,
0x01};
ASSERT_TRUE(ac.validChecksum(on_auto_auto));
ac.setRaw(on_auto_auto);
- EXPECT_EQ("Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto)",
+ EXPECT_EQ("Power: On, Previous Power: Off, Mode: 0 (Auto), Temp: 15C, "
+ "Fan: 2 (Auto)",
ac.toString());
uint8_t cool_auto_28[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
0x51};
ASSERT_TRUE(ac.validChecksum(cool_auto_28));
ac.setRaw(cool_auto_28);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto)",
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 2 (Auto)",
ac.toString());
uint8_t cool_fan1_28[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x42, 0x00, 0x08, 0x80, 0x05, 0xE0,
0x21};
ASSERT_TRUE(ac.validChecksum(cool_fan1_28));
ac.setRaw(cool_fan1_28);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low)",
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 4 (Low)",
ac.toString());
uint8_t cool_fan2_28[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x32, 0x00, 0x08, 0x80, 0x05, 0xE0,
0x51};
ASSERT_TRUE(ac.validChecksum(cool_fan2_28));
ac.setRaw(cool_fan2_28);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium)",
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 3 (Medium)",
ac.toString());
uint8_t cool_fan3_28[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x52, 0x00, 0x08, 0x80, 0x05, 0xE0,
0x31};
ASSERT_TRUE(ac.validChecksum(cool_fan3_28));
ac.setRaw(cool_fan3_28);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 5 (UNKNOWN)",
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 5 (UNKNOWN)",
ac.toString());
uint8_t cool_fan4_28[kSharpAcStateLength] = {
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x72, 0x00, 0x08, 0x80, 0x05, 0xE0,
0x11};
ASSERT_TRUE(ac.validChecksum(cool_fan4_28));
ac.setRaw(cool_fan4_28);
- EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High)",
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 2 (Cool), Temp: 28C, "
+ "Fan: 7 (High)",
ac.toString());
/* Unsupported / Not yet reverse engineered.
uint8_t cool_fan4_28_ion_on[kSharpAcStateLength] = {
@@ -683,7 +692,8 @@ TEST(TestSharpAcClass, KnownStates) {
0x11};
ASSERT_TRUE(ac.validChecksum(dry_auto));
ac.setRaw(dry_auto);
- EXPECT_EQ("Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto)",
+ EXPECT_EQ("Power: On, Previous Power: On, Mode: 3 (Dry), Temp: 15C, "
+ "Fan: 2 (Auto)",
ac.toString());
}
@@ -714,3 +724,89 @@ TEST(TestSharpAcClass, toCommon) {
ASSERT_EQ(-1, ac.toCommon().sleep);
ASSERT_EQ(-1, ac.toCommon().clock);
}
+
+TEST(TestSharpAcClass, PreviousPower) {
+ IRSharpAc ac(kGpioUnused);
+ ac.setPower(false, false);
+ EXPECT_FALSE(ac.getPower());
+ EXPECT_FALSE(ac.getPreviousPower());
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.getPreviousPower());
+ ac.setPower(false);
+ EXPECT_FALSE(ac.getPower());
+ EXPECT_TRUE(ac.getPreviousPower());
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.getPreviousPower());
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_TRUE(ac.getPreviousPower());
+ ac.setPreviousPower(false);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.getPreviousPower());
+ ac.setPreviousPower(true);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_TRUE(ac.getPreviousPower());
+ ac.setPower(true, false);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.getPreviousPower());
+
+ // Data from: https://github.com/crankyoldgit/IRremoteESP8266/pull/1074#discussion_r403407146
+ // Command ON (previously OFF) -> 0xAA 5A CF 10 CB 11 22 00 08 80 00 E0 51
+ const uint8_t on_prev_off[] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xCB, 0x11, 0x22,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0x51};
+ ac.setRaw(on_prev_off);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.getPreviousPower());
+ // Command ON (previously ON) -> 0xAA 5A CF 10 CB 31 22 00 08 80 04 E0 31
+ const uint8_t on_prev_on[] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xCB, 0x31, 0x22,
+ 0x00, 0x08, 0x80, 0x04, 0xE0, 0x31};
+ ac.setRaw(on_prev_on);
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_TRUE(ac.getPreviousPower());
+ // Command OFF (previously ON) -> 0xAA 5A CF 10 CB 21 22 00 08 80 00 E0 61
+ const uint8_t off_prev_on[] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xCB, 0x21, 0x22,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0x61};
+ ac.setRaw(off_prev_on);
+ EXPECT_FALSE(ac.getPower());
+ EXPECT_TRUE(ac.getPreviousPower());
+ /* Extra test data if needed.
+ // Power:OFF Mode:2(Cool) Fan:2(Auto) Temp:22
+ const uint8_t collect1[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x21, 0x22,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0xA1};
+ // Power:ON Mode:2(Cool) Fan:2(Auto) Temp:22
+ const uint8_t collect2[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x11, 0x22,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0x91};
+ // Power:ON Mode:2(Cool) Fan:2(Auto) Temp:23
+ const uint8_t collect3[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC8, 0x31, 0x22,
+ 0x00, 0x08, 0x80, 0x04, 0xE0, 0x01};
+ // Power:ON Mode:2(Cool) Fan:2(Auto) Temp:22
+ const uint8_t collect4[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x31, 0x22,
+ 0x00, 0x08, 0x80, 0x04, 0xE0, 0xF1};
+ // Power:ON Mode:3(Dry) Fan:Automaticly 2(Auto)
+ // Temp:Automaticly 15
+ const uint8_t collect5[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x31, 0x23,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0x11};
+ // Power:ON Mode:2(Cool) Fan:2(Auto) Temp:22
+ const uint8_t collect6[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x31, 0x22,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0xB1};
+ // Power:ON Mode:2(Cool) Fan:3(Medium) Temp:22
+ const uint8_t collect7[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x31, 0x32,
+ 0x00, 0x08, 0x80, 0x05, 0xE0, 0xF1};
+ // Power:OFF Mode:2(Cool) Fan:3(Medium) Temp:22
+ const uint8_t collect8[13] = {
+ 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x21, 0x32,
+ 0x00, 0x08, 0x80, 0x00, 0xE0, 0xB1};
+ */
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Sherwood_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Sherwood_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Sherwood_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Sony_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Sony_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Sony_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Sony_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.6/test/ir_Symphony_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Symphony_test.cpp
new file mode 100644
index 000000000..ee4aadfda
--- /dev/null
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Symphony_test.cpp
@@ -0,0 +1,157 @@
+// Copyright 2020 David Conran
+
+#include "IRac.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for sendSymphony().
+
+// Test sending typical data only.
+TEST(TestSendSymphony, SendDataOnly) {
+ IRsendTest irsend(kGpioUnused);
+ irsend.begin();
+ irsend.sendSymphony(0x137);
+ EXPECT_EQ(
+ "f38000d50"
+ "m1250s400m1250s400m400s1250m1250s400m1250s400m400s1250m400s1250m1250s400"
+ "m400s1250m400s1250m400s1250"
+ "m400s8000"
+ "m1250s400m1250s400m400s1250m1250s400m1250s400m400s1250m400s1250m1250s400"
+ "m400s1250m400s1250m400s1250"
+ "m400s8000",
+ irsend.outputStr());
+}
+
+// Tests for decodeSymphony().
+
+// Decode normal Symphony messages.
+TEST(TestDecodeSymphony, SyntheticSelfDecode) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ // Real-life Symphony code from an actual capture/decode.
+ irsend.reset();
+ irsend.sendSymphony(0x123);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::SYMPHONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSymphonyBits, irsend.capture.bits);
+ EXPECT_EQ(0x123, irsend.capture.value);
+ EXPECT_EQ(0, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+ EXPECT_FALSE(irsend.capture.repeat);
+}
+
+// Decode a real Symphony message.
+TEST(TestDecodeSymphony, RealMessageDecode) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ // Real-life Symphony code from an actual capture/decode.
+ // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1057#issue-577216614
+ irsend.reset();
+ const uint16_t button_1[95] = {
+ 1296, 412, 1294, 386, 420, 1224, 1322, 390, 1290, 390, 420, 1224, 452,
+ 1220, 1314, 394, 420, 1222, 482, 1190, 480, 1192, 452, 7960,
+ 1290, 420, 1290, 390, 418, 1226, 1318, 394, 1262, 416, 420, 1224, 454,
+ 1220, 1292, 416, 422, 1222, 450, 1222, 452, 1218, 454, 8208,
+ 1296, 414, 1292, 386, 418, 1226, 1292, 422, 1260, 420, 424, 1218, 454,
+ 1226, 1312, 390, 420, 1224, 454, 1220, 482, 1186, 454, 7960,
+ 1318, 392, 1264, 416, 392, 1252, 1318, 394, 1288, 394, 418, 1224, 452,
+ 1224, 1292, 422, 414, 1222, 458, 1214, 450, 1222, 454};
+ irsend.sendRaw(button_1, 95, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::SYMPHONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSymphonyBits, irsend.capture.bits);
+ EXPECT_EQ(0x137, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+ EXPECT_FALSE(irsend.capture.repeat);
+
+ // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1057#issuecomment-596038442
+ irsend.reset();
+ const uint16_t power[23] = {
+ 1308, 368, 1310, 368, 448, 1222, 1310, 372, 1308, 400, 442, 1198, 472,
+ 1198, 1284, 396, 444, 1224, 470, 1200, 470, 1198, 472};
+ irsend.sendRaw(power, 23, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::SYMPHONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSymphonyBits, irsend.capture.bits);
+ EXPECT_EQ(0x137, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+ EXPECT_FALSE(irsend.capture.repeat);
+
+ irsend.reset();
+ const uint16_t swing[23] = {
+ 1290, 418, 1286, 392, 422, 1248, 1284, 400, 1294, 386, 422, 1248, 422,
+ 1250, 444, 1228, 424, 1248, 446, 1226, 1258, 420, 446};
+ irsend.sendRaw(swing, 23, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::SYMPHONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSymphonyBits, irsend.capture.bits);
+ EXPECT_EQ(0x13E, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+ EXPECT_FALSE(irsend.capture.repeat);
+}
+
+// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1057#issuecomment-596543641
+TEST(TestDecodeSymphony, RealMessageSentViaLibrary) {
+ IRsendTest irsend(kGpioUnused);
+ IRrecv irrecv(kGpioUnused);
+ irsend.begin();
+
+ irsend.reset();
+ // Generated by the library/ESP8266.
+ const uint16_t rawdata_lib[47] = {
+ 1222, 430, 1250, 436, 410, 1242, 1274, 446, 1274, 412, 414, 1266, 410,
+ 1264, 1252, 436, 436, 1240, 410, 1270, 438, 1242, 410, 8012, 1254, 434,
+ 1258, 432, 438, 1240, 1276, 416, 1252, 434, 438, 1234, 412, 1270, 1250,
+ 442, 412, 1264, 438, 1238, 410, 1270, 438};
+ irsend.sendRaw(rawdata_lib, 47, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::SYMPHONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSymphonyBits, irsend.capture.bits);
+ EXPECT_EQ(0x137, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+ EXPECT_FALSE(irsend.capture.repeat);
+
+ irsend.reset();
+ // Generated by the real remote.
+ const uint16_t rawdata_remote[47] = {
+ 1286, 396, 1286, 396, 446, 1226, 1288, 400, 1294, 388, 444, 1228, 446,
+ 1226, 1286, 396, 444, 1226, 448, 1226, 468, 1204, 448, 7968, 1286, 396,
+ 1286, 396, 470, 1202, 1286, 400, 1286, 396, 446, 1224, 448, 1226, 1288,
+ 396, 446, 1226, 472, 1200, 448, 1226, 472};
+ irsend.sendRaw(rawdata_remote, 47, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(decode_type_t::SYMPHONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSymphonyBits, irsend.capture.bits);
+ EXPECT_EQ(0x137, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+ EXPECT_FALSE(irsend.capture.repeat);
+}
+
+
+TEST(TestUtils, Housekeeping) {
+ ASSERT_EQ("SYMPHONY", typeToString(decode_type_t::SYMPHONY));
+ ASSERT_EQ(decode_type_t::SYMPHONY, strToDecodeType("SYMPHONY"));
+ ASSERT_FALSE(hasACState(decode_type_t::SYMPHONY));
+ ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SYMPHONY));
+ ASSERT_EQ(kSymphonyBits, IRsendTest::defaultBits(decode_type_t::SYMPHONY));
+ ASSERT_EQ(kSymphonyDefaultRepeat,
+ IRsendTest::minRepeats(decode_type_t::SYMPHONY));
+}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Tcl_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Tcl_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Tcl_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Tcl_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Teco_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Teco_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Teco_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Teco_test.cpp
index 635e93a44..f4196c3ae 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Teco_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Teco_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2019 David Conran
#include "ir_Teco.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -387,7 +388,6 @@ TEST(TestDecodeTeco, NormalDecodeWithStrict) {
TEST(TestDecodeTeco, RealNormalExample) {
IRsendTest irsend(0);
IRrecv irrecv(0);
- IRTecoAc ac(0);
irsend.begin();
uint16_t rawData1[73] = {
@@ -408,12 +408,12 @@ TEST(TestDecodeTeco, RealNormalExample) {
EXPECT_EQ(expected1, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
- ac.begin();
- ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 0 (Auto), Sleep: On, "
"Swing: On, Light: Off, Humid: Off, Save: Off, Timer: Off",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
uint16_t rawData2[73] = {
9048, 4472, 636, 548, 636, 1654, 638, 546, 642, 1650, 642, 546, 638,
@@ -433,12 +433,11 @@ TEST(TestDecodeTeco, RealNormalExample) {
EXPECT_EQ(expected2, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
- ac.begin();
- ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: On, Mode: 2 (Dry), Temp: 21C, Fan: 2 (Medium), Sleep: Off, "
"Swing: On, Light: Off, Humid: Off, Save: Off, Timer: Off",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Toshiba_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Toshiba_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Toshiba_test.cpp
index 66c258ae4..e0ae82987 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Toshiba_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Toshiba_test.cpp
@@ -1,5 +1,6 @@
// Copyright 2017 David Conran
#include "ir_Toshiba.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -499,6 +500,11 @@ TEST(TestDecodeToshibaAC, SyntheticExample) {
ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type);
ASSERT_EQ(kToshibaACBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto)",
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Test decoding against captures from a real Toshiba A/C remote.
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Trotec_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Trotec_test.cpp
similarity index 95%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Trotec_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Trotec_test.cpp
index 43cb3fc06..4e8d639fe 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Trotec_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Trotec_test.cpp
@@ -1,5 +1,6 @@
// Copyright 2019 David Conran
#include "ir_Trotec.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -97,11 +98,11 @@ TEST(TestDecodeTrotec, SyntheticDecode) {
EXPECT_EQ(decode_type_t::TROTEC, irsend.capture.decode_type);
EXPECT_EQ(kTrotecBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
- IRTrotecESP ac(0);
- ac.setRaw(irsend.capture.state);
EXPECT_EQ(
"Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 2 (Medium), Sleep: On",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
@@ -176,4 +177,5 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ("TROTEC", typeToString(decode_type_t::TROTEC));
ASSERT_EQ(decode_type_t::TROTEC, strToDecodeType("TROTEC"));
ASSERT_TRUE(hasACState(decode_type_t::TROTEC));
+ ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::TROTEC));
}
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Vestel_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Vestel_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Vestel_test.cpp
index d20a882a6..d3f1febf8 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Vestel_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Vestel_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2019 David Conran
#include "ir_Vestel.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -441,7 +442,6 @@ TEST(TestDecodeVestelAc, NormalDecodeWithStrict) {
TEST(TestDecodeVestelAc, RealNormalExample) {
IRsendTest irsend(0);
IRrecv irrecv(0);
- IRVestelAc ac(0);
irsend.begin();
uint16_t rawData[115] = {
@@ -465,12 +465,12 @@ TEST(TestDecodeVestelAc, RealNormalExample) {
EXPECT_EQ(0xF4410001FF1201ULL, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
- ac.begin();
- ac.setRaw(irsend.capture.value);
EXPECT_EQ(
"Power: On, Mode: 4 (Heat), Temp: 16C, Fan: 1 (Auto), Sleep: Off, "
"Turbo: Off, Ion: On, Swing: Off",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestDecodeVestelAc, RealTimerExample) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Whirlpool_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Whirlpool_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Whirlpool_test.cpp
index 901318326..a6374a7f6 100644
--- a/lib/IRremoteESP8266-2.7.4/test/ir_Whirlpool_test.cpp
+++ b/lib/IRremoteESP8266-2.7.6/test/ir_Whirlpool_test.cpp
@@ -1,6 +1,7 @@
// Copyright 2018 David Conran
#include "ir_Whirlpool.h"
+#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
@@ -66,13 +67,13 @@ TEST(TestDecodeWhirlpoolAC, SyntheticDecode) {
EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
- IRWhirlpoolAc ac(0);
- ac.setRaw(irsend.capture.state);
EXPECT_EQ(
"Model: 1 (DG11J13A), Power Toggle: Off, Mode: 1 (Auto), Temp: 25C, "
"Fan: 0 (Auto), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, "
"Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (Temp)",
- ac.toString());
+ IRAcUtils::resultAcToString(&irsend.capture));
+ stdAc::state_t r, p;
+ ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
TEST(TestDecodeWhirlpoolAC, Real26CFanAutoCoolingSwingOnClock1918) {
diff --git a/lib/IRremoteESP8266-2.7.4/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266-2.7.6/test/ir_Whynter_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/test/ir_Whynter_test.cpp
rename to lib/IRremoteESP8266-2.7.6/test/ir_Whynter_test.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/tools/Makefile b/lib/IRremoteESP8266-2.7.6/tools/Makefile
similarity index 96%
rename from lib/IRremoteESP8266-2.7.4/tools/Makefile
rename to lib/IRremoteESP8266-2.7.6/tools/Makefile
index 0ee8cc563..cfbf2e33c 100644
--- a/lib/IRremoteESP8266-2.7.4/tools/Makefile
+++ b/lib/IRremoteESP8266-2.7.6/tools/Makefile
@@ -51,7 +51,8 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o ir_Pioneer.o \
ir_MWM.o ir_Vestel.o ir_Teco.o ir_Tcl.o ir_Lego.o \
ir_MitsubishiHeavy.o ir_Goodweather.o ir_Inax.o ir_Argo.o \
- ir_Trotec.o ir_Neoclima.o ir_Amcor.o ir_Epson.o
+ ir_Trotec.o ir_Neoclima.o ir_Amcor.o ir_Epson.o ir_Symphony.o \
+ ir_Airwell.o
# Common object files
COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRtext.o IRac.o $(PROTOCOLS)
@@ -237,5 +238,11 @@ ir_Amcor.o : $(USER_DIR)/ir_Amcor.cpp $(USER_DIR)/ir_Amcor.h $(GTEST_HEADERS)
ir_Epson.o : $(USER_DIR)/ir_Epson.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Epson.cpp
+ir_Symphony.o : $(USER_DIR)/ir_Symphony.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Symphony.cpp
+
+ir_Airwell.o : $(USER_DIR)/ir_Airwell.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Airwell.cpp
+
IRac.o : $(USER_DIR)/IRac.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRac.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.7.6/tools/RawToGlobalCache.sh
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/RawToGlobalCache.sh
rename to lib/IRremoteESP8266-2.7.6/tools/RawToGlobalCache.sh
diff --git a/lib/IRremoteESP8266-2.7.4/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.7.6/tools/auto_analyse_raw_data.py
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/auto_analyse_raw_data.py
rename to lib/IRremoteESP8266-2.7.6/tools/auto_analyse_raw_data.py
diff --git a/lib/IRremoteESP8266-2.7.4/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.7.6/tools/auto_analyse_raw_data_test.py
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/auto_analyse_raw_data_test.py
rename to lib/IRremoteESP8266-2.7.6/tools/auto_analyse_raw_data_test.py
diff --git a/lib/IRremoteESP8266-2.7.4/tools/gc_decode.cpp b/lib/IRremoteESP8266-2.7.6/tools/gc_decode.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/gc_decode.cpp
rename to lib/IRremoteESP8266-2.7.6/tools/gc_decode.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/tools/generate_irtext_h.sh b/lib/IRremoteESP8266-2.7.6/tools/generate_irtext_h.sh
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/generate_irtext_h.sh
rename to lib/IRremoteESP8266-2.7.6/tools/generate_irtext_h.sh
diff --git a/lib/IRremoteESP8266-2.7.4/tools/mkkeywords b/lib/IRremoteESP8266-2.7.6/tools/mkkeywords
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/mkkeywords
rename to lib/IRremoteESP8266-2.7.6/tools/mkkeywords
diff --git a/lib/IRremoteESP8266-2.7.4/tools/mode2_decode.cpp b/lib/IRremoteESP8266-2.7.6/tools/mode2_decode.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/mode2_decode.cpp
rename to lib/IRremoteESP8266-2.7.6/tools/mode2_decode.cpp
diff --git a/lib/IRremoteESP8266-2.7.4/tools/scrape_supported_devices.py b/lib/IRremoteESP8266-2.7.6/tools/scrape_supported_devices.py
similarity index 100%
rename from lib/IRremoteESP8266-2.7.4/tools/scrape_supported_devices.py
rename to lib/IRremoteESP8266-2.7.6/tools/scrape_supported_devices.py
diff --git a/lib/OpenTherm-0.9.0/LICENSE b/lib/OpenTherm-0.9.0/LICENSE
new file mode 100644
index 000000000..42a9cdf66
--- /dev/null
+++ b/lib/OpenTherm-0.9.0/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Ihor Melnyk
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/lib/OpenTherm-0.9.0/README.md b/lib/OpenTherm-0.9.0/README.md
new file mode 100644
index 000000000..9482c7403
--- /dev/null
+++ b/lib/OpenTherm-0.9.0/README.md
@@ -0,0 +1,65 @@
+# OpenTherm Arduino/ESP8266 Library
+
+This library provides implementation of OpenTherm protocol.
+
+OpenTherm Library is based on OpenTherm protocol specification v2.2 and works with all OpenTherm compatible boilers. Library can be easily installed into Arduino IDE and compiled for Arduino, ESP8266 and other similar controllers.
+
+OpenTherm protocol requires simple low voltage twowire connection to boiler, but voltage levels (7..15V) still much higher than Arduino/ESP8266 levels, which requires [OpenTherm Adapter](http://ihormelnyk.com/opentherm_adapter).
+
+This version of library uses interrupts to achieve better stability and synchronization with boiler.
+
+## Using OpenTherm Library you will be able:
+- control your boiler remotely (get status, switch on/off heating/water heating, set water temperature and much more)
+- make custom thermostat
+
+## Configuration and Usage:
+```c
+#include
+```
+You have to choose 2 controller GPIO pins which will be used for communication and connected to [OpenTherm Adapter](http://ihormelnyk.com/opentherm_adapter). Controller(Arduino/ESP8266) input pin should support interrupts.
+Controller output pin should be connected to OpenTherm Adapter input pin and vise versa.
+```c
+const int inPin = 2;
+const int outPin = 3;
+```
+Define OpenTherm class instance using constructor which accepts as arguments pin numbers:
+```c
+OpenTherm ot(inPin, outPin);
+```
+Define interrupts handler function for specified above instance:
+```c
+void handleInterrupt() {
+ ot.handleInterrupt();
+}
+```
+Use begin function to initialize OpenTherm instance, specify interrupts handler function as argument
+```c
+void setup()
+{
+ ot.begin(handleInterrupt);
+}
+```
+According to OpenTherm Protocol specification master (controller) must communicate at least every 1 sec. So lets make some requests in loop function:
+```c
+void loop()
+{
+ //Set/Get Boiler Status
+ ot.setBoilerStatus(enableCentralHeating, enableHotWater, enableCooling);
+ //Set Boiler Temperature to 64 degrees C
+ ot.setBoilerTemperature(64);
+ //Get Boiler Temperature
+ float temperature = ot.getBoilerTemperature();
+ delay(1000);
+}
+```
+
+In details [OpenTherm Library](http://ihormelnyk.com/opentherm_library) described [here](http://ihormelnyk.com/opentherm_library).
+
+## OpenTherm Adapter Schematic
+
+
+## Arduino UNO Connection
+
+
+## License
+Copyright (c) 2018 [Ihor Melnyk](http://ihormelnyk.com). Licensed under the [MIT license](/LICENSE?raw=true).
diff --git a/lib/OpenTherm-0.9.0/keywords.txt b/lib/OpenTherm-0.9.0/keywords.txt
new file mode 100644
index 000000000..881d1da7d
--- /dev/null
+++ b/lib/OpenTherm-0.9.0/keywords.txt
@@ -0,0 +1,40 @@
+#######################################
+# Syntax Coloring Map For OpenTherm
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+OpenTherm KEYWORD1
+OpenThermStatus KEYWORD1
+OpenThermResponseStatus KEYWORD1
+OpenThermRequestType KEYWORD1
+OpenThermMessageID KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+begin KEYWORD2
+isReady KEYWORD2
+sendRequest KEYWORD2
+sendRequestAync KEYWORD2
+buildRequest KEYWORD2
+getLastResponseStatus KEYWORD2
+handleInterrupt KEYWORD2
+process KEYWORD2
+end KEYWORD2
+doSomething KEYWORD2
+
+setBoilerStatus KEYWORD2
+setBoilerTemperature KEYWORD2
+getBoilerTemperature KEYWORD2
+
+#######################################
+# Instances (KEYWORD2)
+#######################################
+
+#######################################
+# Constants (LITERAL1)
+#######################################
\ No newline at end of file
diff --git a/lib/OpenTherm-0.9.0/library.properties b/lib/OpenTherm-0.9.0/library.properties
new file mode 100644
index 000000000..003b43eef
--- /dev/null
+++ b/lib/OpenTherm-0.9.0/library.properties
@@ -0,0 +1,10 @@
+name=OpenTherm Library
+version=0.9.0
+author=Ihor Melnyk
+maintainer=Ihor Melnyk
+sentence=OpenTherm Library for HVAC system control communication using Arduino and ESP8266 hardware.
+paragraph=OpenTherm Library is based on OpenTherm protocol specification v2.2 and works with all OpenTherm compatible boilers.
+category=Communication
+url=https://github.com/ihormelnyk/opentherm_library
+architectures=*
+includes=OpenTherm.h
diff --git a/lib/OpenTherm-0.9.0/src/OpenTherm.cpp b/lib/OpenTherm-0.9.0/src/OpenTherm.cpp
new file mode 100644
index 000000000..a08608649
--- /dev/null
+++ b/lib/OpenTherm-0.9.0/src/OpenTherm.cpp
@@ -0,0 +1,410 @@
+/*
+OpenTherm.cpp - OpenTherm Communication Library For Arduino, ESP8266
+Copyright 2018, Ihor Melnyk
+*/
+
+#include "OpenTherm.h"
+
+OpenTherm::OpenTherm(int inPin, int outPin, bool isSlave):
+ status(OpenThermStatus::NOT_INITIALIZED),
+ inPin(inPin),
+ outPin(outPin),
+ isSlave(isSlave),
+ response(0),
+ responseStatus(OpenThermResponseStatus::NONE),
+ responseTimestamp(0),
+ handleInterruptCallback(NULL),
+ processResponseCallback(NULL)
+{
+}
+
+void OpenTherm::begin(void(*handleInterruptCallback)(void), void(*processResponseCallback)(unsigned long, int))
+{
+ pinMode(inPin, INPUT);
+ pinMode(outPin, OUTPUT);
+ if (handleInterruptCallback != NULL) {
+ this->handleInterruptCallback = handleInterruptCallback;
+ attachInterrupt(digitalPinToInterrupt(inPin), handleInterruptCallback, CHANGE);
+ }
+ activateBoiler();
+ status = OpenThermStatus::READY;
+ this->processResponseCallback = processResponseCallback;
+}
+
+void OpenTherm::begin(void(*handleInterruptCallback)(void))
+{
+ begin(handleInterruptCallback, NULL);
+}
+
+bool ICACHE_RAM_ATTR OpenTherm::isReady()
+{
+ return status == OpenThermStatus::READY;
+}
+
+int ICACHE_RAM_ATTR OpenTherm::readState() {
+ return digitalRead(inPin);
+}
+
+void OpenTherm::setActiveState() {
+ digitalWrite(outPin, LOW);
+}
+
+void OpenTherm::setIdleState() {
+ digitalWrite(outPin, HIGH);
+}
+
+void OpenTherm::activateBoiler() {
+ setIdleState();
+ delay(1000);
+}
+
+void OpenTherm::sendBit(bool high) {
+ if (high) setActiveState(); else setIdleState();
+ delayMicroseconds(500);
+ if (high) setIdleState(); else setActiveState();
+ delayMicroseconds(500);
+}
+
+bool OpenTherm::sendRequestAync(unsigned long request)
+{
+ //Serial.println("Request: " + String(request, HEX));
+ noInterrupts();
+ const bool ready = isReady();
+ interrupts();
+
+ if (!ready)
+ return false;
+
+ status = OpenThermStatus::REQUEST_SENDING;
+ response = 0;
+ responseStatus = OpenThermResponseStatus::NONE;
+
+ sendBit(HIGH); //start bit
+ for (int i = 31; i >= 0; i--) {
+ sendBit(bitRead(request, i));
+ }
+ sendBit(HIGH); //stop bit
+ setIdleState();
+
+ status = OpenThermStatus::RESPONSE_WAITING;
+ responseTimestamp = micros();
+ return true;
+}
+
+unsigned long OpenTherm::sendRequest(unsigned long request)
+{
+ if (!sendRequestAync(request)) return 0;
+ while (!isReady()) {
+ process();
+ yield();
+ }
+ return response;
+}
+
+bool OpenTherm::sendResponse(unsigned long request)
+{
+ status = OpenThermStatus::REQUEST_SENDING;
+ response = 0;
+ responseStatus = OpenThermResponseStatus::NONE;
+
+ sendBit(HIGH); //start bit
+ for (int i = 31; i >= 0; i--) {
+ sendBit(bitRead(request, i));
+ }
+ sendBit(HIGH); //stop bit
+ setIdleState();
+ status = OpenThermStatus::READY;
+ return true;
+}
+
+OpenThermResponseStatus OpenTherm::getLastResponseStatus()
+{
+ return responseStatus;
+}
+
+void ICACHE_RAM_ATTR OpenTherm::handleInterrupt()
+{
+ if (isReady())
+ {
+ if (isSlave && readState() == HIGH) {
+ status = OpenThermStatus::RESPONSE_WAITING;
+ }
+ else {
+ return;
+ }
+ }
+
+ unsigned long newTs = micros();
+ if (status == OpenThermStatus::RESPONSE_WAITING) {
+ if (readState() == HIGH) {
+ status = OpenThermStatus::RESPONSE_START_BIT;
+ responseTimestamp = newTs;
+ }
+ else {
+ status = OpenThermStatus::RESPONSE_INVALID;
+ responseTimestamp = newTs;
+ }
+ }
+ else if (status == OpenThermStatus::RESPONSE_START_BIT) {
+ if ((newTs - responseTimestamp < 750) && readState() == LOW) {
+ status = OpenThermStatus::RESPONSE_RECEIVING;
+ responseTimestamp = newTs;
+ responseBitIndex = 0;
+ }
+ else {
+ status = OpenThermStatus::RESPONSE_INVALID;
+ responseTimestamp = newTs;
+ }
+ }
+ else if (status == OpenThermStatus::RESPONSE_RECEIVING) {
+ if ((newTs - responseTimestamp) > 750) {
+ if (responseBitIndex < 32) {
+ response = (response << 1) | !readState();
+ responseTimestamp = newTs;
+ responseBitIndex++;
+ }
+ else { //stop bit
+ status = OpenThermStatus::RESPONSE_READY;
+ responseTimestamp = newTs;
+ }
+ }
+ }
+}
+
+void OpenTherm::process()
+{
+ noInterrupts();
+ OpenThermStatus st = status;
+ unsigned long ts = responseTimestamp;
+ interrupts();
+
+ if (st == OpenThermStatus::READY) return;
+ unsigned long newTs = micros();
+ if (st != OpenThermStatus::NOT_INITIALIZED && (newTs - ts) > 1000000) {
+ status = OpenThermStatus::READY;
+ responseStatus = OpenThermResponseStatus::TIMEOUT;
+ if (processResponseCallback != NULL) {
+ processResponseCallback(response, responseStatus);
+ }
+ }
+ else if (st == OpenThermStatus::RESPONSE_INVALID) {
+ status = OpenThermStatus::DELAY;
+ responseStatus = OpenThermResponseStatus::INVALID;
+ if (processResponseCallback != NULL) {
+ processResponseCallback(response, responseStatus);
+ }
+ }
+ else if (st == OpenThermStatus::RESPONSE_READY) {
+ status = OpenThermStatus::DELAY;
+ responseStatus = (isSlave ? isValidRequest(response) : isValidResponse(response)) ? OpenThermResponseStatus::SUCCESS : OpenThermResponseStatus::INVALID;
+ if (processResponseCallback != NULL) {
+ processResponseCallback(response, responseStatus);
+ }
+ }
+ else if (st == OpenThermStatus::DELAY) {
+ if ((newTs - ts) > 100000) {
+ status = OpenThermStatus::READY;
+ }
+ }
+}
+
+bool OpenTherm::parity(unsigned long frame) //odd parity
+{
+ byte p = 0;
+ while (frame > 0)
+ {
+ if (frame & 1) p++;
+ frame = frame >> 1;
+ }
+ return (p & 1);
+}
+
+OpenThermMessageType OpenTherm::getMessageType(unsigned long message)
+{
+ OpenThermMessageType msg_type = static_cast((message >> 28) & 7);
+ return msg_type;
+}
+
+OpenThermMessageID OpenTherm::getDataID(unsigned long frame)
+{
+ return (OpenThermMessageID)((frame >> 16) & 0xFF);
+}
+
+unsigned long OpenTherm::buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data)
+{
+ unsigned long request = data;
+ if (type == OpenThermMessageType::WRITE_DATA) {
+ request |= 1ul << 28;
+ }
+ request |= ((unsigned long)id) << 16;
+ if (OpenTherm::parity(request)) request |= (1ul << 31);
+ return request;
+}
+
+unsigned long OpenTherm::buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data)
+{
+ unsigned long response = data;
+ response |= type << 28;
+ response |= ((unsigned long)id) << 16;
+ if (OpenTherm::parity(response)) response |= (1ul << 31);
+ return response;
+}
+
+bool OpenTherm::isValidResponse(unsigned long response)
+{
+ if (OpenTherm::parity(response)) return false;
+ byte msgType = (response << 1) >> 29;
+ return msgType == READ_ACK || msgType == WRITE_ACK;
+}
+
+bool OpenTherm::isValidRequest(unsigned long request)
+{
+ if (OpenTherm::parity(request)) return false;
+ byte msgType = (request << 1) >> 29;
+ return msgType == READ_DATA || msgType == WRITE_DATA;
+}
+
+void OpenTherm::end() {
+ if (this->handleInterruptCallback != NULL) {
+ detachInterrupt(digitalPinToInterrupt(inPin));
+ }
+}
+
+const char *OpenTherm::statusToString(OpenThermResponseStatus status)
+{
+ switch (status) {
+ case NONE: return "NONE";
+ case SUCCESS: return "SUCCESS";
+ case INVALID: return "INVALID";
+ case TIMEOUT: return "TIMEOUT";
+ default: return "UNKNOWN";
+ }
+}
+
+const char *OpenTherm::messageTypeToString(OpenThermMessageType message_type)
+{
+ switch (message_type) {
+ case READ_DATA: return "READ_DATA";
+ case WRITE_DATA: return "WRITE_DATA";
+ case INVALID_DATA: return "INVALID_DATA";
+ case RESERVED: return "RESERVED";
+ case READ_ACK: return "READ_ACK";
+ case WRITE_ACK: return "WRITE_ACK";
+ case DATA_INVALID: return "DATA_INVALID";
+ case UNKNOWN_DATA_ID: return "UNKNOWN_DATA_ID";
+ default: return "UNKNOWN";
+ }
+}
+
+//building requests
+
+unsigned long OpenTherm::buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2) {
+ unsigned int data = enableCentralHeating | (enableHotWater << 1) | (enableCooling << 2) | (enableOutsideTemperatureCompensation << 3) | (enableCentralHeating2 << 4);
+ data <<= 8;
+ return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Status, data);
+}
+
+unsigned long OpenTherm::buildSetBoilerTemperatureRequest(float temperature) {
+ unsigned int data = temperatureToData(temperature);
+ return buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TSet, data);
+}
+
+unsigned long OpenTherm::buildSetHotWaterTemperatureRequest(float temperature) {
+ unsigned int data = temperatureToData(temperature);
+ return buildRequest(OpenThermMessageType::WRITE_DATA, OpenThermMessageID::TdhwSet, data);
+}
+
+unsigned long OpenTherm::buildGetBoilerTemperatureRequest() {
+ return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::Tboiler, 0);
+}
+
+unsigned long OpenTherm::buildSlaveConfigurationRequest() {
+ return buildRequest(OpenThermMessageType::READ_DATA, OpenThermMessageID::SConfigSMemberIDcode, 0);
+}
+
+//parsing responses
+bool OpenTherm::isFault(unsigned long response) {
+ return response & 0x1;
+}
+
+bool OpenTherm::isCentralHeatingActive(unsigned long response) {
+ return response & 0x2;
+}
+
+bool OpenTherm::isHotWaterActive(unsigned long response) {
+ return response & 0x4;
+}
+
+bool OpenTherm::isFlameOn(unsigned long response) {
+ return response & 0x8;
+}
+
+bool OpenTherm::isCoolingActive(unsigned long response) {
+ return response & 0x10;
+}
+
+bool OpenTherm::isDiagnostic(unsigned long response) {
+ return response & 0x40;
+}
+
+uint16_t OpenTherm::getUInt(const unsigned long response) {
+ const uint16_t u88 = response & 0xffff;
+ return u88;
+}
+
+float OpenTherm::getFloat(const unsigned long response) {
+ const uint16_t u88 = getUInt(response);
+ const float f = (u88 & 0x8000) ? -(0x10000L - u88) / 256.0f : u88 / 256.0f;
+ return f;
+}
+
+unsigned int OpenTherm::temperatureToData(float temperature) {
+ if (temperature < 0) temperature = 0;
+ if (temperature > 100) temperature = 100;
+ unsigned int data = (unsigned int)(temperature * 256);
+ return data;
+}
+
+//basic requests
+
+unsigned long OpenTherm::setBoilerStatus(bool enableCentralHeating, bool enableHotWater, bool enableCooling, bool enableOutsideTemperatureCompensation, bool enableCentralHeating2) {
+ return sendRequest(buildSetBoilerStatusRequest(enableCentralHeating, enableHotWater, enableCooling, enableOutsideTemperatureCompensation, enableCentralHeating2));
+}
+
+bool OpenTherm::setBoilerTemperature(float temperature) {
+ unsigned long response = sendRequest(buildSetBoilerTemperatureRequest(temperature));
+ return isValidResponse(response);
+}
+
+bool OpenTherm::setHotWaterTemperature(float temperature) {
+ unsigned long response = sendRequest(buildSetHotWaterTemperatureRequest(temperature));
+ return isValidResponse(response);
+}
+
+float OpenTherm::getBoilerTemperature() {
+ unsigned long response = sendRequest(buildGetBoilerTemperatureRequest());
+ return isValidResponse(response) ? getFloat(response) : 0;
+}
+
+float OpenTherm::getReturnTemperature() {
+ unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::Tret, 0));
+ return isValidResponse(response) ? getFloat(response) : 0;
+}
+
+float OpenTherm::getModulation() {
+ unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::RelModLevel, 0));
+ return isValidResponse(response) ? getFloat(response) : 0;
+}
+
+float OpenTherm::getPressure() {
+ unsigned long response = sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::CHPressure, 0));
+ return isValidResponse(response) ? getFloat(response) : 0;
+}
+
+unsigned char OpenTherm::getFault() {
+ return ((sendRequest(buildRequest(OpenThermRequestType::READ, OpenThermMessageID::ASFflags, 0)) >> 8) & 0xff);
+}
+
+unsigned long OpenTherm::getSlaveConfiguration() {
+ return sendRequest(buildSlaveConfigurationRequest());
+}
\ No newline at end of file
diff --git a/lib/OpenTherm-0.9.0/src/OpenTherm.h b/lib/OpenTherm-0.9.0/src/OpenTherm.h
new file mode 100644
index 000000000..22bf965ad
--- /dev/null
+++ b/lib/OpenTherm-0.9.0/src/OpenTherm.h
@@ -0,0 +1,193 @@
+/*
+OpenTherm.h - OpenTherm Library for the ESP8266/Arduino platform
+https://github.com/ihormelnyk/OpenTherm
+http://ihormelnyk.com/pages/OpenTherm
+Licensed under MIT license
+Copyright 2018, Ihor Melnyk
+
+Frame Structure:
+P MGS-TYPE SPARE DATA-ID DATA-VALUE
+0 000 0000 00000000 00000000 00000000
+*/
+
+#ifndef OpenTherm_h
+#define OpenTherm_h
+
+#include
+#include
+
+enum OpenThermResponseStatus {
+ NONE,
+ SUCCESS,
+ INVALID,
+ TIMEOUT
+};
+
+
+enum OpenThermMessageType {
+ /* Master to Slave */
+ READ_DATA = B000,
+ READ = READ_DATA, // for backwared compatibility
+ WRITE_DATA = B001,
+ WRITE = WRITE_DATA, // for backwared compatibility
+ INVALID_DATA = B010,
+ RESERVED = B011,
+ /* Slave to Master */
+ READ_ACK = B100,
+ WRITE_ACK = B101,
+ DATA_INVALID = B110,
+ UNKNOWN_DATA_ID = B111
+};
+
+typedef OpenThermMessageType OpenThermRequestType; // for backwared compatibility
+
+enum OpenThermMessageID {
+ Status, // flag8 / flag8 Master and Slave Status flags.
+ TSet, // f8.8 Control setpoint ie CH water temperature setpoint (°C)
+ MConfigMMemberIDcode, // flag8 / u8 Master Configuration Flags / Master MemberID Code
+ SConfigSMemberIDcode, // flag8 / u8 Slave Configuration Flags / Slave MemberID Code
+ Command, // u8 / u8 Remote Command
+ ASFflags, // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code
+ RBPflags, // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags
+ CoolingControl, // f8.8 Cooling control signal (%)
+ TsetCH2, // f8.8 Control setpoint for 2e CH circuit (°C)
+ TrOverride, // f8.8 Remote override room setpoint
+ TSP, // u8 / u8 Number of Transparent-Slave-Parameters supported by slave
+ TSPindexTSPvalue, // u8 / u8 Index number / Value of referred-to transparent slave parameter.
+ FHBsize, // u8 / u8 Size of Fault-History-Buffer supported by slave
+ FHBindexFHBvalue, // u8 / u8 Index number / Value of referred-to fault-history buffer entry.
+ MaxRelModLevelSetting, // f8.8 Maximum relative modulation level setting (%)
+ MaxCapacityMinModLevel, // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%)
+ TrSet, // f8.8 Room Setpoint (°C)
+ RelModLevel, // f8.8 Relative Modulation Level (%)
+ CHPressure, // f8.8 Water pressure in CH circuit (bar)
+ DHWFlowRate, // f8.8 Water flow rate in DHW circuit. (litres/minute)
+ DayTime, // special / u8 Day of Week and Time of Day
+ Date, // u8 / u8 Calendar date
+ Year, // u16 Calendar year
+ TrSetCH2, // f8.8 Room Setpoint for 2nd CH circuit (°C)
+ Tr, // f8.8 Room temperature (°C)
+ Tboiler, // f8.8 Boiler flow water temperature (°C)
+ Tdhw, // f8.8 DHW temperature (°C)
+ Toutside, // f8.8 Outside temperature (°C)
+ Tret, // f8.8 Return water temperature (°C)
+ Tstorage, // f8.8 Solar storage temperature (°C)
+ Tcollector, // f8.8 Solar collector temperature (°C)
+ TflowCH2, // f8.8 Flow water temperature CH2 circuit (°C)
+ Tdhw2, // f8.8 Domestic hot water temperature 2 (°C)
+ Texhaust, // s16 Boiler exhaust temperature (°C)
+ TdhwSetUBTdhwSetLB = 48, // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C)
+ MaxTSetUBMaxTSetLB, // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C)
+ HcratioUBHcratioLB, // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment
+ TdhwSet = 56, // f8.8 DHW setpoint (°C) (Remote parameter 1)
+ MaxTSet, // f8.8 Max CH water setpoint (°C) (Remote parameters 2)
+ Hcratio, // f8.8 OTC heat curve ratio (°C) (Remote parameter 3)
+ RemoteOverrideFunction = 100, // flag8 / - Function of manual and program changes in master and remote room setpoint.
+ OEMDiagnosticCode = 115, // u16 OEM-specific diagnostic/service code
+ BurnerStarts, // u16 Number of starts burner
+ CHPumpStarts, // u16 Number of starts CH pump
+ DHWPumpValveStarts, // u16 Number of starts DHW pump/valve
+ DHWBurnerStarts, // u16 Number of starts burner during DHW mode
+ BurnerOperationHours, // u16 Number of hours that burner is in operation (i.e. flame on)
+ CHPumpOperationHours, // u16 Number of hours that CH pump has been running
+ DHWPumpValveOperationHours, // u16 Number of hours that DHW pump has been running or DHW valve has been opened
+ DHWBurnerOperationHours, // u16 Number of hours that burner is in operation during DHW mode
+ OpenThermVersionMaster, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master.
+ OpenThermVersionSlave, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave.
+ MasterVersion, // u8 / u8 Master product version number and type
+ SlaveVersion, // u8 / u8 Slave product version number and type
+};
+
+enum OpenThermStatus {
+ NOT_INITIALIZED,
+ READY,
+ DELAY,
+ REQUEST_SENDING,
+ RESPONSE_WAITING,
+ RESPONSE_START_BIT,
+ RESPONSE_RECEIVING,
+ RESPONSE_READY,
+ RESPONSE_INVALID
+};
+
+class OpenTherm
+{
+public:
+ OpenTherm(int inPin = 4, int outPin = 5, bool isSlave = false);
+ volatile OpenThermStatus status;
+ void begin(void(*handleInterruptCallback)(void));
+ void begin(void(*handleInterruptCallback)(void), void(*processResponseCallback)(unsigned long, int));
+ bool isReady();
+ unsigned long sendRequest(unsigned long request);
+ bool sendResponse(unsigned long request);
+ bool sendRequestAync(unsigned long request);
+ static unsigned long buildRequest(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
+ static unsigned long buildResponse(OpenThermMessageType type, OpenThermMessageID id, unsigned int data);
+ OpenThermResponseStatus getLastResponseStatus();
+ const char *statusToString(OpenThermResponseStatus status);
+ void handleInterrupt();
+ void process();
+ void end();
+
+ static bool parity(unsigned long frame);
+ OpenThermMessageType getMessageType(unsigned long message);
+ OpenThermMessageID getDataID(unsigned long frame);
+ const char *messageTypeToString(OpenThermMessageType message_type);
+ bool isValidRequest(unsigned long request);
+ bool isValidResponse(unsigned long response);
+
+ //requests
+ unsigned long buildSetBoilerStatusRequest(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false);
+ unsigned long buildSetBoilerTemperatureRequest(float temperature);
+ unsigned long buildGetBoilerTemperatureRequest();
+ unsigned long buildSetHotWaterTemperatureRequest(float temperature);
+ unsigned long buildSlaveConfigurationRequest();
+
+
+ //responses
+ static bool isFault(unsigned long response);
+ static bool isCentralHeatingActive(unsigned long response);
+ static bool isHotWaterActive(unsigned long response);
+ static bool isFlameOn(unsigned long response);
+ static bool isCoolingActive(unsigned long response);
+ static bool isDiagnostic(unsigned long response);
+ static uint16_t getUInt(const unsigned long response);
+ static float getFloat(const unsigned long response);
+ static unsigned int temperatureToData(float temperature);
+
+ //basic requests
+ unsigned long setBoilerStatus(bool enableCentralHeating, bool enableHotWater = false, bool enableCooling = false, bool enableOutsideTemperatureCompensation = false, bool enableCentralHeating2 = false);
+ bool setBoilerTemperature(float temperature);
+ bool setHotWaterTemperature(float temperature);
+ float getBoilerTemperature();
+ float getReturnTemperature();
+ float getModulation();
+ float getPressure();
+ unsigned char getFault();
+ unsigned long getSlaveConfiguration();
+
+private:
+ const int inPin;
+ const int outPin;
+ const bool isSlave;
+
+ volatile unsigned long response;
+ volatile OpenThermResponseStatus responseStatus;
+ volatile unsigned long responseTimestamp;
+ volatile byte responseBitIndex;
+
+ int readState();
+ void setActiveState();
+ void setIdleState();
+ void activateBoiler();
+
+ void sendBit(bool high);
+ void(*handleInterruptCallback)();
+ void(*processResponseCallback)(unsigned long, int);
+};
+
+#ifndef ICACHE_RAM_ATTR
+#define ICACHE_RAM_ATTR
+#endif
+
+#endif // OpenTherm_h
\ No newline at end of file
diff --git a/lib/TasmotaSerial-2.4.1/README.md b/lib/TasmotaSerial-3.0.0/README.md
similarity index 86%
rename from lib/TasmotaSerial-2.4.1/README.md
rename to lib/TasmotaSerial-3.0.0/README.md
index 019aafc07..d2196ed4c 100644
--- a/lib/TasmotaSerial-2.4.1/README.md
+++ b/lib/TasmotaSerial-3.0.0/README.md
@@ -1,6 +1,7 @@
# TasmotaSerial
Implementation of software serial with hardware serial fallback library for the ESP8266
+Implementation of dual UART hardware serial for the ESP32
Allows for several instances to be active at the same time.
diff --git a/lib/TasmotaSerial-2.4.1/examples/swsertest/swsertest.ino b/lib/TasmotaSerial-3.0.0/examples/swsertest/swsertest.ino
similarity index 100%
rename from lib/TasmotaSerial-2.4.1/examples/swsertest/swsertest.ino
rename to lib/TasmotaSerial-3.0.0/examples/swsertest/swsertest.ino
diff --git a/lib/TasmotaSerial-2.4.1/keywords.txt b/lib/TasmotaSerial-3.0.0/keywords.txt
similarity index 96%
rename from lib/TasmotaSerial-2.4.1/keywords.txt
rename to lib/TasmotaSerial-3.0.0/keywords.txt
index 9cf6d825c..f9bde9254 100644
--- a/lib/TasmotaSerial-2.4.1/keywords.txt
+++ b/lib/TasmotaSerial-3.0.0/keywords.txt
@@ -1,6 +1,6 @@
#######################################
# Syntax Coloring Map for TasmotaSerial
-# (esp8266)
+# (esp8266 and esp32)
#######################################
#######################################
diff --git a/lib/TasmotaSerial-2.4.1/library.json b/lib/TasmotaSerial-3.0.0/library.json
similarity index 70%
rename from lib/TasmotaSerial-2.4.1/library.json
rename to lib/TasmotaSerial-3.0.0/library.json
index 64cde09c9..19197cce4 100644
--- a/lib/TasmotaSerial-2.4.1/library.json
+++ b/lib/TasmotaSerial-3.0.0/library.json
@@ -1,15 +1,17 @@
{
"name": "TasmotaSerial",
- "version": "2.4.1",
+ "version": "3.0.0",
"keywords": [
"serial", "io", "TasmotaSerial"
],
- "description": "Implementation of software serial with hardware serial fallback for ESP8266.",
+ "description": "Implementation of software serial with hardware serial fallback for ESP8266 and ESP32.",
"repository":
{
"type": "git",
"url": "https://github.com/arendst/Tasmota/lib/TasmotaSerial"
},
"frameworks": "arduino",
- "platforms": "espressif8266"
+ "platforms": [
+ "espressif8266", "espressif32"
+ ]
}
diff --git a/lib/TasmotaSerial-2.4.1/library.properties b/lib/TasmotaSerial-3.0.0/library.properties
similarity index 71%
rename from lib/TasmotaSerial-2.4.1/library.properties
rename to lib/TasmotaSerial-3.0.0/library.properties
index b326d7404..d1d9e718a 100644
--- a/lib/TasmotaSerial-2.4.1/library.properties
+++ b/lib/TasmotaSerial-3.0.0/library.properties
@@ -1,9 +1,9 @@
name=TasmotaSerial
-version=2.4.1
+version=3.0.0
author=Theo Arends
maintainer=Theo Arends
-sentence=Implementation of software serial with hardware serial fallback for ESP8266.
+sentence=Implementation of software serial with hardware serial fallback for ESP8266 and ESP32.
paragraph=
category=Signal Input/Output
url=
-architectures=esp8266
+architectures=esp8266,esp32
diff --git a/lib/TasmotaSerial-2.4.1/src/TasmotaSerial.cpp b/lib/TasmotaSerial-3.0.0/src/TasmotaSerial.cpp
similarity index 90%
rename from lib/TasmotaSerial-2.4.1/src/TasmotaSerial.cpp
rename to lib/TasmotaSerial-3.0.0/src/TasmotaSerial.cpp
index 1fad7c0f5..6b41d068c 100644
--- a/lib/TasmotaSerial-2.4.1/src/TasmotaSerial.cpp
+++ b/lib/TasmotaSerial-3.0.0/src/TasmotaSerial.cpp
@@ -1,5 +1,5 @@
/*
- TasmotaSerial.cpp - Minimal implementation of software serial for Tasmota
+ TasmotaSerial.cpp - Implementation of software serial with hardware serial fallback for Tasmota
Copyright (C) 2020 Theo Arends
@@ -27,6 +27,8 @@ extern "C" {
#include
+#ifdef ESP8266
+
// for STAGE and pre-2.6, we can have a single wrapper using attachInterruptArg()
void ICACHE_RAM_ATTR callRxRead(void *self) { ((TasmotaSerial*)self)->rxRead(); };
@@ -79,6 +81,12 @@ static void (*ISRList[16])() = {
tms_isr_15
};
+#else // ESP32
+
+ static int tasmota_serial_index = 2; // Allow UART2 and UART1 only
+
+#endif // ESP8266
+
TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size)
{
m_valid = false;
@@ -87,12 +95,13 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
m_stop_bits = 1;
m_nwmode = nwmode;
serial_buffer_size = buffer_size;
- if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
- return;
- }
m_rx_pin = receive_pin;
m_tx_pin = transmit_pin;
m_in_pos = m_out_pos = 0;
+#ifdef ESP8266
+ if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
+ return;
+ }
if (hardware_fallback && (((3 == m_rx_pin) && (1 == m_tx_pin)) || ((3 == m_rx_pin) && (-1 == m_tx_pin)) || ((-1 == m_rx_pin) && (1 == m_tx_pin)))) {
m_hardserial = true;
}
@@ -120,11 +129,16 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
digitalWrite(m_tx_pin, HIGH);
}
}
+#else // ESP32
+ if (transmit_pin > 33) { return; } // GPIO34 - GPIO39 are Input only
+ m_hardserial = true;
+#endif // ESP8266 - ESP32
m_valid = true;
}
TasmotaSerial::~TasmotaSerial()
{
+#ifdef ESP8266
if (!m_hardserial) {
if (m_rx_pin > -1) {
detachInterrupt(m_rx_pin);
@@ -134,6 +148,7 @@ TasmotaSerial::~TasmotaSerial()
}
}
}
+#endif // ESP8266
}
bool TasmotaSerial::isValidGPIOpin(int pin)
@@ -144,6 +159,7 @@ bool TasmotaSerial::isValidGPIOpin(int pin)
bool TasmotaSerial::begin(long speed, int stop_bits) {
m_stop_bits = ((stop_bits -1) &1) +1;
if (m_hardserial) {
+#ifdef ESP8266
Serial.flush();
if (2 == m_stop_bits) {
Serial.begin(speed, SERIAL_8N2);
@@ -153,6 +169,21 @@ bool TasmotaSerial::begin(long speed, int stop_bits) {
if (m_hardswap) {
Serial.swap();
}
+#else // ESP32
+ if (tasmota_serial_index > 0) { // We only support UART1 and UART2 and keep UART0 for debugging
+ m_uart = tasmota_serial_index;
+ tasmota_serial_index--;
+ TSerial = new HardwareSerial(m_uart);
+ if (2 == m_stop_bits) {
+ TSerial->begin(speed, SERIAL_8N2, m_rx_pin, m_tx_pin);
+ } else {
+ TSerial->begin(speed, SERIAL_8N1, m_rx_pin, m_tx_pin);
+ }
+ } else {
+ m_valid = false;
+ }
+// Serial.printf("TSR: Using UART%d\n", m_uart);
+#endif // ESP8266 - ESP32
} else {
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed;
@@ -168,12 +199,20 @@ bool TasmotaSerial::begin() {
}
bool TasmotaSerial::hardwareSerial() {
+#ifdef ESP8266
return m_hardserial;
+#else
+ return false; // On ESP32 do not mess with Serial0 buffers
+#endif
}
void TasmotaSerial::flush() {
if (m_hardserial) {
+#ifdef ESP8266
Serial.flush();
+#else
+ TSerial->flush();
+#endif
} else {
m_in_pos = m_out_pos = 0;
}
@@ -181,7 +220,11 @@ void TasmotaSerial::flush() {
int TasmotaSerial::peek() {
if (m_hardserial) {
+#ifdef ESP8266
return Serial.peek();
+#else
+ return TSerial->peek();
+#endif
} else {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1;
return m_buffer[m_out_pos];
@@ -191,7 +234,11 @@ int TasmotaSerial::peek() {
int TasmotaSerial::read()
{
if (m_hardserial) {
+#ifdef ESP8266
return Serial.read();
+#else
+ return TSerial->read();
+#endif
} else {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1;
uint32_t ch = m_buffer[m_out_pos];
@@ -203,7 +250,11 @@ int TasmotaSerial::read()
int TasmotaSerial::available()
{
if (m_hardserial) {
+#ifdef ESP8266
return Serial.available();
+#else
+ return TSerial->available();
+#endif
} else {
int avail = m_in_pos - m_out_pos;
if (avail < 0) avail += serial_buffer_size;
@@ -248,7 +299,11 @@ void TasmotaSerial::_fast_write(uint8_t b) {
size_t TasmotaSerial::write(uint8_t b)
{
if (m_hardserial) {
+#ifdef ESP8266
return Serial.write(b);
+#else
+ return TSerial->write(b);
+#endif
} else {
if (-1 == m_tx_pin) return 0;
if (m_high_speed) {
diff --git a/lib/TasmotaSerial-2.4.1/src/TasmotaSerial.h b/lib/TasmotaSerial-3.0.0/src/TasmotaSerial.h
similarity index 90%
rename from lib/TasmotaSerial-2.4.1/src/TasmotaSerial.h
rename to lib/TasmotaSerial-3.0.0/src/TasmotaSerial.h
index 3ef4ee43b..42a3f120e 100644
--- a/lib/TasmotaSerial-2.4.1/src/TasmotaSerial.h
+++ b/lib/TasmotaSerial-3.0.0/src/TasmotaSerial.h
@@ -1,5 +1,5 @@
/*
- TasmotaSerial.h - Minimal implementation of software serial for Tasmota
+ TasmotaSerial.h - Implementation of software serial with hardware serial fallback for Tasmota
Copyright (C) 2020 Theo Arends
@@ -36,6 +36,10 @@
#include
#include
+#ifdef ESP32
+#include
+#endif
+
class TasmotaSerial : public Stream {
public:
TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE);
@@ -55,6 +59,10 @@ class TasmotaSerial : public Stream {
uint32_t getLoopReadMetric(void) const { return m_bit_follow_metric; }
+#ifdef ESP32
+ uint32_t getUart(void) const { return m_uart; }
+#endif
+
using Print::write;
private:
@@ -83,6 +91,12 @@ class TasmotaSerial : public Stream {
uint8_t *m_buffer;
void _fast_write(uint8_t b); // IRAM minimized version
+
+#ifdef ESP32
+ HardwareSerial *TSerial;
+ int m_uart = 0;
+#endif
+
};
#endif // TasmotaSerial_h
diff --git a/lib/Unishox-1.0-shadinger/generator/generator.c b/lib/Unishox-1.0-shadinger/generator/generator.c
new file mode 100644
index 000000000..81c46649e
--- /dev/null
+++ b/lib/Unishox-1.0-shadinger/generator/generator.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 Siara Logics (cc)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @author Arundale R.
+ *
+ */
+
+// Pre-compute c_95[] and l_95[]
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef unsigned char byte;
+
+enum {SHX_SET1 = 0, SHX_SET1A, SHX_SET1B, SHX_SET2, SHX_SET3, SHX_SET4, SHX_SET4A};
+char us_vcodes[] = {0, 2, 3, 4, 10, 11, 12, 13, 14, 30, 31};
+char us_vcode_lens[] = {2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5};
+char us_sets[][11] =
+ {{ 0, ' ', 'e', 0, 't', 'a', 'o', 'i', 'n', 's', 'r'},
+ { 0, 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b', 'g', 'w'},
+ {'f', 'y', 'v', 'k', 'q', 'j', 'x', 'z', 0, 0, 0},
+ { 0, '9', '0', '1', '2', '3', '4', '5', '6', '7', '8'},
+ {'.', ',', '-', '/', '?', '+', ' ', '(', ')', '$', '@'},
+ {';', '#', ':', '<', '^', '*', '"', '{', '}', '[', ']'},
+ {'=', '%', '\'', '>', '&', '_', '!', '\\', '|', '~', '`'}};
+ // {{ 0, ' ', 'e', 0, 't', 'a', 'o', 'i', 'n', 's', 'r'},
+ // { 0, 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b', 'g', 'w'},
+ // {'f', 'y', 'v', 'k', 'q', 'j', 'x', 'z', 0, 0, 0},
+ // { 0, '9', '0', '1', '2', '3', '4', '5', '6', '7', '8'},
+ // {'.', ',', '-', '/', '=', '+', ' ', '(', ')', '$', '%'},
+ // {'&', ';', ':', '<', '>', '*', '"', '{', '}', '[', ']'},
+ // {'@', '?', '\'', '^', '#', '_', '!', '\\', '|', '~', '`'}};
+
+unsigned int c_95[95] ;
+unsigned char l_95[95] ;
+
+
+void init_coder() {
+ for (int i = 0; i < 7; i++) {
+ for (int j = 0; j < 11; j++) {
+ char c = us_sets[i][j];
+ if (c != 0 && c != 32) {
+ int ascii = c - 32;
+ //int prev_code = c_95[ascii];
+ //int prev_code_len = l_95[ascii];
+ switch (i) {
+ case SHX_SET1: // just us_vcode
+ c_95[ascii] = (us_vcodes[j] << (16 - us_vcode_lens[j]));
+ l_95[ascii] = us_vcode_lens[j];
+ //checkPreus_vcodes(c, prev_code, prev_code_len, c_95[ascii], l_95[ascii]);
+ if (c >= 'a' && c <= 'z') {
+ ascii -= ('a' - 'A');
+ //prev_code = c_95[ascii];
+ //prev_code_len = l_95[ascii];
+ c_95[ascii] = (2 << 12) + (us_vcodes[j] << (12 - us_vcode_lens[j]));
+ l_95[ascii] = 4 + us_vcode_lens[j];
+ }
+ break;
+ case SHX_SET1A: // 000 + us_vcode
+ c_95[ascii] = 0 + (us_vcodes[j] << (13 - us_vcode_lens[j]));
+ l_95[ascii] = 3 + us_vcode_lens[j];
+ //checkPreus_vcodes(c, prev_code, prev_code_len, c_95[ascii], l_95[ascii]);
+ if (c >= 'a' && c <= 'z') {
+ ascii -= ('a' - 'A');
+ //prev_code = c_95[ascii];
+ //prev_code_len = l_95[ascii];
+ c_95[ascii] = (2 << 12) + 0 + (us_vcodes[j] << (9 - us_vcode_lens[j]));
+ l_95[ascii] = 4 + 3 + us_vcode_lens[j];
+ }
+ break;
+ case SHX_SET1B: // 00110 + us_vcode
+ c_95[ascii] = (6 << 11) + (us_vcodes[j] << (11 - us_vcode_lens[j]));
+ l_95[ascii] = 5 + us_vcode_lens[j];
+ //checkPreus_vcodes(c, prev_code, prev_code_len, c_95[ascii], l_95[ascii]);
+ if (c >= 'a' && c <= 'z') {
+ ascii -= ('a' - 'A');
+ //prev_code = c_95[ascii];
+ //prev_code_len = l_95[ascii];
+ c_95[ascii] = (2 << 12) + (6 << 7) + (us_vcodes[j] << (7 - us_vcode_lens[j]));
+ l_95[ascii] = 4 + 5 + us_vcode_lens[j];
+ }
+ break;
+ case SHX_SET2: // 0011100 + us_vcode
+ c_95[ascii] = (28 << 9) + (us_vcodes[j] << (9 - us_vcode_lens[j]));
+ l_95[ascii] = 7 + us_vcode_lens[j];
+ break;
+ case SHX_SET3: // 0011101 + us_vcode
+ c_95[ascii] = (29 << 9) + (us_vcodes[j] << (9 - us_vcode_lens[j]));
+ l_95[ascii] = 7 + us_vcode_lens[j];
+ break;
+ case SHX_SET4: // 0011110 + us_vcode
+ c_95[ascii] = (30 << 9) + (us_vcodes[j] << (9 - us_vcode_lens[j]));
+ l_95[ascii] = 7 + us_vcode_lens[j];
+ break;
+ case SHX_SET4A: // 0011111 + us_vcode
+ c_95[ascii] = (31 << 9) + (us_vcodes[j] << (9 - us_vcode_lens[j]));
+ l_95[ascii] = 7 + us_vcode_lens[j];
+ }
+ //checkPreus_vcodes(c, prev_code, prev_code_len, c_95[ascii], l_95[ascii]);
+ }
+ }
+ }
+ c_95[0] = 16384;
+ l_95[0] = 3;
+
+}
+
+int main(int argv, char *args[]) {
+ init_coder();
+
+ printf("uint16_t c_95[95] PROGMEM = {");
+ for (uint8_t i = 0; i<95; i++) {
+ if (i) { printf(", "); }
+ printf("0x%04X", c_95[i]);
+ }
+ printf(" };\n");
+
+ printf("uint8_t l_95[95] PROGMEM = {");
+ for (uint8_t i = 0; i<95; i++) {
+ if (i) { printf(", "); }
+ printf("%6d", l_95[i]);
+ }
+ printf(" };\n");
+
+ printf("\n\n");
+
+ printf("uint16_t c_95[95] PROGMEM = {");
+ for (uint8_t i = 0; i<95; i++) {
+ if (i) { printf(", "); }
+ printf("%5d", c_95[i]);
+ }
+ printf(" };\n");
+
+ printf("uint8_t l_95[95] PROGMEM = {");
+ for (uint8_t i = 0; i<95; i++) {
+ if (i) { printf(", "); }
+ printf("%5d", l_95[i]);
+ }
+ printf(" };\n");
+
+
+ printf("uint16_t cl_95[95] PROGMEM = {");
+ for (uint8_t i = 0; i<95; i++) {
+ if (i) { printf(", "); }
+ printf("0x%04X + %2d", c_95[i], l_95[i]);
+ }
+ printf(" };\n");
+
+}
\ No newline at end of file
diff --git a/lib/Unishox-1.0-shadinger/generator/remapping.xlsx b/lib/Unishox-1.0-shadinger/generator/remapping.xlsx
new file mode 100644
index 000000000..94a82ecde
Binary files /dev/null and b/lib/Unishox-1.0-shadinger/generator/remapping.xlsx differ
diff --git a/lib/Unishox-1.0-shadinger/library.properties b/lib/Unishox-1.0-shadinger/library.properties
new file mode 100644
index 000000000..138b2027c
--- /dev/null
+++ b/lib/Unishox-1.0-shadinger/library.properties
@@ -0,0 +1,8 @@
+name=Unishox Compressor Decompressor highly customized and optimized for ESP8266 and Tasmota
+version=1.0
+author=Arundale Ramanathan, Stephan Hadinger
+maintainer=Arun , Stephan
+sentence=Unishox compression for Tasmota Rules
+paragraph=It is based on Unishox hybrid encoding technique. This version has specific Unicode code removed for size.
+url=https://github.com/siara-cc/Unishox
+architectures=esp8266
diff --git a/lib/Unishox-1.0-shadinger/src/unishox.cpp b/lib/Unishox-1.0-shadinger/src/unishox.cpp
new file mode 100644
index 000000000..72c9d3915
--- /dev/null
+++ b/lib/Unishox-1.0-shadinger/src/unishox.cpp
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2019 Siara Logics (cc)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @author Arundale R.
+ *
+ */
+
+/*
+ *
+ * This is a highly modified and optimized version of Unishox
+ * for Tasmota, aimed at compressing `Rules` which are typically
+ * short strings from 50 to 500 bytes.
+ *
+ * - moved to C++ (but still C-style)
+ * - c_95[] and l_95[] are pre-computed
+ * - all arrays in PROGMEM
+ * - removed all Unicode specific code to get code smaller, Unicode is rare in rules and encoded as pure binary
+ * - removed prev_lines management to reduce code size, we don't track previous encodings
+ * - using C++ const instead of #define
+ * - reusing the Unicode market to encode pure binary, which is 3 bits instead of 9
+ * - reverse binary encoding to 255-byte, favoring short encoding for values above 127, typical of Unicode
+ * - remove 2 bits encoding for Counts, since it could lead to a series of more than 8 consecutive 0-bits and output NULL char.
+ * Minimum encoding is 5 bits, which means spending 3+1=4 more bits for values in the range 0..3
+ * - removed CRLF encoding and reusing entry for RPT, saving 3 bits for repeats. Note: any CR will be binary encded
+ * - add safeguard to the output size (len_out), note that the compress buffer needs to be 4 bytes larger than actual compressed output.
+ * This is needed to avoid crash, since output can have ~30 bits
+ * - combined c_95[] and l_95[] to a single array to save space
+ * - Changed mapping of some characters in Set3, Set4 and Set4A, favoring frequent characters in rules and javascript
+ * - Added escape mechanism to ensure we never output NULL char. The marker is 0x2A which looked rare in preliminary tests
+ *
+ * @author Stephan Hadinger
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "unishox.h"
+
+typedef unsigned char byte;
+// we squeeze both c_95[] and l_95[] in a sinle array.
+// c_95[] uses only the 3 upper nibbles (or 12 most signifcant bits), while the last nibble encodes length (3..13)
+uint16_t cl_95[95] PROGMEM = {0x4000 + 3, 0x3F80 + 11, 0x3D80 + 11, 0x3C80 + 10, 0x3BE0 + 12, 0x3E80 + 10, 0x3F40 + 11, 0x3EC0 + 10, 0x3BA0 + 11, 0x3BC0 + 11, 0x3D60 + 11, 0x3B60 + 11, 0x3A80 + 10, 0x3AC0 + 10, 0x3A00 + 9, 0x3B00 + 10, 0x38C0 + 10, 0x3900 + 10, 0x3940 + 11, 0x3960 + 11, 0x3980 + 11, 0x39A0 + 11, 0x39C0 + 11, 0x39E0 + 12, 0x39F0 + 12, 0x3880 + 10, 0x3CC0 + 10, 0x3C00 + 9, 0x3D00 + 10, 0x3E00 + 9, 0x3F00 + 10, 0x3B40 + 11, 0x3BF0 + 12, 0x2B00 + 8, 0x21C0 + 11, 0x20C0 + 10, 0x2100 + 10, 0x2600 + 7, 0x2300 + 11, 0x21E0 + 12, 0x2140 + 11, 0x2D00 + 8, 0x2358 + 13, 0x2340 + 12, 0x2080 + 10, 0x21A0 + 11, 0x2E00 + 8, 0x2C00 + 8, 0x2180 + 11, 0x2350 + 13, 0x2F80 + 9, 0x2F00 + 9, 0x2A00 + 8, 0x2160 + 11, 0x2330 + 12, 0x21F0 + 12, 0x2360 + 13, 0x2320 + 12, 0x2368 + 13, 0x3DE0 + 12, 0x3FA0 + 11, 0x3DF0 + 12, 0x3D40 + 11, 0x3F60 + 11, 0x3FF0 + 12, 0xB000 + 4, 0x1C00 + 7, 0x0C00 + 6, 0x1000 + 6, 0x6000 + 3, 0x3000 + 7, 0x1E00 + 8, 0x1400 + 7, 0xD000 + 4, 0x3580 + 9, 0x3400 + 8, 0x0800 + 6, 0x1A00 + 7, 0xE000 + 4, 0xC000 + 4, 0x1800 + 7, 0x3500 + 9, 0xF800 + 5, 0xF000 + 5, 0xA000 + 4, 0x1600 + 7, 0x3300 + 8, 0x1F00 + 8, 0x3600 + 9, 0x3200 + 8, 0x3680 + 9, 0x3DA0 + 11, 0x3FC0 + 11, 0x3DC0 + 11, 0x3FE0 + 12 };
+// Original version with c/l separate
+// uint16_t c_95[95] PROGMEM = {0x4000, 0x3F80, 0x3D80, 0x3C80, 0x3BE0, 0x3E80, 0x3F40, 0x3EC0, 0x3BA0, 0x3BC0, 0x3D60, 0x3B60, 0x3A80, 0x3AC0, 0x3A00, 0x3B00, 0x38C0, 0x3900, 0x3940, 0x3960, 0x3980, 0x39A0, 0x39C0, 0x39E0, 0x39F0, 0x3880, 0x3CC0, 0x3C00, 0x3D00, 0x3E00, 0x3F00, 0x3B40, 0x3BF0, 0x2B00, 0x21C0, 0x20C0, 0x2100, 0x2600, 0x2300, 0x21E0, 0x2140, 0x2D00, 0x2358, 0x2340, 0x2080, 0x21A0, 0x2E00, 0x2C00, 0x2180, 0x2350, 0x2F80, 0x2F00, 0x2A00, 0x2160, 0x2330, 0x21F0, 0x2360, 0x2320, 0x2368, 0x3DE0, 0x3FA0, 0x3DF0, 0x3D40, 0x3F60, 0x3FF0, 0xB000, 0x1C00, 0x0C00, 0x1000, 0x6000, 0x3000, 0x1E00, 0x1400, 0xD000, 0x3580, 0x3400, 0x0800, 0x1A00, 0xE000, 0xC000, 0x1800, 0x3500, 0xF800, 0xF000, 0xA000, 0x1600, 0x3300, 0x1F00, 0x3600, 0x3200, 0x3680, 0x3DA0, 0x3FC0, 0x3DC0, 0x3FE0 };
+// uint8_t l_95[95] PROGMEM = { 3, 11, 11, 10, 12, 10, 11, 10, 11, 11, 11, 11, 10, 10, 9, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 10, 10, 9, 10, 9, 10, 11, 12, 8, 11, 10, 10, 7, 11, 12, 11, 8, 13, 12, 10, 11, 8, 8, 11, 13, 9, 9, 8, 11, 12, 12, 13, 12, 13, 12, 11, 12, 11, 11, 12, 4, 7, 6, 6, 3, 7, 8, 7, 4, 9, 8, 6, 7, 4, 4, 7, 9, 5, 5, 4, 7, 8, 8, 9, 8, 9, 11, 11, 11, 12 };
+
+enum {SHX_STATE_1 = 1, SHX_STATE_2}; // removed Unicode state
+
+enum {SHX_SET1 = 0, SHX_SET1A, SHX_SET1B, SHX_SET2, SHX_SET3, SHX_SET4, SHX_SET4A};
+// changed mapping in Set3, Set4, Set4A to accomodate frequencies in Rules and Javascript
+char sets[][11] PROGMEM =
+ {{ 0, ' ', 'e', 0, 't', 'a', 'o', 'i', 'n', 's', 'r'},
+ { 0, 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b', 'g', 'w'},
+ {'f', 'y', 'v', 'k', 'q', 'j', 'x', 'z', 0, 0, 0},
+ { 0, '9', '0', '1', '2', '3', '4', '5', '6', '7', '8'},
+ {'.', ',', '-', '/', '?', '+', ' ', '(', ')', '$', '@'},
+ {';', '#', ':', '<', '^', '*', '"', '{', '}', '[', ']'},
+ {'=', '%', '\'', '>', '&', '_', '!', '\\', '|', '~', '`'}};
+ // {{ 0, ' ', 'e', 0, 't', 'a', 'o', 'i', 'n', 's', 'r'},
+ // { 0, 'l', 'c', 'd', 'h', 'u', 'p', 'm', 'b', 'g', 'w'},
+ // {'f', 'y', 'v', 'k', 'q', 'j', 'x', 'z', 0, 0, 0},
+ // { 0, '9', '0', '1', '2', '3', '4', '5', '6', '7', '8'},
+ // {'.', ',', '-', '/', '=', '+', ' ', '(', ')', '$', '%'},
+ // {'&', ';', ':', '<', '>', '*', '"', '{', '}', '[', ']'},
+ // {'@', '?', '\'', '^', '#', '_', '!', '\\', '|', '~', '`'}};
+
+// Decoder is designed for using less memory, not speed
+// Decode lookup table for code index and length
+// First 2 bits 00, Next 3 bits indicate index of code from 0,
+// last 3 bits indicate code length in bits
+// 0, 1, 2, 3, 4,
+char us_vcode[32] PROGMEM =
+ {2 + (0 << 3), 3 + (3 << 3), 3 + (1 << 3), 4 + (6 << 3), 0,
+// 5, 6, 7, 8, 9, 10
+ 4 + (4 << 3), 3 + (2 << 3), 4 + (8 << 3), 0, 0, 0,
+// 11, 12, 13, 14, 15
+ 4 + (7 << 3), 0, 4 + (5 << 3), 0, 5 + (9 << 3),
+// 16, 17, 18, 19, 20, 21, 22, 23
+ 0, 0, 0, 0, 0, 0, 0, 0,
+// 24, 25, 26, 27, 28, 29, 30, 31
+ 0, 0, 0, 0, 0, 0, 0, 5 + (10 << 3)};
+// 0, 1, 2, 3, 4, 5, 6, 7,
+char us_hcode[32] PROGMEM =
+ {1 + (1 << 3), 2 + (0 << 3), 0, 3 + (2 << 3), 0, 0, 0, 5 + (3 << 3),
+// 8, 9, 10, 11, 12, 13, 14, 15,
+ 0, 0, 0, 0, 0, 0, 0, 5 + (5 << 3),
+// 16, 17, 18, 19, 20, 21, 22, 23
+ 0, 0, 0, 0, 0, 0, 0, 5 + (4 << 3),
+// 24, 25, 26, 27, 28, 29, 30, 31
+ 0, 0, 0, 0, 0, 0, 0, 5 + (6 << 3)};
+
+const char ESCAPE_MARKER = 0x2A; // Escape any null char
+
+const uint16_t TERM_CODE = 0x37C0; // 0b0011011111000000
+const uint16_t TERM_CODE_LEN = 10;
+const uint16_t DICT_CODE = 0x0000;
+const uint16_t DICT_CODE_LEN = 5;
+const uint16_t DICT_OTHER_CODE = 0x0000; // not used
+const uint16_t DICT_OTHER_CODE_LEN = 6;
+// const uint16_t RPT_CODE = 0x2370;
+// const uint16_t RPT_CODE_LEN = 13;
+const uint16_t RPT_CODE_TASMOTA = 0x3780;
+const uint16_t RPT_CODE_TASMOTA_LEN = 10;
+const uint16_t BACK2_STATE1_CODE = 0x2000; // 0010 = back to lower case
+const uint16_t BACK2_STATE1_CODE_LEN = 4;
+const uint16_t BACK_FROM_UNI_CODE = 0xFE00;
+const uint16_t BACK_FROM_UNI_CODE_LEN = 8;
+// const uint16_t CRLF_CODE = 0x3780;
+// const uint16_t CRLF_CODE_LEN = 10;
+const uint16_t LF_CODE = 0x3700;
+const uint16_t LF_CODE_LEN = 9;
+const uint16_t TAB_CODE = 0x2400;
+const uint16_t TAB_CODE_LEN = 7;
+// const uint16_t UNI_CODE = 0x8000; // Unicode disabled
+// const uint16_t UNI_CODE_LEN = 3;
+// const uint16_t UNI_STATE_SPL_CODE = 0xF800;
+// const uint16_t UNI_STATE_SPL_CODE_LEN = 5;
+// const uint16_t UNI_STATE_DICT_CODE = 0xFC00;
+// const uint16_t UNI_STATE_DICT_CODE_LEN = 7;
+// const uint16_t CONT_UNI_CODE = 0x2800;
+// const uint16_t CONT_UNI_CODE_LEN = 7;
+const uint16_t ALL_UPPER_CODE = 0x2200;
+const uint16_t ALL_UPPER_CODE_LEN = 8;
+const uint16_t SW2_STATE2_CODE = 0x3800;
+const uint16_t SW2_STATE2_CODE_LEN = 7;
+const uint16_t ST2_SPC_CODE = 0x3B80;
+const uint16_t ST2_SPC_CODE_LEN = 11;
+const uint16_t BIN_CODE_TASMOTA = 0x8000;
+const uint16_t BIN_CODE_TASMOTA_LEN = 3;
+// const uint16_t BIN_CODE = 0x2000;
+// const uint16_t BIN_CODE_LEN = 9;
+
+#define NICE_LEN 5
+
+// uint16_t mask[] PROGMEM = {0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 0xFC00, 0xFE00, 0xFF00};
+uint8_t mask[] PROGMEM = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
+
+int append_bits(char *out, size_t ol, unsigned int code, int clen, byte state) {
+
+ byte cur_bit;
+ byte blen;
+ unsigned char a_byte;
+
+ if (state == SHX_STATE_2) {
+ // remove change state prefix
+ if ((code >> 9) == 0x1C) {
+ code <<= 7;
+ clen -= 7;
+ }
+ //if (code == 14272 && clen == 10) {
+ // code = 9084;
+ // clen = 14;
+ //}
+ }
+ while (clen > 0) {
+ cur_bit = ol % 8;
+ blen = (clen > 8 ? 8 : clen);
+ // a_byte = (code & pgm_read_word(&mask[blen - 1])) >> 8;
+ // a_byte = (code & (pgm_read_word(&mask[blen - 1]) << 8)) >> 8;
+ a_byte = (code >> 8) & pgm_read_word(&mask[blen - 1]);
+ a_byte >>= cur_bit;
+ if (blen + cur_bit > 8)
+ blen = (8 - cur_bit);
+ if (out) { // if out == nullptr, then we are in dry-run mode
+ if (cur_bit == 0)
+ out[ol / 8] = a_byte;
+ else
+ out[ol / 8] |= a_byte;
+ }
+ code <<= blen;
+ ol += blen;
+ if ((out) && (0 == ol % 8)) { // if out == nullptr, dry-run mode. We miss the escaping of characters in the length
+ // we completed a full byte
+ char last_c = out[(ol / 8) - 1];
+ if ((0 == last_c) || (ESCAPE_MARKER == last_c)) {
+ out[ol / 8] = 1 + last_c; // increment to 0x01 or 0x2B
+ out[(ol / 8) -1] = ESCAPE_MARKER; // replace old value with marker
+ ol += 8; // add one full byte
+ }
+ }
+ clen -= blen;
+ }
+ return ol;
+}
+
+// First five bits are code and Last three bits of codes represent length
+// removing last 2 bytes, unused, we will never have values above 600 bytes
+// const byte codes[7] = {0x01, 0x82, 0xC3, 0xE5, 0xED, 0xF5, 0xFD};
+// const byte bit_len[7] = {2, 5, 7, 9, 12, 16, 17};
+// const uint16_t adder[7] = {0, 4, 36, 164, 676, 4772, 0};
+byte codes[] PROGMEM = { 0x82, 0xC3, 0xE5, 0xED, 0xF5 };
+byte bit_len[] PROGMEM = { 5, 7, 9, 12, 16 };
+// uint16_t adder[7] PROGMEM = { 0, 32, 160, 672, 4768 }; // no more used
+
+int encodeCount(char *out, int ol, int count) {
+ int till = 0;
+ int base = 0;
+ for (int i = 0; i < sizeof(bit_len); i++) {
+ uint32_t bit_len_i = pgm_read_byte(&bit_len[i]);
+ till += (1 << bit_len_i);
+ if (count < till) {
+ byte codes_i = pgm_read_byte(&codes[i]);
+ ol = append_bits(out, ol, (codes_i & 0xF8) << 8, codes_i & 0x07, 1);
+ // ol = append_bits(out, ol, (count - pgm_read_word(&adder[i])) << (16 - bit_len_i), bit_len_i, 1);
+ ol = append_bits(out, ol, (count - base) << (16 - bit_len_i), bit_len_i, 1);
+ return ol;
+ }
+ base = till;
+ }
+ return ol;
+}
+
+int matchOccurance(const char *in, int len, int l, char *out, int *ol, byte *state, byte *is_all_upper) {
+ int j, k;
+ int longest_dist = 0;
+ int longest_len = 0;
+ for (j = l - NICE_LEN; j >= 0; j--) {
+ for (k = l; k < len && j + k - l < l; k++) {
+ if (in[k] != in[j + k - l])
+ break;
+ }
+ // while ((((unsigned char) in[k]) >> 6) == 2)
+ // k--; // Skip partial UTF-8 matches
+ //if ((in[k - 1] >> 3) == 0x1E || (in[k - 1] >> 4) == 0x0E || (in[k - 1] >> 5) == 0x06)
+ // k--;
+ if (k - l > NICE_LEN - 1) {
+ int match_len = k - l - NICE_LEN;
+ int match_dist = l - j - NICE_LEN + 1;
+ if (match_len > longest_len) {
+ longest_len = match_len;
+ longest_dist = match_dist;
+ }
+ }
+ }
+ if (longest_len) {
+ if (*state == SHX_STATE_2 || *is_all_upper) {
+ *is_all_upper = 0;
+ *state = SHX_STATE_1;
+ *ol = append_bits(out, *ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, *state);
+ }
+ *ol = append_bits(out, *ol, DICT_CODE, DICT_CODE_LEN, 1);
+ *ol = encodeCount(out, *ol, longest_len);
+ *ol = encodeCount(out, *ol, longest_dist);
+ l += (longest_len + NICE_LEN);
+ l--;
+ return l;
+ }
+ return -l;
+}
+
+// Compress a buffer.
+// Inputs:
+// - in: non-null pointer to a buffer of bytes to be compressed. Progmem is not valid. Null bytes are valid.
+// - len: size of the input buffer. 0 is valid for empty buffer
+// - out: pointer to output buffer. out is nullptr, the compressor does a dry-run and reports the compressed size without writing bytes
+// - len_out: length in bytes of the output buffer.
+// Output:
+// - if >= 0: size of the compressed buffer. The output buffer does not contain NULL bytes, and it is not NULL terminated
+// - if < 0: an error occured, most certainly the output buffer was not large enough
+int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out) {
+
+ char *ptr;
+ byte bits;
+ byte state;
+
+ int l, ll, ol;
+ char c_in, c_next;
+ byte is_upper, is_all_upper;
+
+ ol = 0;
+ state = SHX_STATE_1;
+ is_all_upper = 0;
+ for (l=0; l 0) {
+ continue;
+ }
+ l = -l;
+ }
+ if (state == SHX_STATE_2) { // if Set2
+ if ((c_in >= ' ' && c_in <= '@') ||
+ (c_in >= '[' && c_in <= '`') ||
+ (c_in >= '{' && c_in <= '~')) {
+ } else {
+ state = SHX_STATE_1; // back to Set1 and lower case
+ ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state);
+ }
+ }
+
+ is_upper = 0;
+ if (c_in >= 'A' && c_in <= 'Z')
+ is_upper = 1;
+ else {
+ if (is_all_upper) {
+ is_all_upper = 0;
+ ol = append_bits(out, ol, BACK2_STATE1_CODE, BACK2_STATE1_CODE_LEN, state);
+ }
+ }
+
+ c_next = 0;
+ if (l+1 < len)
+ c_next = in[l+1];
+
+ if (c_in >= 32 && c_in <= 126) {
+ if (is_upper && !is_all_upper) {
+ for (ll=l+5; ll>=l && ll 'Z')
+ break;
+ }
+ if (ll == l-1) {
+ ol = append_bits(out, ol, ALL_UPPER_CODE, ALL_UPPER_CODE_LEN, state); // CapsLock
+ is_all_upper = 1;
+ }
+ }
+ if (state == SHX_STATE_1 && c_in >= '0' && c_in <= '9') {
+ ol = append_bits(out, ol, SW2_STATE2_CODE, SW2_STATE2_CODE_LEN, state); // Switch to sticky Set2
+ state = SHX_STATE_2;
+ }
+ c_in -= 32;
+ if (is_all_upper && is_upper)
+ c_in += 32;
+ if (c_in == 0 && state == SHX_STATE_2)
+ ol = append_bits(out, ol, ST2_SPC_CODE, ST2_SPC_CODE_LEN, state); // space from Set2 ionstead of Set1
+ else {
+ // ol = append_bits(out, ol, pgm_read_word(&c_95[c_in]), pgm_read_byte(&l_95[c_in]), state); // original version with c/l in split arrays
+ uint16_t cl = pgm_read_word(&cl_95[c_in]);
+ ol = append_bits(out, ol, cl & 0xFFF0, cl & 0x000F, state);
+ }
+ } else
+ // if (c_in == 13 && c_next == 10) { // CRLF disabled
+ // ol = append_bits(out, ol, CRLF_CODE, CRLF_CODE_LEN, state); // CRLF
+ // l++;
+ // } else
+ if (c_in == 10) {
+ ol = append_bits(out, ol, LF_CODE, LF_CODE_LEN, state); // LF
+ } else
+ if (c_in == '\t') {
+ ol = append_bits(out, ol, TAB_CODE, TAB_CODE_LEN, state); // TAB
+ } else {
+ ol = append_bits(out, ol, BIN_CODE_TASMOTA, BIN_CODE_TASMOTA_LEN, state); // Binary, we reuse the Unicode marker which 3 bits instead of 9
+ ol = encodeCount(out, ol, (unsigned char) 255 - c_in);
+ }
+
+ // check that we have some headroom in the output buffer
+ if (ol / 8 >= len_out - 4) {
+ return -1; // we risk overflow and crash
+ }
+ }
+
+ bits = ol % 8;
+ if (bits) {
+ ol = append_bits(out, ol, TERM_CODE, 8 - bits, 1); // 0011 0111 1100 0000 TERM = 0011 0111 11
+ }
+ return ol/8+(ol%8?1:0);
+}
+
+int getBitVal(const char *in, int bit_no, int count) {
+ char c_in = in[bit_no >> 3];
+ if ((bit_no >> 3) && (ESCAPE_MARKER == in[(bit_no >> 3) - 1])) { // if previous byte is a marker, decrement
+ c_in--;
+ }
+ return (c_in & (0x80 >> (bit_no % 8)) ? 1 << count : 0);
+}
+
+// Returns:
+// 0..11
+// or -1 if end of stream
+int getCodeIdx(char *code_type, const char *in, int len, int *bit_no_p) {
+ int code = 0;
+ int count = 0;
+ do {
+ // detect marker
+ if (ESCAPE_MARKER == in[*bit_no_p >> 3]) {
+ *bit_no_p += 8; // skip marker
+ }
+ if (*bit_no_p >= len)
+ return -1; // invalid state
+ code += getBitVal(in, *bit_no_p, count);
+ (*bit_no_p)++;
+ count++;
+ uint8_t code_type_code = pgm_read_byte(&code_type[code]);
+ if (code_type_code && (code_type_code & 0x07) == count) {
+ return code_type_code >> 3;
+ }
+ } while (count < 5);
+ return 1; // skip if code not found
+}
+
+int getNumFromBits(const char *in, int bit_no, int count) {
+ int ret = 0;
+ while (count--) {
+ if (ESCAPE_MARKER == in[bit_no >> 3]) {
+ bit_no += 8; // skip marker
+ }
+ ret += getBitVal(in, bit_no++, count);
+ }
+ return ret;
+}
+
+// const byte bit_len[7] = {5, 2, 7, 9, 12, 16, 17};
+// const uint16_t adder[7] = {4, 0, 36, 164, 676, 4772, 0};
+
+// byte bit_len[7] PROGMEM = { 5, 7, 9, 12, 16 };
+// byte bit_len_read[7] PROGMEM = {5, 2, 7, 9, 12, 16 };
+// uint16_t adder_read[7] PROGMEM = {4, 0, 36, 164, 676, 4772, 0};
+// uint16_t adder_read[] PROGMEM = {0, 0, 32, 160, 672, 4768 };
+
+// byte bit_len[7] PROGMEM = { 5, 7, 9, 12, 16 };
+// uint16_t adder_read[] PROGMEM = {0, 32, 160, 672, 4768 };
+
+// Code size optimized, recalculate adder[] like in encodeCount
+int readCount(const char *in, int *bit_no_p, int len) {
+ int idx = getCodeIdx(us_hcode, in, len, bit_no_p);
+ if (idx >= 1) idx--; // we skip v = 1 (code '0') since we no more accept 2 bits encoding
+ if ((idx >= sizeof(bit_len)) || (idx < 0)) return 0; // unsupported or end of stream
+
+ int base;
+ int till = 0;
+ byte bit_len_idx; // bit_len[0]
+ for (uint32_t i = 0; i <= idx; i++) {
+ base = till;
+ bit_len_idx = pgm_read_byte(&bit_len[i]);
+ till += (1 << bit_len_idx);
+ }
+ int count = getNumFromBits(in, *bit_no_p, bit_len_idx) + base;
+
+ (*bit_no_p) += bit_len_idx;
+ return count;
+}
+
+int decodeRepeat(const char *in, int len, char *out, int ol, int *bit_no) {
+ int dict_len = readCount(in, bit_no, len) + NICE_LEN;
+ int dist = readCount(in, bit_no, len) + NICE_LEN - 1;
+ memcpy(out + ol, out + ol - dist, dict_len);
+ ol += dict_len;
+
+ return ol;
+}
+
+int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out) {
+
+ int dstate;
+ int bit_no;
+ byte is_all_upper;
+
+ int ol = 0;
+ bit_no = 0;
+ dstate = SHX_SET1;
+ is_all_upper = 0;
+
+ len <<= 3; // *8, len in bits
+ out[ol] = 0;
+ while (bit_no < len) {
+ int h, v;
+ char c = 0;
+ byte is_upper = is_all_upper;
+ int orig_bit_no = bit_no;
+ v = getCodeIdx(us_vcode, in, len, &bit_no); // read vCode
+ if (v < 0) break; // end of stream
+ h = dstate; // Set1 or Set2
+ if (v == 0) { // Switch which is common to Set1 and Set2, first entry
+ h = getCodeIdx(us_hcode, in, len, &bit_no); // read hCode
+ if (h < 0) break; // end of stream
+ if (h == SHX_SET1) { // target is Set1
+ if (dstate == SHX_SET1) { // Switch from Set1 to Set1 us UpperCase
+ if (is_all_upper) { // if CapsLock, then back to LowerCase
+ is_upper = is_all_upper = 0;
+ continue;
+ }
+ v = getCodeIdx(us_vcode, in, len, &bit_no); // read again vCode
+ if (v < 0) break; // end of stream
+ if (v == 0) {
+ h = getCodeIdx(us_hcode, in, len, &bit_no); // read second hCode
+ if (h < 0) break; // end of stream
+ if (h == SHX_SET1) { // If double Switch Set1, the CapsLock
+ is_all_upper = 1;
+ continue;
+ }
+ }
+ is_upper = 1; // anyways, still uppercase
+ } else {
+ dstate = SHX_SET1; // if Set was not Set1, switch to Set1
+ continue;
+ }
+ } else
+ if (h == SHX_SET2) { // If Set2, switch dstate to Set2
+ if (dstate == SHX_SET1) // TODO: is this test useful, there are only 2 states possible
+ dstate = SHX_SET2;
+ continue;
+ }
+ if (h != SHX_SET1) { // all other Sets (why not else)
+ v = getCodeIdx(us_vcode, in, len, &bit_no); // we changed set, now read vCode for char
+ if (v < 0) break; // end of stream
+ }
+ }
+
+ if (v == 0 && h == SHX_SET1A) {
+ if (is_upper) {
+ out[ol++] = 255 - readCount(in, &bit_no, len); // binary
+ } else {
+ ol = decodeRepeat(in, len, out, ol, &bit_no); // dist
+ }
+ continue;
+ }
+
+ if (h == SHX_SET1 && v == 3) {
+ // was Unicode, will do Binary instead
+ out[ol++] = 255 - readCount(in, &bit_no, len); // binary
+ continue;
+ }
+ if (h < 7 && v < 11) // TODO: are these the actual limits? Not 11x7 ?
+ c = pgm_read_byte(&sets[h][v]);
+ if (c >= 'a' && c <= 'z') {
+ if (is_upper)
+ c -= 32; // go to UpperCase for letters
+ } else { // handle all other cases
+ if (is_upper && dstate == SHX_SET1 && v == 1)
+ c = '\t'; // If UpperCase Space, change to TAB
+ if (h == SHX_SET1B) {
+ if (8 == v) { // was LF or RPT, now only LF
+ // if (is_upper) { // rpt
+ // int count = readCount(in, &bit_no, len);
+ // count += 4;
+ // char rpt_c = out[ol - 1];
+ // while (count--)
+ // out[ol++] = rpt_c;
+ // } else {
+ out[ol++] = '\n';
+ // }
+ continue;
+ }
+ if (9 == v) { // was CRLF, now RPT
+ // out[ol++] = '\r'; // CRLF removed
+ // out[ol++] = '\n';
+ int count = readCount(in, &bit_no, len);
+ count += 4;
+ if (ol + count >= len_out) {
+ return -1; // overflow
+ }
+ char rpt_c = out[ol - 1];
+ while (count--)
+ out[ol++] = rpt_c;
+ continue;
+ }
+ if (10 == v) {
+ break; // TERM, stop decoding
+ }
+ }
+ }
+ out[ol++] = c;
+
+ if (ol >= len_out) {
+ return -1; // overflow
+ }
+ }
+
+ return ol;
+
+}
diff --git a/lib/Unishox-1.0-shadinger/src/unishox.h b/lib/Unishox-1.0-shadinger/src/unishox.h
new file mode 100644
index 000000000..4d6b81641
--- /dev/null
+++ b/lib/Unishox-1.0-shadinger/src/unishox.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 Siara Logics (cc)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @author Arundale R.
+ *
+ */
+#ifndef unishox
+#define unishox
+
+extern int32_t unishox_compress(const char *in, size_t len, char *out, size_t len_out);
+extern int32_t unishox_decompress(const char *in, size_t len, char *out, size_t len_out);
+
+#endif
+
diff --git a/lib/Xlatb_RA8876-gemu-1.0/RA8876.cpp b/lib/Xlatb_RA8876-gemu-1.0/RA8876.cpp
index a3c73f3fb..850b2bb8a 100644
--- a/lib/Xlatb_RA8876-gemu-1.0/RA8876.cpp
+++ b/lib/Xlatb_RA8876-gemu-1.0/RA8876.cpp
@@ -66,9 +66,13 @@ RA8876::RA8876(int8_t cs,int8_t mosi,int8_t miso,int8_t sclk,int8_t bp) : Render
//#define RA8876_CS_LOW digitalWrite(m_csPin, LOW)
//#define RA8876_CS_HIGH digitalWrite(m_csPin, HIGH)
+#ifdef ESP8266
#define RA8876_CS_LOW GPOC=(1< 76 kb / sec
// can use any pin
diff --git a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd2in9.h b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd2in9.h
index 99459b198..3fc8ea190 100644
--- a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd2in9.h
+++ b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd2in9.h
@@ -68,8 +68,8 @@ public:
int16_t width;
int16_t height;
- Epd();
- ~Epd();
+// Epd();
+// ~Epd();
int Init(const unsigned char* lut);
void Init(int8_t p);
void SendCommand(unsigned char command);
diff --git a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd4in2.cpp b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd4in2.cpp
index e2fe5dd34..8450a9647 100644
--- a/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd4in2.cpp
+++ b/lib/esp-epaper-29-ws-20171230-gemu-1.1/src/epd4in2.cpp
@@ -130,14 +130,14 @@ int Epd42::Init(void) {
SendCommand(PANEL_SETTING);
// SendData(0xbf); // KW-BF KWR-AF BWROTP 0f
// SendData(0x0b);
-// SendData(0x0F); //300x400 Red mode, LUT from OTP
-// SendData(0x1F); //300x400 B/W mode, LUT from OTP
- SendData(0x3F); //300x400 B/W mode, LUT set by register
-// SendData(0x2F); //300x400 Red mode, LUT set by register
+// SendData(0x0F); //300x400 Red mode, LUT from OTP
+// SendData(0x1F); //300x400 B/W mode, LUT from OTP
+ SendData(0x3F); //300x400 B/W mode, LUT set by register
+// SendData(0x2F); //300x400 Red mode, LUT set by register
SendCommand(PLL_CONTROL);
SendData(0x3C); // 3A 100Hz 29 150Hz 39 200Hz 31 171Hz 3C 50Hz (default) 0B 10Hz
- //SendData(0x0B); //0B is 10Hz
+ //SendData(0x0B); //0B is 10Hz
/* EPD hardware init end */
return 0;
}
@@ -502,12 +502,15 @@ const unsigned char lut_wb_quick[] PROGMEM =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-
-
#define PIN_OUT_SET 0x60000304
#define PIN_OUT_CLEAR 0x60000308
+#ifdef ESP32
+#define SSPI_USEANYPIN 1
+#define PWRITE digitalWrite
+#else
#define PWRITE ydigitalWrite
+#endif
#ifndef SSPI_USEANYPIN
// uses about 2.75 usecs, 365 kb /sec
@@ -530,6 +533,7 @@ void ICACHE_RAM_ATTR Epd42::fastSPIwrite(uint8_t d,uint8_t dc) {
}
#else
+#ifndef ESP32
extern void ICACHE_RAM_ATTR ydigitalWrite(uint8_t pin, uint8_t val) {
//stopWaveform(pin);
if(pin < 16){
@@ -540,6 +544,7 @@ extern void ICACHE_RAM_ATTR ydigitalWrite(uint8_t pin, uint8_t val) {
else GP16O &= ~1;
}
}
+#endif
// about 13 us => 76 kb / sec
// can use any pin
void Epd42::fastSPIwrite(uint8_t d,uint8_t dc) {
diff --git a/libesp32/ESP32-Mail-Client/LICENSE b/libesp32/ESP32-Mail-Client/LICENSE
new file mode 100755
index 000000000..2b2f9d774
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 mobizt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/libesp32/ESP32-Mail-Client/README.md b/libesp32/ESP32-Mail-Client/README.md
new file mode 100755
index 000000000..bd4cb6328
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/README.md
@@ -0,0 +1,2138 @@
+# Mail Client Arduino Library for ESP32 v 2.1.4
+
+This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download via SMTP and IMAP servers.
+
+The library was test and work well with ESP32s based module.
+
+Copyright (c) 2019 K. Suwatchai (Mobizt).
+
+
+
+## Tested Devices
+
+This following devices were tested and work well.
+
+ * Sparkfun ESP32 Thing
+ * NodeMCU-32
+ * WEMOS LOLIN32
+ * TTGO T8 V1.8
+ * M5Stack ESP32
+
+
+
+## Features
+
+* Support Email sending with or without attachment via IMAP server.
+
+* Support SSL/TLS and STARTTLS protocols.
+
+* Working with SD card allows large file attachment supported or SPIFFS for small file size attachment.
+
+* Support Email reading via search and fetch modes (with or without attachment downloads).
+
+* Support large attachment download via SD card or SPIFFS for small file size attachment.
+
+* Message text and its header are able to download and save to SD card or SPIFFS.
+
+* Support Email message fetch and search via IMAP command as in RFC 3501 (depending on IMAP server implementation).
+
+* Support Ethernet.
+
+* Built-in Time function.
+
+
+
+
+## Prerequisites
+
+
+For library version 1.2.0 or newer, STARTTLS was supported and can be enable automatically when port 587 for SMTP was used or can set manually thrugh smtpData.setSTARTTLS(true) and for IMAP through imapData.setSTARTTLS(true).
+
+
+
+## Installing
+
+
+Click on **Clone or download** dropdown at the top of repository, select **Download ZIP** and save file on your computer.
+
+From Arduino IDE, goto menu **Sketch** -> **Include Library** -> **Add .ZIP Library...** and choose **ESP32-Mail-Client-master.zip** that previously downloaded.
+
+Go to menu **Files** -> **Examples** -> **ESP32-Mail-Client-master** and choose one from examples
+
+
+
+## Usages
+
+
+__Declaration and Initialization__
+
+
+
+**The first thing to do to use this library.**
+
+```C++
+
+
+//1. Include ESP32 Mail Client library (this library)
+
+#include "ESP32_MailClient.h"
+
+
+//2. For sending Email, declare Email Sending data object in global scope.
+SMTPData smtpData;
+
+//Or
+
+//For receiving Email, declare Email receiving data object in global scope.
+IMAPData imapData;
+
+
+//3 Setup SMTP server login credential in setup()
+
+smtpData.setLogin("smtp.gmail.com", 587, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
+
+//Or
+
+//Setup IMAP server login credential in setup()
+
+imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
+
+
+//4 For SMTP, set some custom message header (optional)
+smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)");
+
+smtpData.addCustomMessageHeader("Message-ID: <10000.30000@gmail.com>");
+
+
+//5 To debug for SMTP
+
+smtpData.setDebug(true);
+
+//Or IMAP
+imapData.setDebug(true);
+
+
+//6. Send Email
+MailClient.sendMail(smtpData));
+
+//Or Receive Email
+
+MailClient.readdMail(imapData));
+
+
+
+
+
+```
+
+___
+
+
+__Send and Receive Email__
+
+
+**Compose Email**
+
+This library allows you to set sender, recipient, importance (priority), CC, BCC and attachment data (binary or from SD card file).
+
+To set sender, use `smtpData.setSender` e.g. `smtpData.setSender("Jarvis", "SOME_EMAIL_ACCOUNT@SOME_EMAIL.com")`.
+
+To set priority, use `smtpData.setPriority` e.g. `smtpData.setPriority("High")`.
+
+To set message subject, use `smtpData.setSubject` e.g. `smtpData.setSubject("ESP32 Send Mail Test")`.
+
+To set message text, use `smtpData.setMessage` e.g. `smtpData.setMessage("This is plain text message", false);`.
+
+To set sender, use `smtpData.addRecipient` e.g. `smtpData.addRecipient("SOME_RECIPIENT@SOME_MAIL.com")`.
+
+To add attachment, use `smtpData.addAttachData` e.g. `smtpData.addAttachData("test.png", "image/png", (uint8_t *)imageData, sizeof imageData);`.
+
+
+When completed all required message data, sending Email `MailClient.sendMail(smtpData)`.
+
+
+
+**Get Email**
+
+To read or receive Email, mailbox folder should be assigned via `imapData.setFolder` e.g. `imapData.setFolder("INBOX")`.
+
+Then set search criteria to search specified mailbox folder via `imapData.setSearchCriteria` e.g. `imapData.setSearchCriteria("UID SEARCH ALL")`.
+
+Then set search limit to limut the memory and time usages `imapData.setSearchLimit`.
+
+From search criteria, UID of message will be available to fetch or read.
+
+Whit search, body message and attachment can be ignore to reduce the network data usage.
+
+Begin receive Email `MailClient.readMail(imapData)`.
+
+From above settings, you will get the following header information
+
+Messsage UID via `imapData.getUID`.
+
+Messsage ID via `imapData.getMessageID`.
+
+Accept Language via `imapData.getAcceptLanguage`.
+
+Content Language via `imapData.getContentLanguage`.
+
+Sender via `imapData.getFrom`.
+
+Sender Charset via `imapData.getFromCharset`.
+
+Recipient via `imapData.getTo`.
+
+Recipient Charset via `imapData.getToCharset`.
+
+CC via `imapData.getCC`.
+
+CC Charset via `imapData.getCCCharset`.
+
+Date via `imapData.getDate`.
+
+Subject via `imapData.getSubject`.
+
+Subject Charset via `imapData.getSubjectCharset`.
+
+In addition, by setting search criteria, the following infomation are available.
+
+Mailbox folder count via `imapData.getFolderCount`.
+
+Mailbox folder name via `imapData.getFolder`.
+
+Supported flags count via `imapData.getFlagCount`.
+
+Supported flags name via `imapData.getFlag`.
+
+Total message in folder via `imapData.totalMessages`.
+
+Total message from search result via `imapData.searchCount`.
+
+Available message from search result (limited by `imapData.setSearchLimit`) via `imapData.availableMessages`.
+
+When fetch specific message via `imapData.setFetchUID`, availability of attachment file can be determined via
+`imapData.getAttachmentCount` for that message which will be automatically download by setting `imapData.setDownloadAttachment(true)`
+prior to `MailClient.readMail`.
+
+
+
+See [full examples](https://github.com/mobizt/ESP32-Mail-Client/tree/master/examples) for all features usages.
+
+
+
+
+
+## All Supported Functions
+
+
+**These are all functions available from the library and the descriptions.**
+
+
+__Global functions__
+
+
+**Sending Email via SMTP server.**
+
+param *`smtpData`* - SMTP Data object to hold data and instances.
+
+return - *`Boolean`* type status indicates the success of operation.
+
+```C++
+bool sendMail(SMTPData &smtpData);
+```
+
+
+
+
+**Reading Email via IMAP server.**
+
+param *`imapData`* - IMAP Data object to hold data and instances.
+
+return - *`Boolean`* type status indicates the success of operation.
+
+```C++
+bool readMail(IMAPData &imapData);
+```
+
+
+
+
+
+**Set the argument to the Flags for message.**
+
+param *`imapData`* - IMAP Data object to hold data and instances.
+
+param *`msgUID`* - The UID of message.
+
+param *`flags`* - The flag list.
+
+return - *`Boolean`* type status indicates the success of operation.
+
+```C++
+bool setFlag(IMAPData &imapData, int msgUID, const String &flags);
+```
+
+
+
+
+
+**Add the argument to the Flags for message.**
+
+param *`imapData`* - IMAP Data object to hold data and instances.
+
+param *`msgUID`* - The UID of message.
+
+param *`flags`* - The flag list.
+
+return - *`Boolean`* type status indicates the success of operation.
+
+```C++
+bool addFlag(IMAPData &imapData, int msgUID, const String &flags);
+```
+
+
+
+
+
+
+**Remove the argument from the Flags for message.**
+
+param *`imapData`* - IMAP Data object to hold data and instances.
+
+param *`msgUID`* - The UID of message.
+
+param *`flags`* - The flag list.
+
+return - *`Boolean`* type status indicates the success of operation.
+
+```C++
+bool removeFlag(IMAPData &imapData, int msgUID, const String &flags);
+```
+
+
+
+
+
+**Get the Email sending error details.**
+
+return - *`Error details string (String object).`*
+
+```C++
+String smtpErrorReason();
+```
+
+
+
+
+**Get the Email reading error details.**
+
+return - *`Error details string (String object).`*
+
+```C++
+String imapErrorReason();
+```
+
+
+
+
+
+**Init SD card with GPIO pins.**
+
+param *`sck`* -SPI Clock pin.
+
+param *`miso`* - SPI MISO pin.
+
+param *`m0si`* - SPI MOSI pin.
+
+param *`ss`* - SPI Chip/Slave Select pin.
+
+return *`Boolean`* type status indicates the success of operation.
+
+
+```C++
+bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss);
+```
+
+
+
+
+
+
+**Init SD card with default GPIO pins.**
+
+return *`Boolean`* type status indicates the success of operation.
+
+
+```C++
+bool sdBegin(void);
+```
+
+
+
+
+
+
+
+### IMAPData object call for receiving Email.
+
+
+**Set the IMAP server login credentials.**
+
+param *`host`* - IMAP server e.g. imap.gmail.com.
+
+param *`port`* - IMAP port e.g. 993 for gmail.
+
+param *`loginEmail`* - The Email address of account.
+
+param *`loginPassword`* - The account password.
+
+param *`rootCA`* - Root CA certificate base64 string
+
+```C++
+void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword);
+
+void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA);
+
+```
+
+
+
+
+
+**Set STARTTLS mode to enable STARTTLS protocol.**
+
+param *`starttls`* - bool flag that enables STARTTLS mode
+
+```C++
+void setSTARTTLS(bool starttls);
+```
+
+
+
+
+
+
+**Set debug print to serial.**
+
+param *`debug`* - bool flag to enable debug
+
+```C++
+void setDebug(bool debug);
+```
+
+
+
+
+
+
+**Set the mailbox folder to search or fetch.**
+
+param *`folderName`* - Known mailbox folder. Default value is INBOX
+
+```C++
+void setFolder(const String &folderName);
+```
+
+
+
+**Set the maximum message buffer size for text/html result from search or fetch the message.**
+
+param *`size`* - The message size in byte.
+
+```C++
+void setMessageBufferSize(size_t size);
+```
+
+
+
+**Set the maximum attachment file size to be downloaded.**
+
+param *`size`* - The attachement file size in byte.
+
+```C++
+void setAttachmentSizeLimit(size_t size);
+```
+
+
+
+**Set the search criteria used in selected mailbox search.**
+
+In case of message UID was set via setFetchUID function, search operation will not process,
+
+you need to clear message UID by calling imapData.setFetchUID("") to clear.
+
+param *`criteria`* - Search criteria String.
+
+If folder is not set, the INBOX folder will be used
+
+Example:
+
+*`SINCE 10-Feb-2019`* will search all messages that received since 10 Feb 2019
+
+*`UID SEARCH ALL`* will seach all message which will return the message UID that can be use later for fetch one or more messages.
+
+
+Search criteria can be consisted these keywords
+
+
+*`ALL`* - All messages in the mailbox; the default initial key for ANDing.
+
+*`ANSWERED`* - Messages with the \Answered flag set.
+
+*`BCC`* - Messages that contain the specified string in the envelope structure's BCC field.
+
+*`BEFORE`* - Messages whose internal date (disregarding time and timezone) is earlier than the specified date.
+
+*`BODY`* - Messages that contain the specified string in the body of the message.
+
+*`CC`* - Messages that contain the specified string in the envelope structure's CC field.
+
+*`DELETED`* - Messages with the \Deleted flag set.
+
+*`DRAFT`* - Messages with the \Draft flag set.
+
+*`FLAGGED`* - Messages with the \Flagged flag set.
+
+*`FROM`* - Messages that contain the specified string in the envelope structure's FROM field.
+
+*`HEADER`* - Messages that have a header with the specified field-name (as defined in [RFC-2822])
+
+and that contains the specified string in the text of the header (what comes after the colon).
+
+If the string to search is zero-length, this matches all messages that have a header line with
+
+the specified field-name regardless of the contents.
+
+*`KEYWORD`* - Messages with the specified keyword flag set.
+
+*`LARGER`* - Messages with an (RFC-2822) size larger than the specified number of octets.
+
+*`NEW`* - Messages that have the \Recent flag set but not the \Seen flag.
+
+This is functionally equivalent to `*"(RECENT UNSEEN)"*`.
+
+*`NOT`* - Messages that do not match the specified search key.
+
+*`OLD`* - Messages that do not have the \Recent flag set. This is functionally equivalent to
+
+*`"NOT RECENT"`* (as opposed to *`"NOT NEW"`*).
+
+*`ON`* - Messages whose internal date (disregarding time and timezone) is within the specified date.
+
+*`OR`* - Messages that match either search key.
+
+*`RECENT`* - Messages that have the \Recent flag set.
+
+*`SEEN`* - Messages that have the \Seen flag set.
+
+*`SENTBEFORE`* - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is earlier than the specified date.
+
+*`SENTON`* - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within the specified date.
+
+*`SENTSINCE`* - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within or later than the specified date.
+
+*`SINCE`* - Messages whose internal date (disregarding time and timezone) is within or later than the specified date.
+
+*`SMALLER`* - Messages with an (RFC-2822) size smaller than the specified number of octets.
+
+*`SUBJECT`* - Messages that contain the specified string in the envelope structure's SUBJECT field.
+
+*`TEXT`* - Messages that contain the specified string in the header or body of the message.
+
+*`TO`* - Messages that contain the specified string in the envelope structure's TO field.
+
+*`UID`* - Messages with unique identifiers corresponding to the specified unique identifier set.
+
+Sequence set ranges are permitted.
+
+*`UNANSWERED`* - Messages that do not have the \Answered flag set.
+
+*`UNDELETED`* - Messages that do not have the \Deleted flag set.
+
+*`UNDRAFT`* - Messages that do not have the \Draft flag set.
+
+*`UNFLAGGED`* - Messages that do not have the \Flagged flag set.
+
+*`UNKEYWORD`* - Messages that do not have the specified keyword flag set.
+
+*`UNSEEN`* - Messages that do not have the \Seen flag set.
+
+```C++
+void setSearchCriteria(const String &criteria);
+```
+
+
+
+
+
+**Set to search the unseen message.**
+
+param *`unseenSearch`* - Boolean flag to enable unseen message search.
+
+This function will be overridden (omitted) by setFetchUID as setSearchCriteria.
+
+```C++
+void setSearchUnseenMessage(bool unseenSearch);
+```
+
+
+
+
+
+
+**Set the download folder.**
+
+param *`path`* - Path in SD card.
+
+All text/html message and attachemnts will be saved to message UID folder which created in defined path
+
+e.g. *`"/{DEFINED_PATH}/{MESSAGE_UID}/{ATTACHMENT_FILE...}"`*.
+
+```C++
+void setSaveFilePath(const String &path);
+```
+
+
+
+
+**Specify message UID to fetch or read.**
+
+param *`fetchUID`* - The message UID.
+
+Specify the message UID to fetch (read) only specific message instead of search.
+
+```C++
+void setFetchUID(const String &fetchUID);
+```
+
+
+
+
+
+**Set storage type to save download attached file or messages.**
+
+param *`storageType`* - The storage type to save file, MailClientStorageType::SD or MailClientStorageType::SPIFFS
+
+```C++
+void setFileStorageType(uint8_t storageType);
+```
+
+
+
+
+
+
+**Enable/disable attachment download.**
+
+param *`download`* - Boolean flag to enable/disable attachment download.
+
+```C++
+void setDownloadAttachment(bool download);
+```
+
+
+
+**Enable/disable html message result.**
+
+param *`htmlFormat`* - Boolean flag to enable/disable html message result.
+
+The default value is false.
+
+```C++
+void setHTMLMessage(bool htmlFormat);
+```
+
+
+
+
+**Enable/disable plain text message result.**
+
+param *`textFormat`* - Boolean flag to enable/disable plain text message result.
+
+The default value is true.
+
+```C++
+void setTextMessage(bool textFormat);
+```
+
+
+
+
+
+**Set the maximum message to search.**
+
+param *`limit`* - Any number from 0 to 65535.
+
+The default value is 20.
+
+```C++
+void setSearchLimit(uint16_t limit);
+```
+
+
+
+**Enable/disable recent sort result.**
+
+param *`recentSort`* - Boolean flag to enable/disable recent message sort result.
+
+The default value is true.
+
+```C++
+void setRecentSort(bool recentSort);
+```
+
+
+
+**Assign callback function that return status of message fetching or reading.**
+
+param *`readCallback`* - The function that accept readStatusCallback as parameter.
+
+```C++
+void setReadCallback(readStatusCallback readCallback);
+```
+
+
+
+**Enable/disable attachement download progress while fetching or receiving message.**
+
+param *`report`* - Boolean flag to enable/disable attachement download progress while fetching or receiving message.
+
+To get the download status, Callback function should be set via setReadCallback.
+
+```C++
+void setDownloadReport(bool report);
+```
+
+
+
+**Determine only message header is return when search.**
+
+```C++
+bool isHeaderOnly();
+```
+
+
+
+**Get the sender name/Email for selected message from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Sender name/Email String.`*
+
+```C++
+String getFrom(uint16_t messageIndex);
+```
+
+
+
+**Get the sender name/Email charactor encoding.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Sender name/Email charactor encoding which use for decoding.`*
+
+```C++
+String getFromCharset(uint16_t messageIndex);
+```
+
+
+
+**Get the recipient name/Email for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Recipient name/Email String.`*
+
+```C++
+String getTo(uint16_t messageIndex);
+```
+
+
+
+
+**Get the recipient name/Email charactor encoding.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Recipient name/Email charactor encoding which use in decoding to local language.`*
+
+```C++
+String getToCharset(uint16_t messageIndex);
+```
+
+
+
+
+**Get the CC name/Email for selected message index of IMAPData result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`CC name/Email String.`*
+
+```C++
+String getCC(uint16_t messageIndex);
+```
+
+
+
+**Get the CC name/Email charactor encoding.**
+
+param *`messageIndex`* - The index of message.
+
+return *`CC name/Email charactor encoding which use in decoding to local language.`*
+
+```C++
+String getCCCharset(uint16_t messageIndex);
+```
+
+
+
+
+**Get the message subject for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Message subject name/Email String.`*
+
+```C++
+String getSubject(uint16_t messageIndex);
+```
+
+
+
+
+**Get the message subject charactor encoding.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Message subject charactor encoding which use in decoding to local language.`*
+
+```C++
+String getSubjectCharset(uint16_t messageIndex);
+```
+
+
+
+**Get the html message for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The html message String or empty String upon the setHTMLMessage was set.`*
+
+```C++
+String getHTMLMessage(uint16_t messageIndex);
+```
+
+
+
+**Get the plain text message for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The plain text message String or empty String upon the setTextMessage was set.`*
+
+```C++
+String getTextMessage(uint16_t messageIndex);
+```
+
+
+**Get the html message charactor encoding.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Html message charactor encoding which use in decoding to local language.`*
+
+```C++
+String getHTMLMessgaeCharset(uint16_t messageIndex);
+```
+
+
+
+
+**Get the text message charactor encoding.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The text message charactor encoding which use in decoding to local language.`*
+
+```C++
+String getTextMessgaeCharset(uint16_t messageIndex);
+```
+
+
+
+
+**Get the date of received message for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The date String.`*
+
+```C++
+String getDate(uint16_t messageIndex);
+```
+
+
+
+
+**Get the message UID for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`UID String that can be use in setFetchUID.`*
+
+```C++
+String getUID(uint16_t messageIndex);
+```
+
+
+
+
+**Get the message number for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The message number which vary upon search criteria and sorting.`*
+
+```C++
+String getNumber(uint16_t messageIndex);
+```
+
+
+
+
+**Get the message ID for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The message ID String.`*
+
+```C++
+String getMessageID(uint16_t messageIndex);
+```
+
+
+
+
+**Get the accept language for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The accept language String.`*
+
+```C++
+String getAcceptLanguage(uint16_t messageIndex);
+```
+
+
+
+**Get the content language of text or html for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`The content language String.`*
+
+```C++
+String getContentLanguage(uint16_t messageIndex);
+```
+
+
+
+
+**Determine fetch error status for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Fetch error status.`*
+
+```C++
+bool isFetchMessageFailed(uint16_t messageIndex);
+```
+
+
+
+**Get fetch error reason for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Fetch error reason String for selected message index.`*
+
+```C++
+String getFetchMessageFailedReason(uint16_t messageIndex);
+```
+
+
+
+
+**Determine the attachment download error for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Fetch status.`*
+
+```C++
+bool isDownloadAttachmentFailed(uint16_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+
+**Get the attachment download error reason for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Download error reason String for selected message index.`*
+
+```C++
+String getDownloadAttachmentFailedReason(uint16_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+**Determine the downloaded/saved text message error status for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Text message download status.`*
+
+```C++
+bool isDownloadMessageFailed(uint16_t messageIndex);
+```
+
+
+
+
+
+**Get the attachment or message downloadeds error reason for selected message index from search result.**
+
+param *`messageIndex`* - The index of message.
+
+return *`Downloaded error reason String for selected message index.`*
+
+```C++
+String getDownloadMessageFailedReason(uint16_t messageIndex);
+```
+
+
+
+
+**Assign the download and decode flags for html message download.**
+
+param *`download`* - Boolean flag to enable/disable message download.
+
+return *`decoded`* - Boolean flag to enable/disable html message decoding (support utf8 and base64 encoding).
+
+```C++
+void saveHTMLMessage(bool download, bool decoded);
+```
+
+
+
+
+**Assign the download and decode flags for plain text message download.**
+
+param *`download`* - Boolean flag to enable/disable message download.
+
+return *`decoded`* - Boolean flag to enable/disable plain text message decoding (support utf8 and base64 encoding).
+
+```C++
+void saveTextMessage(bool download, bool decoded);
+```
+
+
+
+
+**Determine the mailbox folder count.**
+
+return *`Folder count number.`*
+
+```C++
+uint16_t getFolderCount();
+```
+
+
+
+
+**Get the mailbox folder name at selected index.**
+
+param *`folderIndex`* - Index of folder.
+
+return *`Folder name String.`*
+
+Use folder name from this function for fetch or search.
+
+```C++
+String getFolder(uint16_t folderIndex);
+```
+
+
+
+**Determin the number of supported flags count.**
+
+return *`Flag count number.`*
+
+```C++
+uint16_t getFlagCount();
+```
+
+
+
+
+**Get the flag name for selected index.**
+
+param *`folderIndex`* - Index of folder.
+
+return *`Flag name String.`*
+
+Use flags from this function for fetch or search.
+
+```C++
+String getFlag(uint16_t flagIndex);
+```
+
+
+
+
+**Get the number of message in selected mailbox folder.**
+
+return *`Total message number.`*
+
+```C++
+size_t totalMessages();
+```
+
+
+
+
+**Get the number of message from search result.**
+
+return *`Search result number.`*
+
+```C++
+size_t searchCount();
+```
+
+
+
+
+**Get the number of message available from search result which less than search limit.**
+
+return *`Available message number.`*
+
+```C++
+size_t availableMessages();
+```
+
+
+
+
+
+**Get the number of attachments for selected message index from search result.**
+
+param *`messageIndex`* - Index of message.
+
+return *`Number of attachments`*
+
+```C++
+size_t getAttachmentCount(uint16_t messageIndex);
+```
+
+
+
+
+
+**Get file name of attachment for selected attachment index and message index from search result.**
+
+param *`messageIndex`* - Index of message.
+
+param *`attachmentIndex`* - Index of attachment.
+
+return *`The attachment file name String at the selected index.`*
+
+```C++
+String getAttachmentFileName(size_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+
+**Get the name of attachment for selected attachment index and message index from search result.**
+
+param *`messageIndex`* - Index of message.
+
+param *`attachmentIndex`* - Index of attachment.
+
+return *`The attachment name String at the selected index.`*
+
+```C++
+String getAttachmentName(size_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+
+**Get attachment file size for selected attachment index and message index from search result.**
+
+param *`messageIndex`* - Index of message.
+
+param *`attachmentIndex`* - Index of attachment.
+
+return *`The attachment file size in byte at the selected index.`*
+
+```C++
+int getAttachmentFileSize(size_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+
+**Get creation date of attachment for selected attachment index and message index from search result.**
+
+param *`messageIndex`* - Index of message.
+
+param *`attachmentIndex`* - Index of attachment.
+
+return *`The attachment creation date String at the selected index.`*
+
+```C++
+String getAttachmentCreationDate(size_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+
+**Get attachment file type for selected attachment index and message index from search result.**
+
+param *`messageIndex`* - Index of message.
+
+param *`attachmentIndex`* - Index of attachment.
+
+return *`File MIME String at the selected index`* e.g. image/jpeg.
+
+```C++
+String getAttachmentType(size_t messageIndex, size_t attachmentIndex);
+```
+
+
+
+
+**Clear IMAPData object data.**
+
+```C++
+void empty();
+```
+
+
+
+
+### SMTPData object call for sending Email.
+
+
+**Set SMTP server login credentials**
+
+param *`host`* - SMTP server e.g. smtp.gmail.com
+
+param *`port`* - SMTP port.
+
+param *`loginEmail`* - The account Email.
+
+param *`loginPassword`* - The account password.
+
+param *`rootCA`* - Root CA certificate base64 string
+
+```C++
+void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword);
+
+void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA);
+
+```
+
+
+
+
+
+**Set STARTTLS mode to enable STARTTLS protocol.**
+
+param *`starttls`* - bool flag that enables STARTTLS mode
+
+```C++
+void setSTARTTLS(bool starttls);
+```
+
+
+
+
+
+
+**Set debug print to serial.**
+
+param *`debug`* - bool flag to enable debug
+
+```C++
+void setDebug(bool debug);
+```
+
+
+
+
+
+
+**Set Sender info**
+
+param *`fromName`* - Sender's name
+
+param *`senderEmail`* - Sender's Email.
+
+```C++
+void setSender(const String &fromName, const String &senderEmail);
+```
+
+
+
+
+
+**Get Sender's name**
+
+return *`Sender's name String.`*
+
+```C++
+String getFromName();
+```
+
+
+
+
+
+**Get Sender's Email.**
+
+return *`Sender's Email String.`*
+
+```C++
+String getSenderEmail();
+```
+
+
+
+
+**Set Email priority or importance**
+
+param *`priority`* - Number from 1 to 5, 1 for highest, 3 for normal and 5 for lowest priority
+
+```C++
+void setPriority(int priority);
+```
+
+
+
+
+
+**Set Email priority or importance.**
+
+param *`priority`* - String (High, Normal or Low)
+
+```C++
+void setPriority(const String &priority);
+```
+
+
+
+
+**Get Email priority**
+
+return *`Number`* represents Email priority (1 for highest, 3 for normal, 5 for low priority).
+
+```C++
+uint8_t getPriority();
+```
+
+
+
+
+**Add one or more recipient**
+
+param *`email`* - Recipient Email String of one recipient.
+
+To add multiple recipients, call addRecipient for each recipient.
+
+```C++
+void addRecipient(const String &email);
+```
+
+
+
+
+**Remove recipient**
+
+param *`email`* - Recipient Email String.
+
+```C++
+void removeRecipient(const String &email);
+```
+
+
+
+
+**Remove recipient**
+
+param *`index`* - Index of recipients in Email object that previously added.
+
+```C++
+void removeRecipient(uint8_t index);
+```
+
+
+
+
+**Clear all recipients**
+```C++
+void clearRecipient();
+```
+
+
+
+
+**Get one recipient**
+
+param *`index`* - Index of recipients.
+
+return *`Recipient Email`* String at the index.
+
+```C++
+String getRecipient(uint8_t index);
+```
+
+
+
+
+
+**Get number of recipients**
+
+return *`Number`* of recipients.
+
+```C++
+uint8_t recipientCount();
+```
+
+
+
+
+**Set the Email subject.**
+
+param *`subject`* - The subject.
+
+```C++
+void setSubject(const String &subject);
+```
+
+
+
+
+**Get the Email subject.**
+
+return *`Subject String.`*
+
+```C++
+String getSubject();
+```
+
+
+
+
+**Set the Email message**
+
+param *`message`* - The message can be in normal text or html format.
+
+param *`htmlFormat`* - The html format flag, True for send the message as html format
+
+```C++
+void setMessage(const String &message, bool htmlFormat);
+```
+
+
+
+
+**Get the message**
+
+return *`Message String.`*
+
+```C++
+String getMessage();
+```
+
+
+
+
+**Determine message is being send in html format.**
+
+return *`Boolean`* status.
+
+```C++
+bool htmlFormat();
+```
+
+
+
+
+
+**Add Carbon Copy (CC) Email.**
+
+param *`email`* - The CC Email String.
+
+```C++
+void addCC(const String &email);
+```
+
+
+
+
+
+**Remove specified Carbon Copy (CC) Email**
+
+param *`email`* - The CC Email String to remove.
+
+```C++
+void removeCC(const String &email);
+```
+
+
+
+
+
+**Remove specified Carbon Copy (CC) Email**
+
+param *`index`* - The CC Email index to remove.
+
+```C++
+void removeCC(uint8_t index);
+```
+
+
+
+
+
+**Clear all Carbon Copy (CC) Emails**
+
+```C++
+void clearCC();
+```
+
+
+
+
+
+**Get Carbon Copy (CC) Email at specified index.**
+
+param *`index`* - The CC Email index to get.
+return *`The CC Email string`* at the index.
+
+```C++
+String getCC(uint8_t index);
+```
+
+
+
+
+
+**Get the number of Carbon Copy (CC) Email.**
+
+return *`Number`* of CC Emails.
+
+```C++
+uint8_t ccCount();
+```
+
+
+
+
+
+**Add Blind Carbon Copy (BCC) Email**
+
+param *`email`* - The BCC Email String.
+
+```C++
+void addBCC(const String &email);
+```
+
+
+
+
+
+**Remove specified Blind Carbon Copy (BCC) Email**
+
+param *`email`* - The BCC Email String to remove.
+
+```C++
+void removeBCC(const String &email);
+```
+
+
+
+
+
+**Remove specified Blind Carbon Copy (BCC) Email**
+
+param *`index`* - The BCC Email index to remove.
+
+```C++
+void removeBCC(uint8_t index);
+```
+
+
+
+
+
+
+**Clear all Blind Carbon Copy (BCC) Emails**
+
+```C++
+void clearBCC();
+```
+
+
+
+
+
+**Get Blind Carbon Copy (BCC) Email at specified index.**
+
+param *`index`* - The BCC Email index to get.
+
+return *`The BCC Email string`* at the index.
+
+```C++
+String getBCC(uint8_t index);
+```
+
+
+
+
+
+**Get the number of Blind Carbon Copy (BCC) Email**
+
+return *`Number`* of BCC Emails.
+
+```C++
+uint8_t bccCount();
+```
+
+
+
+
+
+**Add attchement data (binary) from internal memory (flash or ram).**
+
+param *`fileName`* - The file name String that recipient can be saved.
+
+param *`mimeType`* - The MIME type of file (image/jpeg, image/png, text/plain...). Can be empty String.
+
+param *`data`* - The byte array of data (uint8_t).
+
+param *`size`* - The data length in byte.
+
+```C++
+void addAttachData(const String &fileName, const String &mimeType, uint8_t *data, uint16_t size);
+```
+
+
+
+
+
+**Remove specified attachment data.**
+
+param *`fileName`* - The file name of the attachment data to remove.
+
+```C++
+void removeAttachData(const String &fileName);
+```
+
+
+
+
+
+**Remove specified attachment data.**
+
+param *`index`* - The index of the attachment data (count only data type attachment) to remove.
+
+```C++
+void removeAttachData(uint8_t index);
+```
+
+
+
+
+**Get the number of attachment data.**
+
+return *`Number`* of attach data.
+
+```C++
+uint8_t attachDataCount();
+```
+
+
+
+**Add attchement file from SD card**
+
+param *`fileName`* - The file name String that recipient can be saved.
+
+param *`mimeType`* - The MIME type of file (image/jpeg, image/png, text/plain...). Can be omitted.
+
+```C++
+void addAttachFile(const String &filePath, const String &mimeType = "");
+```
+
+
+
+
+**Remove specified attachment file from Email object.**
+
+param *`fileName`* - The file name of the attachment file to remove.
+
+```C++
+void removeAttachFile(const String &filePath);
+```
+
+
+
+
+**Set storage type for all attach files.**
+
+param *`storageType`* - The storage type to read attach file, MailClientStorageType::SD or MailClientStorageType::SPIFFS.
+
+```C++
+void setFileStorageType(uint8_t storageType);
+```
+
+
+
+
+
+
+**Remove specified attachment file.**
+
+param *`index`* - The index of the attachment file (count only file type attachment) to remove.
+
+```C++
+void removeAttachFile(uint8_t index);
+```
+
+
+
+
+**Clear all attachment data.**
+
+```C++
+void clearAttachData();
+```
+
+
+
+
+**Clear all attachment file.**
+
+```C++
+void clearAttachFile();
+```
+
+
+
+
+**Clear all attachments (both data and file type attachments).**
+
+```C++
+void clearAttachment();
+```
+
+
+
+
+**Get number of attachments (both data and file type attachments).**
+
+return *`Number`* of all attachemnts.
+
+```C++
+uint8_t attachFileCount();
+```
+
+
+
+
+
+**Add one or more custom message header field.**
+
+param *`field`* - custom header String inform of FIELD: VALUE
+
+This header field will add to message header.
+
+```C++
+void addCustomMessageHeader(const String &field);
+```
+
+
+
+
+
+
+**Remove one custom message header field that previously added..**
+
+param *`field`* - custom custom message header field String to remove.
+
+```C++
+void removeCustomMessageHeader(const String &field);
+```
+
+
+
+
+
+**Remove one custom message header field that previously added by its index.**
+
+param *`index`* - custom message header field index (number) to remove.
+
+
+```C++
+void removeCustomMessageHeader(uint8_t index);
+```
+
+
+
+
+
+**Clear all ccustom message header field that previously added.**
+
+```C++
+void clearCustomMessageHeader();
+```
+
+
+
+
+
+
+**Get the number of custom message header field that previously added.**
+
+return *`Number`* of custom message header field.
+
+```C++
+uint8_t CustomMessageHeaderCount();
+```
+
+
+
+
+
+
+**Get custom message header field that previously added by index.**
+
+param *`index`* - The custom message header field index to get.
+
+return *`The custom message header field string at the index`*.
+
+```C++
+String getCustomMessageHeader(uint8_t index);
+```
+
+
+
+
+
+**Clear all data from Email object to free memory.**
+
+```C++
+void empty();
+```
+
+
+
+
+
+**Set the Email sending status callback function to Email object.**
+
+param *`sendCallback`* - The callback function that accept the sendStatusCallback param.
+
+```C++
+void setSendCallback(sendStatusCallback sendCallback);
+```
+
+
+
+
+__MailClient.Time functions__
+
+
+**Get the time from NTP server and set to device.**
+
+param *`gmtOffset`* - The GMT time offset in hour.
+
+param *`daylightOffset`* - The Daylight time offset in hour.
+
+return - *`Boolean`* type status indicates the success of operation.
+
+This requires internet connectivity.
+
+```C++
+bool setClock(float gmtOffset, float daylightOffset);
+```
+
+
+
+
+
+
+**Get the Unix time.**
+
+return - *`uint32_t`* value of current Unix time.
+
+```C++
+uint32_t getUnixTime();
+```
+
+
+
+
+
+
+**Get timestamp from defined year, month, date, hour, minute, and second.**
+
+param *`year`* - Year.
+param *`mon`* - Month (1 to 12).
+param *`date`* - Date.
+param *`hour`* - Hour.
+param *`mins`* - Minute.
+param *`sec`* - Second.
+
+return - *`time_t`* value of timestamp.
+
+```C++
+time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec);
+```
+
+
+
+
+
+
+**Get current year.**
+
+return - *`int`* value of current year.
+
+```C++
+int getYear();
+```
+
+
+
+
+
+
+**Get current month.**
+
+return - *`int`* value of current month.
+
+```C++
+int getMonth();
+```
+
+
+
+
+
+**Get current date.**
+
+return - *`int`* value of current date.
+
+```C++
+int getDay();
+```
+
+
+
+
+
+
+**Get current day of week.**
+
+return - *`int`* value of day of week.
+
+1 for sunday and 7 for saturday
+
+```C++
+int getDayOfWeek();
+```
+
+
+
+
+
+**Get current day of week in String.**
+
+return - *`String`* value of day of week.
+
+Returns sunday, monday, tuesday, wednesday, thurseday, friday and saturday.
+
+```C++
+String getDayOfWeekString();
+```
+
+
+
+
+
+
+**Get current hour.**
+
+return - *`int`* value of current hour (0 to 23).
+
+```C++
+int getHour();
+```
+
+
+
+
+
+
+**Get current minute.**
+
+return - *`int`* value of current minute (0 to 59).
+
+```C++
+int getMin();
+```
+
+
+
+
+
+
+**Get current second.**
+
+return - *`int`* value of current second (0 to 59).
+
+```C++
+int getSecond();
+```
+
+
+
+
+
+
+
+**Get the total days of current year.**
+
+return - *`int`* value of total days of current year.
+
+```C++
+int getNumberOfDayThisYear();
+```
+
+
+
+
+
+
+**Get the total days of from January 1, 1970 to specific date.**
+
+param *`year`* - Year from 1970.
+param *`mon`* - Month (1 to 12).
+param *`date`* - Date.
+
+return - *`int`* value of total days.
+
+```C++
+int getTotalDays(int year, int month, int day);
+```
+
+
+
+
+
+**Get the day of week from specific date.**
+
+param *`year`* - Year.
+param *`month`* - Month (1 to 12).
+param *`day`* - Date.
+
+return - *`int`* value of day of week.
+
+1 for sunday and 7 for saturday
+
+```C++
+int dayofWeek(int year, int month, int day);
+```
+
+
+
+
+
+
+**Get the second of current hour.**
+
+return - *`int`* value of current second.
+
+```C++
+int getCurrentSecond();
+```
+
+
+
+
+
+**Get the current timestamp.**
+
+return - *`uint64_t`* value of current timestamp.
+
+```C++
+uint64_t getCurrentTimestamp();
+```
+
+
+
+
+
+
+**Get time (year, month, day, hour, minute, and second) from second counted from January 1, 1970.**
+
+param *`secCount`* - The seconds from January 1, 1970 00.00.
+param *`yrs`* - The return year.
+param *`months`* - The return month.
+param *`days`* - The return day.
+param *`hr`* - The return hour.
+param *`min`* - The return minute.
+param *`sec`* - The return second.
+
+```C++
+void getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec);
+```
+
+
+
+
+
+
+## License
+
+The MIT License (MIT)
+
+Copyright (c) 2019 K. Suwatchai (Mobizt)
+
+
+Permission is hereby granted, free of charge, to any person returning a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+
diff --git a/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino b/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino
new file mode 100755
index 000000000..4c3540898
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino
@@ -0,0 +1,278 @@
+/*
+ * Created by K. Suwatchai (Mobizt)
+ *
+ * Email: k_suwatchai@hotmail.com
+ *
+ * Github: https://github.com/mobizt
+ *
+ * Copyright (c) 2019 mobizt
+ *
+*/
+
+
+//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
+
+//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
+
+/*
+ ===========================================================================================================================
+ To prevent stack overrun in case of you want to download email attachments in IMAP readMail,
+ increase the stack size in app_main() in esp32 main.cpp will help by change the stack size from 8192 to any more value
+ as following
+
+ xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
+ to
+ xTaskCreatePinnedToCore(loopTask, "loopTask", 16384, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
+
+ For Arduino, file esp32's main.cpp is at C:\Users\USER_NAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\main.cpp
+ And for platformIO, that file is at C:\Users\USER_NAME\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp
+ ===========================================================================================================================
+
+*/
+
+#include
+#include "ESP32_MailClient.h"
+#include "SD.h"
+
+#define WIFI_SSID "YOUR_WIFI_SSID"
+#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
+
+
+
+//The Email Reading data object contains config and data that received
+IMAPData imapData;
+
+//Callback function to get the Email reading status
+void readCallback(ReadStatus info);
+
+//List all files in SD card
+void printDirectory(File &dir, int depth);
+
+void readEmail();
+
+unsigned long lastTime = 0;
+
+void setup()
+{
+
+ Serial.begin(115200);
+ Serial.println();
+
+ Serial.print("Connecting to AP");
+
+ WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
+ while (WiFi.status() != WL_CONNECTED)
+ {
+ Serial.print(".");
+ delay(200);
+ }
+
+ Serial.println("");
+ Serial.println("WiFi connected.");
+ Serial.println("IP address: ");
+ Serial.println(WiFi.localIP());
+
+ Serial.println();
+
+ MailClient.sdBegin();
+ //MailClient.sdBegin(14,2,15,13); //SCK, MISO, MOSI,SS for TTGO T8 v1.7 or 1.8
+
+ File dir = SD.open("/");
+
+ printDirectory(dir, 0);
+
+ Serial.println();
+
+ imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
+ imapData.setFolder("INBOX");
+
+ //Clear fetch UID
+ //If fetch UID was set, no search is perform.
+ imapData.setFetchUID("");
+
+ //imapData.setSearchCriteria("UID SINCE 10-Feb-2019");
+ //imapData.setSearchCriteria("UID 700:*");
+ //imapData.setSearchCriteria("UID SEARCH NOT SEEN");
+ //imapData.setSearchCriteria("UID SEARCH UNSEEN");
+ imapData.setSearchCriteria("UID SEARCH ALL");
+
+ //To fetch or read one message UID = 320
+ //imapData.setFechUID("320");
+
+ //Set SD folder to save download messages and attachments
+ imapData.setSaveFilePath("/email_data");
+
+ //Save attachament
+ imapData.setDownloadAttachment(true);
+
+ //Set fetch/search result to return html message
+ imapData.setHTMLMessage(true);
+
+ //Set fetch/search result to return text message
+ imapData.setTextMessage(true);
+
+ //Set to save html message in SD card with decoded content.
+ imapData.saveHTMLMessage(true, true);
+
+ //Set to save text message in SD card with decoded content.
+ imapData.saveTextMessage(true, true);
+
+ //Set the maximum result when search criteria was set.
+ imapData.setSearchLimit(10);
+
+ //Set the sort order of returning message upon most recent received email.
+ imapData.setRecentSort(true);
+
+ //Set the return tex/html message size in byte.
+ imapData.setMessageBufferSize(200);
+
+ //Set the maximum attachment size 5 MB (each file)
+ imapData.setAttachmentSizeLimit(1024 * 1024 * 5);
+
+ //Set the Email receive callback function.
+ imapData.setReadCallback(readCallback);
+
+ //Set to get attachment downloading progress status.
+ imapData.setDownloadReport(true);
+
+ //Set the storage types to save download attachments or messages (SD is default)
+ //imapData.setFileStorageType(MailClientStorageType::SPIFFS)
+ imapData.setFileStorageType(MailClientStorageType::SD);
+
+ MailClient.readMail(imapData);
+}
+
+void readEmail()
+{
+
+ Serial.println();
+ Serial.println("Read Email...");
+
+ imapData.setFetchUID("10");
+ imapData.setSearchCriteria("");
+ MailClient.readMail(imapData);
+
+ imapData.setFetchUID("11");
+ imapData.setSearchCriteria("");
+ MailClient.readMail(imapData);
+
+ imapData.setFetchUID("12");
+ imapData.setSearchCriteria("");
+ MailClient.readMail(imapData);
+}
+
+void loop()
+{
+
+ if (millis() - lastTime > 1000 * 60 * 3)
+ {
+
+ lastTime = millis();
+ Serial.println(ESP.getFreeHeap());
+
+ readEmail();
+ }
+}
+
+//Callback function to get the Email reading status
+void readCallback(ReadStatus msg)
+{
+ //Print the current status
+ Serial.println("INFO: " + msg.info());
+
+ if (msg.status() != "")
+ Serial.println("STATUS: " + msg.status());
+
+ //Show the result when reading finished
+ if (msg.success())
+ {
+
+ for (int i = 0; i < imapData.availableMessages(); i++)
+ {
+ Serial.println("=================");
+
+ //Search result number which varied upon search crieria
+ Serial.println("Messsage Number: " + imapData.getNumber(i));
+
+ //UID only available when assigned UID keyword in setSearchCriteria
+ //e.g. imapData.setSearchCriteria("UID SEARCH ALL");
+ Serial.println("Messsage UID: " + imapData.getUID(i));
+ Serial.println("Messsage ID: " + imapData.getMessageID(i));
+ Serial.println("Accept Language: " + imapData.getAcceptLanguage(i));
+ Serial.println("Content Language: " + imapData.getContentLanguage(i));
+ Serial.println("From: " + imapData.getFrom(i));
+ Serial.println("From Charset: " + imapData.getFromCharset(i));
+ Serial.println("To: " + imapData.getTo(i));
+ Serial.println("To Charset: " + imapData.getToCharset(i));
+ Serial.println("CC: " + imapData.getCC(i));
+ Serial.println("CC Charset: " + imapData.getCCCharset(i));
+ Serial.println("Date: " + imapData.getDate(i));
+ Serial.println("Subject: " + imapData.getSubject(i));
+ Serial.println("Subject Charset: " + imapData.getSubjectCharset(i));
+
+ //If setHeaderOnly to false;
+ if (!imapData.isHeaderOnly())
+ {
+ Serial.println("Text Message: " + imapData.getTextMessage(i));
+ Serial.println("Text Message Charset: " + imapData.getTextMessgaeCharset(i));
+ Serial.println("HTML Message: " + imapData.getHTMLMessage(i));
+ Serial.println("HTML Message Charset: " + imapData.getHTMLMessgaeCharset(i));
+ if (imapData.isFetchMessageFailed(i))
+ Serial.println("Fetch Error: " + imapData.getFetchMessageFailedReason(i));
+
+ if (imapData.isDownloadMessageFailed(i))
+ Serial.println("Save Content Error: " + imapData.getDownloadMessageFailedReason(i));
+
+ if (imapData.getAttachmentCount(i) > 0)
+ {
+
+ Serial.println("**************");
+ Serial.println("Attachment: " + String(imapData.getAttachmentCount(i)) + " file(s)");
+
+ for (int j = 0; j < imapData.getAttachmentCount(i); j++)
+ {
+ Serial.println("File Index: " + String(j + 1));
+ Serial.println("Filename: " + imapData.getAttachmentFileName(i, j));
+ Serial.println("Name: " + imapData.getAttachmentName(i, j));
+ Serial.println("Size: " + String(imapData.getAttachmentFileSize(i, j)));
+ Serial.println("Type: " + imapData.getAttachmentType(i, j));
+ Serial.println("Creation Date: " + imapData.getAttachmentCreationDate(i, j));
+ if (imapData.isDownloadAttachmentFailed(i, j))
+ Serial.println("Download Attachment Error: " + imapData.getDownloadAttachmentFailedReason(i, j));
+ }
+ }
+ }
+
+ Serial.println();
+ }
+ }
+}
+
+//List all files in SD card
+void printDirectory(File &dir, int depth)
+{
+ while (true)
+ {
+ File entry = dir.openNextFile();
+ if (!entry)
+ break;
+
+ for (uint8_t i = 0; i < depth; i++)
+ Serial.print("| ");
+
+ std::string name = entry.name();
+ if (entry.isDirectory())
+ {
+ Serial.print("+----" + String(name.substr(name.find_last_of("/\\") + 1).c_str()) + "\r\n");
+ printDirectory(entry, depth + 1);
+ }
+ else
+ {
+ Serial.print("+--" + String(name.substr(name.find_last_of("/\\") + 1).c_str()));
+ Serial.print("\t\t\t(");
+ Serial.print(entry.size(), DEC);
+ Serial.println(")");
+ }
+ entry.close();
+ }
+}
diff --git a/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino b/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino
new file mode 100755
index 000000000..4d4a5b1aa
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino
@@ -0,0 +1,180 @@
+
+
+/*
+ * Created by K. Suwatchai (Mobizt)
+ *
+ * Email: k_suwatchai@hotmail.com
+ *
+ * Github: https://github.com/mobizt
+ *
+ * Copyright (c) 2019 mobizt
+ *
+*/
+
+
+//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
+
+//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
+
+
+#include
+#include "ESP32_MailClient.h"
+#include "SD.h"
+
+//For demo only
+#include "image.h"
+
+#define WIFI_SSID "YOUR_WIFI_SSID"
+#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
+
+
+//The Email Sending data object contains config and data to send
+SMTPData smtpData;
+
+//Callback function to get the Email sending status
+void sendCallback(SendStatus info);
+
+void setup()
+{
+
+ Serial.begin(115200);
+ Serial.println();
+
+ Serial.print("Connecting to AP");
+
+ WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
+ while (WiFi.status() != WL_CONNECTED)
+ {
+ Serial.print(".");
+ delay(200);
+ }
+
+ Serial.println("");
+ Serial.println("WiFi connected.");
+ Serial.println("IP address: ");
+ Serial.println(WiFi.localIP());
+ Serial.println();
+
+
+ Serial.println("Mounting SD Card...");
+
+ if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8
+ {
+
+ Serial.println("Preparing attach file...");
+
+ File file = SD.open("/text_file.txt", FILE_WRITE);
+ file.print("Hello World!\r\nHello World!");
+ file.close();
+
+ file = SD.open("/binary_file.dat", FILE_WRITE);
+
+ static uint8_t buf[512];
+
+ buf[0] = 'H';
+ buf[1] = 'E';
+ buf[2] = 'A';
+ buf[3] = 'D';
+ file.write(buf, 4);
+
+ size_t i;
+ memset(buf, 0xff, 512);
+ for (i = 0; i < 2048; i++)
+ {
+ file.write(buf, 512);
+ }
+
+ buf[0] = 'T';
+ buf[1] = 'A';
+ buf[2] = 'I';
+ buf[3] = 'L';
+ file.write(buf, 4);
+
+ file.close();
+ }
+ else
+ {
+ Serial.println("SD Card Monting Failed");
+ }
+
+ Serial.println();
+
+
+ Serial.println("Sending email...");
+
+ //Set the Email host, port, account and password
+ smtpData.setLogin("outlook.office365.com", 587, "YOUR_EMAIL_ACCOUNT@outlook.com", "YOUR_EMAIL_PASSWORD");
+
+ //For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be
+ //enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
+ //smtpData.setSTARTTLS(true);
+
+ //Set the sender name and Email
+ smtpData.setSender("ESP32", "SOME_EMAIL_ACCOUNT@SOME_EMAIL.com");
+
+ //Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
+ smtpData.setPriority("High");
+
+ //Set the subject
+ smtpData.setSubject("ESP32 SMTP Mail Sending Test");
+
+ //Set the message - normal text or html format
+ smtpData.setMessage("Hello World! - From ESP32 ", true);
+
+ //Add recipients, can add more than one recipient
+ smtpData.addRecipient("SOME_RECIPIENT@SOME_MAIL.com");
+
+
+
+ //Add attachments, can add the file or binary data from flash memory, file in SD card
+ //Data from internal memory
+ smtpData.addAttachData("firebase_logo.png", "image/png", (uint8_t *)dummyImageData, sizeof dummyImageData);
+
+ //Add attach files from SD card
+ //Comment these two lines, if no SD card connected
+ //Two files that previousely created.
+ smtpData.addAttachFile("/binary_file.dat");
+ smtpData.addAttachFile("/text_file.txt");
+
+
+ //Add some custom header to message
+ //See https://tools.ietf.org/html/rfc822
+ //These header fields can be read from raw or source of message when it received)
+ smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)");
+ //Be careful when set Message-ID, it should be unique, otherwise message will not store
+ //smtpData.addCustomMessageHeader("Message-ID: ");
+
+ //Set the storage types to read the attach files (SD is default)
+ //smtpData.setFileStorageType(MailClientStorageType::SPIFFS);
+ smtpData.setFileStorageType(MailClientStorageType::SD);
+
+
+
+ smtpData.setSendCallback(sendCallback);
+
+ //Start sending Email, can be set callback function to track the status
+ if (!MailClient.sendMail(smtpData))
+ Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
+
+ //Clear all data from Email object to free memory
+ smtpData.empty();
+
+}
+
+void loop()
+{
+}
+
+//Callback function to get the Email sending status
+void sendCallback(SendStatus msg)
+{
+ //Print the current status
+ Serial.println(msg.info());
+
+ //Do something when complete
+ if (msg.success())
+ {
+ Serial.println("----------------");
+ }
+}
+
diff --git a/libesp32/ESP32-Mail-Client/examples/Send_email/image.h b/libesp32/ESP32-Mail-Client/examples/Send_email/image.h
new file mode 100755
index 000000000..4b8b3542d
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/examples/Send_email/image.h
@@ -0,0 +1,1074 @@
+#include
+
+static const uint8_t dummyImageData[] PROGMEM = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
+0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82,
+0x70, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
+0x65, 0x00, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x49, 0x6D, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61,
+0x64, 0x79, 0x71, 0xC9, 0x65, 0x3C, 0x00, 0x00, 0x42, 0x9A, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA,
+0xEC, 0xDD, 0x7F, 0x90, 0x6C, 0xD9, 0x41, 0xD8, 0xF7, 0xD3, 0xF3, 0xE6, 0xFD, 0xD8, 0xDD, 0xA7,
+0xDD, 0xD1, 0xB2, 0x20, 0x88, 0x70, 0x5E, 0x63, 0xB0, 0xB4, 0x20, 0xE1, 0x37, 0x26, 0x50, 0x05,
+0x68, 0x57, 0xAF, 0x57, 0x3F, 0xA1, 0x70, 0x15, 0x4A, 0x59, 0x80, 0x88, 0xA9, 0xF8, 0x29, 0x02,
+0x1B, 0x12, 0x5C, 0xBB, 0x40, 0x28, 0x48, 0x19, 0x67, 0xA5, 0x42, 0xC6, 0x8A, 0xA3, 0x64, 0xE5,
+0x18, 0x63, 0x91, 0x22, 0x48, 0xB8, 0xCA, 0x95, 0xC4, 0x71, 0x2C, 0x1C, 0x40, 0x6F, 0x77, 0xE3,
+0x18, 0xA5, 0xE2, 0x3F, 0x53, 0x05, 0x55, 0xB6, 0x14, 0x6C, 0x09, 0xF4, 0x0B, 0xAD, 0x24, 0x76,
+0xB5, 0xDA, 0xDD, 0x37, 0x3F, 0x7B, 0xBA, 0xEF, 0x49, 0x9F, 0xDB, 0x7D, 0x7B, 0x6E, 0xFF, 0x98,
+0x79, 0x3D, 0x33, 0xDD, 0x3D, 0x7D, 0xBB, 0x3F, 0x9F, 0xD2, 0xCC, 0x9B, 0xD7, 0x33, 0xD3, 0xD3,
+0x73, 0x67, 0xDE, 0xD5, 0xF9, 0xEE, 0xE9, 0x73, 0x6E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0F, 0x35, 0x87, 0x00,
+0x58, 0x35, 0xF1, 0xFF, 0xFC, 0xBE, 0x46, 0xEF, 0xCD, 0x17, 0x6A, 0x6F, 0x7E, 0xF2, 0x0F, 0x1D,
+0x11, 0x00, 0x10, 0x20, 0x00, 0xD3, 0x8E, 0x8E, 0x9B, 0x9D, 0x3F, 0x1E, 0xED, 0xBC, 0x6C, 0x1E,
+0xDE, 0x18, 0x8B, 0xB7, 0x3E, 0xDC, 0x79, 0xF9, 0xAD, 0xDA, 0x5B, 0x9E, 0xFA, 0x98, 0x23, 0x05,
+0x00, 0x02, 0x04, 0xE0, 0x2C, 0xE1, 0x51, 0xEF, 0xFC, 0xF1, 0x91, 0x81, 0xF0, 0x18, 0x8C, 0x8F,
+0xB2, 0x0F, 0x74, 0x22, 0xE4, 0x67, 0x1C, 0x35, 0x00, 0x10, 0x20, 0x00, 0xA7, 0x89, 0x8F, 0x14,
+0x1D, 0xBF, 0xDF, 0x79, 0xD9, 0x08, 0xB1, 0x1D, 0x42, 0xF3, 0xAB, 0x9D, 0x97, 0x17, 0x43, 0x68,
+0x37, 0x43, 0xC8, 0x3A, 0x2F, 0x17, 0xEE, 0xEA, 0xBC, 0x5C, 0x09, 0xE1, 0xF2, 0xFD, 0x21, 0xAC,
+0xDF, 0x53, 0x7C, 0xDA, 0x87, 0x3B, 0x11, 0xF2, 0x4E, 0x47, 0x0F, 0x00, 0x04, 0x08, 0xC0, 0x49,
+0x03, 0xE4, 0x0F, 0x42, 0x9A, 0xF9, 0xD8, 0x7F, 0x2E, 0x84, 0xDD, 0x2F, 0x87, 0x3C, 0x42, 0xC6,
+0xCF, 0x7C, 0x74, 0x02, 0xE4, 0x6A, 0x08, 0x57, 0xAF, 0x75, 0xCE, 0x8A, 0x17, 0xD2, 0xDF, 0xFE,
+0xE3, 0x4E, 0x84, 0xFC, 0xB6, 0x23, 0x08, 0x00, 0x02, 0x04, 0x60, 0xD2, 0xF8, 0xB8, 0xD9, 0xF9,
+0xE3, 0x43, 0x61, 0xFB, 0xF3, 0xDD, 0x99, 0x8F, 0xFC, 0xC6, 0x78, 0x87, 0x33, 0x62, 0x27, 0x3E,
+0x5E, 0xF6, 0xE7, 0xD3, 0xCC, 0xC8, 0x0B, 0x9D, 0x0F, 0xFE, 0xA6, 0xDA, 0x5B, 0x9E, 0x7E, 0xC1,
+0x91, 0x04, 0x80, 0xE9, 0x5A, 0x73, 0x08, 0x80, 0x25, 0xF5, 0x78, 0xD8, 0xFB, 0xF2, 0xE4, 0xF1,
+0x91, 0x7F, 0x4C, 0x3B, 0xE4, 0xC1, 0x12, 0x5B, 0x1B, 0x9D, 0xBF, 0x3D, 0xE6, 0x10, 0x02, 0xC0,
+0xF4, 0x99, 0x01, 0x01, 0x96, 0x4E, 0xBE, 0xF0, 0x3C, 0x6B, 0x7E, 0x3A, 0xBC, 0xF8, 0x47, 0x93,
+0xC7, 0xC7, 0xE1, 0x67, 0x87, 0x70, 0xD7, 0x2B, 0x42, 0xB8, 0xF2, 0x8A, 0x34, 0xFB, 0x61, 0x16,
+0x04, 0x00, 0xA6, 0xCC, 0x0C, 0x08, 0xB0, 0x8C, 0xEA, 0x61, 0xEF, 0xB9, 0xD3, 0xC5, 0x47, 0x92,
+0x3E, 0x37, 0xB6, 0xCD, 0x82, 0x00, 0x80, 0x00, 0x01, 0x98, 0x48, 0x23, 0xB4, 0xB6, 0x4E, 0x17,
+0x1F, 0xF9, 0x9B, 0xED, 0xEE, 0xA2, 0xF5, 0x10, 0x1E, 0x8F, 0x4F, 0xBF, 0xA5, 0xEE, 0x70, 0x02,
+0x80, 0x00, 0x01, 0x38, 0xCE, 0xB5, 0xD0, 0xDA, 0x3D, 0x5D, 0x7C, 0x14, 0xD2, 0xCE, 0x59, 0x69,
+0xAB, 0xDE, 0xB4, 0x96, 0x04, 0x00, 0x10, 0x20, 0x00, 0x47, 0x3A, 0xD8, 0xAA, 0x9F, 0x29, 0x3E,
+0x0A, 0xDD, 0x59, 0x90, 0x9B, 0x66, 0x41, 0x00, 0x40, 0x80, 0x00, 0x1C, 0x2D, 0x6B, 0x6D, 0x9E,
+0x39, 0x3E, 0x92, 0xB4, 0x83, 0x56, 0x3B, 0x9F, 0x49, 0xF9, 0x90, 0x83, 0x0A, 0x00, 0x02, 0x04,
+0x60, 0x34, 0x29, 0x9E, 0x7E, 0xEB, 0x46, 0xC8, 0xF6, 0x36, 0xCE, 0x1C, 0x1F, 0x85, 0x9D, 0x2F,
+0xA6, 0xD7, 0x8D, 0xF8, 0xF4, 0x5B, 0x1A, 0x8E, 0x2E, 0x00, 0x08, 0x10, 0x80, 0x61, 0x9B, 0x77,
+0x5E, 0xFF, 0x71, 0x82, 0xC5, 0xE9, 0x69, 0x31, 0x7B, 0x7A, 0x09, 0xD1, 0x5A, 0x10, 0x00, 0x10,
+0x20, 0x00, 0x23, 0xEA, 0x21, 0x66, 0xD3, 0x89, 0x8F, 0x42, 0x77, 0x2D, 0x48, 0x23, 0x3E, 0xFD,
+0xE6, 0x86, 0xC3, 0x0B, 0x00, 0x02, 0x04, 0x60, 0x30, 0x40, 0xF2, 0x19, 0x8B, 0x29, 0xC5, 0x47,
+0xFA, 0x9C, 0x74, 0x7F, 0xDD, 0x2B, 0xAA, 0x5B, 0x0B, 0x02, 0x00, 0x02, 0x04, 0xA0, 0xA4, 0xBD,
+0x77, 0x63, 0xAA, 0xF1, 0x51, 0xE8, 0xCE, 0x82, 0xD4, 0xE3, 0xD3, 0x6F, 0xBE, 0xE9, 0x20, 0x03,
+0x80, 0x00, 0x01, 0xE8, 0xCA, 0x0E, 0xEA, 0x53, 0x8F, 0x8F, 0xFC, 0x7E, 0x9B, 0xC5, 0x2C, 0x88,
+0xB5, 0x20, 0x00, 0x20, 0x40, 0x00, 0x8A, 0x50, 0xD8, 0xAF, 0x4F, 0x3D, 0x3E, 0x0A, 0x69, 0x16,
+0x24, 0xB6, 0xD3, 0x2C, 0xC8, 0xBB, 0x1D, 0x68, 0x00, 0x10, 0x20, 0xC0, 0x8A, 0x8B, 0x4F, 0xBF,
+0x75, 0x33, 0xB4, 0x9B, 0xB3, 0x89, 0x8F, 0x3C, 0x6E, 0x9A, 0xDD, 0x2B, 0xA4, 0x87, 0xF0, 0x68,
+0x27, 0x42, 0x36, 0x1C, 0x71, 0x00, 0x10, 0x20, 0xC0, 0x6A, 0xAB, 0x87, 0xF6, 0xDE, 0x6C, 0xE2,
+0xA3, 0xB0, 0xF7, 0x5C, 0x9A, 0x05, 0x49, 0xF1, 0xF1, 0x98, 0xC3, 0x0D, 0x00, 0x02, 0x04, 0x58,
+0x6D, 0x9B, 0xDD, 0x2B, 0x97, 0xCF, 0x28, 0x3E, 0xF2, 0x0F, 0x6B, 0x9B, 0x05, 0x01, 0x00, 0x01,
+0x02, 0x90, 0xBB, 0x16, 0x62, 0x6B, 0x76, 0xF1, 0x51, 0x48, 0x6B, 0x41, 0xB2, 0x66, 0x8A, 0x8F,
+0x27, 0x1C, 0x72, 0x00, 0x10, 0x20, 0xC0, 0xAA, 0x6A, 0xBE, 0x50, 0x9F, 0x79, 0x7C, 0xE4, 0x9F,
+0x12, 0x8B, 0x6D, 0x79, 0x6F, 0xC6, 0xA7, 0xDF, 0x5C, 0x77, 0xE0, 0x01, 0x40, 0x80, 0x00, 0x2B,
+0x29, 0x6B, 0xCC, 0x25, 0x3E, 0x92, 0xFD, 0xE7, 0xBB, 0x8B, 0xD2, 0x6D, 0xCB, 0x0B, 0x00, 0x02,
+0x04, 0x58, 0x3D, 0xF1, 0xE9, 0xB7, 0xD4, 0x7B, 0x41, 0x30, 0xFB, 0xF8, 0x28, 0xEC, 0x3C, 0x93,
+0x5E, 0xA7, 0x59, 0x90, 0x86, 0x9F, 0x00, 0x00, 0x08, 0x10, 0x60, 0xB5, 0xD4, 0x43, 0x6B, 0x77,
+0x7E, 0xF1, 0x91, 0x34, 0x5F, 0x0C, 0xA1, 0xB5, 0x95, 0xDE, 0x32, 0x0B, 0x02, 0x00, 0x02, 0x04,
+0x58, 0x31, 0x9B, 0x21, 0x3B, 0x98, 0x5F, 0x7C, 0x14, 0xBA, 0x6B, 0x41, 0x1A, 0x66, 0x41, 0x00,
+0x40, 0x80, 0x00, 0xAB, 0xE5, 0x5A, 0x77, 0x0B, 0xDE, 0x39, 0xC6, 0x47, 0x72, 0xB0, 0x65, 0x16,
+0x04, 0x00, 0x04, 0x08, 0xB0, 0x72, 0x5A, 0xDB, 0x9B, 0x73, 0x8F, 0x8F, 0xC2, 0xD6, 0xE7, 0xD3,
+0xEB, 0x34, 0x0B, 0x72, 0xD3, 0x0F, 0x02, 0x00, 0x04, 0x08, 0xB0, 0x0A, 0x62, 0x56, 0x3F, 0x97,
+0xF8, 0x48, 0xD2, 0xE2, 0xF7, 0xB4, 0x2B, 0x96, 0x59, 0x10, 0x00, 0x10, 0x20, 0xC0, 0x8A, 0x68,
+0xEF, 0xD4, 0xCF, 0x25, 0x3E, 0x0A, 0x69, 0x2D, 0x48, 0x8C, 0xF5, 0xF8, 0xD4, 0x9B, 0x6E, 0xFA,
+0x61, 0x00, 0x80, 0x00, 0x01, 0x96, 0x58, 0x7C, 0xFA, 0x2D, 0x8D, 0xD0, 0x6E, 0x9E, 0x5F, 0x7C,
+0x24, 0xD9, 0x7E, 0x08, 0xFB, 0xCF, 0xA6, 0xB7, 0x9E, 0xE8, 0x44, 0xC8, 0x86, 0x9F, 0x0A, 0x00,
+0x08, 0x10, 0x60, 0x79, 0xD5, 0x47, 0x77, 0xC0, 0x9A, 0x63, 0x7C, 0x14, 0x5F, 0x2B, 0x9F, 0x05,
+0x69, 0xA7, 0xF8, 0x78, 0xCC, 0x8F, 0x04, 0x00, 0x04, 0x08, 0xB0, 0xCC, 0x01, 0x32, 0xB0, 0x03,
+0xD6, 0x39, 0xC4, 0x47, 0xFE, 0x66, 0x3B, 0x84, 0xFD, 0xE7, 0xD2, 0x5B, 0x8F, 0x9A, 0x05, 0x01,
+0x00, 0x01, 0x02, 0x2C, 0xAB, 0xAC, 0x75, 0x3D, 0x1F, 0xFC, 0x9F, 0x67, 0x7C, 0x14, 0xF6, 0x9E,
+0x2D, 0x66, 0x41, 0x2C, 0x48, 0x07, 0x00, 0x01, 0x02, 0x2C, 0xA5, 0xFE, 0x02, 0xF4, 0x73, 0x8E,
+0x8F, 0xFC, 0xE6, 0x4E, 0x08, 0xED, 0x3C, 0x93, 0xDE, 0x7A, 0x2C, 0x3E, 0xF5, 0xA6, 0xBA, 0x1F,
+0x0E, 0x00, 0x08, 0x10, 0x60, 0xD9, 0x64, 0xCD, 0xCD, 0x85, 0x88, 0x8F, 0x42, 0xF3, 0xF9, 0xEE,
+0xD6, 0xBC, 0x66, 0x41, 0x00, 0x40, 0x80, 0x00, 0xCB, 0x25, 0x3E, 0xFD, 0x96, 0x7A, 0x88, 0xAD,
+0xC5, 0x89, 0x8F, 0x42, 0x5A, 0x90, 0x1E, 0xC2, 0x4D, 0xB3, 0x20, 0x00, 0x20, 0x40, 0x80, 0xE5,
+0x4A, 0x90, 0x7A, 0x38, 0xD8, 0x5E, 0xAC, 0xF8, 0x48, 0xD2, 0x2C, 0x48, 0x6B, 0x2B, 0xBD, 0xF5,
+0x21, 0x3F, 0x23, 0x00, 0x10, 0x20, 0xC0, 0xF2, 0x68, 0xF4, 0x9E, 0xEE, 0xB4, 0x38, 0xF1, 0x51,
+0xE8, 0xCE, 0x82, 0x34, 0xE2, 0x53, 0x6F, 0x6C, 0xF8, 0x31, 0x01, 0x80, 0x00, 0x01, 0x96, 0xC3,
+0xB5, 0x89, 0x03, 0x64, 0x9E, 0xF1, 0x91, 0xA4, 0x19, 0x90, 0xD6, 0xED, 0xF4, 0x96, 0xB5, 0x20,
+0x00, 0x20, 0x40, 0x80, 0xA5, 0xD0, 0xDA, 0xAE, 0x2F, 0x64, 0x7C, 0x14, 0x5F, 0xF3, 0x70, 0x16,
+0xE4, 0x6D, 0x7E, 0x58, 0x00, 0x20, 0x40, 0x80, 0xAA, 0xCB, 0x5A, 0x9B, 0x0B, 0x1B, 0x1F, 0xC9,
+0xC1, 0x56, 0x08, 0xFB, 0xCF, 0xA7, 0xB7, 0x9E, 0xF0, 0xC3, 0x02, 0x00, 0x01, 0x02, 0x54, 0x58,
+0x7C, 0xFA, 0xCD, 0x1B, 0x21, 0xDB, 0xDB, 0x58, 0xD8, 0xF8, 0x28, 0x74, 0x67, 0x41, 0xEA, 0xF1,
+0xA9, 0x37, 0xDE, 0xF4, 0x53, 0x03, 0x40, 0x80, 0x00, 0x54, 0xD7, 0x66, 0x68, 0xED, 0x2E, 0x76,
+0x7C, 0x24, 0x69, 0x8D, 0x4A, 0x77, 0x16, 0xC4, 0x5A, 0x10, 0x00, 0x04, 0x88, 0x43, 0x00, 0x54,
+0x58, 0x3D, 0xC4, 0x6C, 0xB1, 0xE3, 0xA3, 0x90, 0xAE, 0x8E, 0x1E, 0xDB, 0x69, 0x16, 0xE4, 0xDD,
+0x7E, 0x6C, 0x00, 0x08, 0x10, 0x80, 0xAA, 0x06, 0x48, 0xF7, 0x5A, 0x1B, 0x8B, 0x1D, 0x1F, 0xF9,
+0xFB, 0xDB, 0x21, 0xEC, 0x3D, 0x97, 0xDE, 0x7A, 0xB4, 0x13, 0x21, 0x1B, 0x7E, 0x74, 0x00, 0x08,
+0x10, 0x80, 0xAA, 0x69, 0xEF, 0xDD, 0xA8, 0x44, 0x7C, 0x14, 0xF6, 0x9E, 0x4D, 0x21, 0x92, 0xE2,
+0xE3, 0x31, 0x3F, 0x3C, 0x00, 0x04, 0x08, 0x40, 0xD5, 0x64, 0xCD, 0x8D, 0xCA, 0xC4, 0x47, 0xFE,
+0xB1, 0xED, 0x6E, 0x84, 0x84, 0xF8, 0x68, 0x7C, 0xEA, 0x0D, 0x75, 0x3F, 0x40, 0x00, 0x04, 0x08,
+0x40, 0xB5, 0x02, 0x64, 0xB3, 0x32, 0xF1, 0x51, 0xD8, 0xFD, 0x52, 0x11, 0x4E, 0x16, 0xA4, 0x03,
+0xB0, 0x92, 0x6A, 0x0E, 0x01, 0x50, 0x45, 0xF1, 0xE9, 0x37, 0x6F, 0x86, 0x9D, 0x67, 0xFE, 0x20,
+0xEC, 0x3F, 0x57, 0x9D, 0xF8, 0x28, 0xBE, 0xDE, 0xE5, 0xFB, 0x43, 0xB8, 0xE7, 0xCF, 0xA5, 0xB7,
+0xBE, 0xA9, 0xF6, 0xD6, 0x7F, 0xF5, 0x99, 0xCA, 0x1D, 0xFB, 0x27, 0x1B, 0xF5, 0x90, 0xD6, 0xDF,
+0x74, 0x7D, 0xA6, 0xF6, 0x7D, 0x1F, 0xFB, 0x8C, 0xDF, 0x48, 0x00, 0x26, 0xB5, 0xEE, 0x10, 0x00,
+0x15, 0x55, 0x0F, 0xED, 0xBD, 0xEA, 0xC5, 0x47, 0x92, 0xB6, 0xE4, 0xBD, 0xEB, 0x15, 0x21, 0xAC,
+0x5D, 0x4A, 0xB3, 0x20, 0xEF, 0xAC, 0x48, 0x74, 0x14, 0x6B, 0x57, 0xFE, 0x5A, 0x29, 0x3E, 0x8A,
+0xF7, 0xA5, 0x00, 0xF9, 0xAD, 0xCE, 0xCB, 0x07, 0x3A, 0x31, 0xF2, 0x82, 0x5F, 0x4D, 0x00, 0x8E,
+0xE3, 0x29, 0x58, 0x40, 0x55, 0x6D, 0x86, 0xD6, 0x4E, 0xF5, 0xE2, 0xA3, 0xB0, 0xFD, 0xF9, 0xF4,
+0xFA, 0x66, 0x7C, 0xEA, 0x0D, 0x8D, 0x0A, 0xC4, 0xC7, 0xDB, 0x3A, 0x7F, 0x7C, 0x3A, 0x74, 0x9F,
+0x36, 0x56, 0x1F, 0x1B, 0x83, 0xDD, 0xF7, 0x7D, 0xBA, 0xF7, 0xB1, 0x00, 0x20, 0x40, 0x80, 0xA5,
+0x73, 0x2D, 0x5F, 0xD4, 0x5D, 0xC5, 0xF8, 0x48, 0x0E, 0xB6, 0x42, 0x6F, 0x0B, 0xE1, 0x85, 0x5E,
+0x0B, 0xD2, 0x09, 0x8A, 0x9B, 0x9D, 0x3F, 0x3E, 0xD2, 0x79, 0xD9, 0xE8, 0x2F, 0xA2, 0xBF, 0xFD,
+0xA9, 0xC1, 0x97, 0xEE, 0xEE, 0x5E, 0xA1, 0xFB, 0x31, 0xF1, 0x23, 0xF1, 0xD6, 0x8D, 0x9B, 0x7E,
+0x3D, 0x01, 0x38, 0x8A, 0x35, 0x20, 0x40, 0x25, 0xC5, 0xDF, 0xFD, 0xAE, 0xDF, 0x0F, 0x5B, 0x9F,
+0x6D, 0x54, 0x32, 0x3E, 0x0A, 0x17, 0xAF, 0x86, 0xF0, 0xB2, 0x6F, 0x4E, 0x6F, 0x3D, 0x52, 0x7B,
+0xEB, 0xBF, 0xFA, 0xD8, 0x02, 0xC6, 0x47, 0xBD, 0xF3, 0xC7, 0x1F, 0xE4, 0x61, 0x91, 0x16, 0xCF,
+0x1F, 0x86, 0xC6, 0x98, 0xFF, 0x37, 0xB9, 0x10, 0xC2, 0x95, 0x07, 0x3A, 0x2F, 0x5F, 0x9F, 0xFE,
+0x96, 0x9E, 0x86, 0xF5, 0x97, 0x6A, 0xDF, 0xFF, 0x7F, 0x7F, 0xC6, 0x6F, 0x2A, 0x00, 0xC3, 0xCC,
+0x80, 0x00, 0x15, 0x2D, 0x90, 0xAC, 0xDA, 0xF1, 0x91, 0x1C, 0xCE, 0x82, 0x3C, 0xB1, 0xA0, 0x47,
+0xF9, 0x89, 0x3C, 0x3E, 0xB6, 0x3F, 0xD7, 0xDD, 0xBD, 0xEB, 0xB8, 0x19, 0xA7, 0xD8, 0xEA, 0x7E,
+0x4C, 0xFA, 0xD8, 0xF4, 0x39, 0x21, 0x7C, 0xC8, 0x2F, 0x29, 0x00, 0x02, 0x04, 0x58, 0x8E, 0xF6,
+0x78, 0xFA, 0xCD, 0x1B, 0x21, 0x3B, 0xA8, 0x76, 0x7C, 0x14, 0xB6, 0xF2, 0xB5, 0x20, 0x9B, 0xF1,
+0xA9, 0x37, 0xDC, 0x5C, 0xA8, 0x63, 0xFC, 0x64, 0x23, 0x05, 0xDE, 0xDB, 0xC2, 0xCE, 0x17, 0xBA,
+0x8B, 0xE6, 0x27, 0xFD, 0x7E, 0x9B, 0xCF, 0x17, 0x11, 0xD2, 0x88, 0xB7, 0x6E, 0x34, 0xFC, 0xB6,
+0x02, 0x20, 0x40, 0x80, 0x65, 0xB0, 0x19, 0xDA, 0xBB, 0xD5, 0x8F, 0x8F, 0x24, 0x6B, 0x16, 0x03,
+0xFC, 0x45, 0x5B, 0x0B, 0xF2, 0x78, 0x3E, 0x3B, 0x93, 0x5F, 0x38, 0xF1, 0x84, 0xDF, 0x6F, 0x8A,
+0x90, 0x0A, 0xAC, 0x6F, 0x01, 0x40, 0x80, 0x00, 0x9C, 0x20, 0x40, 0x9A, 0xD5, 0x8F, 0x8F, 0xC2,
+0xEE, 0x97, 0xD3, 0xEB, 0x7A, 0x7C, 0xF2, 0x91, 0xC7, 0x16, 0xE1, 0xE0, 0xF6, 0x66, 0x3F, 0x1A,
+0xF9, 0x53, 0xAA, 0x4E, 0xFB, 0xFD, 0x76, 0x3F, 0xD7, 0x2C, 0x08, 0x00, 0x02, 0x04, 0x58, 0x0A,
+0xD7, 0xEE, 0x3C, 0x03, 0x52, 0x91, 0xF8, 0x48, 0xD2, 0x2C, 0x48, 0x77, 0xC0, 0xFE, 0x78, 0x27,
+0x42, 0x36, 0x16, 0xE0, 0xF8, 0x76, 0x67, 0x3F, 0x0E, 0xB6, 0x4E, 0xFF, 0xFD, 0xB6, 0xB6, 0xCC,
+0x82, 0x00, 0x20, 0x40, 0x80, 0x25, 0xD1, 0xDA, 0xDA, 0x5C, 0x9A, 0xF8, 0x28, 0x3E, 0xBF, 0xBB,
+0xC3, 0x54, 0x71, 0xB1, 0xBF, 0x73, 0xD3, 0xBB, 0x8E, 0x47, 0x23, 0x6C, 0x7D, 0xEE, 0xEC, 0xDF,
+0xEF, 0xE1, 0x5A, 0x10, 0xD7, 0x06, 0x01, 0x40, 0x80, 0x00, 0x15, 0x16, 0x63, 0x7D, 0xA9, 0xE2,
+0x23, 0xFF, 0xA3, 0x1D, 0xC2, 0xFE, 0x73, 0xE9, 0xAD, 0x47, 0xCF, 0x79, 0x16, 0xE4, 0x89, 0x7C,
+0x4D, 0x4A, 0xD6, 0x3C, 0xFB, 0xF7, 0x9B, 0xEE, 0xA3, 0xF9, 0x7C, 0xF7, 0x3E, 0x01, 0x40, 0x80,
+0x00, 0x95, 0xD5, 0xDA, 0xA9, 0x2F, 0x55, 0x7C, 0x14, 0xD2, 0x2C, 0x48, 0xD6, 0x4C, 0xF1, 0x71,
+0x2E, 0x4F, 0x5B, 0xEA, 0x5D, 0x74, 0xB0, 0x7E, 0xF4, 0xDA, 0x8F, 0x53, 0x7C, 0xBF, 0xDD, 0xFB,
+0xAA, 0xC7, 0x5B, 0xAF, 0xBF, 0xE9, 0x17, 0x17, 0x00, 0x01, 0x02, 0x54, 0x4E, 0x7C, 0xFA, 0xCD,
+0x8D, 0xF1, 0xFF, 0x75, 0xBE, 0xE2, 0xF1, 0x91, 0xDF, 0xD4, 0x2E, 0x16, 0xA4, 0x3F, 0x16, 0x9F,
+0x7C, 0xA4, 0x7E, 0x0E, 0x87, 0xF7, 0xF1, 0xA3, 0x67, 0x3F, 0x4E, 0xF9, 0xFD, 0xE6, 0xBB, 0x7C,
+0x7D, 0x25, 0x04, 0x6B, 0x41, 0x00, 0x10, 0x20, 0x40, 0x45, 0x6D, 0x8C, 0x0E, 0x90, 0x97, 0x20,
+0x3E, 0x0A, 0xCD, 0x7E, 0x00, 0xCC, 0x75, 0xC0, 0x7E, 0xFC, 0xEC, 0xC7, 0x19, 0x8F, 0x6F, 0xF7,
+0x22, 0x86, 0x66, 0x41, 0x00, 0x10, 0x20, 0x40, 0x25, 0x6D, 0x86, 0xD6, 0xEE, 0x72, 0xC6, 0x47,
+0xA1, 0x3B, 0x0B, 0x72, 0x33, 0x3E, 0xF9, 0xC8, 0xE6, 0x9C, 0xE2, 0xA3, 0xFB, 0xB4, 0xAF, 0x14,
+0x0A, 0xB3, 0x88, 0xBB, 0x74, 0x9F, 0xDD, 0xEB, 0x89, 0x3C, 0xD1, 0x89, 0x90, 0x0D, 0xBF, 0xC2,
+0x00, 0x02, 0x04, 0xA0, 0x3A, 0xB2, 0xD6, 0xF5, 0xFC, 0xA9, 0x4A, 0xCB, 0x1A, 0x1F, 0xC9, 0xE1,
+0x85, 0xFC, 0xE6, 0xB5, 0x78, 0xFB, 0xB1, 0x34, 0x43, 0x31, 0x7A, 0xD1, 0xC1, 0x29, 0x1E, 0xDF,
+0x05, 0xD9, 0xE5, 0x0B, 0x00, 0x01, 0x02, 0x70, 0x32, 0xFD, 0x05, 0xE8, 0x4B, 0x1A, 0x1F, 0x85,
+0xEE, 0x2C, 0x48, 0x23, 0x3E, 0xF9, 0x48, 0x63, 0x96, 0x87, 0xB3, 0x37, 0xFB, 0xF1, 0x68, 0x2F,
+0x10, 0x66, 0x13, 0x1F, 0xF9, 0x6D, 0xED, 0x62, 0x16, 0xE4, 0x51, 0xB3, 0x20, 0x00, 0x02, 0x04,
+0xA0, 0x3A, 0xB2, 0xFD, 0xCD, 0xA5, 0x8F, 0x8F, 0xE4, 0xE0, 0xF6, 0xBC, 0x2E, 0xE4, 0xF7, 0x58,
+0x3E, 0x33, 0x31, 0x30, 0xFB, 0x31, 0xA3, 0xE3, 0x6B, 0x16, 0x04, 0x00, 0x01, 0x02, 0x54, 0x49,
+0x7C, 0xEA, 0x4D, 0xF5, 0xC1, 0xFF, 0x4A, 0xBF, 0xA4, 0xF1, 0x51, 0x3C, 0xCE, 0xED, 0x2F, 0xA4,
+0xD7, 0x69, 0x16, 0x64, 0x26, 0x17, 0xF2, 0x1B, 0x3F, 0xFB, 0x31, 0xC3, 0xB8, 0x33, 0x0B, 0x02,
+0x80, 0x00, 0x01, 0x2A, 0xA6, 0x1E, 0x0E, 0xB6, 0x56, 0x23, 0x3E, 0x92, 0xF6, 0x6E, 0xC8, 0xB7,
+0xC5, 0x9D, 0xDD, 0x5A, 0x90, 0xC7, 0xF3, 0xEB, 0x8E, 0xF4, 0x77, 0xBE, 0x9A, 0xC3, 0xCC, 0x52,
+0x77, 0xA1, 0xFB, 0xB9, 0x5D, 0xEB, 0x04, 0x00, 0x01, 0x02, 0x70, 0x12, 0x8D, 0xA3, 0xAF, 0xD0,
+0xBD, 0x64, 0xF1, 0x51, 0x1E, 0xB0, 0xA7, 0x0B, 0xF9, 0x3D, 0xF9, 0xC8, 0xCD, 0x69, 0x1E, 0xC8,
+0xF8, 0x64, 0xA3, 0x1E, 0xD2, 0x53, 0xA1, 0xE6, 0x19, 0x1F, 0x83, 0xDF, 0xD3, 0x63, 0xF1, 0xD6,
+0xEB, 0xEB, 0x7E, 0xA5, 0x01, 0x04, 0x08, 0xC0, 0x22, 0xBB, 0xEF, 0xC4, 0x01, 0x52, 0xE5, 0xF8,
+0x48, 0xF2, 0x0B, 0xF9, 0xE5, 0xB3, 0x20, 0x8F, 0x77, 0x22, 0x64, 0x9A, 0x4F, 0x5B, 0x7A, 0xFC,
+0xF0, 0xBE, 0xE7, 0xBC, 0xA6, 0x66, 0xFF, 0x7C, 0xAE, 0x75, 0x02, 0x80, 0x00, 0x01, 0x38, 0x99,
+0xD6, 0xD6, 0xC9, 0xAE, 0x8B, 0x51, 0xF5, 0xF8, 0x28, 0xEC, 0x7C, 0x21, 0xBF, 0x90, 0x5F, 0x98,
+0xD2, 0xE2, 0xED, 0xDE, 0xEC, 0xC7, 0xCD, 0xEE, 0x4C, 0xC4, 0xBC, 0x17, 0xF4, 0xF7, 0x74, 0x67,
+0x41, 0x6E, 0x9A, 0x05, 0x01, 0x58, 0x3D, 0xEB, 0x0E, 0x01, 0x50, 0x19, 0x59, 0x6B, 0xF2, 0x00,
+0x59, 0x96, 0xF8, 0xC8, 0x3F, 0xA6, 0xB7, 0x78, 0xFB, 0xAE, 0xAF, 0x7F, 0x34, 0x3E, 0xF9, 0xC8,
+0x07, 0x6A, 0xDF, 0xF7, 0xFB, 0x2F, 0x9C, 0xF1, 0x81, 0x3E, 0x9E, 0x5F, 0xCC, 0x71, 0xFF, 0x2B,
+0xE7, 0x13, 0x1F, 0x49, 0x9A, 0x05, 0xB9, 0xF2, 0xB5, 0x21, 0x5C, 0xB8, 0x92, 0x66, 0x41, 0xDE,
+0xE9, 0x97, 0x7B, 0xCC, 0x21, 0xFE, 0xC4, 0x8F, 0xA6, 0x19, 0xAF, 0xB4, 0x01, 0x41, 0x39, 0xD2,
+0xFE, 0xB0, 0xF3, 0xF2, 0xB1, 0xDA, 0xB7, 0xFD, 0xCF, 0x2F, 0x38, 0x42, 0x40, 0x55, 0xD5, 0x1C,
+0x02, 0xA0, 0x12, 0x83, 0xB1, 0xA7, 0xDE, 0xB4, 0x11, 0xF6, 0xBE, 0xFC, 0xD5, 0xC3, 0x35, 0x0B,
+0x2B, 0x12, 0x1F, 0xFD, 0xB3, 0xF5, 0x85, 0x10, 0x36, 0xBE, 0x2D, 0xFD, 0xF9, 0x9E, 0x4E, 0x80,
+0xBC, 0xFB, 0xD4, 0x8F, 0xF2, 0xC9, 0x46, 0x8A, 0xB8, 0x3F, 0x08, 0x2F, 0x7D, 0xB2, 0xD8, 0xE6,
+0x77, 0xFE, 0xF1, 0x51, 0xB8, 0x78, 0x4F, 0x08, 0x2F, 0xFB, 0x96, 0xF4, 0xD6, 0x23, 0xB5, 0xEF,
+0xFF, 0x7F, 0x3E, 0xE6, 0xB7, 0x7C, 0x20, 0x3C, 0xD2, 0xC6, 0x03, 0x37, 0x8F, 0x0C, 0xD2, 0xDA,
+0x85, 0x0F, 0x77, 0xDE, 0xFA, 0x19, 0x21, 0x02, 0x54, 0x91, 0xA7, 0x60, 0x01, 0x55, 0xB1, 0x99,
+0xFF, 0x57, 0xFB, 0x55, 0x8C, 0x8F, 0x62, 0xD0, 0xD9, 0x8D, 0xAF, 0x47, 0x7B, 0x4F, 0xA1, 0x3A,
+0xAD, 0x27, 0x4A, 0xD7, 0x18, 0x39, 0xBF, 0xF8, 0x48, 0xC7, 0x2C, 0xED, 0x68, 0x36, 0x9F, 0x6B,
+0x9D, 0x54, 0x29, 0x3E, 0x52, 0x20, 0x7E, 0x7A, 0x20, 0x3E, 0xE2, 0x41, 0x08, 0xD9, 0xCE, 0xE1,
+0x56, 0xC9, 0x29, 0x46, 0xBB, 0xEF, 0xFF, 0x74, 0xEF, 0xE3, 0x01, 0x04, 0x08, 0xC0, 0x0C, 0xDC,
+0xF9, 0x1A, 0x20, 0xCB, 0x1A, 0x1F, 0x85, 0xF4, 0x34, 0xAC, 0x6C, 0xFF, 0xD4, 0x5B, 0xD8, 0xC6,
+0x5B, 0x37, 0x1A, 0x9D, 0xAF, 0xDD, 0x98, 0x68, 0x16, 0x69, 0xD6, 0xF1, 0x51, 0xE8, 0x3E, 0x96,
+0x46, 0xBC, 0xF5, 0x70, 0x43, 0x7C, 0xE4, 0x31, 0xF1, 0xFB, 0x9D, 0x97, 0x8D, 0x3C, 0x3A, 0x9A,
+0xCF, 0x74, 0x8E, 0xCF, 0xBF, 0xEF, 0xBC, 0x7C, 0xAA, 0xF3, 0xB3, 0xFF, 0xEC, 0xE1, 0xDB, 0xCD,
+0x2F, 0x77, 0xA3, 0x24, 0x7D, 0x5C, 0xE7, 0xE3, 0x45, 0x08, 0x20, 0x40, 0x00, 0x66, 0x15, 0x20,
+0xC7, 0xFD, 0x57, 0xFB, 0x65, 0x8F, 0x8F, 0xE2, 0xEB, 0x15, 0x8B, 0xB7, 0x4F, 0x37, 0x0B, 0xF2,
+0x78, 0x7E, 0x0C, 0x4F, 0x33, 0xFB, 0x31, 0x8B, 0xF8, 0x48, 0xCC, 0x82, 0x8C, 0xC6, 0xC7, 0xC1,
+0x73, 0xDD, 0xD0, 0x68, 0xBD, 0x18, 0x46, 0xA2, 0x3B, 0x85, 0x47, 0xEB, 0xF9, 0x4E, 0x90, 0x7C,
+0xBA, 0xFB, 0xFE, 0x6E, 0x84, 0x3C, 0xE1, 0xF4, 0x00, 0x08, 0x10, 0x80, 0x69, 0x6B, 0xEF, 0xDD,
+0x58, 0xF9, 0xF8, 0x48, 0x0E, 0xB7, 0xB0, 0x3D, 0xD1, 0xA0, 0x33, 0x9F, 0xFD, 0x48, 0xD7, 0x51,
+0x39, 0xCD, 0xEC, 0xC7, 0xAC, 0xE2, 0xA3, 0x50, 0x5C, 0xF1, 0x7D, 0x45, 0x67, 0x41, 0x06, 0xE2,
+0x23, 0xCD, 0x7A, 0x1C, 0x3C, 0x3B, 0xC1, 0x27, 0xB5, 0xBB, 0x33, 0x24, 0x29, 0x56, 0xD2, 0xB1,
+0xFB, 0xC4, 0x8F, 0xBE, 0xCD, 0x49, 0x02, 0x10, 0x20, 0x00, 0xD3, 0xD4, 0xBD, 0x7A, 0xF6, 0x6A,
+0xC7, 0x47, 0x61, 0xEB, 0x73, 0xE9, 0xA6, 0xB7, 0xC5, 0x5B, 0x8D, 0x93, 0x0C, 0xD8, 0x9F, 0x08,
+0xCD, 0xE7, 0x4F, 0x3E, 0xFB, 0x31, 0xEB, 0xF8, 0xC8, 0xE3, 0x72, 0xE6, 0x57, 0x7C, 0xAF, 0x4E,
+0x7C, 0x74, 0x67, 0x35, 0x26, 0x97, 0x62, 0xA5, 0x7D, 0x3B, 0xBD, 0xF5, 0x83, 0x4E, 0x12, 0x80,
+0x00, 0x01, 0x98, 0x6A, 0x80, 0xEC, 0x6F, 0x8A, 0x8F, 0xDE, 0x5F, 0x4F, 0xF8, 0xB4, 0xA5, 0x78,
+0xEB, 0xC6, 0xCD, 0x90, 0x16, 0xF1, 0x9F, 0x74, 0xF6, 0x63, 0x1E, 0xF1, 0x51, 0xE8, 0x3E, 0xB6,
+0xCD, 0x78, 0xEB, 0xE1, 0x9B, 0xE2, 0xE3, 0x84, 0xD2, 0x9A, 0x90, 0x34, 0xBB, 0x05, 0x20, 0x40,
+0x00, 0xA6, 0x34, 0x50, 0x7B, 0xEA, 0x4D, 0x9B, 0xA1, 0x7D, 0xB0, 0xBA, 0xF1, 0x11, 0x07, 0xBF,
+0x74, 0xFE, 0xD7, 0xCE, 0x80, 0xBD, 0xF3, 0x67, 0x23, 0x9B, 0x6C, 0x16, 0xE4, 0xF1, 0x7C, 0xF6,
+0xE3, 0x24, 0x57, 0x91, 0x9F, 0x67, 0x7C, 0xE4, 0x81, 0x79, 0x78, 0xC5, 0x77, 0xF1, 0x71, 0xD2,
+0x3B, 0xEB, 0xFC, 0xDB, 0x68, 0xBF, 0x54, 0x77, 0xA6, 0x00, 0x04, 0x08, 0xC0, 0xF4, 0xD4, 0xF3,
+0xA7, 0xE9, 0xAC, 0x6A, 0x7C, 0x24, 0xB5, 0xEE, 0xDD, 0xF5, 0xEF, 0xB1, 0xB9, 0xD5, 0x79, 0xC9,
+0x07, 0xAD, 0x1F, 0x3A, 0xF6, 0x5E, 0xBA, 0xB3, 0x1F, 0xF5, 0x13, 0xCD, 0x7E, 0xCC, 0x3B, 0x3E,
+0x0A, 0xDD, 0xC7, 0x58, 0x5F, 0xF6, 0x59, 0x90, 0xA9, 0xC6, 0x47, 0x71, 0x9C, 0xB3, 0xFD, 0xCE,
+0xFD, 0xBE, 0xA3, 0xE1, 0x54, 0x01, 0x08, 0x10, 0x80, 0xE9, 0xD8, 0xEC, 0x07, 0xC8, 0x2A, 0xC6,
+0xC7, 0xF0, 0xDD, 0x15, 0x6F, 0xA7, 0xC5, 0xDB, 0x31, 0xD4, 0xB3, 0x8F, 0x36, 0x8E, 0x1B, 0xB0,
+0x3F, 0x1E, 0xF6, 0x9F, 0x9D, 0x7C, 0xF6, 0xE3, 0xBC, 0xE2, 0x23, 0x49, 0x8F, 0x71, 0xEF, 0xD9,
+0xEE, 0x63, 0x16, 0x1F, 0x27, 0x3B, 0xCE, 0xD9, 0x76, 0x37, 0xD4, 0x01, 0x04, 0x08, 0xC0, 0x54,
+0x5C, 0xCB, 0x77, 0xFD, 0x59, 0xC5, 0x35, 0x1F, 0xC5, 0x2D, 0x71, 0xB4, 0x4D, 0x62, 0x67, 0xC0,
+0x1E, 0xF7, 0x9F, 0x4F, 0x6F, 0x8F, 0x1D, 0xB0, 0x67, 0xB7, 0x6E, 0xBC, 0xBB, 0x73, 0xDC, 0xEA,
+0x61, 0xE7, 0x4B, 0x73, 0x78, 0xDC, 0x53, 0x3A, 0xE6, 0x69, 0x16, 0xA4, 0xF3, 0x98, 0xE3, 0xAD,
+0x87, 0xDF, 0x2D, 0x3E, 0x4E, 0x70, 0x9C, 0xB3, 0x03, 0x01, 0x02, 0x08, 0x10, 0x80, 0xA9, 0x69,
+0xBE, 0x50, 0x5F, 0xC9, 0xF8, 0xA8, 0x8D, 0xC6, 0x47, 0x2C, 0xBE, 0x44, 0xF1, 0xD2, 0x1B, 0xB0,
+0xB7, 0x3F, 0xDA, 0x78, 0x6C, 0x28, 0x3E, 0xD2, 0xAE, 0x61, 0x8F, 0xE6, 0x33, 0x0A, 0x77, 0xBA,
+0x80, 0xE3, 0xA2, 0xC4, 0x47, 0xFE, 0xE9, 0xED, 0x62, 0x16, 0xE4, 0xD1, 0x4E, 0x84, 0x6C, 0x88,
+0x8F, 0x09, 0x8F, 0x73, 0xF7, 0xC2, 0x84, 0x37, 0x9C, 0x2C, 0x00, 0x01, 0x02, 0x30, 0x95, 0xD1,
+0x5B, 0xBB, 0xB1, 0x52, 0xF1, 0xD1, 0x8B, 0x8B, 0x38, 0x66, 0x03, 0xAC, 0xEE, 0xAB, 0x5A, 0xE7,
+0x7D, 0xBD, 0x97, 0x56, 0x67, 0xE0, 0xB9, 0x9B, 0x22, 0x23, 0x3C, 0xDE, 0xFE, 0xBD, 0xC6, 0x46,
+0xE9, 0x83, 0x1F, 0xEB, 0x1C, 0xB7, 0x8D, 0xB8, 0xF7, 0xEC, 0x8C, 0x1F, 0xF7, 0x34, 0x8F, 0x79,
+0xEF, 0xB1, 0xEC, 0xFE, 0x59, 0xFA, 0x99, 0xA7, 0xEF, 0xE5, 0x31, 0xF1, 0x71, 0x82, 0xE3, 0xDC,
+0xBE, 0xBD, 0xE1, 0x64, 0x01, 0x08, 0x10, 0x80, 0xB3, 0x0E, 0xB5, 0x9E, 0x7A, 0xE3, 0x46, 0xEF,
+0xE9, 0x25, 0xAB, 0x11, 0x1F, 0xC7, 0x7D, 0x44, 0x3E, 0x03, 0x52, 0xEB, 0x7F, 0xA9, 0xD8, 0x8B,
+0x94, 0x6C, 0xE7, 0xD9, 0x81, 0x01, 0x7B, 0xFB, 0xA3, 0x37, 0x36, 0x62, 0x9A, 0xFD, 0xD8, 0xED,
+0xCE, 0x7E, 0xC4, 0x52, 0xD4, 0x2C, 0x7C, 0x7C, 0x74, 0x83, 0x73, 0x69, 0x66, 0x41, 0xE6, 0x16,
+0x1F, 0xF9, 0xBB, 0xB2, 0x4D, 0x67, 0x0C, 0x40, 0x80, 0x00, 0x9C, 0xDD, 0xE6, 0xC0, 0x0E, 0x58,
+0xCB, 0x1E, 0x1F, 0xC3, 0xEB, 0xCF, 0xE3, 0x60, 0x7C, 0x14, 0x33, 0x23, 0x87, 0x4F, 0xC3, 0x4A,
+0x05, 0xD2, 0x89, 0x8C, 0x4E, 0x6C, 0x74, 0xDE, 0x7C, 0xB4, 0xF5, 0xBB, 0x8D, 0x6E, 0x88, 0xA4,
+0x20, 0xB9, 0xD3, 0xEC, 0xC7, 0x22, 0xC6, 0x47, 0x21, 0xCD, 0x82, 0x74, 0x2F, 0x3E, 0x59, 0xD9,
+0x59, 0x90, 0xB9, 0xC6, 0x47, 0xFE, 0xEE, 0x83, 0xB4, 0x13, 0x96, 0x08, 0x01, 0x04, 0x08, 0xC0,
+0xD9, 0x03, 0x64, 0xD2, 0xEB, 0x57, 0x2C, 0xC7, 0xCC, 0xC7, 0x9D, 0xE2, 0xA3, 0xF8, 0xB2, 0xB1,
+0xF3, 0x6A, 0x60, 0x16, 0xA4, 0x9D, 0x0F, 0xD8, 0x3F, 0x12, 0x62, 0xED, 0xD1, 0xB4, 0x43, 0x56,
+0xCC, 0x17, 0xEE, 0x8F, 0xDE, 0xE7, 0xC2, 0xC7, 0x47, 0x7E, 0x5B, 0xE7, 0xB1, 0xEF, 0x7C, 0x31,
+0xBD, 0xF5, 0x78, 0xBC, 0xF5, 0x70, 0x5D, 0x7C, 0x4C, 0x70, 0x9C, 0xB3, 0xBD, 0xF4, 0xBA, 0xEE,
+0x94, 0x01, 0x08, 0x10, 0x80, 0xB3, 0xB9, 0x36, 0xD9, 0x0C, 0xC8, 0x12, 0xC4, 0xC7, 0xD8, 0xA7,
+0x48, 0x75, 0xC2, 0x63, 0x4C, 0x7C, 0xA4, 0x57, 0x31, 0x94, 0x66, 0x43, 0xD2, 0x2C, 0xC8, 0xCE,
+0x97, 0x42, 0xFB, 0xC5, 0xD8, 0x88, 0xCD, 0xE6, 0x46, 0xDC, 0xFB, 0xEA, 0x40, 0xC0, 0x0C, 0xDC,
+0x7D, 0xB6, 0xE0, 0xF1, 0x51, 0xD8, 0xEF, 0x5F, 0x3C, 0xB1, 0x52, 0xDB, 0xF2, 0x9E, 0x4B, 0x7C,
+0xE4, 0x1F, 0x76, 0xD0, 0x0D, 0x76, 0x00, 0x01, 0x02, 0x70, 0x06, 0xAD, 0xAD, 0x09, 0x06, 0x54,
+0xCB, 0xB3, 0xE6, 0x63, 0x64, 0xF6, 0x23, 0xC4, 0x81, 0x2F, 0x55, 0x9E, 0xF9, 0x08, 0xA5, 0x97,
+0x7C, 0x16, 0x64, 0xFB, 0xF9, 0x90, 0x6D, 0x35, 0x43, 0xEB, 0xCB, 0x5F, 0xEC, 0x7D, 0x66, 0x6D,
+0xF4, 0x4B, 0xC5, 0x8A, 0xC4, 0x47, 0xA1, 0x3B, 0x0B, 0x72, 0xB3, 0x2A, 0xB3, 0x20, 0xE7, 0x16,
+0x1F, 0x79, 0x58, 0xE6, 0x33, 0x20, 0xD7, 0x9D, 0x34, 0x00, 0x01, 0x02, 0x70, 0xB6, 0x41, 0x6A,
+0x7D, 0x25, 0xE2, 0x23, 0xDD, 0x5C, 0x1B, 0xBD, 0x2D, 0xF6, 0x6E, 0x8C, 0xF1, 0x30, 0x3E, 0x0E,
+0xD7, 0x81, 0xD4, 0xBA, 0x8B, 0xD2, 0x7B, 0x1F, 0x9B, 0xBD, 0xD4, 0x09, 0x93, 0x17, 0x3F, 0x17,
+0xB2, 0xE7, 0x9E, 0x0F, 0xB1, 0x15, 0x06, 0x67, 0x3E, 0x4A, 0xB3, 0x26, 0x95, 0x89, 0x8F, 0xA4,
+0x42, 0xB3, 0x20, 0xE7, 0x1A, 0x1F, 0xFD, 0x08, 0xD9, 0xAD, 0x3B, 0x69, 0x00, 0x02, 0x04, 0xE0,
+0x2C, 0x5A, 0x3B, 0xF5, 0xA5, 0x8F, 0x8F, 0xE1, 0xBB, 0x8E, 0x43, 0x33, 0x21, 0xF1, 0xF0, 0x69,
+0x57, 0xFD, 0xA7, 0x62, 0xC5, 0xDA, 0xC0, 0xDB, 0xB1, 0xD5, 0x79, 0xD9, 0xE9, 0xBC, 0xDD, 0xDC,
+0xEA, 0x1E, 0xB6, 0xAF, 0xC4, 0x7E, 0xA4, 0x1C, 0x5E, 0x3C, 0x64, 0x1A, 0x87, 0x6E, 0x8E, 0xF1,
+0x51, 0xD8, 0xFE, 0xD3, 0xF4, 0x7A, 0xA1, 0x67, 0x41, 0x16, 0x22, 0x3E, 0xF2, 0x4F, 0x6B, 0x79,
+0x0A, 0x16, 0x20, 0x40, 0x00, 0x4E, 0x3D, 0x04, 0x7B, 0xEA, 0x8D, 0x8D, 0xDE, 0x7F, 0xFD, 0x5E,
+0xEE, 0xF8, 0xB8, 0xC3, 0xEC, 0x47, 0x71, 0xC3, 0xE1, 0x4C, 0x46, 0x6D, 0xE0, 0x82, 0x84, 0xF9,
+0xD3, 0xAF, 0x5E, 0x1C, 0xBC, 0xFF, 0xB8, 0xDF, 0x7D, 0x29, 0x1E, 0xF7, 0xD8, 0xB5, 0x20, 0x55,
+0x88, 0x8F, 0xA4, 0xD9, 0x19, 0xCC, 0x1F, 0xE4, 0x61, 0xF5, 0x21, 0xF1, 0x71, 0x07, 0xD9, 0x7E,
+0xDA, 0x09, 0xAB, 0xEE, 0xEC, 0x01, 0x08, 0x10, 0x80, 0xD3, 0xD9, 0x18, 0x1F, 0x20, 0x4B, 0x78,
+0x9D, 0x8F, 0x63, 0x66, 0x3F, 0x8A, 0x99, 0x8F, 0x10, 0x4B, 0x97, 0xF3, 0x28, 0xDF, 0x65, 0x3A,
+0x44, 0xCD, 0xD1, 0xAF, 0xD1, 0x4E, 0x51, 0x92, 0xC5, 0xC3, 0x59, 0x90, 0xB2, 0xDA, 0x49, 0x0F,
+0xC3, 0x39, 0xC5, 0x47, 0x61, 0x37, 0x5F, 0x0B, 0xD2, 0x88, 0xB7, 0x1E, 0x6E, 0x88, 0x8F, 0xE3,
+0x02, 0xC4, 0x4E, 0x58, 0x80, 0x00, 0x01, 0x38, 0x8B, 0xCD, 0xD0, 0xDA, 0x5D, 0xFA, 0xF8, 0x38,
+0x6A, 0xF6, 0xA3, 0xBF, 0x08, 0x3D, 0x94, 0x9F, 0x86, 0x55, 0x8A, 0x89, 0x22, 0x4A, 0xB6, 0x8F,
+0xD8, 0xCE, 0x77, 0x2F, 0xA6, 0xFF, 0x20, 0x5E, 0xFE, 0xD0, 0xC3, 0x59, 0x90, 0x2A, 0xC5, 0x47,
+0x92, 0x66, 0x40, 0xD2, 0x4B, 0x8C, 0x0B, 0xB3, 0x16, 0x64, 0xE1, 0xE2, 0x23, 0xBF, 0x8B, 0x7C,
+0x27, 0xAC, 0x86, 0x53, 0x07, 0x20, 0x40, 0x00, 0x4E, 0x23, 0x6B, 0x5D, 0xCF, 0xAF, 0x07, 0xB1,
+0xCC, 0xF1, 0x11, 0x8F, 0x9A, 0xFD, 0xE8, 0xBE, 0x23, 0x96, 0xAF, 0x60, 0x1E, 0x6B, 0x83, 0xBB,
+0x5F, 0xA5, 0x3F, 0x8E, 0x98, 0xFD, 0x28, 0xEE, 0xB4, 0xFD, 0xD5, 0x38, 0x1A, 0x2E, 0xE5, 0xF0,
+0x89, 0x33, 0x38, 0x66, 0xD3, 0x8E, 0x8F, 0xC2, 0xEE, 0x33, 0xF9, 0xE0, 0x3A, 0x7E, 0xF4, 0xA1,
+0x73, 0x1F, 0x60, 0x2F, 0x64, 0x7C, 0xE4, 0xFF, 0x66, 0xF2, 0x19, 0x90, 0x6B, 0x4E, 0x1E, 0x80,
+0x00, 0x01, 0x38, 0x8D, 0x81, 0x05, 0xE8, 0x4B, 0x18, 0x1F, 0x45, 0x04, 0x0C, 0x07, 0xC9, 0x98,
+0x40, 0x89, 0xB1, 0x36, 0x70, 0x7B, 0x7F, 0x46, 0x64, 0x3B, 0x1E, 0xFB, 0xB8, 0xD3, 0x7F, 0x10,
+0xCF, 0xB6, 0x0F, 0x1F, 0xD1, 0xC9, 0x66, 0x41, 0x16, 0x28, 0x3E, 0xD2, 0x63, 0x49, 0x33, 0x20,
+0xCD, 0x7C, 0xA0, 0x7F, 0xAE, 0xB3, 0x20, 0x0B, 0x1B, 0x1F, 0xFD, 0x08, 0xD9, 0xAF, 0x3B, 0x79,
+0x00, 0x02, 0x04, 0xE0, 0x74, 0x03, 0xA9, 0xCD, 0xA5, 0x8E, 0x8F, 0x78, 0xE7, 0x9D, 0xAF, 0x62,
+0xB9, 0x1C, 0x86, 0x17, 0x91, 0xEF, 0xA7, 0x41, 0x79, 0xBC, 0xE3, 0xE3, 0xCE, 0xB7, 0xE7, 0x3D,
+0x6E, 0x16, 0xA4, 0x0A, 0xF1, 0x51, 0xD8, 0xC9, 0x77, 0xC4, 0x4A, 0xB3, 0x20, 0x37, 0xC5, 0xC7,
+0x51, 0xDA, 0x0D, 0x27, 0x0F, 0x40, 0x80, 0x00, 0x9C, 0x74, 0x58, 0xF6, 0xD4, 0x1B, 0xEB, 0xDD,
+0xA7, 0x5F, 0x2D, 0x69, 0x7C, 0x1C, 0x15, 0x24, 0x61, 0x30, 0x44, 0x06, 0xD7, 0x83, 0x0C, 0xC5,
+0xC8, 0x76, 0x9C, 0xE8, 0x71, 0xA7, 0x6B, 0x82, 0x14, 0xB3, 0x20, 0xFD, 0x47, 0x38, 0x70, 0x55,
+0xF5, 0x8A, 0xC4, 0x47, 0x5E, 0x53, 0xCD, 0xEE, 0xB5, 0x41, 0xCE, 0x61, 0x16, 0xA4, 0x1A, 0xF1,
+0x91, 0xFA, 0x63, 0xDB, 0x4E, 0x58, 0x80, 0x00, 0x01, 0x38, 0x85, 0x7A, 0x68, 0x6D, 0x2D, 0x67,
+0x7C, 0x94, 0x76, 0xB4, 0x1A, 0x78, 0xBB, 0xFC, 0xF7, 0x71, 0xB3, 0x1F, 0xE5, 0x19, 0x93, 0x34,
+0xFB, 0xD1, 0x9E, 0xFC, 0x71, 0x17, 0xB3, 0x20, 0xF1, 0x8E, 0xB3, 0x20, 0x0B, 0x1C, 0x1F, 0x85,
+0xEE, 0x8E, 0x58, 0xF5, 0x79, 0xCE, 0x82, 0x54, 0x26, 0x3E, 0xF2, 0x3D, 0x99, 0x0F, 0xBA, 0xFF,
+0x7E, 0x00, 0x04, 0x08, 0xC0, 0x89, 0x46, 0x52, 0x8D, 0xD0, 0x6E, 0x2E, 0x5F, 0x7C, 0x84, 0xD1,
+0xC1, 0x7F, 0xEC, 0x7D, 0xED, 0x71, 0xB3, 0x1C, 0x47, 0x4E, 0x50, 0xEC, 0xC4, 0x13, 0x3D, 0xEE,
+0x7C, 0x16, 0xE4, 0xA5, 0xC1, 0xBB, 0x1F, 0x88, 0x9A, 0x58, 0x91, 0xF8, 0xC8, 0x6B, 0x6A, 0xBE,
+0xB3, 0x20, 0x95, 0x8A, 0x8F, 0xFC, 0xCF, 0x3C, 0x40, 0x5C, 0x90, 0x10, 0x10, 0x20, 0x00, 0x27,
+0x74, 0xDF, 0xD1, 0x17, 0x21, 0xAC, 0x70, 0x7C, 0x0C, 0xAF, 0xE3, 0xE8, 0x0D, 0xFC, 0x63, 0xA8,
+0x0D, 0xCC, 0x7C, 0x94, 0x2F, 0x3A, 0x38, 0x32, 0x4B, 0x52, 0x9E, 0xFD, 0x38, 0xC1, 0xE3, 0x6E,
+0xDF, 0x8E, 0xBD, 0x67, 0xB5, 0x95, 0x66, 0x41, 0x6A, 0x53, 0x1C, 0x14, 0xCF, 0x23, 0x3E, 0x0A,
+0x69, 0x16, 0x24, 0xB6, 0x67, 0x3E, 0x0B, 0x52, 0xB9, 0xF8, 0xC8, 0x7F, 0xD0, 0xF9, 0xF3, 0xED,
+0xEC, 0x84, 0x05, 0x08, 0x10, 0x80, 0x13, 0x69, 0x6D, 0x9D, 0xF2, 0xBF, 0xE0, 0x56, 0x2B, 0x3E,
+0x62, 0x88, 0x63, 0x9F, 0x92, 0xD5, 0xBF, 0x79, 0x60, 0x1B, 0xDE, 0xCE, 0x4B, 0xD6, 0x79, 0xD9,
+0x8A, 0xA7, 0x7B, 0xDC, 0x9D, 0xCF, 0xCD, 0xFA, 0xCF, 0x6A, 0xAB, 0x95, 0xBE, 0x5E, 0x1C, 0xFC,
+0xDA, 0x8B, 0x1E, 0x1F, 0xF9, 0xF7, 0xD2, 0x89, 0xD3, 0xBD, 0x67, 0xD3, 0x5B, 0x4F, 0x74, 0x22,
+0x64, 0x43, 0x7C, 0x0C, 0x1F, 0x9F, 0x7D, 0x33, 0x20, 0x80, 0x00, 0x01, 0x38, 0xD9, 0x60, 0xB9,
+0x75, 0x8A, 0x01, 0x54, 0x85, 0x16, 0x9C, 0x1F, 0x16, 0x48, 0x77, 0xF6, 0x23, 0x0C, 0x46, 0x47,
+0x7F, 0xD7, 0xAA, 0xE1, 0x87, 0xB9, 0x5B, 0x2E, 0x93, 0x93, 0x2B, 0x66, 0x41, 0x62, 0x2C, 0x05,
+0x50, 0x6D, 0x06, 0x03, 0xE0, 0x79, 0x1C, 0xCF, 0xBD, 0x3F, 0x4B, 0xB3, 0x20, 0x29, 0x3E, 0x1E,
+0x13, 0x1F, 0xC3, 0xB7, 0xB7, 0x04, 0x08, 0x20, 0x40, 0x00, 0x26, 0x1E, 0x53, 0x3D, 0xF5, 0x86,
+0x8D, 0xD0, 0xDE, 0x3F, 0xE1, 0x7F, 0xD5, 0xAE, 0x46, 0x7C, 0x94, 0x2F, 0x34, 0x38, 0x6E, 0xDB,
+0xDD, 0xC3, 0x1B, 0x6B, 0xA3, 0x3B, 0x54, 0x65, 0x45, 0x80, 0x9C, 0xE1, 0x71, 0x77, 0xEE, 0xA3,
+0xFD, 0x52, 0x3C, 0x7C, 0x2C, 0xE3, 0xB6, 0xF7, 0x8D, 0xF3, 0x3A, 0x86, 0x67, 0xFD, 0xF9, 0xB5,
+0x8B, 0x59, 0x90, 0x47, 0xA7, 0x39, 0x0B, 0x52, 0xF9, 0xF8, 0xC8, 0x7F, 0xCE, 0xFB, 0x1B, 0xF1,
+0x13, 0xEF, 0xD8, 0x70, 0x36, 0x01, 0x04, 0x08, 0xC0, 0x64, 0x36, 0x43, 0x7B, 0x77, 0xB9, 0xE2,
+0x23, 0x8E, 0xF9, 0xCB, 0xF0, 0x16, 0xBB, 0x21, 0x8C, 0xDD, 0xA9, 0x6A, 0x60, 0xF6, 0x23, 0x3B,
+0xFB, 0x60, 0x36, 0xBB, 0x9D, 0xD6, 0x29, 0xC7, 0xC1, 0xF0, 0x38, 0x4D, 0x84, 0x9C, 0x67, 0x7C,
+0x14, 0xA6, 0x3C, 0x0B, 0xB2, 0x14, 0xF1, 0x91, 0xBF, 0xBF, 0xD9, 0xFD, 0x77, 0x04, 0x20, 0x40,
+0x00, 0x26, 0xD2, 0xBB, 0x06, 0xC8, 0x92, 0xC4, 0xC7, 0xC0, 0x67, 0xC6, 0x23, 0xB7, 0xDD, 0x1D,
+0x89, 0x8E, 0x91, 0xD9, 0x8F, 0x6C, 0x6A, 0x03, 0xFE, 0xF6, 0x71, 0xDB, 0xF2, 0xCE, 0xFC, 0x18,
+0x4E, 0x71, 0x80, 0x9E, 0x7E, 0x4F, 0xF2, 0x6D, 0x79, 0xE3, 0xA3, 0xF1, 0xA3, 0xAF, 0x3B, 0xD3,
+0x7F, 0xF1, 0x5F, 0x9A, 0xF8, 0xC8, 0x7F, 0x5F, 0xF6, 0x05, 0x08, 0x20, 0x40, 0x00, 0x4E, 0x14,
+0x20, 0x07, 0x93, 0x5C, 0x03, 0xA4, 0x22, 0xF1, 0x91, 0x3E, 0xAD, 0x36, 0xF4, 0xF9, 0xE5, 0xB5,
+0x1F, 0xA5, 0x87, 0x76, 0xE4, 0xEC, 0xC7, 0x56, 0xD6, 0x8D, 0x90, 0x29, 0x0D, 0xF8, 0xD3, 0x85,
+0x09, 0xD3, 0xD6, 0xBC, 0xA5, 0x06, 0x1A, 0x9D, 0x05, 0x59, 0xF4, 0xF8, 0x28, 0xA4, 0x59, 0x90,
+0xAC, 0x99, 0xE2, 0xE3, 0x09, 0xF1, 0x51, 0x04, 0xC8, 0x5E, 0x7A, 0x6D, 0x27, 0x2C, 0x40, 0x80,
+0x00, 0x4C, 0xA4, 0xBD, 0x77, 0x63, 0x69, 0xE2, 0xA3, 0xFF, 0xA5, 0xCB, 0x4F, 0xBB, 0x2A, 0x45,
+0x48, 0xF9, 0x42, 0x83, 0xE5, 0x87, 0x59, 0x5E, 0xEA, 0xD1, 0xEE, 0xBC, 0xB1, 0x37, 0x8D, 0x01,
+0xED, 0xE0, 0x7D, 0x14, 0x17, 0x27, 0x0C, 0x47, 0xCD, 0x82, 0xC4, 0x0A, 0xC4, 0x47, 0x71, 0x3F,
+0x3B, 0x69, 0x5B, 0xDE, 0x70, 0x33, 0xFE, 0xDE, 0xEB, 0xEA, 0x2B, 0x1F, 0x1F, 0xF9, 0xC7, 0xA6,
+0x9D, 0x06, 0xDA, 0x66, 0x40, 0x00, 0x01, 0x02, 0x30, 0x59, 0x80, 0x34, 0x37, 0x96, 0x26, 0x3E,
+0xF2, 0xD9, 0x8F, 0x38, 0x72, 0x5B, 0x79, 0xED, 0xC7, 0xE1, 0xCE, 0x57, 0xB5, 0xD1, 0x87, 0x99,
+0x6E, 0xD8, 0x9E, 0x7E, 0x7C, 0xE4, 0x01, 0x92, 0x66, 0x41, 0xF6, 0x87, 0x3E, 0xE2, 0xB8, 0x59,
+0x90, 0x45, 0x8D, 0x8F, 0xF4, 0x47, 0xBA, 0x30, 0x61, 0xF7, 0xBA, 0x31, 0x27, 0xBA, 0x38, 0xE1,
+0x52, 0xC6, 0x47, 0xFF, 0x07, 0xBC, 0x5B, 0x77, 0x32, 0x01, 0x04, 0x08, 0xC0, 0x44, 0x03, 0xA7,
+0xE3, 0xAE, 0x61, 0x50, 0xBD, 0xAD, 0x76, 0x63, 0x2C, 0x87, 0x47, 0xB9, 0x3A, 0xC6, 0xAC, 0xF5,
+0x18, 0x78, 0xC8, 0xB1, 0xFB, 0xB4, 0xAB, 0xBD, 0x29, 0x6C, 0xF7, 0x7B, 0x54, 0xEB, 0xBD, 0xD8,
+0x5B, 0x93, 0x32, 0x6E, 0x16, 0xA4, 0x56, 0xFA, 0xD4, 0x45, 0x8E, 0x8F, 0xDE, 0x63, 0x8D, 0xBB,
+0x5F, 0x4C, 0x7F, 0xBD, 0x99, 0xFD, 0xEE, 0x64, 0xB3, 0x20, 0x4B, 0x1D, 0x1F, 0xF9, 0xBF, 0xA3,
+0xA6, 0x00, 0x01, 0x04, 0x08, 0xC0, 0x1D, 0xC7, 0x5A, 0x4F, 0xBD, 0x61, 0x33, 0x64, 0x07, 0xCB,
+0x11, 0x1F, 0x71, 0xCC, 0x35, 0x36, 0x86, 0x77, 0xBE, 0x8A, 0x43, 0xB3, 0x1F, 0xE5, 0x05, 0x19,
+0xE9, 0xCF, 0xED, 0xD9, 0xC5, 0x47, 0xFE, 0xDE, 0xFD, 0x62, 0xBD, 0xF2, 0x98, 0xB5, 0x20, 0x55,
+0x8A, 0x8F, 0x62, 0x16, 0xE4, 0x60, 0x2B, 0xDD, 0x7C, 0xC7, 0xB5, 0x20, 0x4B, 0x1F, 0x1F, 0xF9,
+0xE7, 0x36, 0x3B, 0xDF, 0xE7, 0x3B, 0x1A, 0xCE, 0x2A, 0x80, 0x00, 0x01, 0x38, 0xDE, 0xC6, 0xF8,
+0x2D, 0x78, 0x2B, 0x78, 0x91, 0xC1, 0x81, 0x41, 0xFC, 0x11, 0xB3, 0x1F, 0x63, 0x3F, 0xB3, 0xF7,
+0x8E, 0xD4, 0x61, 0x7B, 0xB3, 0xFF, 0x1E, 0xD2, 0x2C, 0xC8, 0xD1, 0x6B, 0x41, 0x2A, 0x12, 0x1F,
+0xC5, 0x31, 0x4E, 0x3B, 0x62, 0xC5, 0xDA, 0xDB, 0xDA, 0xBF, 0xF3, 0x50, 0x63, 0xA5, 0xE3, 0x23,
+0xE9, 0x96, 0x65, 0xDD, 0x29, 0x05, 0x10, 0x20, 0x00, 0xC7, 0x6B, 0x84, 0xD6, 0x6E, 0xF5, 0xE3,
+0xA3, 0xBF, 0xF3, 0xD5, 0xF0, 0xCD, 0xC7, 0xCF, 0x7E, 0xE4, 0x8B, 0xD5, 0x8B, 0xA9, 0x88, 0xED,
+0xF9, 0x7C, 0x0F, 0xF9, 0x2C, 0xC8, 0xEE, 0x40, 0x1B, 0xF5, 0x5F, 0x4D, 0x67, 0x68, 0x3D, 0xA7,
+0xF8, 0x48, 0x7F, 0x36, 0xB7, 0xBB, 0xB3, 0x20, 0x71, 0xFC, 0x5A, 0x90, 0x95, 0x89, 0x8F, 0x3C,
+0x40, 0x9A, 0x02, 0x04, 0x10, 0x20, 0x00, 0x13, 0xB8, 0x36, 0x78, 0x0D, 0x90, 0x6A, 0xCE, 0x7C,
+0x0C, 0x3C, 0x8C, 0x09, 0x67, 0x3F, 0x06, 0x86, 0xFB, 0x69, 0xF6, 0xE3, 0x20, 0xCE, 0xED, 0x7B,
+0xC8, 0x5E, 0x18, 0x9E, 0x05, 0xA9, 0xD8, 0xCC, 0x47, 0xE8, 0x3E, 0xF6, 0xBC, 0xDF, 0xBA, 0x3B,
+0x62, 0x35, 0x0E, 0x7E, 0x7B, 0x70, 0x16, 0x64, 0xA5, 0xE2, 0x23, 0xBF, 0x9F, 0xFC, 0xA9, 0x8C,
+0x37, 0x9C, 0x52, 0x00, 0x01, 0x02, 0x70, 0x9C, 0xE6, 0x0B, 0xF5, 0x65, 0x88, 0x8F, 0x93, 0xCF,
+0x7E, 0x94, 0x66, 0x3E, 0xCE, 0x34, 0xFB, 0x71, 0xBA, 0xCF, 0x4B, 0xD7, 0x04, 0x49, 0xBB, 0x62,
+0x95, 0x1A, 0x69, 0xF2, 0xEB, 0x82, 0x2C, 0x52, 0x7C, 0xA4, 0x97, 0xE6, 0x56, 0xC8, 0x9A, 0x69,
+0x16, 0xA4, 0xF6, 0xF8, 0xCA, 0xC6, 0x47, 0xA1, 0xBD, 0x55, 0x77, 0x52, 0x01, 0x16, 0xCD, 0xBA,
+0x43, 0x00, 0x2C, 0x94, 0x98, 0x35, 0x2A, 0x1F, 0x1F, 0xC3, 0xD7, 0xFA, 0x28, 0x7F, 0xC8, 0xF0,
+0xEC, 0x47, 0x2F, 0x3E, 0x06, 0xBE, 0xFA, 0xA9, 0x67, 0x3F, 0xCE, 0xF6, 0x3D, 0xA4, 0xEB, 0x82,
+0xAC, 0xDD, 0x53, 0x6A, 0xA7, 0xDA, 0x22, 0x0C, 0xD0, 0x4F, 0x16, 0x1F, 0xC5, 0xF1, 0xCD, 0xB6,
+0xBE, 0x10, 0x6A, 0xF7, 0x3D, 0xD8, 0xD8, 0xFF, 0xDF, 0x1F, 0x6E, 0x5C, 0xFA, 0xD6, 0x6F, 0x7C,
+0x61, 0x25, 0xE3, 0xA3, 0x5B, 0x96, 0x02, 0x04, 0x58, 0x38, 0x66, 0x40, 0x80, 0xC5, 0x69, 0x8F,
+0xA7, 0xDE, 0xB0, 0xD1, 0x7D, 0xDE, 0x7A, 0x85, 0xE3, 0x63, 0xDC, 0xC0, 0x7D, 0xF8, 0xAA, 0xE7,
+0xE5, 0xD9, 0x8F, 0xF2, 0x00, 0xBB, 0x78, 0xB9, 0x9D, 0x9D, 0xC3, 0xF7, 0xD0, 0x19, 0xB4, 0x77,
+0xA2, 0xA7, 0x7D, 0x7B, 0xE8, 0x1E, 0x4F, 0x35, 0x0B, 0x72, 0xCE, 0xF1, 0x91, 0x75, 0x6E, 0x3B,
+0xD8, 0x0D, 0xD9, 0xEE, 0xF3, 0x21, 0x5C, 0xB9, 0xF8, 0xA1, 0x95, 0x8D, 0x8F, 0xFC, 0x7E, 0xD3,
+0x4E, 0x58, 0x3F, 0xE2, 0x82, 0x84, 0x80, 0x00, 0x01, 0x38, 0x62, 0x10, 0xB6, 0x39, 0xBA, 0x00,
+0xBD, 0x62, 0xF1, 0x11, 0x8F, 0x5E, 0xFB, 0xD1, 0x7F, 0x8A, 0x50, 0x3F, 0x38, 0xE2, 0xE8, 0xB5,
+0x40, 0xD2, 0xAE, 0x57, 0xED, 0xF9, 0x0F, 0x8A, 0x8B, 0x2B, 0xB5, 0xE7, 0x3B, 0x62, 0xB5, 0x8F,
+0xB8, 0x2E, 0x48, 0x55, 0xE2, 0x23, 0xBD, 0x9D, 0x37, 0xDC, 0x76, 0xB8, 0xF4, 0x1F, 0x7E, 0x6D,
+0x7D, 0x65, 0xE3, 0x23, 0x3D, 0xDE, 0xF6, 0x4E, 0x7A, 0xA3, 0xEE, 0xE4, 0x02, 0x08, 0x10, 0x80,
+0xF1, 0x36, 0x7B, 0x3B, 0xF7, 0x54, 0x33, 0x3E, 0x8E, 0xF8, 0x90, 0xE1, 0xB5, 0x1F, 0xA1, 0xB4,
+0xDC, 0x63, 0xE4, 0xEE, 0x76, 0xE2, 0x9C, 0xBF, 0x87, 0xC3, 0xF8, 0xC8, 0x75, 0x06, 0xEE, 0xC5,
+0x2C, 0xC8, 0xC0, 0x5A, 0x90, 0x38, 0xC9, 0x57, 0x5A, 0x9C, 0xF8, 0xA8, 0xDD, 0x73, 0x6F, 0xB8,
+0xFC, 0xED, 0xDF, 0x19, 0xC2, 0x85, 0xCE, 0xFF, 0xCD, 0xAD, 0x6A, 0x7C, 0xE4, 0x3F, 0xCF, 0x66,
+0xF7, 0xDF, 0x15, 0x80, 0x00, 0x01, 0x18, 0xEB, 0x88, 0x6B, 0x80, 0x54, 0x20, 0x3E, 0xCA, 0x83,
+0xF4, 0x81, 0x01, 0x7B, 0x6D, 0x60, 0xED, 0x47, 0x2C, 0x1E, 0x77, 0xF9, 0x62, 0x7F, 0xA7, 0x9E,
+0xFD, 0x98, 0x72, 0x7C, 0xF4, 0xB4, 0x6F, 0x77, 0x67, 0x41, 0x06, 0xAE, 0x0B, 0x52, 0x9B, 0xFD,
+0x63, 0x99, 0x6A, 0x7C, 0x5C, 0xFF, 0xDE, 0x50, 0x5B, 0xBF, 0xB8, 0xDA, 0xF1, 0x91, 0xBF, 0x99,
+0xEF, 0x84, 0x75, 0xDD, 0xA9, 0x05, 0x10, 0x20, 0x00, 0xE3, 0xB4, 0xB6, 0x26, 0xDF, 0x32, 0x74,
+0x91, 0x67, 0x3E, 0x6A, 0x83, 0x17, 0x33, 0x2F, 0x07, 0x4A, 0xB1, 0xE0, 0x7C, 0x64, 0xA7, 0xDB,
+0x13, 0xCF, 0x7E, 0xCC, 0x26, 0x3E, 0x72, 0xA5, 0x59, 0x90, 0x50, 0xCC, 0xDE, 0x1C, 0x3B, 0x0B,
+0x22, 0x3E, 0x16, 0x32, 0x3E, 0xFA, 0x45, 0xB9, 0x53, 0x77, 0x72, 0x01, 0x04, 0x08, 0xC0, 0xF8,
+0x41, 0x59, 0x7D, 0xC2, 0x8F, 0x5B, 0xAC, 0xF8, 0x18, 0x5E, 0xA8, 0xDD, 0xFF, 0x7B, 0x6D, 0x60,
+0xE6, 0x23, 0xF6, 0x9F, 0x7B, 0x55, 0x1B, 0xDD, 0x0D, 0x6B, 0xE7, 0x24, 0xB3, 0x1F, 0x33, 0x8C,
+0x8F, 0x62, 0xCC, 0x9A, 0x66, 0x41, 0x0E, 0x4A, 0x03, 0xFD, 0x5E, 0x10, 0x88, 0x8F, 0x8A, 0xC5,
+0x47, 0xF7, 0xA7, 0xE9, 0x29, 0x58, 0x80, 0x00, 0x01, 0x18, 0x3F, 0x4E, 0x9A, 0xE0, 0xBF, 0xD4,
+0x56, 0x20, 0x3E, 0x46, 0x66, 0x0C, 0xCA, 0x0B, 0xCE, 0xC3, 0xE1, 0x62, 0xF4, 0xFE, 0x27, 0x66,
+0xE1, 0x04, 0xB3, 0x1F, 0xB3, 0x8F, 0x8F, 0x5C, 0x96, 0xC6, 0xEF, 0x71, 0x20, 0xA4, 0x46, 0xBF,
+0x57, 0xF1, 0xB1, 0xF8, 0xF1, 0x91, 0x7E, 0x96, 0x7B, 0x76, 0xC2, 0x02, 0x04, 0x08, 0xC0, 0xC8,
+0xF0, 0xE9, 0xC9, 0x47, 0x1A, 0xA1, 0xDD, 0xAC, 0x56, 0x7C, 0x1C, 0xF3, 0xA1, 0xFD, 0x6D, 0x77,
+0x63, 0x77, 0xE6, 0xE3, 0x70, 0xF0, 0x5C, 0x1B, 0xBD, 0xCB, 0xDD, 0x38, 0xE1, 0xDD, 0xCF, 0x29,
+0x3E, 0x8A, 0x71, 0xEB, 0x76, 0xDA, 0x9A, 0x77, 0xA8, 0x0F, 0xE2, 0xD0, 0xFD, 0x9C, 0xF9, 0x21,
+0x89, 0x8F, 0x99, 0xC6, 0x47, 0x1E, 0xF6, 0x7B, 0xE9, 0xF5, 0x86, 0xB3, 0x0C, 0x20, 0x40, 0x00,
+0x06, 0x6D, 0x1C, 0xBB, 0x03, 0xD6, 0x02, 0xC7, 0xC7, 0x51, 0x17, 0x1D, 0xEC, 0x0E, 0x9A, 0xCB,
+0x37, 0xD6, 0x06, 0x67, 0x3F, 0xF2, 0x51, 0x7E, 0x98, 0x70, 0xF6, 0x63, 0xBE, 0xF1, 0xD1, 0x1F,
+0xBB, 0xBE, 0x18, 0xFB, 0xD7, 0x2C, 0xE9, 0x3F, 0x04, 0x33, 0x1F, 0xD5, 0x89, 0x8F, 0xFC, 0x43,
+0xF2, 0x85, 0xE8, 0x0D, 0xA7, 0x18, 0x40, 0x80, 0x00, 0x0C, 0xDA, 0x3C, 0x72, 0x07, 0xAC, 0x45,
+0x8D, 0x8F, 0x38, 0xFE, 0xB6, 0xD8, 0x0B, 0x8D, 0xF2, 0x75, 0x3E, 0x46, 0xAE, 0xAB, 0x71, 0xA2,
+0xD9, 0x8F, 0xF3, 0x89, 0x8F, 0xBC, 0x8F, 0xB6, 0xF3, 0x6B, 0xD9, 0xF5, 0x1F, 0x45, 0x39, 0xA8,
+0xE2, 0x34, 0x8E, 0xAB, 0xF8, 0x98, 0xFD, 0xE3, 0xCD, 0xF2, 0x19, 0x90, 0x6B, 0x4E, 0x31, 0x80,
+0x00, 0x01, 0x18, 0x18, 0x24, 0xB5, 0xAE, 0x77, 0xF7, 0x7E, 0xAD, 0x48, 0x7C, 0x0C, 0x7F, 0xC4,
+0xC8, 0x8E, 0x57, 0x71, 0xE4, 0xB3, 0x47, 0x66, 0x3F, 0xD2, 0xB7, 0xBB, 0x1D, 0x67, 0xFC, 0x3D,
+0x9C, 0x3E, 0x3E, 0xFA, 0x0F, 0xF3, 0xAB, 0xDD, 0x59, 0x90, 0x7C, 0xB6, 0x26, 0x4E, 0xE3, 0x21,
+0x8A, 0x8F, 0xB9, 0xC5, 0x47, 0xFF, 0x87, 0x68, 0x27, 0x2C, 0x40, 0x80, 0x00, 0x0C, 0x6A, 0x6D,
+0x6D, 0x54, 0x2A, 0x3E, 0x62, 0x18, 0xDD, 0x15, 0xAA, 0x3F, 0xD3, 0x11, 0x4B, 0x7F, 0x3F, 0x66,
+0xF6, 0xA3, 0x02, 0xF1, 0x91, 0xB7, 0xE1, 0x7E, 0xE7, 0x7E, 0xF6, 0xE2, 0xE0, 0xA3, 0x3A, 0xF5,
+0x2C, 0x88, 0xF8, 0x98, 0x7B, 0x7C, 0x74, 0x35, 0x9C, 0x64, 0x00, 0x01, 0x02, 0x30, 0x30, 0xA6,
+0x3A, 0x68, 0x54, 0x26, 0x3E, 0x86, 0x1F, 0x62, 0x1C, 0xDC, 0x19, 0x6A, 0xDC, 0x43, 0x2F, 0x0F,
+0xA8, 0x73, 0x69, 0xF6, 0x63, 0x2F, 0x2E, 0x7C, 0x7C, 0x14, 0x8F, 0x25, 0xAD, 0x05, 0x09, 0xE3,
+0x62, 0xAA, 0x17, 0x11, 0x27, 0x5A, 0x44, 0x2F, 0x3E, 0xE6, 0xFF, 0x78, 0xB3, 0xED, 0xB4, 0x13,
+0x56, 0xDD, 0x89, 0x06, 0x10, 0x20, 0x00, 0x21, 0xDF, 0x01, 0xAB, 0x9E, 0x8F, 0x2E, 0xAB, 0x12,
+0x1F, 0x47, 0xCE, 0x7E, 0x0C, 0xAE, 0xD3, 0x2E, 0x66, 0x3F, 0x46, 0xBE, 0x9D, 0xF4, 0xF7, 0xED,
+0xEA, 0xC4, 0x47, 0x3E, 0x7E, 0xDD, 0xEF, 0xBE, 0x14, 0xB7, 0x0C, 0xEE, 0x88, 0x25, 0x3E, 0x16,
+0x3A, 0x3E, 0xF2, 0x1F, 0x60, 0xBE, 0x10, 0x5D, 0x80, 0x00, 0x02, 0x04, 0xA0, 0xA7, 0x1E, 0x0E,
+0xB6, 0xAA, 0x11, 0x1F, 0xC3, 0x63, 0xCC, 0xFE, 0xE0, 0x39, 0x1E, 0x5E, 0xFB, 0xE3, 0xA8, 0xCB,
+0x85, 0x14, 0xB7, 0xB7, 0xC2, 0x31, 0xB3, 0x1F, 0x8B, 0x17, 0x1F, 0x85, 0xD6, 0xF3, 0xF1, 0x70,
+0x2B, 0xE1, 0x13, 0xCD, 0x82, 0x88, 0x8F, 0x73, 0x8D, 0x8F, 0xFC, 0xD3, 0xED, 0x84, 0x05, 0x08,
+0x10, 0x80, 0xB2, 0x46, 0xBE, 0x05, 0x6F, 0x15, 0xE2, 0x63, 0xEC, 0xEC, 0x47, 0xEC, 0xEE, 0x7C,
+0x35, 0x34, 0x0E, 0xED, 0xCF, 0x7E, 0x94, 0x9F, 0x7A, 0x95, 0xFE, 0xDC, 0xAA, 0x5E, 0x7C, 0xE4,
+0xB7, 0xB4, 0xBA, 0xBB, 0x62, 0x85, 0x70, 0x92, 0x59, 0x10, 0xF1, 0x71, 0xEE, 0xF1, 0x91, 0xB4,
+0xF3, 0x1F, 0x9C, 0x9D, 0xB0, 0x00, 0x01, 0x02, 0xD0, 0x73, 0x5F, 0x68, 0xEF, 0x2F, 0x7E, 0x7C,
+0x0C, 0x8F, 0x33, 0xCB, 0xD7, 0xF9, 0xB8, 0xD3, 0xEC, 0x47, 0x21, 0xFD, 0x87, 0xE8, 0x83, 0x38,
+0x83, 0xEF, 0x61, 0xB6, 0xF1, 0xD1, 0x1F, 0xC7, 0xBE, 0x74, 0x87, 0x59, 0x10, 0xF1, 0xB1, 0x78,
+0xF1, 0x51, 0xC8, 0xF6, 0xEB, 0x4E, 0x35, 0x80, 0x00, 0x01, 0x48, 0x5A, 0x5B, 0x9B, 0x55, 0x89,
+0x8F, 0x81, 0x41, 0x76, 0x71, 0x9D, 0x8F, 0x49, 0x66, 0x3F, 0x8A, 0x97, 0xED, 0xEA, 0xC6, 0x47,
+0xFE, 0xDE, 0xD2, 0x2C, 0x48, 0xFF, 0xA3, 0xCB, 0xB3, 0x20, 0x51, 0x7C, 0x2C, 0x64, 0x7C, 0x74,
+0x7F, 0x78, 0x9B, 0x4E, 0x36, 0x80, 0x00, 0x01, 0x48, 0xB2, 0xD3, 0x0E, 0x8C, 0xE6, 0x1C, 0x1F,
+0xE5, 0x19, 0x8E, 0xF2, 0x75, 0x3E, 0xC6, 0xCD, 0x7E, 0xC4, 0x30, 0xB8, 0x3B, 0x56, 0x32, 0x76,
+0xF6, 0xA3, 0x3A, 0xF1, 0x51, 0xC8, 0x67, 0x41, 0xDA, 0xC7, 0xEC, 0x88, 0x25, 0x3E, 0x16, 0x2F,
+0x3E, 0xF2, 0x7F, 0x67, 0x3B, 0x1B, 0xF1, 0x13, 0x3F, 0xBC, 0xE1, 0x84, 0x03, 0x08, 0x10, 0x80,
+0xF6, 0xDE, 0x29, 0x06, 0x45, 0x73, 0x8E, 0x8F, 0xFE, 0xE0, 0x3A, 0x0C, 0x2E, 0x38, 0x1F, 0x7A,
+0xDE, 0x51, 0x7F, 0xF6, 0x63, 0x28, 0x44, 0xC6, 0xCF, 0x7E, 0x54, 0x2F, 0x3E, 0xF2, 0x8F, 0x6C,
+0x75, 0x7E, 0x64, 0x5B, 0x83, 0xDF, 0xDE, 0x61, 0x84, 0xC5, 0xC1, 0x35, 0x2F, 0xE2, 0x63, 0x71,
+0x1E, 0x6F, 0x96, 0x5F, 0xD2, 0xDE, 0x2C, 0x08, 0x20, 0x40, 0x80, 0xD5, 0x16, 0x9F, 0x7C, 0xA4,
+0x11, 0xDA, 0xBB, 0x8B, 0x1F, 0x1F, 0xFD, 0x01, 0x73, 0x1C, 0xB9, 0xEA, 0x79, 0x2C, 0x6F, 0xC1,
+0x3B, 0xBC, 0x1E, 0xA4, 0xF8, 0xC0, 0xB4, 0xEB, 0xD5, 0x41, 0xAC, 0x7C, 0x7C, 0xF4, 0x9B, 0xF1,
+0x76, 0x77, 0x16, 0x64, 0x60, 0x2D, 0x48, 0xCD, 0xCC, 0xC7, 0xC2, 0xC6, 0x47, 0x7E, 0xB0, 0x0F,
+0x04, 0x08, 0x20, 0x40, 0x00, 0x42, 0xDA, 0x82, 0x37, 0x1F, 0xC9, 0x2E, 0x70, 0x7C, 0x8C, 0x1B,
+0x74, 0x8E, 0x59, 0xFB, 0x31, 0xF6, 0xB6, 0xE2, 0x4B, 0xEE, 0x2C, 0x4F, 0x7C, 0xE4, 0xB2, 0x14,
+0x21, 0xE5, 0x7B, 0x89, 0x23, 0x4F, 0x3B, 0x2B, 0xAF, 0x81, 0x11, 0x1F, 0xE7, 0x1C, 0x1F, 0xF9,
+0xCF, 0x6C, 0x2F, 0xBD, 0xB6, 0x13, 0x16, 0x20, 0x40, 0x00, 0x01, 0xD2, 0xBF, 0x06, 0xC8, 0x22,
+0xC6, 0xC7, 0x98, 0xA7, 0x16, 0x75, 0xEF, 0xA5, 0x36, 0x30, 0xD3, 0x31, 0x30, 0xFB, 0x11, 0xC6,
+0xCC, 0x7E, 0xB4, 0x97, 0x28, 0x3E, 0x7A, 0xDA, 0x5B, 0xC5, 0x5A, 0x90, 0x30, 0xB8, 0x06, 0xA6,
+0x36, 0xF8, 0xFD, 0x8B, 0x8F, 0x05, 0x88, 0x8F, 0xFC, 0xCD, 0xF4, 0xC3, 0x6A, 0x9B, 0x01, 0x01,
+0x04, 0x08, 0xB0, 0xE2, 0xDA, 0x7B, 0x37, 0x16, 0x36, 0x3E, 0x86, 0x07, 0x9D, 0xB5, 0xC3, 0xD0,
+0x18, 0x37, 0xCB, 0x31, 0x7C, 0x6D, 0x8C, 0xFE, 0x97, 0xDD, 0x89, 0x4B, 0x17, 0x1F, 0xB9, 0x4E,
+0x38, 0xB4, 0xBE, 0x9A, 0xF5, 0x1E, 0x57, 0x6D, 0xE0, 0x70, 0xF5, 0x8F, 0x53, 0x14, 0x1F, 0x0B,
+0x11, 0x1F, 0xFD, 0x9F, 0xD9, 0x9E, 0x00, 0x01, 0x04, 0x08, 0xB0, 0xEA, 0x01, 0xB2, 0x3F, 0xC1,
+0x02, 0xF4, 0x73, 0x8A, 0x8F, 0xDE, 0x9A, 0x8F, 0xD1, 0x9D, 0x65, 0x6B, 0x47, 0xAC, 0xFD, 0xA8,
+0x8D, 0xEE, 0x86, 0xB5, 0x5B, 0xCC, 0x7E, 0x2C, 0x59, 0x7C, 0xF4, 0x06, 0xE4, 0x69, 0x4B, 0xDE,
+0xEC, 0x60, 0x68, 0x8C, 0x5E, 0x9A, 0x29, 0xCA, 0x17, 0xE4, 0x67, 0xE2, 0x63, 0x21, 0xE2, 0x23,
+0x0F, 0x90, 0x7D, 0xBB, 0x60, 0x01, 0x02, 0x04, 0x58, 0x71, 0x59, 0x73, 0xB3, 0x2A, 0xF1, 0x31,
+0xB0, 0xDB, 0xD3, 0xD0, 0xC7, 0xF6, 0xD7, 0xA7, 0x97, 0x27, 0x3B, 0xD2, 0xE4, 0xC0, 0x76, 0x5C,
+0xDA, 0xF8, 0xE8, 0x37, 0xE4, 0x8B, 0x71, 0x20, 0x2C, 0xCA, 0xF1, 0xD1, 0x0F, 0xB2, 0x4C, 0x7C,
+0x9C, 0x7B, 0x7C, 0xE4, 0xEF, 0x6A, 0x86, 0xF8, 0x89, 0x1F, 0x6E, 0x38, 0xF1, 0x00, 0x02, 0x04,
+0x58, 0x49, 0xF1, 0xC9, 0x47, 0x36, 0x7B, 0x5B, 0x83, 0x2E, 0x56, 0x7C, 0x1C, 0x35, 0xE8, 0x2C,
+0x6F, 0xBB, 0x5B, 0x9E, 0x01, 0x29, 0x66, 0x3F, 0x86, 0xBF, 0xEC, 0x6E, 0x9C, 0xCA, 0xE0, 0x75,
+0x91, 0xE3, 0x23, 0x6F, 0xC8, 0xED, 0xEE, 0xD6, 0xBC, 0xFD, 0x19, 0x8E, 0x70, 0x78, 0x21, 0xC6,
+0xF2, 0x8B, 0xF8, 0x38, 0xE7, 0xF8, 0xC8, 0x7F, 0x58, 0xFB, 0xE9, 0x75, 0xDD, 0xD9, 0x07, 0x10,
+0x20, 0xC0, 0xAA, 0xDA, 0x38, 0x7A, 0x0B, 0xDE, 0xF3, 0x8F, 0x8F, 0x91, 0xD9, 0x8F, 0x72, 0x78,
+0x0C, 0x7C, 0x42, 0x6D, 0x70, 0xF6, 0x23, 0x1F, 0xE8, 0x75, 0x5E, 0x76, 0xB2, 0xA5, 0x8F, 0x8F,
+0xE2, 0xA6, 0xD6, 0x73, 0xF1, 0xF0, 0x1A, 0x28, 0x9D, 0xD0, 0x28, 0x66, 0x3C, 0x06, 0xE2, 0x23,
+0x13, 0x1F, 0xE7, 0x1A, 0x1F, 0xF9, 0xEF, 0xE5, 0x9E, 0x00, 0x01, 0x04, 0x08, 0xB0, 0xD2, 0x1A,
+0xA1, 0xB5, 0xBB, 0x78, 0xF1, 0x11, 0xC7, 0xDF, 0xE5, 0xC0, 0x16, 0xBB, 0xF1, 0xF0, 0xA2, 0x83,
+0x61, 0xDC, 0x0E, 0xBB, 0xBB, 0xD9, 0x99, 0xBF, 0x8D, 0xAA, 0xC4, 0x47, 0x3E, 0xAE, 0xDD, 0xEF,
+0xBE, 0x94, 0x9F, 0x76, 0x55, 0x04, 0x47, 0x7F, 0xE6, 0x23, 0x8A, 0x8F, 0x73, 0x8D, 0x8F, 0xFC,
+0xC3, 0xF2, 0x05, 0x49, 0x37, 0x9C, 0x7A, 0x00, 0x01, 0x02, 0xAC, 0xAA, 0x6B, 0xA3, 0xD7, 0x00,
+0x59, 0x8C, 0xA7, 0x5D, 0x1D, 0x35, 0xFB, 0x31, 0x6E, 0x07, 0xAC, 0xD1, 0xD9, 0x8F, 0x38, 0x74,
+0xDD, 0x8F, 0xE5, 0x8E, 0x8F, 0xE2, 0xED, 0xF6, 0x0B, 0x45, 0x98, 0xD5, 0x3A, 0xD1, 0xD1, 0x9B,
+0xF9, 0x28, 0x3D, 0x15, 0xAB, 0x76, 0xB7, 0xF8, 0x58, 0x88, 0xFB, 0x6D, 0x6F, 0xD5, 0x9D, 0x7A,
+0x00, 0x01, 0x02, 0xAC, 0xA6, 0xE6, 0x0B, 0xF5, 0x85, 0x8B, 0x8F, 0xF4, 0x47, 0x6D, 0xF4, 0x6E,
+0x63, 0x18, 0x5C, 0xE3, 0x71, 0xF4, 0xEC, 0x47, 0xE7, 0xD5, 0x56, 0x3C, 0xE3, 0x43, 0xA9, 0x5E,
+0x7C, 0xA4, 0x83, 0x96, 0x9E, 0xDD, 0x93, 0x9E, 0x51, 0x57, 0xC4, 0x47, 0x2C, 0x3D, 0xED, 0x2A,
+0xA4, 0xF8, 0xD8, 0x14, 0x1F, 0x0B, 0x71, 0xBF, 0xB1, 0x25, 0x40, 0x00, 0x01, 0x02, 0xAC, 0xA8,
+0x98, 0x35, 0x16, 0x2A, 0x3E, 0x86, 0xFF, 0x3A, 0x66, 0xED, 0xC7, 0xB8, 0x4F, 0x8D, 0xE5, 0x0B,
+0x80, 0xA4, 0x09, 0x9D, 0xBD, 0x78, 0x86, 0x87, 0x52, 0xCD, 0xF8, 0x28, 0x8E, 0x4F, 0xBE, 0x23,
+0x56, 0x7A, 0xDA, 0x55, 0xBB, 0x37, 0x0B, 0xD2, 0x5B, 0xF3, 0x71, 0x45, 0x7C, 0x2C, 0xCE, 0xFD,
+0xC6, 0x03, 0x3B, 0x61, 0x01, 0x02, 0x04, 0x58, 0xC1, 0xF6, 0x78, 0xF2, 0x91, 0x8D, 0xC3, 0x1D,
+0xB0, 0x16, 0x24, 0x3E, 0x8E, 0x99, 0xFD, 0x88, 0x43, 0xC1, 0x51, 0xEC, 0xF2, 0x34, 0xF4, 0x81,
+0xBD, 0x6D, 0x77, 0x57, 0x33, 0x3E, 0x92, 0x7C, 0x16, 0x64, 0xEB, 0x70, 0xF6, 0x43, 0x7C, 0x2C,
+0xE0, 0xFD, 0xB6, 0x77, 0xD2, 0x6B, 0xD7, 0x03, 0x01, 0x04, 0x08, 0xB0, 0x72, 0x36, 0xBB, 0x3B,
+0x60, 0x2D, 0xD6, 0x56, 0xBB, 0x47, 0xCD, 0x7E, 0x1C, 0x37, 0x03, 0x72, 0x38, 0xFA, 0x0E, 0xA7,
+0x9E, 0xFD, 0x58, 0x86, 0xF8, 0x28, 0xC2, 0x2C, 0x35, 0x46, 0xB1, 0xE0, 0xFC, 0xCA, 0x5F, 0x12,
+0x1F, 0x0B, 0x77, 0xBF, 0xDD, 0xF0, 0x77, 0x45, 0x74, 0x40, 0x80, 0x00, 0xAB, 0x18, 0x20, 0xFB,
+0x8B, 0x13, 0x1F, 0x13, 0xCC, 0x7E, 0x94, 0x07, 0xD9, 0x87, 0x57, 0xFC, 0x2E, 0xAD, 0x1D, 0xD9,
+0x12, 0x1F, 0xF9, 0x9F, 0xAD, 0x74, 0x59, 0x94, 0x97, 0x85, 0xBB, 0xBE, 0x43, 0x7C, 0x2C, 0xE4,
+0xFD, 0xC6, 0xFC, 0xD2, 0xF5, 0xD7, 0x9D, 0x82, 0x00, 0x01, 0x02, 0xAC, 0x98, 0x78, 0xCC, 0x35,
+0x40, 0xE6, 0x1C, 0x1F, 0xC3, 0x37, 0x4F, 0x32, 0xFB, 0x11, 0x87, 0xC2, 0x21, 0x8D, 0xE9, 0xF6,
+0xE3, 0x29, 0x1E, 0xCA, 0x92, 0xC5, 0x47, 0xE7, 0x65, 0x6D, 0xE3, 0xDE, 0x70, 0xF5, 0x75, 0xE2,
+0x63, 0xA1, 0xEF, 0xB7, 0x7D, 0xBB, 0xEE, 0x1C, 0x04, 0x08, 0x10, 0x60, 0xB5, 0xB4, 0xB6, 0xCE,
+0x70, 0x2D, 0x82, 0xE9, 0x5F, 0xE1, 0xFC, 0xE4, 0xB3, 0x1F, 0xA5, 0x4A, 0x39, 0xE5, 0xDA, 0x8F,
+0x65, 0x8D, 0x8F, 0x7B, 0xDF, 0xDA, 0x89, 0x8F, 0x4B, 0xE2, 0x63, 0xA1, 0xEF, 0x37, 0xB6, 0x3D,
+0x05, 0x0B, 0x10, 0x20, 0xC0, 0x8A, 0x89, 0x59, 0x7D, 0x21, 0xE2, 0x63, 0xF8, 0x5D, 0x77, 0x9A,
+0xFD, 0xE8, 0x8D, 0xB4, 0x07, 0xEE, 0x29, 0xCD, 0x7E, 0x1C, 0xC4, 0x13, 0x3E, 0x14, 0xF1, 0x21,
+0x3E, 0xCE, 0xF1, 0x7E, 0xBB, 0x3B, 0x61, 0x89, 0x10, 0x40, 0x80, 0x00, 0x2B, 0xA4, 0xB5, 0x73,
+0x8A, 0x00, 0x99, 0x4D, 0x7C, 0x4C, 0x3C, 0xFB, 0x91, 0x95, 0xB6, 0xDC, 0x3D, 0xC3, 0xEC, 0x87,
+0xF8, 0x10, 0x1F, 0xE7, 0x7E, 0xBF, 0xED, 0xBD, 0xF4, 0xBA, 0x1E, 0x00, 0x04, 0x08, 0xB0, 0x0A,
+0xE2, 0x93, 0x8D, 0xC6, 0xE1, 0x16, 0xBC, 0xE7, 0x1C, 0x1F, 0x71, 0xC2, 0xD9, 0x8F, 0x52, 0x78,
+0x0C, 0xDC, 0x5B, 0x33, 0x9E, 0x68, 0xF6, 0x43, 0x7C, 0x88, 0x8F, 0xF3, 0xBF, 0xDF, 0x50, 0x2C,
+0x44, 0x37, 0x03, 0x02, 0x08, 0x10, 0x60, 0x65, 0x6C, 0x9C, 0x2C, 0x40, 0x66, 0x14, 0x1F, 0xBD,
+0xB1, 0xF5, 0x48, 0x90, 0x0C, 0xDD, 0x58, 0xCC, 0x7C, 0xC4, 0xE1, 0x87, 0x73, 0xC2, 0x9D, 0xAF,
+0xC4, 0x87, 0xF8, 0x58, 0x88, 0xF8, 0x48, 0xB2, 0x7C, 0x06, 0xC4, 0x4E, 0x58, 0x80, 0x00, 0x01,
+0x56, 0xC6, 0x66, 0x68, 0x4D, 0xBA, 0x03, 0xD6, 0x0C, 0xE3, 0x23, 0x1E, 0x7F, 0xD5, 0xF3, 0xC3,
+0xAB, 0x9C, 0xC7, 0xF1, 0xEB, 0x41, 0xF6, 0x7A, 0x57, 0x3E, 0x17, 0x1F, 0xE2, 0xA3, 0x4A, 0xF1,
+0x51, 0x68, 0xEF, 0xB8, 0x18, 0x21, 0x20, 0x40, 0x80, 0x15, 0x91, 0xB5, 0xAE, 0x87, 0x38, 0xC9,
+0xC8, 0x7D, 0x86, 0xF1, 0x71, 0x54, 0x90, 0x0C, 0xAD, 0xFD, 0xE8, 0x2E, 0x38, 0xAF, 0x8D, 0x3E,
+0x92, 0x74, 0xC3, 0x4E, 0x9C, 0xF0, 0xA1, 0x88, 0x0F, 0xF1, 0xB1, 0x60, 0xF1, 0xD1, 0x2D, 0x90,
+0x86, 0x93, 0x11, 0x20, 0x40, 0x80, 0xD5, 0xD0, 0xDA, 0x9A, 0xE0, 0xBF, 0xBC, 0xCE, 0x76, 0xE6,
+0xA3, 0x3F, 0xE3, 0x31, 0xB0, 0xAE, 0xA3, 0x36, 0x30, 0xD3, 0x11, 0x4B, 0x33, 0x1F, 0x23, 0x77,
+0x3B, 0xE1, 0xEC, 0x87, 0xF8, 0x10, 0x1F, 0x8B, 0x19, 0x1F, 0x31, 0x7F, 0x1A, 0x56, 0xFC, 0xC4,
+0x0F, 0xD7, 0x9D, 0x90, 0x00, 0x01, 0x02, 0x2C, 0xBF, 0xEC, 0xA0, 0x71, 0x6E, 0xF1, 0x31, 0xAC,
+0x76, 0x18, 0x22, 0xC3, 0x33, 0x1F, 0xA1, 0xDC, 0x1F, 0xE5, 0x77, 0x66, 0x61, 0xA2, 0xD9, 0x0F,
+0xF1, 0x21, 0x3E, 0x16, 0x36, 0x3E, 0x92, 0xEE, 0x85, 0x40, 0x05, 0x08, 0x20, 0x40, 0x80, 0xE5,
+0x16, 0x9F, 0x6C, 0xD4, 0x8F, 0x7F, 0xFA, 0xD5, 0x8C, 0xE3, 0x23, 0x0E, 0x7D, 0x95, 0xFE, 0xDF,
+0x6B, 0x03, 0x33, 0x1F, 0x87, 0xB3, 0x23, 0xB5, 0xD1, 0xDD, 0xB0, 0x76, 0xEF, 0x3C, 0xFB, 0x21,
+0x3E, 0xC4, 0xC7, 0x42, 0xC7, 0x47, 0xBF, 0xA4, 0x43, 0xC3, 0x59, 0x09, 0x10, 0x20, 0xC0, 0xB2,
+0xAB, 0x87, 0xD6, 0xD6, 0xC2, 0xC4, 0xC7, 0xC8, 0xD3, 0xB0, 0xCA, 0x0B, 0xCE, 0x43, 0x69, 0x21,
+0x7A, 0xF9, 0x3E, 0xEE, 0x30, 0xFB, 0x21, 0x3E, 0xC4, 0xC7, 0xE2, 0xC7, 0x47, 0x47, 0x7B, 0x3B,
+0xBD, 0xBE, 0xE6, 0x94, 0x04, 0x08, 0x10, 0x60, 0xD9, 0x35, 0x42, 0xBB, 0x39, 0xFF, 0xF8, 0x38,
+0x66, 0x4C, 0xD6, 0xDF, 0x76, 0xB7, 0x37, 0xF3, 0x71, 0xB8, 0xFB, 0x55, 0x6D, 0xF4, 0x21, 0xEE,
+0xC6, 0x63, 0x1F, 0xAA, 0xF8, 0x10, 0x1F, 0x95, 0x88, 0x8F, 0x42, 0xB6, 0x5F, 0x77, 0x4A, 0x02,
+0xE6, 0x6D, 0xDD, 0x21, 0x00, 0xE6, 0xEC, 0xBE, 0xD1, 0x6B, 0x80, 0xCC, 0x2F, 0x3E, 0x46, 0x66,
+0x3F, 0x8A, 0xF0, 0x88, 0xA5, 0xAB, 0x9C, 0x87, 0xEE, 0xA0, 0xFC, 0xA4, 0xB3, 0x1F, 0xE2, 0x43,
+0x7C, 0x54, 0x2A, 0x3E, 0xF2, 0x77, 0xB5, 0x1A, 0x4E, 0x49, 0xC0, 0xBC, 0x99, 0x01, 0x01, 0xE6,
+0xAB, 0xB5, 0xB5, 0x79, 0x2E, 0xF1, 0x11, 0xC7, 0xDF, 0x16, 0x87, 0xDE, 0x55, 0x0C, 0xC0, 0xC7,
+0x7E, 0xFC, 0xF6, 0xD1, 0xB3, 0x1F, 0x8B, 0x1C, 0x1F, 0x51, 0x7C, 0x88, 0x8F, 0xA3, 0x64, 0x3B,
+0x69, 0x27, 0x2C, 0xD7, 0x03, 0x01, 0x04, 0x08, 0xB0, 0xC4, 0xB2, 0xD6, 0xE6, 0xDC, 0xE3, 0x63,
+0xF8, 0xAB, 0x0D, 0x5F, 0xD5, 0x7C, 0x64, 0xF6, 0x63, 0xCC, 0xDA, 0x8F, 0xB4, 0xE8, 0x7C, 0x37,
+0x56, 0x32, 0x3E, 0x6A, 0xC7, 0xC4, 0xC7, 0xC0, 0x6D, 0xE2, 0x63, 0xB5, 0xE2, 0x23, 0xFF, 0xF7,
+0x98, 0xCF, 0x46, 0x6E, 0x3A, 0x31, 0x01, 0x02, 0x04, 0x58, 0x5E, 0xED, 0xBD, 0x8D, 0xB9, 0xC7,
+0x47, 0x31, 0x0A, 0x1F, 0xBA, 0x2D, 0x8E, 0xB9, 0xDB, 0x63, 0x67, 0x3F, 0x2A, 0x16, 0x1F, 0xE1,
+0xC8, 0xF8, 0x08, 0x03, 0x8B, 0xEC, 0x8B, 0xDD, 0xBE, 0x32, 0xF1, 0xB1, 0x5A, 0xF1, 0x91, 0x7F,
+0xD8, 0x81, 0x00, 0x01, 0x04, 0x08, 0xB0, 0xBC, 0xE2, 0x93, 0x8D, 0x46, 0xF7, 0xDA, 0x03, 0xF3,
+0x5F, 0x70, 0x3E, 0x3C, 0xF0, 0x2E, 0xDE, 0x38, 0x1C, 0x80, 0x0F, 0x87, 0x48, 0x39, 0x9A, 0x42,
+0xF7, 0xC2, 0x83, 0x15, 0x8B, 0x8F, 0x91, 0x9B, 0xFA, 0xC7, 0xA0, 0x76, 0x78, 0x2C, 0x86, 0x9E,
+0x76, 0x75, 0x41, 0x7C, 0xAC, 0x4E, 0x7C, 0xE4, 0xBF, 0xDB, 0x76, 0xC2, 0x02, 0x04, 0x08, 0xB0,
+0xD4, 0x05, 0x12, 0xEB, 0x21, 0x6B, 0xCD, 0x77, 0xD0, 0x39, 0x76, 0xF6, 0x23, 0xE6, 0x3B, 0x5F,
+0x95, 0x2F, 0xED, 0x51, 0x1E, 0x88, 0x8F, 0x7C, 0xFE, 0x76, 0xF5, 0xE3, 0x23, 0xF6, 0xB7, 0x19,
+0xAE, 0x1D, 0xBE, 0xAF, 0xF4, 0xB4, 0xAB, 0xAC, 0x17, 0x1F, 0x2F, 0x13, 0x1F, 0xAB, 0x13, 0x1F,
+0xFD, 0x4F, 0x69, 0x99, 0x01, 0x01, 0x04, 0x08, 0xB0, 0xB4, 0x8E, 0xB9, 0x06, 0xC8, 0xEC, 0x06,
+0x9D, 0x83, 0xB3, 0x1F, 0xA5, 0x8B, 0x81, 0x8C, 0x59, 0xFB, 0x31, 0x32, 0x84, 0x4B, 0xBD, 0x34,
+0x34, 0xFB, 0x51, 0x85, 0xF8, 0x18, 0xFF, 0x71, 0x83, 0xF1, 0x31, 0x3C, 0xF3, 0x21, 0x3E, 0x56,
+0x30, 0x3E, 0x92, 0x6C, 0x5F, 0x80, 0x00, 0x02, 0x04, 0x58, 0x52, 0xED, 0xBD, 0x1B, 0x73, 0x1D,
+0x74, 0x8E, 0xCC, 0x7E, 0xC4, 0xFE, 0x75, 0x3F, 0x06, 0x16, 0xA4, 0x97, 0x67, 0x3F, 0xCA, 0x41,
+0x92, 0xFE, 0xDC, 0xAA, 0x66, 0x7C, 0x8C, 0x5D, 0x74, 0x5E, 0xBA, 0xBD, 0x7C, 0xBD, 0x93, 0x35,
+0xF1, 0xB1, 0xBA, 0xF1, 0x91, 0x07, 0xC8, 0xDE, 0x86, 0x9D, 0xB0, 0x00, 0x01, 0x02, 0x2C, 0xA7,
+0x6C, 0xFF, 0xE4, 0x83, 0x9C, 0x33, 0x0E, 0x3A, 0x63, 0x69, 0x0F, 0xDA, 0xB1, 0x3B, 0x5F, 0x1D,
+0x37, 0x8C, 0x4B, 0xEB, 0x73, 0x0F, 0xE2, 0x72, 0xC4, 0x47, 0x2C, 0xCF, 0x7C, 0x1C, 0x06, 0x97,
+0xF8, 0x58, 0xF1, 0xF8, 0xC8, 0x3F, 0xDD, 0x42, 0x74, 0x60, 0xBE, 0x5C, 0x88, 0x10, 0x98, 0x63,
+0x80, 0x34, 0x4F, 0x36, 0xC8, 0x39, 0xEB, 0xA0, 0xB3, 0x56, 0x8C, 0xCD, 0x0E, 0xFF, 0xB3, 0xFF,
+0x89, 0x66, 0x3F, 0xB6, 0x97, 0x34, 0x3E, 0x7A, 0x17, 0x59, 0x5C, 0x7B, 0x79, 0x27, 0x3E, 0xDE,
+0x22, 0x3E, 0x56, 0x3A, 0x3E, 0xF2, 0x7F, 0x97, 0x7B, 0xE9, 0x75, 0xDD, 0x09, 0x0A, 0x98, 0x17,
+0x33, 0x20, 0xC0, 0x7C, 0x86, 0x49, 0xB7, 0x6E, 0x6C, 0x86, 0x76, 0x73, 0x7E, 0x83, 0xCE, 0xFE,
+0x0C, 0x47, 0x3C, 0xFA, 0xBA, 0x1F, 0xC3, 0xB7, 0x95, 0x3F, 0xBF, 0x34, 0xFB, 0x51, 0xF9, 0xF8,
+0x18, 0xF8, 0x36, 0x4B, 0x33, 0x1F, 0xE2, 0x43, 0x7C, 0x08, 0x10, 0x40, 0x80, 0x00, 0x4B, 0x6C,
+0xA3, 0xBB, 0x05, 0xEF, 0x9C, 0x06, 0x9D, 0xB5, 0xA1, 0x01, 0x5A, 0xEF, 0xBF, 0xFC, 0x0F, 0x07,
+0x4A, 0x3E, 0xFB, 0x31, 0x3C, 0x9E, 0xCB, 0xD7, 0x7E, 0x64, 0x95, 0x8D, 0x8F, 0x30, 0x1C, 0x1F,
+0xE3, 0x9E, 0x76, 0x25, 0x3E, 0xC4, 0x47, 0xFF, 0xAE, 0xDA, 0x69, 0x27, 0xAC, 0x1B, 0x01, 0x60,
+0x4E, 0x3C, 0x05, 0x0B, 0x98, 0x97, 0x46, 0xEF, 0xAA, 0xCB, 0xB3, 0x1F, 0x74, 0x0E, 0xED, 0x76,
+0x35, 0xFA, 0x94, 0xAB, 0xD2, 0x33, 0xB3, 0xC6, 0xCD, 0x88, 0xA4, 0x5D, 0xAF, 0x5A, 0xD5, 0x8D,
+0x8F, 0x28, 0x3E, 0xC4, 0xC7, 0x49, 0x65, 0x7B, 0x75, 0xA7, 0x28, 0x40, 0x80, 0x00, 0xCB, 0xE6,
+0xDA, 0x1D, 0x03, 0x64, 0x56, 0x03, 0xFE, 0x31, 0x6B, 0x3F, 0x46, 0x6E, 0x2B, 0xBF, 0x6F, 0x27,
+0x2E, 0xC7, 0xD3, 0xAE, 0xC4, 0x87, 0xF8, 0x98, 0x38, 0x40, 0xF6, 0x05, 0x08, 0x30, 0x37, 0x9E,
+0x82, 0x05, 0xCC, 0x47, 0xF3, 0x85, 0xFA, 0xCC, 0x07, 0x9D, 0xBD, 0xBD, 0x65, 0xE3, 0x40, 0x64,
+0x1C, 0x0E, 0xCA, 0xC3, 0xB8, 0xD9, 0x8F, 0x30, 0x3A, 0xFB, 0x11, 0x5B, 0xCB, 0xB7, 0xDB, 0x55,
+0x58, 0x5F, 0x0F, 0x57, 0x1B, 0xFF, 0x51, 0x2F, 0x3E, 0xBE, 0x2C, 0x3E, 0xC4, 0xC7, 0x70, 0x81,
+0x84, 0xF8, 0x89, 0x1F, 0x6E, 0x38, 0x51, 0x01, 0x02, 0x04, 0x58, 0x1E, 0xB1, 0xBD, 0x39, 0xFB,
+0x41, 0x67, 0xE9, 0x7E, 0x6A, 0xA5, 0x59, 0x80, 0x81, 0x40, 0x39, 0xBC, 0x2D, 0x0E, 0x8F, 0xE9,
+0xD2, 0xED, 0xDB, 0x4B, 0x10, 0x1F, 0x61, 0x34, 0x3E, 0xD2, 0xCC, 0xC7, 0xDA, 0xD5, 0xAB, 0xDD,
+0xF0, 0x68, 0x3D, 0x2F, 0x3E, 0xC4, 0xC7, 0xA0, 0xF6, 0x76, 0x7A, 0x5D, 0x77, 0xA2, 0x02, 0x04,
+0x08, 0xB0, 0x1C, 0xED, 0x71, 0xEB, 0xC6, 0x46, 0x88, 0x07, 0x1B, 0x33, 0x1D, 0x74, 0xF6, 0xEE,
+0x67, 0x78, 0x41, 0x79, 0x2C, 0x0D, 0xCC, 0x07, 0xA2, 0x23, 0x0E, 0x0E, 0xD8, 0xF3, 0xB7, 0x77,
+0x3A, 0xAF, 0xDA, 0xD3, 0x78, 0x3C, 0x8B, 0x17, 0x1F, 0x17, 0xEE, 0xBF, 0xAF, 0x1B, 0x1F, 0xE9,
+0xA9, 0x57, 0xE2, 0x43, 0x7C, 0x0C, 0xEB, 0x3E, 0x3D, 0x52, 0x80, 0x00, 0x02, 0x04, 0x58, 0x1A,
+0x9B, 0xA1, 0xB5, 0x3B, 0xD7, 0xF8, 0x18, 0x79, 0x1A, 0xD6, 0xF0, 0xEC, 0xC7, 0xD0, 0xC2, 0xF3,
+0x98, 0x75, 0xFE, 0xB2, 0x9D, 0x89, 0x0F, 0xF1, 0xB1, 0x7A, 0xF1, 0x91, 0x7F, 0x99, 0xFC, 0x62,
+0x84, 0x76, 0xC2, 0x02, 0x04, 0x08, 0xB0, 0x44, 0x01, 0x32, 0xBC, 0x00, 0x7D, 0xD6, 0x8B, 0xBC,
+0xCB, 0xDB, 0xEE, 0x0E, 0x47, 0x47, 0xAC, 0x0D, 0x3D, 0x94, 0xCE, 0x8D, 0xBB, 0x71, 0x0A, 0x63,
+0x3D, 0xF1, 0x21, 0x3E, 0xAA, 0xFA, 0xB5, 0x3A, 0x5A, 0x2F, 0x6D, 0x38, 0x55, 0x01, 0x02, 0x04,
+0x58, 0x16, 0x83, 0xD7, 0x00, 0x99, 0x41, 0x7C, 0x8C, 0xCC, 0x7E, 0x14, 0x6F, 0x97, 0x16, 0x65,
+0x77, 0xD5, 0x06, 0x66, 0x3F, 0xF2, 0xF8, 0x48, 0x13, 0x1F, 0x3B, 0x71, 0x6A, 0x8F, 0x45, 0x7C,
+0x88, 0x8F, 0xCA, 0xC5, 0x47, 0xFE, 0x25, 0x8F, 0x59, 0xA7, 0x05, 0x20, 0x40, 0x80, 0x4A, 0x69,
+0xEF, 0xDD, 0x98, 0x59, 0x7C, 0xC4, 0xF1, 0xEF, 0x1A, 0xDE, 0x62, 0xB7, 0x18, 0xA0, 0x0F, 0x7E,
+0x7C, 0xEF, 0x2F, 0x67, 0x9E, 0xFD, 0x10, 0x1F, 0xE2, 0xA3, 0xE2, 0xF1, 0x91, 0x7F, 0xD9, 0x83,
+0x10, 0x3F, 0xFE, 0x43, 0x22, 0x04, 0x10, 0x20, 0xC0, 0x12, 0xC8, 0x9A, 0xF5, 0x99, 0xC4, 0xC7,
+0xF0, 0xDF, 0xC6, 0xEC, 0x78, 0x35, 0x38, 0xFB, 0x51, 0x5E, 0xFB, 0x11, 0xBB, 0x7F, 0xB6, 0xC3,
+0x19, 0x67, 0x3F, 0xC4, 0x87, 0xF8, 0x58, 0x82, 0xF8, 0xC8, 0xFF, 0x9D, 0xEE, 0xA4, 0xD7, 0x75,
+0x27, 0x2C, 0x40, 0x80, 0x00, 0xD5, 0xD7, 0xDA, 0xA9, 0xCF, 0x24, 0x3E, 0x62, 0x77, 0x3C, 0x3E,
+0xFC, 0xEE, 0x18, 0x6A, 0x23, 0xE3, 0xDD, 0xC1, 0xD9, 0x8F, 0x78, 0xF8, 0x70, 0xB6, 0xCF, 0x32,
+0xFB, 0x21, 0x3E, 0xC4, 0xC7, 0x92, 0xC4, 0x47, 0xFE, 0xE5, 0x53, 0x8D, 0x07, 0x33, 0x20, 0x80,
+0x00, 0x01, 0xAA, 0x2D, 0xDE, 0xBA, 0xB1, 0x19, 0xB2, 0xFD, 0x99, 0x0D, 0xD0, 0x06, 0xB6, 0xD1,
+0x2D, 0x47, 0x48, 0x69, 0xD7, 0xAB, 0xC1, 0x10, 0x29, 0xC5, 0x47, 0x1A, 0x6F, 0xED, 0xC5, 0xA9,
+0x3D, 0x16, 0xF1, 0x21, 0x3E, 0x2A, 0x1B, 0x1F, 0x49, 0xB6, 0x97, 0x5E, 0x5F, 0x77, 0xD6, 0x02,
+0x04, 0x08, 0x50, 0xF5, 0x04, 0xA9, 0x8F, 0xEC, 0x80, 0x35, 0x8D, 0x01, 0xDA, 0x31, 0xB3, 0x1F,
+0xA5, 0x26, 0x19, 0x1C, 0xA8, 0x0F, 0xCF, 0x9E, 0x6C, 0x8B, 0x0F, 0xF1, 0x21, 0x3E, 0x06, 0x23,
+0x64, 0xA7, 0xEE, 0x9C, 0x05, 0x08, 0x10, 0xA0, 0xEA, 0xC6, 0x5F, 0x03, 0x64, 0x0A, 0x03, 0xB4,
+0xA3, 0x66, 0x3F, 0xC6, 0xAD, 0xFD, 0xC8, 0x9F, 0x76, 0x55, 0xBE, 0xAB, 0xB4, 0xF3, 0xD5, 0xA9,
+0x66, 0x3F, 0xC4, 0x87, 0xF8, 0x58, 0xD2, 0xF8, 0xC8, 0x1F, 0x8E, 0x9D, 0xB0, 0x00, 0x01, 0x02,
+0x54, 0x5D, 0xD6, 0xBA, 0xDE, 0x7B, 0x6E, 0xF9, 0xF4, 0x06, 0x68, 0x13, 0xCC, 0x7E, 0x1C, 0x6E,
+0xC1, 0x5B, 0xEB, 0x6E, 0xB5, 0x3B, 0x7C, 0x51, 0xC2, 0x97, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0xA3,
+0xFF, 0x5E, 0xF7, 0xD2, 0x4E, 0x58, 0x75, 0x27, 0x2E, 0x40, 0x80, 0x00, 0xD5, 0xD5, 0xDA, 0x3A,
+0xC3, 0xC5, 0xCD, 0xE2, 0x9D, 0xC7, 0xB5, 0x47, 0xCD, 0x7E, 0x0C, 0xDD, 0xC7, 0xC0, 0x4D, 0xE9,
+0xA2, 0xCF, 0x07, 0x71, 0x6A, 0x8F, 0x45, 0x7C, 0x88, 0x8F, 0xA5, 0x88, 0x8F, 0x5E, 0x80, 0x04,
+0x3B, 0x61, 0x01, 0x02, 0x04, 0xA8, 0xB4, 0x98, 0x35, 0xA6, 0x3E, 0x40, 0x9B, 0x78, 0xF6, 0x63,
+0x70, 0x31, 0x7A, 0xFF, 0xED, 0x6D, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0xF8, 0x87, 0x96, 0xEA, 0x3C,
+0x34, 0x02, 0x80, 0x00, 0x01, 0x2A, 0xD9, 0x1E, 0xB7, 0x5E, 0x7F, 0xCA, 0x05, 0xE8, 0xF1, 0xD8,
+0x77, 0x4D, 0x36, 0xFB, 0x31, 0xF4, 0xB4, 0xAB, 0xC2, 0x89, 0x67, 0x3F, 0xC4, 0x87, 0xF8, 0x58,
+0x91, 0xF8, 0x48, 0xBA, 0x33, 0x20, 0xD7, 0x9C, 0xBD, 0x00, 0x01, 0x02, 0x54, 0x55, 0x3D, 0xB4,
+0xB6, 0xA6, 0x3B, 0x40, 0xBB, 0xD3, 0x75, 0x3F, 0xFA, 0x5B, 0xED, 0xD6, 0xC6, 0x6F, 0xCB, 0xBB,
+0x2D, 0x3E, 0xC4, 0x87, 0xF8, 0x38, 0x3E, 0x42, 0xEC, 0x84, 0x05, 0xCC, 0xD6, 0xBA, 0x43, 0x00,
+0xCC, 0xD0, 0x66, 0x68, 0x9F, 0x64, 0x06, 0x24, 0xDE, 0xF1, 0xDD, 0x47, 0x5D, 0xF5, 0xBC, 0xFF,
+0x94, 0xAB, 0xD2, 0xCC, 0x47, 0xF9, 0xF6, 0x5C, 0x33, 0x9E, 0x60, 0xF6, 0x43, 0x7C, 0x88, 0x8F,
+0x15, 0x8C, 0x8F, 0xAE, 0x86, 0x53, 0x17, 0x30, 0x4B, 0x66, 0x40, 0x80, 0x59, 0xBA, 0x36, 0xF9,
+0x53, 0xB0, 0x4E, 0x31, 0x40, 0x1B, 0x59, 0xFB, 0x11, 0x47, 0x6F, 0x2B, 0xDF, 0xFD, 0x96, 0xF8,
+0x10, 0x1F, 0xE2, 0xE3, 0x8E, 0xDA, 0xDB, 0x76, 0xC2, 0x02, 0x04, 0x08, 0x50, 0x51, 0xAD, 0xAD,
+0x09, 0xAF, 0x29, 0x70, 0xE7, 0x99, 0x8F, 0x81, 0x2D, 0x74, 0xFB, 0xB3, 0x1F, 0xB5, 0xD2, 0x4C,
+0x47, 0x1C, 0x78, 0xFF, 0xE1, 0x40, 0xBE, 0x77, 0x1F, 0xE9, 0x9A, 0x1F, 0xED, 0x29, 0x3C, 0x16,
+0xF1, 0x21, 0x3E, 0x96, 0x39, 0x3E, 0xF2, 0x87, 0x9C, 0x2F, 0x44, 0x17, 0x20, 0x80, 0x00, 0x01,
+0x2A, 0x28, 0x6B, 0x4D, 0x10, 0x20, 0x27, 0x1C, 0xA0, 0xD5, 0x0E, 0x43, 0x64, 0x78, 0xE6, 0xA3,
+0xFC, 0xEC, 0xAB, 0x81, 0xBB, 0x4D, 0x6F, 0xEF, 0x4C, 0xF2, 0x75, 0xC4, 0x87, 0xF8, 0x58, 0xF1,
+0xF8, 0x38, 0x0C, 0x10, 0x17, 0x24, 0x04, 0x04, 0x08, 0x50, 0x41, 0xED, 0xBD, 0x8D, 0x33, 0x0F,
+0xD0, 0xE2, 0xD0, 0x47, 0xF6, 0xFF, 0x5E, 0x1B, 0x98, 0xF9, 0x38, 0x9C, 0xFD, 0x38, 0x1C, 0xD4,
+0xF7, 0x3F, 0x67, 0xA2, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0x47, 0xF7, 0xDF, 0xED, 0x76, 0x7A,
+0x6D, 0x27, 0x2C, 0x40, 0x80, 0x00, 0xD5, 0x12, 0x6F, 0xBD, 0xBE, 0x71, 0xFC, 0xFA, 0x8F, 0xD3,
+0xC5, 0xC7, 0xE0, 0xD3, 0xB0, 0x86, 0x16, 0x9C, 0x87, 0xA1, 0xA7, 0x5D, 0xA5, 0x3F, 0xB3, 0x30,
+0xC1, 0xDA, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x80, 0x6C, 0xDF, 0x0C, 0x08, 0x20, 0x40, 0x80,
+0xCA, 0x39, 0xE6, 0x1A, 0x20, 0x67, 0x18, 0xA0, 0xF5, 0xB7, 0xDD, 0x8D, 0xA3, 0xD1, 0x11, 0x6B,
+0xA3, 0xE3, 0xE3, 0xDD, 0x78, 0x87, 0x2F, 0x27, 0x3E, 0xC4, 0x87, 0xF8, 0x18, 0xFD, 0x36, 0x5A,
+0x02, 0x04, 0x10, 0x20, 0x40, 0x05, 0x03, 0xE4, 0x60, 0xEB, 0xCC, 0x03, 0xB4, 0xF1, 0xDB, 0xEE,
+0xC6, 0xC1, 0xAB, 0x9C, 0x87, 0xEE, 0xC0, 0x7E, 0x60, 0xF6, 0x23, 0x49, 0xB3, 0x1F, 0xC7, 0xAE,
+0xFD, 0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x8C, 0x95, 0xED, 0x6C, 0xC4, 0x8F, 0xFF, 0xD0, 0x86, 0xD3,
+0x18, 0x20, 0x40, 0x80, 0xEA, 0x68, 0xEF, 0x5E, 0x3F, 0xD3, 0x00, 0x2D, 0x8E, 0xBF, 0x2D, 0x0E,
+0xBD, 0xAB, 0x18, 0xC4, 0x87, 0x38, 0x66, 0x8C, 0x7C, 0xEC, 0xEC, 0x87, 0xF8, 0x10, 0x1F, 0xE2,
+0xE3, 0xE8, 0x6F, 0x27, 0x5F, 0x34, 0x65, 0x16, 0x04, 0x10, 0x20, 0x40, 0x95, 0x02, 0xA4, 0x59,
+0x3F, 0xEB, 0x00, 0x6D, 0x74, 0xF6, 0x23, 0x0E, 0x5C, 0x60, 0x70, 0x38, 0x3A, 0x26, 0x9F, 0xFD,
+0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x1C, 0xFF, 0x2D, 0xED, 0x0B, 0x10, 0x40, 0x80, 0x00, 0x15, 0x93,
+0x35, 0x37, 0x4F, 0x3D, 0x40, 0x8B, 0xDD, 0x31, 0xFB, 0xF0, 0x00, 0x38, 0x0E, 0xDD, 0x78, 0xEC,
+0xEC, 0xC7, 0xF6, 0x51, 0xB3, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x3B, 0xFF, 0xFB, 0xDD, 0x4B,
+0xAF, 0xED, 0x84, 0x05, 0x08, 0x10, 0xA0, 0x1A, 0xE2, 0xAD, 0xD7, 0x6F, 0x1E, 0x2E, 0x40, 0x3F,
+0xDD, 0x00, 0xAD, 0xBC, 0x93, 0x55, 0x2C, 0x6D, 0x87, 0x15, 0x4B, 0xBB, 0x5E, 0x0D, 0x86, 0x48,
+0xE9, 0x73, 0xD2, 0xB3, 0x47, 0x76, 0xA3, 0xF8, 0x10, 0x1F, 0xE2, 0xE3, 0xD4, 0xDF, 0x5A, 0x3B,
+0xBD, 0x98, 0x01, 0x01, 0x04, 0x08, 0x50, 0x19, 0x1B, 0xA1, 0xBD, 0x7B, 0xBA, 0x01, 0xDA, 0xC8,
+0xEC, 0x47, 0xEC, 0xEF, 0x7C, 0x55, 0xDE, 0x5D, 0x77, 0x60, 0x30, 0x3F, 0xFC, 0xF9, 0xDB, 0xE2,
+0x43, 0x7C, 0x88, 0x8F, 0x33, 0xCB, 0x76, 0xEB, 0x4E, 0x65, 0x80, 0x00, 0x01, 0x2A, 0x22, 0x36,
+0x42, 0x7B, 0xFF, 0xEC, 0xE3, 0xDE, 0x18, 0x07, 0x2F, 0x40, 0x38, 0x66, 0xED, 0x47, 0x7F, 0x28,
+0x58, 0xDC, 0x96, 0xD6, 0x7E, 0xEC, 0x45, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x99, 0xBF, 0xCD, 0x7D,
+0x01, 0x02, 0x08, 0x10, 0xA0, 0x32, 0xAE, 0x1D, 0x7F, 0x11, 0xC2, 0x63, 0xC6, 0x75, 0xB5, 0xA1,
+0x41, 0xDE, 0xD0, 0xEC, 0x47, 0xFF, 0x2A, 0xE7, 0xC5, 0x80, 0xBE, 0x74, 0x11, 0xC2, 0xF1, 0xB3,
+0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x53, 0xE9, 0xFC, 0x1B, 0x8E, 0x1F, 0x7F, 0x7B, 0xC3, 0xE9,
+0x0C, 0x10, 0x20, 0xC0, 0xE2, 0x6B, 0xBE, 0x50, 0x3F, 0xDB, 0xD8, 0x37, 0x0E, 0x5D, 0xF7, 0x23,
+0x0C, 0x0C, 0xEA, 0x8F, 0x1C, 0x0E, 0x1E, 0x84, 0xA1, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7,
+0xA9, 0x7F, 0x0F, 0xB2, 0x7C, 0x16, 0xB3, 0x1E, 0x00, 0x04, 0x08, 0xB0, 0xF8, 0x83, 0x97, 0x53,
+0x2C, 0x5E, 0xED, 0xCF, 0x7E, 0xC4, 0x81, 0xDB, 0x26, 0x9A, 0xFD, 0x28, 0xDE, 0xDE, 0x16, 0x1F,
+0xE2, 0x43, 0x7C, 0x4C, 0xED, 0xF7, 0xA0, 0x3B, 0x8B, 0x29, 0x40, 0x00, 0x01, 0x02, 0x2C, 0xF8,
+0xD8, 0xE5, 0xD6, 0xC3, 0x1B, 0x21, 0x3B, 0x38, 0xD5, 0x15, 0x94, 0x63, 0x2C, 0x3F, 0xED, 0xAA,
+0x34, 0xEE, 0x9B, 0x74, 0xF6, 0xE3, 0x20, 0x8A, 0x0F, 0xF1, 0x21, 0x3E, 0xA6, 0xF5, 0x7B, 0x10,
+0xD3, 0x3F, 0xAA, 0x70, 0xC3, 0x59, 0x0D, 0x10, 0x20, 0xC0, 0xA2, 0xDB, 0xEC, 0xEE, 0x80, 0x75,
+0xC6, 0x41, 0xDE, 0xA9, 0x67, 0x3F, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x53, 0xFB, 0x3D, 0x68, 0x6F,
+0xD5, 0x9D, 0xD2, 0x00, 0x01, 0x02, 0x54, 0x20, 0x40, 0x4E, 0xB8, 0x00, 0x7D, 0x68, 0xB7, 0xAB,
+0x63, 0x67, 0x3F, 0xE2, 0xD0, 0xC7, 0x24, 0xFD, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x54,
+0x7F, 0x0F, 0x62, 0x4B, 0x80, 0x00, 0x02, 0x04, 0x58, 0x78, 0x1B, 0x27, 0x9A, 0x01, 0x39, 0xE2,
+0xB9, 0x55, 0x03, 0x57, 0x3D, 0x2F, 0xCF, 0x7E, 0x0C, 0xDD, 0x96, 0xDF, 0x70, 0x3B, 0x13, 0x1F,
+0xE2, 0x43, 0x7C, 0xCC, 0xE2, 0xF7, 0x20, 0x1E, 0xA4, 0x9D, 0xB0, 0x5C, 0x90, 0x10, 0x10, 0x20,
+0xC0, 0x02, 0x6B, 0xEF, 0x4D, 0xFE, 0x9C, 0xF1, 0xDE, 0xC0, 0xA7, 0xBF, 0x85, 0xEE, 0xD0, 0xEC,
+0x47, 0xFF, 0x0A, 0xE7, 0xA5, 0xF7, 0x87, 0xE1, 0xAB, 0x9E, 0xA7, 0x5D, 0xAF, 0xDA, 0xE2, 0x43,
+0x7C, 0x88, 0x8F, 0x99, 0xFC, 0x1E, 0xB4, 0x77, 0xD2, 0xEB, 0xBA, 0x13, 0x1B, 0x20, 0x40, 0x80,
+0xC5, 0x95, 0x35, 0x27, 0x1B, 0xAC, 0x0C, 0x0F, 0x7C, 0x6A, 0xA5, 0xF0, 0x18, 0x5A, 0xFB, 0x31,
+0x72, 0x5B, 0xF9, 0x7D, 0x3B, 0x99, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0x56, 0xBF, 0x07, 0xDD, 0x9D,
+0xB0, 0xCC, 0x80, 0x00, 0x53, 0xB5, 0xEE, 0x10, 0x00, 0x53, 0xD5, 0xDA, 0xB9, 0x73, 0x80, 0x94,
+0x06, 0x3E, 0xE5, 0xAB, 0x98, 0xC7, 0x70, 0x38, 0xC0, 0x0F, 0xE3, 0x66, 0x3F, 0xC2, 0xF0, 0xEC,
+0x47, 0x27, 0x3E, 0xDA, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x99, 0xFD, 0x1E, 0x74, 0x77, 0xC2, 0xBA,
+0xEE, 0xC4, 0x06, 0x4C, 0x93, 0x19, 0x10, 0x60, 0x7A, 0x63, 0x9A, 0x5B, 0x0F, 0x6F, 0xDE, 0xF1,
+0x0A, 0xE8, 0xE3, 0x06, 0x3E, 0xB5, 0xC3, 0xD0, 0x18, 0x9E, 0xF9, 0x28, 0x6E, 0x8B, 0xC3, 0xE3,
+0xC3, 0x74, 0x3F, 0x3B, 0x53, 0x18, 0x30, 0x8A, 0x0F, 0xF1, 0x21, 0x3E, 0x8E, 0xD7, 0xBE, 0x5D,
+0x0F, 0x00, 0x02, 0x04, 0x58, 0x50, 0xF5, 0x63, 0x03, 0x64, 0x68, 0xE0, 0x13, 0x87, 0xDE, 0x88,
+0xA5, 0x41, 0xFE, 0x40, 0x74, 0xC4, 0xC1, 0xDB, 0xF3, 0xD7, 0x29, 0x3E, 0xCE, 0x3A, 0xFB, 0x21,
+0x3E, 0xC4, 0x87, 0xF8, 0x98, 0x84, 0xA7, 0x60, 0x01, 0x02, 0x04, 0x58, 0x58, 0x9B, 0xA1, 0xB5,
+0x7B, 0xE2, 0xF8, 0x18, 0x59, 0x84, 0x3E, 0x3C, 0xFB, 0x51, 0x7E, 0xDA, 0x55, 0x7A, 0x23, 0x2D,
+0xFB, 0x38, 0xEB, 0xEC, 0x87, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0x32, 0xD9, 0x9E, 0x9D, 0xB0, 0x00,
+0x01, 0x02, 0x2C, 0xA8, 0xAC, 0x75, 0x3D, 0xC4, 0xF6, 0xC9, 0x07, 0x3E, 0xE5, 0x6D, 0x77, 0x87,
+0xA3, 0x23, 0xD6, 0x4A, 0x77, 0xD3, 0xBB, 0x9F, 0xDD, 0x78, 0xB6, 0x71, 0xA3, 0xF8, 0x10, 0x1F,
+0xE2, 0x63, 0x72, 0xED, 0xBD, 0xF4, 0x7A, 0xC3, 0x09, 0x0E, 0x10, 0x20, 0xC0, 0xE2, 0x69, 0x6D,
+0x6D, 0x4C, 0x32, 0xF0, 0x39, 0xEA, 0xA2, 0x83, 0xB1, 0x7C, 0x6D, 0x8F, 0xD0, 0x0D, 0x80, 0xC3,
+0xD9, 0x8F, 0xDE, 0x8D, 0x67, 0x9D, 0xFD, 0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x9C, 0xF0, 0xF3, 0xF3,
+0x85, 0xE8, 0x0D, 0x27, 0x38, 0x40, 0x80, 0x00, 0x0B, 0x38, 0xD0, 0xC9, 0x1A, 0x27, 0x1E, 0xF8,
+0x8C, 0xD9, 0x62, 0xB7, 0x18, 0xEC, 0x97, 0xEB, 0xA4, 0x7F, 0x57, 0x67, 0x99, 0xFD, 0x10, 0x1F,
+0xE2, 0x43, 0x7C, 0x9C, 0x5C, 0x96, 0xCF, 0x80, 0x5C, 0x73, 0x82, 0x03, 0x04, 0x08, 0xB0, 0x58,
+0xE3, 0x9C, 0x5B, 0x0F, 0x0F, 0x2E, 0x40, 0x3F, 0x6A, 0xB0, 0x3F, 0x10, 0x1E, 0xA5, 0x1B, 0x47,
+0x66, 0x3F, 0x8A, 0x81, 0x7F, 0xE9, 0x86, 0xF4, 0xEC, 0xAE, 0xED, 0x53, 0x0E, 0xA8, 0xC4, 0x87,
+0xF8, 0x10, 0x1F, 0xA7, 0xD7, 0x9E, 0x60, 0x7B, 0x6D, 0x00, 0x01, 0x02, 0xCC, 0x59, 0x3D, 0xB4,
+0xB6, 0x4E, 0x36, 0xF0, 0x29, 0xAF, 0xFD, 0x08, 0x83, 0x03, 0xFE, 0xF2, 0xBE, 0xBB, 0xFD, 0xBB,
+0x13, 0x1F, 0xE2, 0x43, 0x7C, 0x9C, 0xD3, 0xEF, 0x41, 0xBB, 0xE1, 0x14, 0x07, 0x08, 0x10, 0x60,
+0xD1, 0x6C, 0x86, 0x76, 0xF3, 0xD8, 0x81, 0xCF, 0x71, 0x6B, 0x3F, 0xC2, 0xC8, 0xEC, 0x47, 0x1C,
+0xDC, 0xFD, 0x2A, 0xCD, 0x7E, 0xEC, 0x9D, 0x62, 0x50, 0x25, 0x3E, 0xC4, 0x87, 0xF8, 0x38, 0xBB,
+0xEE, 0x4E, 0x58, 0x75, 0xA7, 0x39, 0x40, 0x80, 0x00, 0x8B, 0xE4, 0x5A, 0x68, 0xEF, 0x9F, 0x68,
+0x3C, 0x58, 0x5E, 0xFB, 0x51, 0xDE, 0xF9, 0x2A, 0x0E, 0x0F, 0xA0, 0xD2, 0x5F, 0xB7, 0xC5, 0x87,
+0xF8, 0x10, 0x1F, 0xE7, 0xF6, 0x7B, 0x90, 0xE5, 0x0B, 0xD1, 0x05, 0x08, 0x20, 0x40, 0x80, 0x05,
+0x72, 0xB0, 0xB5, 0x39, 0xD1, 0x10, 0xF0, 0xB8, 0xB5, 0x1F, 0x43, 0xD7, 0xFF, 0xE8, 0x7F, 0x60,
+0xDA, 0xF9, 0xEA, 0xA4, 0xB3, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x29, 0xDE, 0xB7, 0x9D, 0xB0,
+0x00, 0x01, 0x02, 0x2C, 0xDC, 0xE0, 0xA7, 0x35, 0xF9, 0x85, 0xCA, 0x86, 0x77, 0xBE, 0x2A, 0x6D,
+0xC1, 0x3B, 0xF6, 0x02, 0x85, 0x2F, 0x89, 0x0F, 0xF1, 0x21, 0x3E, 0xCE, 0x2D, 0x3E, 0x92, 0xF6,
+0x76, 0xFA, 0x37, 0x6E, 0x27, 0x2C, 0x40, 0x80, 0x00, 0x0B, 0xA4, 0xBD, 0xB7, 0x71, 0xC7, 0x61,
+0xE0, 0xB1, 0xB3, 0x1F, 0x71, 0xF4, 0x63, 0x92, 0xF4, 0x1F, 0x5E, 0x0F, 0x4E, 0x30, 0xB8, 0x12,
+0x1F, 0xE2, 0x43, 0x7C, 0xCC, 0xE8, 0xEB, 0xB4, 0xEB, 0x4E, 0x74, 0x80, 0x00, 0x01, 0x16, 0x63,
+0xFC, 0x73, 0xEB, 0xE1, 0xC6, 0xC4, 0xEB, 0x3F, 0xC6, 0xCE, 0x7E, 0xC4, 0xEE, 0xE0, 0x7F, 0xE0,
+0xB6, 0x70, 0xF2, 0xB5, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x19, 0x7E, 0xAD, 0x13, 0xCC, 0x72,
+0x02, 0x08, 0x10, 0x60, 0xC6, 0x06, 0xAF, 0x01, 0x32, 0x6E, 0x28, 0x78, 0xE4, 0xEC, 0x47, 0x1C,
+0x8A, 0x93, 0x92, 0x93, 0xCC, 0x7E, 0x88, 0x0F, 0xF1, 0x21, 0x3E, 0x66, 0x2B, 0xDB, 0xD9, 0x88,
+0x1F, 0x7F, 0xFB, 0x86, 0xD3, 0x1D, 0x20, 0x40, 0x80, 0xC5, 0x08, 0x90, 0x83, 0xAD, 0x89, 0xC6,
+0x86, 0xFD, 0xEB, 0x7E, 0xA4, 0xB1, 0x53, 0x16, 0x07, 0x03, 0x20, 0x84, 0xD3, 0xCD, 0x7E, 0x88,
+0x0F, 0xF1, 0x21, 0x3E, 0xE6, 0x10, 0x20, 0xF9, 0x42, 0x74, 0xB3, 0x20, 0x80, 0x00, 0x01, 0x16,
+0x40, 0x7B, 0xF7, 0xFA, 0x91, 0xC3, 0xC1, 0xF2, 0xAE, 0x56, 0xA5, 0xC0, 0xC8, 0x9F, 0x76, 0x35,
+0x34, 0x66, 0x1C, 0xB8, 0xEE, 0x47, 0xDA, 0xF5, 0x6A, 0x92, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4,
+0xC7, 0x9C, 0xBE, 0xAE, 0x00, 0x01, 0x04, 0x08, 0xB0, 0x30, 0x01, 0xD2, 0xAC, 0x1F, 0xF9, 0xBE,
+0x5A, 0x29, 0x3C, 0x42, 0xED, 0xF0, 0x69, 0x57, 0x31, 0x8C, 0xAE, 0x07, 0x29, 0x8F, 0x25, 0x77,
+0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x0B, 0x13, 0x1F, 0xF9, 0xBF, 0xF3, 0xED, 0xF4, 0xDA, 0x4E, 0x58,
+0xC0, 0x99, 0xAD, 0x3B, 0x04, 0xC0, 0x99, 0x65, 0xCD, 0xCD, 0xB1, 0x43, 0xC2, 0x58, 0x1E, 0x1E,
+0xD6, 0xFA, 0xBB, 0x5D, 0xC5, 0xE1, 0xEB, 0x7C, 0xC4, 0x31, 0xB3, 0x1F, 0x6D, 0xF1, 0x21, 0x3E,
+0xC4, 0xC7, 0xC2, 0xC4, 0x47, 0xFF, 0x31, 0xB4, 0xCD, 0x80, 0x00, 0x67, 0x66, 0x06, 0x04, 0x38,
+0xDB, 0x78, 0xE4, 0xD6, 0xC3, 0xF5, 0x23, 0x77, 0xC0, 0xAA, 0x1D, 0x86, 0xC6, 0xF0, 0xCC, 0x47,
+0xF1, 0xB4, 0xAC, 0x91, 0x31, 0xD5, 0x24, 0xB3, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x73, 0xFA,
+0x8F, 0x0D, 0x7B, 0x02, 0x04, 0x10, 0x20, 0xC0, 0xB9, 0xEB, 0x04, 0xC8, 0xEE, 0xF8, 0x61, 0x61,
+0x79, 0x06, 0xA4, 0x34, 0xF3, 0x71, 0xB8, 0x36, 0xA4, 0x76, 0x18, 0x06, 0xC5, 0xE7, 0xEC, 0xDE,
+0x61, 0xF6, 0x43, 0x7C, 0x88, 0x0F, 0xF1, 0x71, 0x8E, 0x01, 0xB2, 0x6F, 0x17, 0x2C, 0x40, 0x80,
+0x00, 0xE7, 0xAE, 0x11, 0xDA, 0xCD, 0xB1, 0xF1, 0x31, 0xB2, 0x08, 0x7D, 0x78, 0xF6, 0xA3, 0x3C,
+0xB6, 0xCA, 0x77, 0xC5, 0x0A, 0xC7, 0xEF, 0x7C, 0x25, 0x3E, 0xC4, 0x87, 0xF8, 0x38, 0xE7, 0xC7,
+0xD3, 0x0C, 0xF1, 0xE3, 0x6F, 0x6F, 0x38, 0xED, 0x01, 0x02, 0x04, 0x38, 0x4F, 0xD7, 0x8E, 0xBA,
+0x06, 0xC8, 0xE0, 0x95, 0xCE, 0x0F, 0x83, 0x23, 0x96, 0x66, 0x3F, 0x06, 0xC6, 0x58, 0xBB, 0xF1,
+0xE8, 0xB1, 0xA5, 0xF8, 0x10, 0x1F, 0xE2, 0xE3, 0xFC, 0x65, 0x7B, 0xE9, 0x75, 0xDD, 0x69, 0x0F,
+0x10, 0x20, 0xC0, 0xF9, 0x69, 0xBE, 0x50, 0x1F, 0x19, 0x1A, 0xC6, 0xC3, 0xA7, 0x5D, 0x0D, 0x2C,
+0x30, 0xEF, 0x7F, 0x40, 0x6D, 0x74, 0xFD, 0x47, 0x9A, 0xFD, 0x38, 0x6A, 0xED, 0x87, 0xF8, 0x10,
+0x1F, 0xE2, 0x63, 0x11, 0x1E, 0x94, 0x00, 0x01, 0x04, 0x08, 0xB0, 0x00, 0xB2, 0xD6, 0xE6, 0x51,
+0x03, 0xA8, 0xE1, 0x2D, 0x76, 0x8B, 0x20, 0x08, 0x71, 0xCC, 0x38, 0xEB, 0xA8, 0xD9, 0x0F, 0xF1,
+0x21, 0x3E, 0xC4, 0xC7, 0x62, 0xC4, 0x47, 0xFE, 0x47, 0xBB, 0xF3, 0xD2, 0xBA, 0xE1, 0xC4, 0x07,
+0x08, 0x10, 0xE0, 0x7C, 0x86, 0x24, 0xB7, 0x1E, 0xDE, 0xE8, 0x0C, 0x46, 0x36, 0x06, 0x86, 0x87,
+0xBD, 0x8B, 0x0C, 0x0E, 0xAC, 0xF7, 0x88, 0x83, 0xE3, 0xC7, 0x89, 0x67, 0x3F, 0xC4, 0x87, 0xF8,
+0x10, 0x1F, 0x8B, 0x13, 0x1F, 0xFD, 0x7F, 0xAF, 0x7B, 0x75, 0x67, 0x3F, 0x40, 0x80, 0x00, 0xE7,
+0x65, 0x33, 0xB4, 0x76, 0x46, 0x07, 0x50, 0xBD, 0x0B, 0x0C, 0x8E, 0xDC, 0x7C, 0xD4, 0xEC, 0xC7,
+0xD6, 0x98, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0xE2, 0xC5, 0x47, 0x7E, 0x53, 0x4B, 0x80,
+0x00, 0x02, 0x04, 0x38, 0x37, 0xF5, 0xB4, 0x00, 0x3D, 0x96, 0x06, 0x50, 0x83, 0x33, 0x21, 0xA1,
+0xB4, 0xEF, 0xEE, 0xE1, 0x70, 0x66, 0xE0, 0xA2, 0x83, 0x69, 0xCB, 0xDD, 0xBD, 0x28, 0x3E, 0xC4,
+0x87, 0xF8, 0xA8, 0x42, 0x7C, 0xE4, 0x37, 0x1F, 0xD8, 0x09, 0x0B, 0x10, 0x20, 0xC0, 0xB9, 0x8D,
+0x4F, 0xEA, 0xA1, 0xB5, 0x5B, 0x1A, 0xFD, 0x87, 0xFE, 0xEC, 0x47, 0x1C, 0x09, 0x8E, 0xDA, 0xE8,
+0x70, 0x26, 0xDD, 0xB0, 0x2D, 0x3E, 0xC4, 0x87, 0xF8, 0xA8, 0x4C, 0x7C, 0xE4, 0xFF, 0xD1, 0x60,
+0x3B, 0xBD, 0x76, 0x3D, 0x10, 0x40, 0x80, 0x00, 0xE7, 0xA0, 0xBD, 0x77, 0x63, 0x60, 0xB7, 0xAB,
+0xF2, 0xD8, 0x65, 0xCC, 0xDA, 0x8F, 0x81, 0xEB, 0x81, 0x24, 0x69, 0xED, 0xC7, 0x5E, 0x14, 0x1F,
+0xE2, 0x43, 0x7C, 0x54, 0x25, 0x3E, 0xF2, 0x7F, 0xB7, 0xF9, 0xB6, 0xDB, 0xAE, 0x88, 0x0E, 0x08,
+0x10, 0xE0, 0x1C, 0x64, 0xCD, 0xFA, 0x60, 0x1D, 0x0C, 0xCE, 0x7E, 0x1C, 0x6E, 0xC1, 0x5B, 0x1B,
+0x7F, 0x81, 0xC2, 0x2D, 0xF1, 0x21, 0x3E, 0xC4, 0x47, 0xA5, 0xE2, 0x23, 0xFF, 0x90, 0x83, 0xF4,
+0xFA, 0xBA, 0x13, 0x20, 0x20, 0x40, 0x80, 0xF9, 0x0F, 0x55, 0x0E, 0xB6, 0xEB, 0x03, 0x51, 0x51,
+0x8C, 0x5F, 0xE2, 0x98, 0xB1, 0xD5, 0xF0, 0x3A, 0xF3, 0x34, 0x86, 0xD9, 0x8F, 0xE2, 0x43, 0x7C,
+0x88, 0x8F, 0x2A, 0xC5, 0x47, 0xA1, 0x7D, 0xBB, 0xEE, 0x0C, 0x08, 0x08, 0x10, 0x60, 0xBE, 0x43,
+0x95, 0x8F, 0x3E, 0xB4, 0x19, 0xB2, 0xFD, 0xA1, 0xC0, 0x98, 0x60, 0xF6, 0xA3, 0x78, 0x5A, 0xD6,
+0xB6, 0xF8, 0x10, 0x1F, 0xE2, 0xA3, 0x92, 0xF1, 0x91, 0x7F, 0x78, 0xDB, 0x53, 0xB0, 0x00, 0x01,
+0x02, 0xCC, 0x7D, 0x0C, 0x95, 0xEF, 0x80, 0x75, 0xEA, 0xD9, 0x8F, 0x83, 0x28, 0x3E, 0xC4, 0x87,
+0xF8, 0xA8, 0x62, 0x7C, 0xE4, 0x9F, 0x92, 0xEF, 0x84, 0x25, 0x42, 0x00, 0x01, 0x02, 0xCC, 0xD5,
+0xE6, 0xE1, 0x0E, 0x58, 0x27, 0x9D, 0xFD, 0xC8, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x55, 0x8D, 0x8F,
+0xA4, 0x9D, 0xFF, 0xDB, 0xAF, 0x3B, 0x0D, 0x02, 0x02, 0x04, 0x98, 0x9F, 0xEC, 0xE0, 0x5A, 0xC8,
+0xDA, 0xA7, 0x98, 0xFD, 0xE8, 0xFC, 0xAD, 0x29, 0x3E, 0xC4, 0x87, 0xF8, 0xA8, 0x6C, 0x7C, 0xE4,
+0x9F, 0x7A, 0xD0, 0xFD, 0x8F, 0x10, 0x00, 0x02, 0x04, 0x98, 0x9B, 0x56, 0x79, 0x01, 0x7A, 0x6D,
+0x30, 0x38, 0xCA, 0xA1, 0x50, 0xBA, 0x2D, 0x1F, 0xEF, 0xBC, 0x94, 0x89, 0x0F, 0xF1, 0x21, 0x3E,
+0xAA, 0x1C, 0x1F, 0xF9, 0x7F, 0x80, 0xD8, 0x4B, 0x57, 0x44, 0xB7, 0x13, 0x16, 0x20, 0x40, 0x80,
+0x79, 0x8E, 0x5F, 0xB2, 0xC6, 0xE8, 0x53, 0xAE, 0x86, 0xAE, 0xF3, 0x11, 0x86, 0xAE, 0x7A, 0xBE,
+0x9B, 0x75, 0xAF, 0x7C, 0x2E, 0x3E, 0xC4, 0x87, 0xF8, 0xA8, 0x6E, 0x7C, 0xF4, 0x23, 0x64, 0xDF,
+0xC5, 0x08, 0x01, 0x01, 0x02, 0xCC, 0x47, 0xF6, 0x7B, 0x0F, 0xD5, 0x43, 0xBB, 0x39, 0x76, 0xED,
+0xC7, 0xC8, 0x6D, 0xFD, 0x4F, 0xEA, 0xDC, 0xB2, 0x13, 0xC5, 0x87, 0xF8, 0x10, 0x1F, 0xCB, 0x10,
+0x1F, 0xDD, 0x7F, 0xD4, 0x0D, 0x67, 0x43, 0x40, 0x80, 0x00, 0xF3, 0x1A, 0xC3, 0xD4, 0x63, 0xEB,
+0x76, 0x3F, 0x16, 0xC2, 0xB8, 0xD9, 0x8F, 0xD2, 0xAC, 0x48, 0xFE, 0x2A, 0x5D, 0xF1, 0xBC, 0x2D,
+0x3E, 0xC4, 0x87, 0xF8, 0x58, 0x8E, 0xF8, 0x08, 0xF9, 0xD3, 0xB0, 0xE2, 0xC7, 0xDF, 0x5E, 0x77,
+0x42, 0x04, 0x04, 0x08, 0x30, 0x8F, 0x61, 0xCC, 0x66, 0x9A, 0x01, 0x19, 0x9E, 0xF9, 0x28, 0x16,
+0x9C, 0x0F, 0x8C, 0xBD, 0xD2, 0x5F, 0xD2, 0xB2, 0x8F, 0xA1, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4,
+0x47, 0xA8, 0xF6, 0xF1, 0xB7, 0x13, 0x16, 0x20, 0x40, 0x80, 0x39, 0xBA, 0x16, 0xDB, 0x07, 0x03,
+0x33, 0x1F, 0xFD, 0xD9, 0x8F, 0x58, 0x2B, 0x05, 0x44, 0x6F, 0xD0, 0xB3, 0x3B, 0x38, 0xFB, 0x21,
+0x3E, 0xC4, 0x87, 0xF8, 0x08, 0xD5, 0x3F, 0xFE, 0xDD, 0x9D, 0xB0, 0x1A, 0x4E, 0x87, 0x80, 0x00,
+0x01, 0x66, 0xEF, 0x60, 0x6B, 0x33, 0x94, 0x9F, 0x72, 0x55, 0x9E, 0xFD, 0x08, 0xA5, 0xA7, 0x5D,
+0xA5, 0x3F, 0x87, 0x66, 0x3F, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x61, 0x39, 0x8E, 0x7F, 0xDA, 0x09,
+0x2B, 0x84, 0x6B, 0x4E, 0x88, 0x80, 0x00, 0x01, 0x66, 0x2F, 0x3B, 0xA8, 0x17, 0x63, 0x9B, 0x7E,
+0x6B, 0x14, 0x31, 0xD1, 0x1B, 0x88, 0x1D, 0xEE, 0x7C, 0x75, 0x78, 0x21, 0x10, 0xF1, 0x21, 0x3E,
+0xC4, 0x47, 0x58, 0xAE, 0xE3, 0x9F, 0xED, 0xD7, 0x9D, 0x10, 0x01, 0x01, 0x02, 0xCC, 0x5E, 0x7B,
+0xBF, 0x1E, 0xCB, 0xD7, 0xF6, 0x08, 0xDD, 0x98, 0x18, 0x78, 0xDA, 0x55, 0x3E, 0x38, 0x09, 0xFD,
+0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0x47, 0x58, 0xBE, 0xE3, 0x1F, 0x5B, 0x0D, 0x27, 0x44, 0x40,
+0x80, 0x00, 0xB3, 0x6D, 0x8F, 0xDF, 0x79, 0xB8, 0x11, 0xD3, 0x16, 0xBC, 0x61, 0x30, 0x1C, 0x42,
+0xE9, 0x69, 0x57, 0xFD, 0xF1, 0xD8, 0x76, 0x1C, 0xB9, 0x3A, 0xBA, 0xF8, 0x10, 0x1F, 0xE2, 0x63,
+0x89, 0x8E, 0x7F, 0xB6, 0x93, 0x76, 0xC2, 0x72, 0x3D, 0x10, 0x40, 0x80, 0x00, 0x33, 0x95, 0x5F,
+0x03, 0x64, 0x70, 0xF6, 0x23, 0xE6, 0x33, 0x1F, 0x03, 0x63, 0xB1, 0xB4, 0xE8, 0x7C, 0x37, 0x8A,
+0x0F, 0xF1, 0x21, 0x3E, 0x96, 0x35, 0x3E, 0xF2, 0x00, 0xC9, 0xFF, 0x63, 0xC4, 0xA6, 0xD3, 0x22,
+0x20, 0x40, 0x80, 0x59, 0x8E, 0x6F, 0xEA, 0xF1, 0x60, 0xAB, 0x14, 0x0F, 0x61, 0xE4, 0xCA, 0xE7,
+0xB9, 0x6D, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x52, 0xC7, 0x47, 0xFE, 0x25, 0x0F, 0x04, 0x08, 0x20,
+0x40, 0x80, 0x19, 0x8F, 0x37, 0xDA, 0xBB, 0xD7, 0x43, 0x39, 0x3A, 0xCA, 0x17, 0x21, 0x2C, 0xB4,
+0x3B, 0x7F, 0xDF, 0x8D, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x65, 0x3F, 0xFE, 0xED, 0xED, 0xF4, 0xDA,
+0x4E, 0x58, 0x80, 0x00, 0x01, 0x66, 0xA8, 0xD5, 0xAC, 0x1F, 0xEE, 0x7C, 0x15, 0x07, 0xC6, 0x3F,
+0xFD, 0xB8, 0xD8, 0x16, 0x1F, 0xE2, 0x43, 0x7C, 0xAC, 0xCC, 0xF1, 0xCF, 0xF6, 0xCD, 0x80, 0x00,
+0x02, 0x04, 0x98, 0xE1, 0x50, 0x27, 0x6B, 0x6E, 0x1E, 0x5E, 0x00, 0xA4, 0x56, 0xDA, 0x82, 0xB7,
+0xF7, 0xFE, 0xF4, 0x8C, 0x8C, 0xDD, 0x28, 0x3E, 0xC4, 0x87, 0xF8, 0x58, 0x95, 0xE3, 0x1F, 0x5B,
+0x02, 0x04, 0x10, 0x20, 0xC0, 0x6C, 0xB4, 0xFE, 0xC5, 0xC3, 0xF5, 0xD0, 0xDE, 0x3F, 0x5C, 0x70,
+0x1E, 0xC7, 0x8C, 0x83, 0xB6, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x2B, 0x75, 0xFC, 0xB3, 0xBD, 0x0D,
+0x3B, 0x61, 0x01, 0x02, 0x04, 0x98, 0xD1, 0x70, 0x27, 0xD6, 0xE3, 0xC1, 0xCE, 0xC0, 0xF0, 0x27,
+0x96, 0x87, 0x42, 0x69, 0x43, 0x9C, 0x66, 0x14, 0x1F, 0xE2, 0x43, 0x7C, 0xAC, 0xD2, 0xF1, 0xB7,
+0x10, 0x1D, 0x10, 0x20, 0xC0, 0x0C, 0xC7, 0x3C, 0x8D, 0x98, 0x15, 0x5B, 0xF0, 0x76, 0x03, 0xA3,
+0x56, 0x7E, 0xF7, 0xB6, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0xE5, 0x8E, 0x7F, 0xB6, 0x97, 0x5E, 0xD7,
+0x9D, 0x20, 0x01, 0x01, 0x02, 0xCC, 0x62, 0xD8, 0x73, 0x2D, 0x5D, 0x03, 0x24, 0x14, 0x31, 0x11,
+0x4A, 0x5B, 0xF1, 0xA6, 0x9B, 0xF7, 0xA3, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0xD5, 0x8E, 0xBF, 0x00,
+0x01, 0x04, 0x08, 0x30, 0x33, 0xFB, 0x2F, 0xD4, 0x87, 0xAF, 0xED, 0xD1, 0x7F, 0x0A, 0xD6, 0xED,
+0x4C, 0x7C, 0x88, 0x0F, 0xF1, 0xB1, 0x8A, 0xC7, 0x3F, 0xA6, 0x7D, 0xB7, 0x5B, 0x37, 0x9C, 0x20,
+0x01, 0x01, 0x02, 0x4C, 0x5F, 0x36, 0xBA, 0xDB, 0x4D, 0x2D, 0x8D, 0x89, 0xD2, 0x15, 0xCF, 0x0F,
+0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x2B, 0x7B, 0xFC, 0xB3, 0xBD, 0xBA, 0x13, 0x24, 0x20, 0x40, 0x80,
+0xA9, 0x6A, 0x7E, 0xE4, 0xA1, 0x8D, 0x4E, 0x80, 0x6C, 0xE4, 0x4F, 0xBF, 0x0A, 0x83, 0x8B, 0xCF,
+0xB3, 0xDB, 0x41, 0x7C, 0x88, 0x0F, 0xF1, 0xB1, 0xCA, 0xC7, 0x3F, 0xDB, 0x17, 0x20, 0x80, 0x00,
+0x01, 0xA6, 0xAC, 0x16, 0x36, 0x63, 0x6B, 0xA7, 0x5F, 0x1A, 0xB5, 0x62, 0x4C, 0xB4, 0x1B, 0xBA,
+0x57, 0x3E, 0x17, 0x1F, 0xE2, 0x43, 0x7C, 0xAC, 0xEE, 0xF1, 0x8F, 0x07, 0x21, 0x7E, 0xFC, 0xED,
+0x0D, 0x27, 0x4A, 0x40, 0x80, 0x00, 0xD3, 0x54, 0x4F, 0x0B, 0xD0, 0x63, 0xAF, 0x46, 0x8A, 0x3F,
+0xB3, 0xDB, 0x51, 0x7C, 0x88, 0x0F, 0xF1, 0xB1, 0xEA, 0xC7, 0xDF, 0x42, 0x74, 0x40, 0x80, 0x00,
+0x33, 0x18, 0x9F, 0xD5, 0x63, 0x6B, 0xB7, 0x3B, 0x01, 0xD2, 0x1B, 0x18, 0xC5, 0xAD, 0xCE, 0x5B,
+0x2D, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0xCA, 0x1F, 0xFF, 0xAC, 0x29, 0x40, 0x00, 0x01, 0x02, 0x4C,
+0x59, 0x7B, 0xAF, 0xBF, 0xCB, 0x4D, 0xAD, 0xB7, 0xDB, 0x55, 0x9A, 0xFD, 0x10, 0x1F, 0xE2, 0x43,
+0x7C, 0x38, 0xFE, 0xF9, 0xC5, 0x08, 0xED, 0x84, 0x05, 0x08, 0x10, 0x60, 0xBA, 0x01, 0xD2, 0xAC,
+0x97, 0xC7, 0x6C, 0xD9, 0x56, 0xE7, 0xCF, 0xAC, 0x37, 0x56, 0x12, 0x1F, 0xE2, 0x43, 0x7C, 0x38,
+0xFE, 0xD9, 0xEE, 0x86, 0x13, 0x25, 0x30, 0x89, 0x75, 0x87, 0x00, 0x98, 0x48, 0x6B, 0xA7, 0x17,
+0x20, 0xBD, 0xD9, 0x8F, 0xAD, 0xD8, 0x9F, 0xF9, 0x08, 0xE2, 0x43, 0x7C, 0x88, 0x0F, 0xC7, 0x3F,
+0xB6, 0x37, 0x9D, 0x28, 0x81, 0x49, 0x98, 0x01, 0x01, 0xEE, 0xA8, 0xF9, 0xDB, 0x0F, 0x6D, 0x86,
+0x6C, 0xBF, 0xD3, 0x1E, 0xB5, 0xFC, 0xEF, 0xF9, 0xEC, 0x47, 0xBB, 0x74, 0x15, 0x74, 0xF1, 0x21,
+0x3E, 0xC4, 0x87, 0xE3, 0xDF, 0xDD, 0x09, 0x4B, 0x84, 0x00, 0x02, 0x04, 0x98, 0x8A, 0x7C, 0x07,
+0xAC, 0x7C, 0x8C, 0x94, 0xC2, 0xE3, 0x76, 0x31, 0x58, 0xAA, 0x85, 0xDA, 0xC5, 0xF5, 0x70, 0xF5,
+0xAD, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x95, 0x3F, 0xFE, 0xED, 0xED, 0xF4, 0xBD, 0xD4, 0x9D, 0x2E,
+0x01, 0x01, 0x02, 0x4C, 0xC3, 0x66, 0x68, 0xEF, 0x75, 0xC7, 0x18, 0x2F, 0xC5, 0x7C, 0xED, 0x47,
+0xFE, 0xD4, 0xAB, 0xF5, 0x4E, 0x7C, 0xA4, 0x99, 0x8F, 0x97, 0x8B, 0x0F, 0xF1, 0x21, 0x3E, 0x56,
+0xFE, 0xF8, 0x77, 0x77, 0xC2, 0x32, 0x03, 0x02, 0xDC, 0x91, 0x35, 0x20, 0xC0, 0x1D, 0xD5, 0xB2,
+0x83, 0x6B, 0x31, 0x3D, 0xE7, 0xAA, 0xF3, 0xBF, 0x6C, 0xBB, 0x3B, 0x64, 0x4A, 0x33, 0x1F, 0xF7,
+0xBC, 0x59, 0x7C, 0x88, 0x0F, 0xF1, 0xE1, 0xF8, 0xF7, 0xBE, 0x97, 0x98, 0x07, 0xC8, 0x75, 0x67,
+0x4C, 0x40, 0x80, 0x00, 0x67, 0xD7, 0xDA, 0xAE, 0xA7, 0xB5, 0xE7, 0x69, 0xF6, 0x23, 0x8D, 0x33,
+0x52, 0x7C, 0xDC, 0xFD, 0x26, 0xF1, 0x21, 0x3E, 0xC4, 0x87, 0xE3, 0x3F, 0xF4, 0xBD, 0xB4, 0x8B,
+0xCD, 0x2A, 0x00, 0x04, 0x08, 0x70, 0x06, 0xB5, 0xD0, 0x6E, 0x84, 0x56, 0xCC, 0x17, 0x9F, 0x87,
+0x4B, 0x9D, 0xF8, 0x78, 0xE3, 0xEB, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x8E, 0xFF, 0x98, 0xEF, 0xC5,
+0x4E, 0x58, 0xC0, 0x9D, 0x59, 0x03, 0x02, 0x1C, 0xAB, 0xFD, 0x3B, 0xAF, 0xAB, 0xA7, 0xA7, 0x56,
+0xB4, 0xBE, 0x22, 0x3E, 0xC4, 0x87, 0xF8, 0x70, 0xFC, 0xEF, 0xF0, 0xBD, 0x64, 0x7B, 0x21, 0x7E,
+0xFC, 0xAF, 0xD4, 0x9D, 0x39, 0x01, 0x01, 0x02, 0x9C, 0x45, 0x3D, 0xBB, 0x7D, 0x3B, 0xC4, 0xAC,
+0x13, 0x1F, 0x6F, 0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x38, 0xFE, 0xC7, 0x7C, 0x2F, 0xED, 0xDD, 0xFC,
+0x9C, 0xE1, 0xB4, 0x09, 0x08, 0x10, 0xE0, 0xD4, 0x0E, 0xF6, 0xB3, 0xCD, 0xD6, 0xED, 0x2C, 0xDC,
+0xD5, 0x89, 0x8F, 0x35, 0xF1, 0x21, 0x3E, 0xC4, 0x87, 0xE3, 0x7F, 0xCC, 0xF7, 0x12, 0xDB, 0x07,
+0x61, 0xFF, 0xF6, 0x41, 0xC3, 0x99, 0x13, 0x38, 0x8E, 0x35, 0x20, 0xC0, 0xB1, 0x6E, 0x7F, 0x39,
+0xBB, 0xB6, 0x7E, 0xED, 0x7A, 0xB8, 0x78, 0xE5, 0x6A, 0x58, 0x13, 0x1F, 0xE2, 0x43, 0x7C, 0x88,
+0x8F, 0x23, 0xEC, 0xBE, 0x90, 0x85, 0xBD, 0x17, 0xB7, 0x42, 0xBC, 0xBC, 0x77, 0xCD, 0x99, 0x13,
+0x10, 0x20, 0xC0, 0xA9, 0xAD, 0x7D, 0xE3, 0xD7, 0xBD, 0x3A, 0x76, 0xCE, 0x14, 0xB7, 0xFF, 0xF4,
+0xD9, 0xB0, 0xBE, 0xF6, 0x5C, 0xB8, 0xE7, 0x81, 0x0B, 0x61, 0xED, 0xD4, 0x67, 0x0E, 0xF1, 0x21,
+0x3E, 0xC4, 0xC7, 0xB2, 0xC5, 0xC7, 0xFE, 0x56, 0x0C, 0xBB, 0x5F, 0xCD, 0x42, 0xD6, 0xEA, 0xBD,
+0x3F, 0xDB, 0xDD, 0x70, 0xE6, 0x04, 0x8E, 0x1D, 0x5B, 0x38, 0x04, 0xC0, 0x71, 0xFE, 0xCD, 0xAD,
+0x7B, 0xDF, 0x71, 0xB0, 0xBD, 0xFB, 0xFE, 0xB8, 0xF7, 0xEC, 0x56, 0x6B, 0x2F, 0x86, 0x17, 0xFF,
+0xB4, 0x15, 0xB6, 0x9F, 0xCB, 0xF2, 0x8B, 0x11, 0x8A, 0x0F, 0xF1, 0x21, 0x3E, 0x56, 0x37, 0x3E,
+0xD2, 0xF9, 0xE0, 0xF6, 0x17, 0xDB, 0x61, 0xFB, 0xD9, 0x76, 0x11, 0x1F, 0x2F, 0x74, 0x5E, 0xDE,
+0xF3, 0xE4, 0x2F, 0xFC, 0x7F, 0x3F, 0xE4, 0xCC, 0x09, 0x1C, 0xA7, 0xE6, 0x10, 0x00, 0x93, 0xF8,
+0xF8, 0x7B, 0x36, 0x5F, 0xF9, 0x75, 0xAF, 0x6A, 0xBF, 0xFF, 0xC2, 0xC5, 0xF8, 0x8E, 0xFC, 0xE4,
+0xB1, 0x16, 0xC2, 0x95, 0x7B, 0xD7, 0xC2, 0x95, 0x8D, 0x49, 0xFE, 0x3B, 0x86, 0xF8, 0x10, 0x1F,
+0xE2, 0x63, 0x59, 0xE2, 0x23, 0x6B, 0x85, 0xB0, 0xF3, 0x95, 0x76, 0x68, 0xEE, 0xC4, 0xF2, 0x6D,
+0xFF, 0x70, 0x6D, 0x3D, 0xFC, 0xD2, 0xD7, 0xFC, 0xC8, 0xA7, 0x5E, 0x70, 0xB6, 0x04, 0x04, 0x08,
+0x30, 0x55, 0x9F, 0xFC, 0x6F, 0xAF, 0x5F, 0x7F, 0xF9, 0x9F, 0x6B, 0x7F, 0xB0, 0x33, 0xD8, 0xF8,
+0xEE, 0xF4, 0xF7, 0xB5, 0xF5, 0x5A, 0xB8, 0xAB, 0x13, 0x21, 0x97, 0xAE, 0xD6, 0xC4, 0x87, 0xF8,
+0x10, 0x1F, 0x4B, 0x1C, 0x1F, 0x69, 0xD6, 0x33, 0x3D, 0xD5, 0x6A, 0xEF, 0xA5, 0xC3, 0xE9, 0xCF,
+0xAC, 0x1D, 0x7E, 0x77, 0xED, 0x42, 0xF8, 0x9B, 0x9D, 0xF0, 0xF8, 0x8C, 0xB3, 0x23, 0x20, 0x40,
+0x80, 0x99, 0xFA, 0xDC, 0x07, 0xFF, 0xE2, 0x0F, 0xDE, 0x73, 0x7F, 0xF6, 0xAB, 0xB5, 0xB5, 0xF0,
+0x8D, 0xE9, 0xEF, 0xEB, 0x57, 0xBA, 0x21, 0x92, 0xFE, 0x14, 0x1F, 0xE2, 0x43, 0x7C, 0x2C, 0x57,
+0x7C, 0x74, 0x17, 0x98, 0x0F, 0x3C, 0xF5, 0xF2, 0x0F, 0x3B, 0x2F, 0x3F, 0xD3, 0x09, 0x8F, 0x8F,
+0x39, 0x1B, 0x02, 0x02, 0x04, 0x98, 0x9B, 0xFF, 0xE3, 0xCD, 0xDF, 0xB5, 0xFE, 0x9D, 0x3F, 0xBA,
+0xF7, 0x5F, 0x5C, 0xBE, 0x1A, 0xDF, 0xDB, 0x09, 0x91, 0xAB, 0xE9, 0xB6, 0x8B, 0x77, 0xD7, 0xC2,
+0xDD, 0xF7, 0xAF, 0x9D, 0x61, 0xA1, 0xBA, 0xF8, 0x30, 0xF8, 0x15, 0x1F, 0x8B, 0xF2, 0xBD, 0x0C,
+0x2F, 0x30, 0xEF, 0x04, 0xC8, 0x9F, 0x76, 0xFE, 0xAD, 0xFF, 0xED, 0x4E, 0x78, 0x7C, 0xD8, 0x19,
+0x10, 0x10, 0x20, 0xC0, 0xB9, 0xF9, 0xDC, 0x07, 0xFF, 0xE2, 0x03, 0x97, 0xEE, 0x8A, 0x7F, 0xEB,
+0xE2, 0x5D, 0xF1, 0xC7, 0xBB, 0x21, 0x12, 0xF3, 0xD9, 0x90, 0xCB, 0xF7, 0xAE, 0xE5, 0x6B, 0x45,
+0xC4, 0x87, 0xC1, 0xAF, 0xF8, 0xA8, 0x56, 0x7C, 0xA4, 0x05, 0xE6, 0x29, 0x3C, 0x0E, 0xF6, 0xFA,
+0xDF, 0x57, 0x5A, 0xDB, 0xF1, 0xF7, 0x3B, 0x2F, 0x1F, 0xB0, 0xCE, 0x03, 0x10, 0x20, 0xC0, 0x22,
+0x85, 0xC8, 0x83, 0x57, 0x5E, 0x96, 0xFD, 0xF2, 0xFA, 0xE5, 0xF8, 0xF6, 0xFC, 0x04, 0xD3, 0x89,
+0x8F, 0x22, 0x44, 0xC4, 0x87, 0xC1, 0xAF, 0xF8, 0x58, 0x7C, 0x69, 0xA6, 0x63, 0x78, 0x81, 0x79,
+0xC7, 0x87, 0x5F, 0xFC, 0x42, 0xFB, 0xE7, 0xFF, 0xFC, 0xCF, 0x7E, 0xFA, 0x39, 0x67, 0x39, 0x40,
+0x80, 0x00, 0x0B, 0xE9, 0x8B, 0xBF, 0xF5, 0xDA, 0xB7, 0xAE, 0x5F, 0x8C, 0xEF, 0xBD, 0x70, 0x29,
+0x7C, 0x67, 0xFA, 0x7B, 0x5A, 0xA8, 0x9E, 0x9E, 0x96, 0x95, 0x9E, 0x9E, 0x25, 0x3E, 0x0C, 0x7E,
+0xC5, 0xC7, 0x02, 0x7E, 0x17, 0xF9, 0x02, 0xF3, 0xF6, 0xC0, 0x02, 0xF3, 0x8E, 0x8F, 0xED, 0xBD,
+0x98, 0xFD, 0xC4, 0x2B, 0xFF, 0xFA, 0x9F, 0x7C, 0xCA, 0x59, 0x0D, 0x10, 0x20, 0xC0, 0xC2, 0xFB,
+0x17, 0x6F, 0xFC, 0x8E, 0xF5, 0xEF, 0xFA, 0xB1, 0xE6, 0x8F, 0x5C, 0xBE, 0x27, 0xBE, 0xEF, 0xF8,
+0x85, 0xEA, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0xF3, 0x94, 0xA2, 0x23, 0xC5, 0x47, 0xB1, 0xC0, 0x3C,
+0xB6, 0xC3, 0xBF, 0xAD, 0x75, 0x77, 0xB6, 0xFA, 0x98, 0x33, 0x19, 0x20, 0x40, 0x80, 0x2A, 0x86,
+0xC8, 0x95, 0xEF, 0x7D, 0xD7, 0xFE, 0xE3, 0x6B, 0xEB, 0xE1, 0xA7, 0x8B, 0x85, 0xEA, 0x97, 0xAE,
+0xAE, 0xE5, 0x21, 0x72, 0xC7, 0x85, 0xEA, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x99, 0x49, 0x4F, 0xB3,
+0x4A, 0x4F, 0xB7, 0xB2, 0xC0, 0x1C, 0x10, 0x20, 0xC0, 0x52, 0xFA, 0xF7, 0x7F, 0xEF, 0xDB, 0xBF,
+0xFE, 0xBE, 0xFF, 0x20, 0xFE, 0xF2, 0xC5, 0x2B, 0xF1, 0xC7, 0xF3, 0x93, 0x4F, 0xEF, 0x42, 0x86,
+0x47, 0x2E, 0x54, 0x17, 0x1F, 0xE2, 0x43, 0x7C, 0xCC, 0xC4, 0xE0, 0x02, 0xF3, 0xFE, 0x15, 0xCC,
+0x2D, 0x30, 0x07, 0x04, 0x08, 0xB0, 0x9C, 0xFE, 0xE4, 0x03, 0xDF, 0xFE, 0x9A, 0xAB, 0x5F, 0x97,
+0x7D, 0x60, 0xFD, 0x52, 0x78, 0x53, 0x11, 0x22, 0x77, 0xDF, 0x7F, 0x61, 0xF0, 0x42, 0x86, 0xE2,
+0x43, 0x7C, 0x88, 0x8F, 0xA9, 0x4B, 0x57, 0x30, 0x4F, 0xE1, 0xB1, 0xBF, 0x95, 0x95, 0xBF, 0x17,
+0x0B, 0xCC, 0x01, 0x01, 0x02, 0xAC, 0x86, 0x2F, 0xFC, 0xC6, 0x6B, 0x7F, 0xE0, 0xF2, 0xD5, 0xF8,
+0xFE, 0xB5, 0xF5, 0xF0, 0x60, 0xFA, 0x7B, 0x5A, 0xA8, 0x7E, 0xCF, 0x03, 0x6B, 0x61, 0xFD, 0x72,
+0xD5, 0x06, 0x8E, 0xE2, 0x43, 0x7C, 0x2C, 0xF8, 0xA1, 0xCC, 0x8A, 0x75, 0x1E, 0xE5, 0x05, 0xE6,
+0xD1, 0x02, 0x73, 0x40, 0x80, 0x00, 0xAB, 0x27, 0x2D, 0x54, 0xFF, 0xEE, 0x77, 0x36, 0xDF, 0x75,
+0xE1, 0x62, 0x7C, 0xF7, 0xDA, 0x85, 0xF0, 0xF5, 0xB1, 0x33, 0xE8, 0xBC, 0x78, 0xA5, 0xBB, 0x63,
+0xD6, 0x85, 0x4B, 0xD3, 0x3C, 0x3D, 0x89, 0x0F, 0xF1, 0xB1, 0x9A, 0xC7, 0xBF, 0x08, 0x8F, 0xD1,
+0x05, 0xE6, 0x9F, 0xFC, 0x98, 0x33, 0x10, 0x20, 0x40, 0x80, 0x95, 0xF5, 0xB9, 0x7F, 0xF4, 0xDA,
+0x07, 0x2E, 0x5D, 0x8D, 0xBF, 0xB0, 0x7E, 0x29, 0xFE, 0x64, 0xB1, 0x50, 0xFD, 0xF2, 0xD5, 0xB5,
+0x3C, 0x44, 0xCE, 0x7E, 0x21, 0x43, 0xF1, 0x21, 0x3E, 0x56, 0xEF, 0xF8, 0x77, 0x17, 0x98, 0x8F,
+0xBB, 0x82, 0xF9, 0x27, 0x3F, 0xEC, 0x8C, 0x03, 0x08, 0x10, 0x80, 0x9E, 0x7F, 0xF3, 0x5F, 0xBF,
+0xF6, 0x95, 0xAF, 0x78, 0x30, 0x7B, 0xFF, 0x85, 0x8B, 0xE1, 0x1D, 0xF9, 0x09, 0xAA, 0xB7, 0x50,
+0xFD, 0xCA, 0xA9, 0xAF, 0xA8, 0x2E, 0x3E, 0xC4, 0xC7, 0x6A, 0x1D, 0xFF, 0xE3, 0xAF, 0x60, 0xFE,
+0x49, 0x0B, 0xCC, 0x01, 0x01, 0x02, 0x30, 0xCE, 0x67, 0x7F, 0xED, 0x35, 0xAF, 0xBB, 0xFB, 0xE5,
+0xF9, 0xFA, 0x90, 0xEF, 0x4E, 0x7F, 0x4F, 0xEB, 0x43, 0xF2, 0x2B, 0xAA, 0x5F, 0x3D, 0xC9, 0x29,
+0x4B, 0x7C, 0x88, 0x8F, 0xD5, 0x39, 0xFE, 0xA3, 0x0B, 0xCC, 0x73, 0xBD, 0x05, 0xE6, 0x7F, 0x62,
+0x81, 0x39, 0x20, 0x40, 0x00, 0x26, 0x0A, 0x91, 0x7F, 0xF4, 0x9A, 0x1F, 0xBC, 0xE7, 0xFE, 0xF8,
+0xAB, 0xC5, 0x85, 0x0C, 0xD3, 0xBA, 0x90, 0x7B, 0xEE, 0x9F, 0xE4, 0x42, 0x86, 0xE2, 0x43, 0x7C,
+0xAC, 0xC6, 0xF1, 0x1F, 0xBF, 0xC0, 0xBC, 0xB8, 0x82, 0xF9, 0x1F, 0x5B, 0x60, 0x0E, 0x08, 0x10,
+0x80, 0x93, 0xFA, 0x48, 0xE3, 0xFA, 0xFA, 0x77, 0xBF, 0xB3, 0xF5, 0x0B, 0x17, 0xAF, 0xC4, 0x5F,
+0x2C, 0xD6, 0x87, 0xA4, 0x85, 0xEA, 0xF7, 0x3C, 0x70, 0xE1, 0x88, 0x0B, 0x19, 0x8A, 0x0F, 0xF1,
+0xB1, 0x1A, 0xC7, 0xDF, 0x02, 0x73, 0x40, 0x80, 0x00, 0xCC, 0xD0, 0x67, 0x7F, 0xED, 0x35, 0x0F,
+0x5C, 0xBC, 0x3B, 0xFC, 0xAD, 0xCB, 0xF7, 0xC4, 0xC7, 0x8A, 0xDB, 0xD2, 0xDA, 0x90, 0xF4, 0xD4,
+0xAC, 0xC3, 0xF5, 0x21, 0xE2, 0x43, 0x7C, 0x2C, 0xFF, 0xF1, 0xB7, 0xC0, 0x1C, 0x10, 0x20, 0x00,
+0xF3, 0x0D, 0x91, 0x07, 0xAF, 0xDC, 0x1B, 0x7F, 0x79, 0xFD, 0x72, 0x78, 0x7B, 0x7E, 0x12, 0x5B,
+0x2B, 0x42, 0x64, 0x56, 0xA7, 0x33, 0xF1, 0x21, 0x3E, 0x16, 0x83, 0x05, 0xE6, 0x80, 0x00, 0x01,
+0x38, 0x47, 0xCF, 0x7C, 0xF8, 0x35, 0x6F, 0x5D, 0xBF, 0x18, 0xDF, 0x7B, 0xE1, 0x52, 0xF8, 0xCE,
+0x34, 0x70, 0x3C, 0xDD, 0x42, 0x75, 0xF1, 0x21, 0x3E, 0x16, 0xFF, 0xF8, 0x5B, 0x60, 0x0E, 0x08,
+0x10, 0x80, 0x05, 0x91, 0xD6, 0x87, 0x7C, 0xCF, 0xBB, 0x0E, 0xDE, 0xB5, 0x7E, 0x29, 0xFE, 0x52,
+0xB1, 0x50, 0x3D, 0xAD, 0x0F, 0x49, 0x21, 0x72, 0xE7, 0x85, 0xEA, 0xE2, 0x43, 0x7C, 0x2C, 0xF6,
+0xF1, 0x3F, 0x6A, 0x81, 0x79, 0x27, 0x3C, 0x7E, 0xAA, 0x13, 0x1E, 0x7F, 0xE4, 0x0C, 0x00, 0x08,
+0x10, 0x80, 0x73, 0xF2, 0xCF, 0x1F, 0x7A, 0xCD, 0x95, 0x87, 0x7E, 0x2A, 0x7B, 0x7C, 0x6D, 0x3D,
+0xFC, 0x74, 0xF9, 0x42, 0x86, 0x29, 0x44, 0xC6, 0x2F, 0x54, 0x17, 0x1F, 0xE2, 0x63, 0xB1, 0x8F,
+0xFF, 0xB8, 0x05, 0xE6, 0xED, 0x83, 0xF8, 0x33, 0xAF, 0xF8, 0x6B, 0x9F, 0xFA, 0x97, 0xFE, 0xC5,
+0x03, 0x02, 0x04, 0x60, 0x41, 0xFC, 0xBB, 0xF7, 0x7D, 0xDB, 0x2B, 0xEE, 0x7B, 0x65, 0x7C, 0xEF,
+0xC5, 0x2B, 0xE1, 0xC7, 0x8B, 0xDB, 0x52, 0x84, 0x9C, 0xEC, 0x42, 0x86, 0xE2, 0x43, 0x7C, 0x9C,
+0x9F, 0xE1, 0x05, 0xE6, 0x1D, 0x2F, 0x74, 0xC2, 0xE3, 0xE7, 0xBF, 0xEE, 0xC7, 0x3E, 0xF5, 0x1B,
+0xFE, 0x85, 0x03, 0x02, 0x04, 0x60, 0x41, 0xFD, 0xF1, 0x7F, 0xFF, 0x6D, 0xAF, 0xB9, 0xF7, 0x1B,
+0xE2, 0x6F, 0x14, 0x17, 0x32, 0x4C, 0xF1, 0x51, 0x84, 0x88, 0xF8, 0x10, 0x1F, 0x8B, 0x78, 0xFC,
+0x87, 0x17, 0x98, 0xC7, 0x2C, 0x6C, 0x75, 0x7E, 0x6F, 0xFF, 0xBB, 0x60, 0x81, 0x39, 0x20, 0x40,
+0x00, 0xAA, 0xE3, 0xF3, 0xFF, 0xE3, 0xB7, 0xFE, 0xC0, 0x95, 0x97, 0x85, 0x74, 0x45, 0xF5, 0x07,
+0xD3, 0xDF, 0xD3, 0x42, 0xF5, 0xBB, 0xEF, 0x5F, 0x0B, 0x97, 0xEE, 0xAE, 0x89, 0x0F, 0xF1, 0xB1,
+0x10, 0x8E, 0x5A, 0x60, 0xDE, 0x79, 0x79, 0x4F, 0x27, 0x3C, 0x3E, 0xE3, 0x5F, 0x31, 0x20, 0x40,
+0x00, 0x2A, 0xE6, 0x9F, 0x3F, 0xF4, 0x9A, 0xF5, 0xEF, 0xFD, 0x1B, 0xD9, 0xBB, 0xD6, 0x2F, 0x85,
+0xF7, 0x97, 0x2F, 0x64, 0x98, 0x42, 0x24, 0x5D, 0x59, 0x5D, 0x7C, 0x88, 0x8F, 0x73, 0x79, 0x14,
+0x47, 0x2C, 0x30, 0x6F, 0x6E, 0xC7, 0x9F, 0xFF, 0x86, 0xFF, 0xEC, 0x53, 0xFF, 0xAF, 0x7F, 0xB9,
+0x80, 0x00, 0x01, 0xA8, 0xB8, 0xCF, 0xFE, 0xDA, 0xB7, 0x3E, 0x70, 0xF9, 0x6A, 0xF8, 0x85, 0xF5,
+0xCB, 0xE1, 0x27, 0x0F, 0x17, 0xAA, 0xD7, 0xCE, 0xB0, 0x50, 0x5D, 0x7C, 0x88, 0x8F, 0xD3, 0x19,
+0x5E, 0x60, 0xDE, 0xF1, 0x99, 0xD6, 0x5E, 0xFC, 0x09, 0x0B, 0xCC, 0x01, 0x01, 0x02, 0xB0, 0x9C,
+0x21, 0xF2, 0xEA, 0xBB, 0x36, 0xC2, 0xBB, 0x2F, 0x5C, 0x0C, 0xEF, 0x48, 0x03, 0xD2, 0xE2, 0x42,
+0x86, 0x27, 0x5B, 0xA8, 0x2E, 0x3E, 0xC4, 0xC7, 0xC9, 0x59, 0x60, 0x0E, 0x20, 0x40, 0x80, 0x95,
+0x0E, 0x91, 0x07, 0x5F, 0x77, 0xF7, 0xCB, 0xF3, 0xF5, 0x21, 0xFD, 0x85, 0xEA, 0x77, 0xDF, 0x7F,
+0x61, 0xCA, 0x17, 0x32, 0x14, 0x1F, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0x50, 0xF2, 0x85,
+0xFF, 0xE9, 0xC1, 0xBF, 0x7A, 0xF9, 0x6A, 0x78, 0x5F, 0x71, 0x21, 0xC3, 0xB4, 0x50, 0xFD, 0xEA,
+0x03, 0xD3, 0xB8, 0x90, 0xA1, 0xF8, 0x58, 0xF5, 0xF8, 0xB0, 0xC0, 0x1C, 0x40, 0x80, 0x00, 0x8C,
+0xF5, 0xCF, 0xBE, 0xE7, 0xD5, 0xEB, 0xAF, 0xFB, 0xC9, 0xDA, 0x2F, 0x5C, 0xBC, 0x12, 0x7E, 0xB1,
+0xBC, 0x50, 0xFD, 0x9E, 0x07, 0x2E, 0x9C, 0x71, 0x7D, 0x88, 0xF8, 0x58, 0xC5, 0xF8, 0xB0, 0xC0,
+0x1C, 0x40, 0x80, 0x00, 0x4C, 0xE4, 0xB3, 0xFF, 0xF0, 0xC1, 0x07, 0x2E, 0xDF, 0x1B, 0xFE, 0x6E,
+0xF9, 0x42, 0x86, 0xE9, 0x8A, 0xEA, 0x69, 0xC7, 0xAC, 0x93, 0xAF, 0x0F, 0x11, 0x1F, 0xAB, 0x18,
+0x1F, 0xFB, 0x5B, 0x69, 0x9D, 0x47, 0xDB, 0x02, 0x73, 0x00, 0x01, 0x02, 0x70, 0xA2, 0x10, 0x79,
+0xF5, 0x5D, 0x2F, 0x0F, 0x1F, 0xB8, 0x70, 0x31, 0x7C, 0x5F, 0x7E, 0xA2, 0x3C, 0xF1, 0x42, 0x75,
+0xF1, 0xB1, 0x6A, 0xF1, 0x91, 0xD6, 0x79, 0x6C, 0x3D, 0x6B, 0x81, 0x39, 0x80, 0x00, 0x01, 0x38,
+0x83, 0x67, 0x3E, 0xF4, 0xE0, 0x5B, 0x2F, 0x5E, 0x09, 0xEF, 0x2E, 0x16, 0xAA, 0xA7, 0xF5, 0x21,
+0x69, 0xDB, 0xDE, 0xE3, 0x17, 0xAA, 0x8B, 0x8F, 0x55, 0x8A, 0x8F, 0x76, 0xB3, 0xBB, 0xB3, 0x95,
+0x05, 0xE6, 0x00, 0x02, 0x04, 0x60, 0x2A, 0xD2, 0xFA, 0x90, 0x87, 0xFE, 0xF3, 0x5A, 0xBA, 0x90,
+0xE1, 0x2F, 0x15, 0x0B, 0xD5, 0xD3, 0xFA, 0x90, 0x14, 0x22, 0xA3, 0x0B, 0xD5, 0xC5, 0xC7, 0xAA,
+0xC4, 0x87, 0x05, 0xE6, 0x00, 0x02, 0x04, 0x60, 0xA6, 0xD2, 0xFA, 0x90, 0xBB, 0x36, 0xC2, 0xCF,
+0xAD, 0xAD, 0x87, 0x9F, 0x2E, 0x16, 0xAA, 0x5F, 0xBA, 0xBB, 0x96, 0x6F, 0xDD, 0xDB, 0x5D, 0xA8,
+0x2E, 0x3E, 0x56, 0x21, 0x3E, 0x8A, 0x05, 0xE6, 0x7B, 0x2F, 0x0E, 0x5C, 0x48, 0xD0, 0x02, 0x73,
+0x00, 0x01, 0x02, 0x30, 0x1B, 0x7F, 0xF4, 0x77, 0x1F, 0x7C, 0xC5, 0xFD, 0xD7, 0xF2, 0xF5, 0x21,
+0xEF, 0x28, 0x6E, 0xBB, 0xF2, 0xB2, 0x5A, 0xB8, 0xEB, 0xE5, 0xB3, 0xBE, 0x90, 0xA1, 0xF8, 0x38,
+0xEF, 0xF8, 0x18, 0xB7, 0xC0, 0xBC, 0x13, 0x22, 0x3F, 0xF5, 0xCA, 0xBF, 0xFE, 0xC7, 0x4F, 0xFA,
+0x97, 0x01, 0x20, 0x40, 0x00, 0x66, 0x2A, 0x2D, 0x54, 0xBF, 0xFB, 0xE5, 0xE1, 0xC3, 0x6B, 0xEB,
+0xB1, 0x7F, 0x21, 0xC3, 0x2B, 0xF7, 0xAD, 0xE5, 0x4F, 0xCD, 0x12, 0x1F, 0xCB, 0x15, 0x1F, 0xE3,
+0x16, 0x98, 0x37, 0x77, 0xE2, 0x7F, 0xF5, 0x0D, 0xEF, 0xFC, 0xD4, 0x07, 0xFD, 0x4B, 0x00, 0x10,
+0x20, 0x00, 0x73, 0xF5, 0xF9, 0x5F, 0x7F, 0xF5, 0x0F, 0xDC, 0x75, 0x5F, 0xF8, 0x60, 0xF9, 0x42,
+0x86, 0x77, 0x7F, 0xCD, 0x5A, 0xFE, 0xF4, 0x2C, 0xF1, 0x51, 0xED, 0xF8, 0x18, 0xB7, 0xC0, 0xBC,
+0xF3, 0xF2, 0xF7, 0xD7, 0xD6, 0xC3, 0xFB, 0x2D, 0x30, 0x07, 0x10, 0x20, 0x00, 0xE7, 0xE6, 0x7F,
+0xFB, 0xAE, 0x6F, 0x59, 0x7F, 0xF8, 0x6F, 0x5E, 0x48, 0x0B, 0xD5, 0xDF, 0x5F, 0xBE, 0x90, 0x61,
+0x7A, 0x5A, 0xD6, 0xF4, 0xAE, 0xA8, 0x2E, 0x3E, 0xE6, 0x15, 0x1F, 0xE3, 0x16, 0x98, 0x67, 0xED,
+0xF0, 0x4F, 0xD6, 0x2E, 0x84, 0x5F, 0xB2, 0xC0, 0x1C, 0x40, 0x80, 0x00, 0x2C, 0x8C, 0xCF, 0xFE,
+0xEA, 0xAB, 0x1E, 0xB8, 0xB2, 0x51, 0xFB, 0xB9, 0x4E, 0x88, 0xFC, 0x62, 0x71, 0x5B, 0xBA, 0x90,
+0x61, 0x0A, 0x91, 0xB3, 0x5D, 0x51, 0x5D, 0x7C, 0xCC, 0x23, 0x3E, 0x2C, 0x30, 0x07, 0x10, 0x20,
+0x00, 0x55, 0x0D, 0x91, 0x57, 0xDF, 0xF5, 0xF2, 0xDA, 0xBB, 0xCB, 0x0B, 0xD5, 0x53, 0x84, 0x4C,
+0x7E, 0x21, 0x43, 0xF1, 0x31, 0xEF, 0xF8, 0xB0, 0xC0, 0x1C, 0x40, 0x80, 0x00, 0x54, 0xDE, 0x33,
+0xBF, 0xF9, 0xEA, 0x81, 0x0B, 0x19, 0xA6, 0xF8, 0x28, 0x42, 0x44, 0x7C, 0x2C, 0x46, 0x7C, 0x58,
+0x60, 0x0E, 0x20, 0x40, 0x00, 0x96, 0xCE, 0x17, 0x7E, 0xE3, 0xD5, 0x7F, 0xF5, 0xF2, 0xD5, 0xF0,
+0xBE, 0xF2, 0x42, 0xF5, 0xAB, 0x5F, 0xBB, 0xC0, 0xEB, 0x43, 0x56, 0x20, 0x3E, 0x2C, 0x30, 0x07,
+0x10, 0x20, 0x00, 0x4B, 0x2D, 0x2D, 0x54, 0x6F, 0xFC, 0xEC, 0x85, 0xC7, 0x6B, 0xB5, 0xF0, 0x58,
+0x79, 0xA1, 0x7A, 0xDA, 0x31, 0xEB, 0xC2, 0xA5, 0x05, 0x3A, 0x15, 0x2F, 0x79, 0x7C, 0x58, 0x60,
+0x0E, 0x20, 0x40, 0x00, 0x56, 0x4A, 0x5A, 0xA8, 0x7E, 0xF9, 0xDE, 0xDA, 0xAF, 0x5C, 0xBC, 0x12,
+0x7E, 0xA2, 0xB8, 0x6D, 0x61, 0x16, 0xAA, 0x2F, 0x71, 0x7C, 0x1C, 0xB5, 0xC0, 0xBC, 0xF3, 0xF2,
+0x9E, 0x4E, 0x78, 0x7C, 0xCC, 0x6F, 0x26, 0x80, 0x00, 0x01, 0x58, 0xF6, 0x10, 0x49, 0x0B, 0xD5,
+0xD3, 0x15, 0xD5, 0xBF, 0x2F, 0x3F, 0x19, 0xF7, 0x2E, 0x64, 0x78, 0x6E, 0x0B, 0xD5, 0x97, 0x38,
+0x3E, 0xC6, 0x2D, 0x30, 0x6F, 0xED, 0xC7, 0x9F, 0x7F, 0xC5, 0x7F, 0xFA, 0xA9, 0x7F, 0xE6, 0x37,
+0x11, 0x40, 0x80, 0x00, 0xAC, 0x94, 0xB4, 0x50, 0xFD, 0xD2, 0xDD, 0xF9, 0xF5, 0x43, 0x5E, 0x9B,
+0xFE, 0x9E, 0xD6, 0x87, 0xA4, 0xD9, 0x90, 0xCB, 0x57, 0xE7, 0x78, 0x7A, 0x5E, 0xD2, 0xF8, 0x18,
+0xB7, 0xC0, 0xBC, 0x7D, 0x10, 0xFE, 0xCE, 0xD7, 0xFD, 0xD8, 0x27, 0xDF, 0xEF, 0x37, 0x0F, 0x40,
+0x80, 0x00, 0xAC, 0xAC, 0x7F, 0xFA, 0x1D, 0xF5, 0xF5, 0xD7, 0x3F, 0x76, 0x39, 0x5D, 0xC8, 0xF0,
+0x97, 0x8A, 0x85, 0xEA, 0x69, 0x5D, 0xC8, 0x3D, 0x5F, 0x33, 0x87, 0x85, 0xEA, 0x4B, 0x18, 0x1F,
+0xC3, 0x0B, 0xCC, 0x93, 0xAC, 0x15, 0xFE, 0x8E, 0x05, 0xE6, 0x00, 0x02, 0x04, 0x80, 0x92, 0xE2,
+0x42, 0x86, 0x17, 0xD6, 0xC3, 0x4F, 0x97, 0x17, 0xAA, 0xDF, 0xF3, 0xB5, 0x17, 0x66, 0xB3, 0x3E,
+0x64, 0xC9, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x29, 0x3C, 0xF3, 0x9B, 0xAF, 0xFA,
+0xE6, 0xF5, 0xCB, 0xB5, 0xF7, 0x96, 0x2F, 0x64, 0x98, 0x16, 0xAA, 0xA7, 0x1D, 0xB3, 0xA6, 0xB6,
+0x3E, 0x64, 0x89, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x14, 0x7C, 0xE9, 0xB7, 0x5E,
+0xF5, 0x9D, 0x17, 0x2E, 0xD6, 0xFE, 0x87, 0xB5, 0xF5, 0xF0, 0x3D, 0xF9, 0x09, 0xBB, 0xB7, 0x50,
+0xFD, 0xAE, 0x8D, 0x33, 0x56, 0xC8, 0x12, 0xC5, 0x87, 0x05, 0xE6, 0x00, 0x02, 0x04, 0x80, 0x29,
+0xFB, 0xFC, 0xAF, 0xBF, 0xEA, 0x07, 0xEE, 0xBA, 0xAF, 0xF6, 0xC1, 0xF2, 0x85, 0x0C, 0x4F, 0xBD,
+0x50, 0x7D, 0x49, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x0C, 0xA5, 0x85, 0xEA, 0x8F,
+0xFC, 0x97, 0x97, 0x1F, 0xED, 0x44, 0xC8, 0xBB, 0xCB, 0xEB, 0x43, 0x52, 0x88, 0x4C, 0xBC, 0x50,
+0x7D, 0x09, 0xE2, 0x63, 0xDC, 0x02, 0xF3, 0x4E, 0x8C, 0xFC, 0x37, 0x9D, 0x63, 0xF0, 0x3E, 0x0B,
+0xCC, 0x01, 0x04, 0x08, 0x00, 0x53, 0x56, 0x2C, 0x54, 0x5F, 0xBF, 0x14, 0x7E, 0xB1, 0xB8, 0xED,
+0xD2, 0xDD, 0xE9, 0x8A, 0xEA, 0x77, 0x58, 0xA8, 0x5E, 0xF1, 0xF8, 0x48, 0x4F, 0xB1, 0x4A, 0xE1,
+0x51, 0x5E, 0x60, 0xDE, 0x6A, 0xC6, 0xFF, 0x75, 0xFD, 0x52, 0xED, 0x17, 0x2D, 0x30, 0x07, 0x10,
+0x20, 0x00, 0xCC, 0x3E, 0x44, 0x5E, 0x7D, 0xCF, 0x03, 0xB5, 0x74, 0xFD, 0x90, 0xBF, 0x5C, 0xDC,
+0x96, 0x2E, 0x62, 0x98, 0x66, 0x44, 0x46, 0x16, 0xAA, 0x57, 0x38, 0x3E, 0xC6, 0x2D, 0x30, 0xCF,
+0xDA, 0xE1, 0x5F, 0xAF, 0x5D, 0x08, 0x7F, 0xDB, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x9C, 0x3D,
+0xF3, 0x9B, 0xAF, 0x7A, 0xEB, 0xC5, 0x2B, 0xB5, 0xC7, 0xCB, 0x0B, 0xD5, 0x53, 0x84, 0xA4, 0x18,
+0xA9, 0x7A, 0x7C, 0xA4, 0x05, 0xE6, 0x69, 0x5B, 0xDD, 0xD2, 0x3A, 0x0F, 0x0B, 0xCC, 0x01, 0x04,
+0x08, 0x00, 0x8B, 0xE0, 0x4B, 0xFF, 0xF8, 0xD5, 0x7F, 0xA3, 0x7C, 0x21, 0xC3, 0xF4, 0x74, 0xAC,
+0xBB, 0xEF, 0x5F, 0xCB, 0x9F, 0x9E, 0x55, 0xB5, 0xF8, 0x48, 0x0B, 0xCC, 0xB7, 0xBF, 0x92, 0xE5,
+0xEB, 0x3D, 0x7A, 0xF2, 0x05, 0xE6, 0xFF, 0xF2, 0x57, 0x6E, 0x7F, 0xE0, 0x3F, 0xF9, 0xC4, 0x97,
+0x5A, 0x7E, 0xDA, 0x00, 0x02, 0x04, 0x80, 0x05, 0x90, 0x2F, 0x54, 0xFF, 0xF9, 0xCB, 0x8F, 0xD7,
+0x6A, 0xE1, 0xB1, 0xDA, 0x5A, 0x3C, 0x5C, 0xA8, 0xBE, 0x31, 0x87, 0x2B, 0xAA, 0x4F, 0x21, 0x3E,
+0xD2, 0x85, 0x04, 0xB7, 0x9F, 0x6D, 0x5B, 0x60, 0x0E, 0x20, 0x40, 0x00, 0xA8, 0x92, 0xCF, 0xFC,
+0x83, 0x6F, 0x79, 0xE0, 0xEE, 0xFB, 0xD7, 0xFE, 0xC1, 0xF0, 0x85, 0x0C, 0x53, 0x88, 0xCC, 0xE4,
+0x8A, 0xEA, 0x67, 0x8C, 0x0F, 0x0B, 0xCC, 0x01, 0x04, 0x08, 0x00, 0xCB, 0x11, 0x22, 0xAF, 0xBE,
+0xFA, 0xB5, 0x6B, 0xBF, 0x51, 0x5B, 0x0B, 0x0F, 0xE5, 0x27, 0xFC, 0xB5, 0xEE, 0x42, 0xF5, 0xF4,
+0x32, 0xB5, 0x2B, 0xAA, 0x9F, 0x21, 0x3E, 0x2C, 0x30, 0x07, 0x10, 0x20, 0x00, 0x2C, 0xA1, 0x67,
+0x7E, 0xF3, 0x2F, 0xBC, 0xF5, 0xD2, 0xDD, 0xF9, 0x8E, 0x59, 0xAF, 0x2D, 0x42, 0xE4, 0xEE, 0xFB,
+0x2F, 0x9C, 0xEE, 0x42, 0x86, 0x53, 0x8A, 0x0F, 0x0B, 0xCC, 0x01, 0x04, 0x08, 0x00, 0x4B, 0xEC,
+0x7F, 0xB9, 0xFE, 0x8D, 0xEB, 0x8D, 0x9F, 0xBD, 0xEB, 0x5D, 0x17, 0xEF, 0xAA, 0xBD, 0xAF, 0xF3,
+0xD7, 0x8D, 0x74, 0x5B, 0xBA, 0xA2, 0xFA, 0xD5, 0x07, 0x66, 0xB9, 0x3E, 0x64, 0x34, 0x3E, 0x2C,
+0x30, 0x07, 0x40, 0x80, 0x00, 0xAC, 0x90, 0xB4, 0x3E, 0xE4, 0xAE, 0x97, 0xD7, 0x7E, 0xEE, 0xC2,
+0x7A, 0xED, 0xA7, 0xCB, 0x57, 0x54, 0x4F, 0x3B, 0x66, 0x5D, 0xB8, 0x34, 0xCD, 0xFF, 0x4B, 0x18,
+0x8C, 0x0F, 0x0B, 0xCC, 0x01, 0x10, 0x20, 0x00, 0x2B, 0xEC, 0x99, 0xDF, 0xFC, 0x0B, 0xDF, 0xBC,
+0x7E, 0xB9, 0xF6, 0xDE, 0xE1, 0x85, 0xEA, 0x57, 0xEE, 0xAD, 0x4D, 0x21, 0x44, 0xE2, 0x40, 0x78,
+0xA4, 0xA7, 0x5A, 0x59, 0x60, 0x0E, 0x80, 0x00, 0x01, 0x20, 0x7C, 0xE5, 0x9F, 0xBE, 0xAA, 0xD1,
+0x89, 0x84, 0x5F, 0x29, 0x2E, 0x64, 0x98, 0xA4, 0x00, 0x49, 0x0B, 0xD5, 0xD3, 0xCC, 0xC8, 0xC9,
+0x77, 0xCD, 0x8A, 0xF9, 0x82, 0xF2, 0xE6, 0x4E, 0x0C, 0xCD, 0xDB, 0xD9, 0xC0, 0x8C, 0x47, 0x6C,
+0x87, 0x7F, 0x5D, 0xB3, 0xC0, 0x1C, 0x40, 0x80, 0x38, 0x04, 0x00, 0xFC, 0xD9, 0x3F, 0x79, 0xD5,
+0x5F, 0xB9, 0x70, 0x31, 0xBC, 0xBF, 0xF3, 0x66, 0xBD, 0x7C, 0x7B, 0x8A, 0x91, 0x22, 0x44, 0xD6,
+0x3B, 0x6F, 0xA7, 0x05, 0xEC, 0xE5, 0x19, 0x92, 0xB4, 0x96, 0x23, 0x05, 0x47, 0xAB, 0xF3, 0x67,
+0x5A, 0x50, 0x7E, 0xB0, 0x1B, 0xCB, 0xEB, 0x3B, 0x0A, 0x9F, 0xE9, 0xBC, 0xBC, 0xA7, 0x13, 0x1E,
+0x1F, 0x76, 0xA4, 0x01, 0x10, 0x20, 0x00, 0xF4, 0xA5, 0x1D, 0xB3, 0xD6, 0x2F, 0xD7, 0x1E, 0xED,
+0xC4, 0xC8, 0xF7, 0x9F, 0xE8, 0x13, 0xE3, 0xD8, 0xDD, 0xAE, 0x7E, 0x7B, 0xEF, 0xA5, 0xF8, 0xEB,
+0xAF, 0xFC, 0x89, 0x4F, 0x3D, 0xE9, 0xC8, 0x02, 0x20, 0x40, 0x00, 0x38, 0x52, 0x5A, 0xAC, 0x7E,
+0xF9, 0x65, 0xB5, 0x37, 0x5E, 0x58, 0xAF, 0x35, 0x6A, 0x6B, 0xA1, 0xB1, 0xB6, 0x1E, 0x1E, 0xBC,
+0x53, 0x7C, 0xC4, 0x2C, 0xFC, 0xDB, 0xCE, 0x9B, 0x7F, 0xB8, 0x76, 0x21, 0xFC, 0x5F, 0x2F, 0x7D,
+0xB1, 0xFD, 0xBB, 0xDF, 0xF4, 0xD8, 0x9F, 0x3C, 0xE7, 0x48, 0x02, 0x20, 0x40, 0x00, 0x38, 0xB1,
+0xB4, 0x8D, 0xEF, 0x77, 0xFF, 0xF8, 0x95, 0x6F, 0x7E, 0xD9, 0x2B, 0xD6, 0xBE, 0x61, 0xF8, 0x7D,
+0x9D, 0xD8, 0xF8, 0xE2, 0x37, 0x3D, 0xFA, 0xC7, 0xFF, 0xCE, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xC7,
+0xFF, 0x2F, 0xC0, 0x00, 0x23, 0xF2, 0x4C, 0x01, 0x21, 0x26, 0xDF, 0x39, 0x00, 0x00, 0x00, 0x00,
+0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82};
diff --git a/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino b/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino
new file mode 100755
index 000000000..e9ff771e4
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino
@@ -0,0 +1,70 @@
+/*
+ * Created by K. Suwatchai (Mobizt)
+ *
+ * Email: k_suwatchai@hotmail.com
+ *
+ * Github: https://github.com/mobizt
+ *
+ * Copyright (c) 2019 mobizt
+ *
+*/
+
+
+#include
+#include "ESP32_MailClient.h"
+
+#define WIFI_SSID "YOUR_WIFI_SSID"
+#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
+
+//The Email Reading data object contains config and data that received
+IMAPData imapData;
+
+void readEmail();
+
+unsigned long lastTime = 0;
+
+void setup()
+{
+
+ Serial.begin(115200);
+ Serial.println();
+
+ Serial.print("Connecting to AP");
+
+ WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
+ while (WiFi.status() != WL_CONNECTED)
+ {
+ Serial.print(".");
+ delay(200);
+ }
+
+ Serial.println("");
+ Serial.println("WiFi connected.");
+ Serial.println("IP address: ");
+ Serial.println(WiFi.localIP());
+
+ Serial.println();
+
+ Serial.println();
+
+ imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
+ imapData.setFolder("INBOX");
+ imapData.setDebug(true);
+
+ //Set \Seen and \Answered to flags for message with UID 100
+ MailClient.setFlag(imapData, 100, "\\Seen \\Answered");
+
+ //Add \Seen and \Answered to flags for message with UID 100
+ //MailClient.addFlag(imapData, 100, "\\Seen \\Answered");
+
+ //Remove \Seen and \Answered from flags for message with UID 100
+ //MailClient.removeFlag(imapData, 100, "\\Seen \\Answered");
+}
+
+
+
+void loop()
+{
+
+}
+
diff --git a/libesp32/ESP32-Mail-Client/examples/Time/Time.ino b/libesp32/ESP32-Mail-Client/examples/Time/Time.ino
new file mode 100755
index 000000000..4726064d3
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/examples/Time/Time.ino
@@ -0,0 +1,136 @@
+/*
+ * Created by K. Suwatchai (Mobizt)
+ *
+ * Email: k_suwatchai@hotmail.com
+ *
+ * Github: https://github.com/mobizt
+ *
+ * Copyright (c) 2019 mobizt
+ *
+*/
+
+
+#include
+#include "ESP32_MailClient.h"
+
+#define WIFI_SSID "YOUR_WIFI_SSID"
+#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
+
+
+void setup()
+{
+
+ Serial.begin(115200);
+ Serial.println();
+
+ Serial.print("Connecting to AP");
+
+ WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
+ while (WiFi.status() != WL_CONNECTED)
+ {
+ Serial.print(".");
+ delay(200);
+ }
+
+ Serial.println("");
+ Serial.println("WiFi connected.");
+ Serial.println("IP address: ");
+ Serial.println(WiFi.localIP());
+
+ Serial.println();
+
+ //Set Clock
+ //GMT offset (3 Hrs), Daylight offset (0 Hrs)
+ MailClient.Time.setClock(3, 0);
+
+ Serial.println("Number of Days This Year (since January): " + String(MailClient.Time.getNumberOfDayThisYear()));
+ Serial.println("Day of Week Number: " + String(MailClient.Time.getDayOfWeek()));
+ Serial.println("Day of Week String: : " + String(MailClient.Time.getDayOfWeekString()));
+ Serial.println("Total seconds today: : " + String(MailClient.Time.getCurrentSecond()));
+ Serial.println();
+}
+
+void loop()
+{
+
+ if (!MailClient.Time.clockReady)
+ return;
+
+ //Print out current date and time
+ int d = MailClient.Time.getDay();
+ int m = MailClient.Time.getMonth();
+ int y = MailClient.Time.getYear();
+ int hr = MailClient.Time.getHour();
+ int min = MailClient.Time.getMin();
+ int sec = MailClient.Time.getSec();
+ Serial.print("Current Time (GMT+3): ");
+ Serial.print(d);
+ Serial.print("/");
+ Serial.print(m);
+ Serial.print("/");
+ Serial.print(y);
+ Serial.print(" ");
+ Serial.print(hr);
+ Serial.print(":");
+ Serial.print(min);
+ Serial.print(":");
+ Serial.println(sec);
+
+ uint32_t todayFromMidnightTimestamp = MailClient.Time.getTimestamp(y, m, d, 0, 0, 0);
+ uint32_t currentTimestamp = MailClient.Time.getUnixTime();
+ uint32_t totalSecondsFromMidnight = currentTimestamp - todayFromMidnightTimestamp;
+
+ //Assumed we countdown until 15:00:00 everyday
+ uint8_t targetSec = 0;
+ uint8_t targetMin = 0;
+ uint8_t targetHr = 15;
+ uint32_t targetSecondsFromMidnight = targetHr * 60 * 60 + targetMin * 60 + targetSec;
+
+ if (targetSecondsFromMidnight >= totalSecondsFromMidnight)
+ {
+ uint32_t diffSeconds = targetSecondsFromMidnight - totalSecondsFromMidnight;
+ int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec;
+ MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec);
+ Serial.print("Everyday countdown until 15:00:00 is ");
+ Serial.print(remainHr);
+ Serial.print(" Hr, ");
+ Serial.print(remainMin);
+ Serial.print(" Min and ");
+ Serial.print(remainSec);
+ Serial.println(" Sec to go.");
+ }
+ else
+ {
+ Serial.println("Everyday countdown until 15:00:00 was passed.");
+ }
+
+ //Assumed we countdown until 18/12/2019 8:30:45
+ uint32_t targetTimestamp = MailClient.Time.getTimestamp(2019, 12, 18, 8, 30, 45);
+ if (targetTimestamp >= currentTimestamp)
+ {
+ uint32_t diffSeconds = targetTimestamp - currentTimestamp;
+ int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec;
+ MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec);
+ Serial.print("One time countdown until 18/12/2019 8:30:45 is ");
+ Serial.print(remainYrs);
+ Serial.print(" Years, ");
+ Serial.print(remainMonths);
+ Serial.print(" Months, ");
+ Serial.print(remainDays);
+ Serial.print(" Days, ");
+ Serial.print(remainHr);
+ Serial.print(" Hr, ");
+ Serial.print(remainMin);
+ Serial.print(" Min and ");
+ Serial.print(remainSec);
+ Serial.println(" Sec to go.");
+ }
+ else
+ {
+ Serial.println("One time countdown until 18/12/2019 8:30:45 was finished.");
+ }
+ Serial.println();
+
+ delay(1000);
+}
+
diff --git a/libesp32/ESP32-Mail-Client/keywords.txt b/libesp32/ESP32-Mail-Client/keywords.txt
new file mode 100755
index 000000000..81b7ee9b2
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/keywords.txt
@@ -0,0 +1,166 @@
+#######################################
+# Syntax Coloring Map ESP32-Mail-Client
+#######################################
+
+#######################################
+# Classes (KEYWORD1)
+#######################################
+
+IMAPData KEYWORD1
+SMTPData KEYWORD1
+attachmentData KEYWORD1
+SendStatus KEYWORD1
+messageBodyData KEYWORD1
+DownloadProgress KEYWORD1
+MessageData KEYWORD1
+
+TIME KEYWORD1
+
+
+##################################
+# Methods and Functions (KEYWORD2)
+##################################
+
+sendMail KEYWORD2
+readMail KEYWORD2
+smtpErrorReason KEYWORD2
+imapErrorReason KEYWORD2
+sdBegin KEYWORD2
+setFlag KEYWORD2
+addFlag KEYWORD2
+removeFlag KEYWORD2
+
+
+setClock KEYWORD2
+getUnixTime KEYWORD2
+getTimestamp KEYWORD2
+getYear KEYWORD2
+getMonth KEYWORD2
+getDay KEYWORD2
+getDayOfWeek KEYWORD2
+getDayOfWeekString KEYWORD2
+getHour KEYWORD2
+getMin KEYWORD2
+getSec KEYWORD2
+getNumberOfDayThisYear KEYWORD2
+getTotalDays KEYWORD2
+dayofweek KEYWORD2
+getCurrentSecond KEYWORD2
+getCurrentTimestamp KEYWORD2
+getTimeFromSec KEYWORD2
+
+#########################################
+# Methods for IMAP Data object (KEYWORD2)
+#########################################
+
+setLogin KEYWORD2
+setSTARTTLS KEYWORD2
+setDebug KEYWORD2
+setFolder KEYWORD2
+setMessageBufferSize KEYWORD2
+setAttachmentSizeLimit KEYWORD2
+setSearchCriteria KEYWORD2
+setSaveFilePath KEYWORD2
+setFechUID KEYWORD2
+setDownloadAttachment KEYWORD2
+setHTMLMessage KEYWORD2
+setTextMessage KEYWORD2
+setSearchLimit KEYWORD2
+setRecentSort KEYWORD2
+setReadCallback KEYWORD2
+setDownloadReport KEYWORD2
+isHeaderOnly KEYWORD2
+getFrom KEYWORD2
+getFromCharset KEYWORD2
+getTo KEYWORD2
+getToCharset KEYWORD2
+getCC KEYWORD2
+getCCCharset KEYWORD2
+getSubject KEYWORD2
+getSubjectCharset KEYWORD2
+getHTMLMessage KEYWORD2
+getTextMessage KEYWORD2
+getHTMLMessgaeCharset KEYWORD2
+getTextMessgaeCharset KEYWORD2
+getDate KEYWORD2
+getUID KEYWORD2
+getNumber KEYWORD2
+getMessageID KEYWORD2
+getAcceptLanguage KEYWORD2
+getContentLanguage KEYWORD2
+isFetchMessageFailed KEYWORD2
+getFetchMessageFailedReason KEYWORD2
+isDownloadAttachmentFailed KEYWORD2
+getDownloadAttachmentFailedReason KEYWORD2
+isDownloadMessageFailed KEYWORD2
+getDownloadMessageFailedReason KEYWORD2
+saveHTMLMessage KEYWORD2
+saveTextMessage KEYWORD2
+getFolderCount KEYWORD2
+getFolder KEYWORD2
+getFlagCount KEYWORD2
+getFlag KEYWORD2
+totalMessages KEYWORD2
+searchCount KEYWORD2
+availableMessages KEYWORD2
+getAttachmentCount KEYWORD2
+getAttachmentFileName KEYWORD2
+getAttachmentName KEYWORD2
+getAttachmentFileSize KEYWORD2
+getAttachmentCreationDate KEYWORD2
+getAttachmentType KEYWORD2
+empty KEYWORD2
+clearMessageData KEYWORD2
+
+#########################################
+# Methods for SMTP Data object (KEYWORD2)
+#########################################
+
+setSender KEYWORD2
+getFromName KEYWORD2
+getSenderEmail KEYWORD2
+setPriority KEYWORD2
+getPriority KEYWORD2
+addRecipient KEYWORD2
+removeRecipient KEYWORD2
+clearRecipient KEYWORD2
+getRecipient KEYWORD2
+recipientCount KEYWORD2
+setSubject KEYWORD2
+getSubject KEYWORD2
+setMessage KEYWORD2
+getMessage KEYWORD2
+htmlFormat KEYWORD2
+addCC KEYWORD2
+removeCC KEYWORD2
+clearCC KEYWORD2
+getCC KEYWORD2
+ccCount KEYWORD2
+addBCC KEYWORD2
+removeBCC KEYWORD2
+clearBCC KEYWORD2
+getBCC KEYWORD2
+bccCount KEYWORD2
+addAttachData KEYWORD2
+removeAttachData KEYWORD2
+attachDataCount KEYWORD2
+addAttachFile KEYWORD2
+removeAttachFile KEYWORD2
+clearAttachData KEYWORD2
+clearAttachFile KEYWORD2
+clearAttachment KEYWORD2
+attachFileCount KEYWORD2
+setSendCallback KEYWORD2
+
+
+############################################################
+# Functions for ReadStatus and SendStatus classes (KEYWORD2)
+############################################################
+
+SendStatus KEYWORD2
+info KEYWORD2
+success KEYWORD2
+ReadStatus KEYWORD2
+status KEYWORD2
+
+clockReady KEYWORD3
\ No newline at end of file
diff --git a/libesp32/ESP32-Mail-Client/library.properties b/libesp32/ESP32-Mail-Client/library.properties
new file mode 100755
index 000000000..6ff993e8b
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/library.properties
@@ -0,0 +1,17 @@
+name=ESP32 Mail Client
+
+version=2.1.4
+
+author=Mobizt
+
+maintainer=Mobizt
+
+sentence=Mail Client Arduino Library for ESP32
+
+paragraph=This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers.
+
+category=Communication
+
+url=https://github.com/mobizt/ESP32-Mail-Client
+
+architectures=esp32
diff --git a/libesp32/ESP32-Mail-Client/media/images/esp32-mail.jpg b/libesp32/ESP32-Mail-Client/media/images/esp32-mail.jpg
new file mode 100755
index 000000000..d4c62c865
Binary files /dev/null and b/libesp32/ESP32-Mail-Client/media/images/esp32-mail.jpg differ
diff --git a/libesp32/ESP32-Mail-Client/media/images/esp32-mail.png b/libesp32/ESP32-Mail-Client/media/images/esp32-mail.png
new file mode 100755
index 000000000..459238782
Binary files /dev/null and b/libesp32/ESP32-Mail-Client/media/images/esp32-mail.png differ
diff --git a/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp b/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp
new file mode 100755
index 000000000..39df83f7e
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp
@@ -0,0 +1,200 @@
+/*
+ * Customized version of ESP32 HTTPClient Library.
+ * Allow custom header and payload with STARTTLS support
+ *
+ * v 1.0.0
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ * HTTPClient Arduino library for ESP32
+ *
+ * Copyright (c) 2015 Markus Sattler. All rights reserved.
+ * This file is part of the HTTPClient for Arduino.
+ * Port to ESP32 by Evandro Luis Copercini (2017),
+ * changed fingerprints to CA verification.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+*/
+
+#ifndef ESP32MailHTTPClient_CPP
+#define ESP32MailHTTPClient_CPP
+
+#ifdef ESP32
+
+#include "ESP32MailHTTPClient.h"
+
+class TransportTraits
+{
+public:
+ virtual ~TransportTraits() {}
+
+ virtual std::unique_ptr create()
+ {
+ return std::unique_ptr(new WiFiClient());
+ }
+
+ virtual bool
+ verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb)
+ {
+ return true;
+ }
+};
+
+class TLSTraits : public TransportTraits
+{
+public:
+ TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {}
+
+ std::unique_ptr create() override
+ {
+ return std::unique_ptr(new WiFiClientSecureESP32());
+ }
+
+ bool verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb) override
+ {
+ WiFiClientSecureESP32 &wcs = static_cast(client);
+ wcs.setCACert(_cacert);
+ wcs.setCertificate(_clicert);
+ wcs.setPrivateKey(_clikey);
+ wcs.setSTARTTLS(starttls);
+ wcs.setDebugCB(cb);
+ return true;
+ }
+
+protected:
+ const char *_cacert;
+ const char *_clicert;
+ const char *_clikey;
+};
+
+ESP32MailHTTPClient::ESP32MailHTTPClient() {}
+
+ESP32MailHTTPClient::~ESP32MailHTTPClient()
+{
+ if (_client)
+ _client->stop();
+}
+
+bool ESP32MailHTTPClient::begin(const char *host, uint16_t port, const char *uri, const char *CAcert)
+{
+ transportTraits.reset(nullptr);
+
+ _host = host;
+ _port = port;
+ _uri = uri;
+ transportTraits = TransportTraitsPtr(new TLSTraits(CAcert));
+ return true;
+}
+
+bool ESP32MailHTTPClient::connected()
+{
+ if (_client)
+ return ((_client->available() > 0) || _client->connected());
+ return false;
+}
+
+bool ESP32MailHTTPClient::sendHeader(const char *header)
+{
+ if (!connected())
+ return false;
+ return (_client->write(header, strlen(header)) == strlen(header));
+}
+
+int ESP32MailHTTPClient::sendRequest(const char *header, const char *payload)
+{
+ size_t size = strlen(payload);
+ if (strlen(header) > 0)
+ {
+ if (!connect())
+ return HTTPC_ERROR_CONNECTION_REFUSED;
+ if (!sendHeader(header))
+ return HTTPC_ERROR_SEND_HEADER_FAILED;
+ }
+ if (size > 0)
+ if (_client->write(&payload[0], size) != size)
+ return HTTPC_ERROR_SEND_PAYLOAD_FAILED;
+
+ return 0;
+}
+
+WiFiClient *ESP32MailHTTPClient::getStreamPtr(void)
+{
+ if (connected())
+ return _client.get();
+ return nullptr;
+}
+
+bool ESP32MailHTTPClient::connect(void)
+{
+ if (connected())
+ {
+ while (_client->available() > 0)
+ _client->read();
+ return true;
+ }
+
+ if (!transportTraits)
+ return false;
+
+ _client = transportTraits->create();
+
+ if (!transportTraits->verify(*_client, _host.c_str(), false, _debugCallback))
+ {
+ _client->stop();
+ return false;
+ }
+
+ if (!_client->connect(_host.c_str(), _port))
+ return false;
+
+ return connected();
+}
+
+bool ESP32MailHTTPClient::connect(bool starttls)
+{
+ if (connected())
+ {
+ while (_client->available() > 0)
+ _client->read();
+ return true;
+ }
+
+ if (!transportTraits)
+ return false;
+
+ _client = transportTraits->create();
+
+ if (!transportTraits->verify(*_client, _host.c_str(), starttls, _debugCallback))
+ {
+ _client->stop();
+ return false;
+ }
+
+ if (!_client->connect(_host.c_str(), _port))
+ return false;
+
+ return connected();
+}
+
+void ESP32MailHTTPClient::setDebugCallback(DebugMsgCallback cb)
+{
+ _debugCallback = std::move(cb);
+}
+
+#endif //ESP32
+
+#endif //ESP32MailHTTPClient_CPP
diff --git a/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h b/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h
new file mode 100755
index 000000000..5df2c8d2d
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h
@@ -0,0 +1,107 @@
+/*
+ * Customized version of ESP32 HTTPClient Library.
+ * Allow custom header and payload with STARTTLS support
+ *
+ * v 1.0.0
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ * HTTPClient Arduino library for ESP32
+ *
+ * Copyright (c) 2015 Markus Sattler. All rights reserved.
+ * This file is part of the HTTPClient for Arduino.
+ * Port to ESP32 by Evandro Luis Copercini (2017),
+ * changed fingerprints to CA verification.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+*/
+
+#ifndef ESP32MailHTTPClient_H
+#define ESP32MailHTTPClient_H
+
+#ifdef ESP32
+
+#include
+#include
+
+#include
+#include "WiFiClientSecureESP32.h"
+
+class ESP32MailHTTPClient : public HTTPClient
+{
+public:
+ ESP32MailHTTPClient();
+ ~ESP32MailHTTPClient();
+
+ /**
+ * Initialization of new http connection.
+ * \param host - Host name without protocols.
+ * \param port - Server's port.
+ * \param uri - The URI of resource.
+ * \param CAcert - The Base64 encode root certificate string
+ * \return True as default.
+ * If no certificate string provided, use (const char*)NULL to CAcert param
+ */
+ bool begin(const char *host, uint16_t port, const char *uri, const char *CAcert);
+
+ /**
+ * Check the http connection status.
+ * \return True if connected.
+ */
+ bool connected();
+
+ /**
+ * Establish http connection if header provided and send it, send payload if provided.
+ * \param header - The header string (constant chars array).
+ * \param payload - The payload string (constant chars array), optional.
+ * \return http status code, Return zero if new http connection and header and/or payload sent
+ * with no error or no header and payload provided. If obly payload provided, no new http connection was established.
+ */
+ int sendRequest(const char *header, const char *payload);
+
+ /**
+ * Send extra header without making new http connection (if sendRequest has been called)
+ * \param header - The header string (constant chars array).
+ * \return True if header sending success.
+ * Need to call sendRequest with header first.
+ */
+ bool sendHeader(const char *header);
+
+ /**
+ * Get the WiFi client pointer.
+ * \return WiFi client pointer.
+ */
+ WiFiClient *getStreamPtr(void);
+
+ uint16_t tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
+ bool connect(void);
+ bool connect(bool starttls);
+ void setDebugCallback(DebugMsgCallback cb);
+
+protected:
+ TransportTraitsPtr transportTraits;
+ std::unique_ptr _client;
+ DebugMsgCallback _debugCallback = NULL;
+
+ std::string _host = "";
+ std::string _uri = "";
+ uint16_t _port = 0;
+};
+
+#endif //ESP32
+
+#endif //ESP32MailHTTPClient_H
diff --git a/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp b/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp
new file mode 100755
index 000000000..8e37b566b
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp
@@ -0,0 +1,191 @@
+/*
+ * ESP32 Internet Time Helper Arduino Library v 1.0.1
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person returning a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef ESP32TimeHelper_CPP
+#define ESP32TimeHelper_CPP
+
+#ifdef ESP32
+
+#include "ESP32TimeHelper.h"
+
+ESP32TimeHelper::ESP32TimeHelper()
+{
+}
+uint32_t ESP32TimeHelper::getUnixTime()
+{
+ uint32_t utime = (msec_time_diff + millis()) / 1000;
+ return utime;
+}
+
+time_t ESP32TimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec)
+{
+ struct tm timeinfo;
+ timeinfo.tm_year = year - 1900;
+ timeinfo.tm_mon = mon - 1;
+ timeinfo.tm_mday = date;
+ timeinfo.tm_hour = hour;
+ timeinfo.tm_min = mins;
+ timeinfo.tm_sec = sec;
+ time_t ts = mktime(&timeinfo);
+ return ts;
+}
+
+bool ESP32TimeHelper::setClock(float gmtOffset, float daylightOffset)
+{
+ TZ = gmtOffset;
+ DST_MN = daylightOffset;
+ configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov", NULL);
+
+ now = time(nullptr);
+ int cnt = 0;
+ while (now < 8 * 3600 * 2 && cnt < 20)
+ {
+ delay(50);
+ now = time(nullptr);
+ cnt++;
+ }
+
+ uint64_t tmp = now;
+ tmp = tmp * 1000;
+ msec_time_diff = tmp - millis();
+
+ getLocalTime(&timeinfo);
+
+ clockReady = now > 8 * 3600 * 2;
+ return clockReady;
+}
+
+int ESP32TimeHelper::getYear()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_year + 1900;
+}
+int ESP32TimeHelper::getMonth()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_mon + 1;
+}
+int ESP32TimeHelper::getDay()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_mday;
+}
+
+int ESP32TimeHelper::getDayOfWeek()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_wday;
+}
+String ESP32TimeHelper::getDayOfWeekString()
+{
+ getLocalTime(&timeinfo);
+ return dow[timeinfo.tm_wday];
+}
+
+int ESP32TimeHelper::getHour()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_hour;
+}
+
+int ESP32TimeHelper::getMin()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_min;
+}
+int ESP32TimeHelper::getSec()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_sec;
+}
+int ESP32TimeHelper::getNumberOfDayThisYear()
+{
+ getLocalTime(&timeinfo);
+ return timeinfo.tm_yday + 1;
+}
+
+int ESP32TimeHelper::totalDays(int y, int m, int d)
+{
+ static char daytab[2][13] =
+ {
+ {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+ int daystotal = d;
+ for (int year = 1; year <= y; year++)
+ {
+ int max_month = (year < y ? 12 : m - 1);
+ int leap = (year % 4 == 0);
+ if (year % 100 == 0 && year % 400 != 0)
+ leap = 0;
+ for (int month = 1; month <= max_month; month++)
+ {
+ daystotal += daytab[leap][month];
+ }
+ }
+ return daystotal;
+}
+int ESP32TimeHelper::getTotalDays(int year, int month, int day)
+{
+ return totalDays(year, month, day) - totalDays(1970, 1, 1);
+}
+
+int ESP32TimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */
+{
+ static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+ year -= month < 3;
+ return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
+}
+
+int ESP32TimeHelper::getCurrentSecond()
+{
+ return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec;
+}
+uint64_t ESP32TimeHelper::getCurrentTimestamp()
+{
+ return now;
+}
+void ESP32TimeHelper::getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec)
+{
+ int _yrs = secCount / (365 * 24 * 3600);
+ secCount = secCount - _yrs * (365 * 24 * 3600);
+ yrs = _yrs;
+ int _months = secCount / (30* 24 * 3600);
+ secCount = secCount - _months * (30 * 24 * 3600);
+ months = _months;
+ int _days = secCount / (24 * 3600);
+ secCount = secCount - _days * (24 * 3600);
+ days = _days;
+ int _hr = secCount / 3600;
+ secCount = secCount - _hr * 3600;
+ hr = _hr;
+ int _min = secCount / 60;
+ secCount = secCount - _min * 60;
+ min = _min;
+ sec = secCount;
+}
+
+#endif //ESP32
+
+#endif //ESP32TimeHelper_CPP
\ No newline at end of file
diff --git a/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h b/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h
new file mode 100755
index 000000000..e4feff648
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h
@@ -0,0 +1,73 @@
+/*
+ * ESP32 Internet Time Helper Arduino Library v 1.0.1
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person returning a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef ESP32TimeHelper_H
+#define ESP32TimeHelper_H
+
+#ifdef ESP32
+
+
+#include
+#include
+#include
+
+class ESP32TimeHelper
+{
+public:
+ ESP32TimeHelper();
+ bool clockReady = false;
+ bool setClock(float gmtOffset, float daylightOffset);
+ uint32_t getUnixTime();
+ time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec);
+ int getYear();
+ int getMonth();
+ int getDay();
+ int getDayOfWeek();
+ String getDayOfWeekString();
+ int getHour();
+ int getMin();
+ int getSec();
+ int getNumberOfDayThisYear();
+ int getTotalDays(int year, int month, int day);
+ int dayofWeek(int year, int month, int day);
+ int getCurrentSecond();
+ uint64_t getCurrentTimestamp();
+ void getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec);
+
+private:
+ time_t now;
+ uint64_t msec_time_diff = 0;
+ struct tm timeinfo;
+ float TZ = 0.0;
+ float DST_MN = 0.0;
+
+ bool setClock();
+ int totalDays(int y, int m, int d);
+ const char *dow[20] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"};
+};
+
+#endif //ESP32
+
+#endif //ESP32TimeHelper_H
diff --git a/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp b/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp
new file mode 100755
index 000000000..85cb0663e
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp
@@ -0,0 +1,4875 @@
+/*
+ *Mail Client Arduino Library for ESP32, version 2.1.4
+ *
+ * April 12, 2020
+ *
+ * This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers.
+ *
+ * The library supports all ESP32 MCU based modules.
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef ESP32_MailClient_CPP
+#define ESP32_MailClient_CPP
+
+#ifdef ESP32
+
+#include "ESP32_MailClient.h"
+
+struct ESP32_MailClient::IMAP_COMMAND_TYPE
+{
+ static const uint8_t LOGIN = 0;
+ static const uint8_t LIST = 1;
+ static const uint8_t SELECT = 2;
+ static const uint8_t EXAMINE = 3;
+ static const uint8_t STATUS = 4;
+ static const uint8_t SEARCH = 5;
+ static const uint8_t FETCH_BODY_HEADER = 6;
+ static const uint8_t FETCH_BODY_MIME = 7;
+ static const uint8_t FETCH_BODY_TEXT = 8;
+ static const uint8_t FETCH_BODY_ATTACHMENT = 9;
+ static const uint8_t LOGOUT = 10;
+};
+
+struct ESP32_MailClient::IMAP_HEADER_TYPE
+{
+ static const uint8_t FROM = 1;
+ static const uint8_t TO = 2;
+ static const uint8_t CC = 3;
+ static const uint8_t SUBJECT = 4;
+ static const uint8_t DATE = 5;
+ static const uint8_t MSG_ID = 6;
+ static const uint8_t CONT_LANG = 7;
+ static const uint8_t ACCEPT_LANG = 8;
+};
+
+
+
+bool ESP32_MailClient::readMail(IMAPData &imapData)
+{
+
+ std::string buf;
+ std::string command = "$";
+
+ size_t mailIndex = 0;
+ int messageDataIndex = 0;
+ int partID = 1;
+ int _partID = 1;
+ bool res = false;
+ bool _res = false;
+ bool starttls = imapData._starttls;
+ bool connected = false;
+
+ int bufSize = 50;
+
+ char *_val = new char[bufSize];
+ char *_part = new char[bufSize];
+
+ unsigned long dataTime = 0;
+
+ int count = 0;
+
+ imapData._net->setDebugCallback(NULL);
+
+ if (imapData._debug)
+ {
+ ESP32MailDebugInfo(ESP32_MAIL_STR_225);
+ ESP32MailDebug(imapData._host.c_str());
+ ESP32MailDebug(String(imapData._port).c_str());
+ }
+
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_50;
+ imapData._cbData._status = ESP32_MAIL_STR_51;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ imapData._net->setDebugCallback(ESP32MailDebug);
+
+ if (imapData._rootCA.size() > 0)
+ imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)imapData._rootCA.front());
+ else
+ imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)NULL);
+
+ while (!imapData._net->connected() && count < 10)
+ {
+
+ count++;
+
+ if (!imapData._net->connect(starttls))
+ {
+
+ _imapStatus = IMAP_STATUS_SERVER_CONNECT_FAILED;
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (!imapData._net->connect(starttls))
+ {
+ goto out;
+ }
+
+ connected = true;
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_54;
+ imapData._cbData._status = ESP32_MAIL_STR_55;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_228);
+
+ //Don't expect handshake from some servers
+ dataTime = millis();
+
+ while (imapData._net->connected() && !imapData._net->getStreamPtr()->available() && millis() - 500 < dataTime)
+ delay(0);
+
+ if (imapData._net->connected() && imapData._net->getStreamPtr()->available())
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+
+ imapData.clearMessageData();
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_56;
+ imapData._cbData._status = ESP32_MAIL_STR_57;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_229);
+
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_130);
+ imapData._net->getStreamPtr()->print(imapData._loginEmail.c_str());
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_131);
+ imapData._net->getStreamPtr()->println(imapData._loginPassword.c_str());
+
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LOGIN))
+ {
+ _imapStatus = IMAP_STATUS_LOGIN_FAILED;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._fetchUID.length() > 0)
+ imapData._headerOnly = false;
+ else
+ imapData._headerOnly = true;
+
+ if (imapData._headerOnly)
+ {
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_58;
+ imapData._cbData._status = ESP32_MAIL_STR_59;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_230);
+
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_133);
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LIST))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ imapData._cbData.empty();
+ }
+
+ if (imapData._readCallback)
+ {
+
+ imapData._cbData._info = ESP32_MAIL_STR_60;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ for (size_t i = 0; i < imapData._folders.size(); i++)
+ {
+ imapData._cbData._info = imapData._folders[i];
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ imapData._cbData._info = ESP32_MAIL_STR_61 + imapData._currentFolder + ESP32_MAIL_STR_97;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_231);
+
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_135);
+ imapData._net->getStreamPtr()->print(imapData._currentFolder.c_str());
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_136);
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::EXAMINE))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._headerOnly)
+ {
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_62 + imapData._nextUID;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ imapData._cbData._info = ESP32_MAIL_STR_63;
+ memset(_val, 0, bufSize);
+ itoa(imapData._totalMessage, _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ imapData._cbData._info = ESP32_MAIL_STR_64;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ for (size_t i = 0; i < imapData._flag.size(); i++)
+ {
+ imapData._cbData._info = imapData._flag[i];
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ imapData._cbData._info = ESP32_MAIL_STR_65;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ imapData._cbData._info = ESP32_MAIL_STR_66;
+ imapData._cbData._status = ESP32_MAIL_STR_67;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ }
+
+ imapData._msgNum.clear();
+ imapData._uidSearch = false;
+ imapData._msgID.clear();
+ imapData._contentLanguage.clear();
+ imapData._acceptLanguage.clear();
+ imapData._attachmentCount.clear();
+ imapData._totalAttachFileSize.clear();
+ imapData._downloadedByte.clear();
+ imapData._error.clear();
+ imapData._errorMsg.clear();
+ imapData._searchCount = 0;
+
+ if (imapData._headerOnly)
+ {
+
+ if (imapData._searchCriteria != "")
+ {
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_232);
+
+ if (imapData._searchCriteria.find(ESP32_MAIL_STR_137) != std::string::npos)
+ {
+ imapData._uidSearch = true;
+ command += ESP32_MAIL_STR_138;
+ }
+ command += ESP32_MAIL_STR_139;
+
+ for (size_t i = 0; i < imapData._searchCriteria.length(); i++)
+ {
+ if (imapData._searchCriteria[i] != ' ' && imapData._searchCriteria[i] != '\r' && imapData._searchCriteria[i] != '\n' && imapData._searchCriteria[i] != '$')
+ buf.append(1, imapData._searchCriteria[i]);
+
+ if (imapData._searchCriteria[i] == ' ')
+ {
+ if ((imapData._uidSearch && buf == ESP32_MAIL_STR_140) || (imapData._unseen && buf.find(ESP32_MAIL_STR_224) != std::string::npos))
+ buf.clear();
+
+ if (buf != ESP32_MAIL_STR_141 && buf != "")
+ {
+ command += ESP32_MAIL_STR_131;
+ command += buf;
+ }
+
+ buf.clear();
+ }
+ }
+
+ if (imapData._unseen && imapData._searchCriteria.find(ESP32_MAIL_STR_223) == std::string::npos)
+ command += ESP32_MAIL_STR_223;
+
+ if (buf.length() > 0)
+ {
+ command += ESP32_MAIL_STR_131;
+ command += buf;
+ }
+
+ imapData._net->getStreamPtr()->println(command.c_str());
+
+ std::string().swap(command);
+
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::SEARCH, 1))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._readCallback)
+ {
+
+ imapData._cbData._info = ESP32_MAIL_STR_68;
+ memset(_val, 0, bufSize);
+ itoa(imapData._emailNumMax, _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ if (imapData._msgNum.size() > 0)
+ {
+
+ imapData._cbData._info = ESP32_MAIL_STR_69;
+ memset(_val, 0, bufSize);
+ itoa(imapData._searchCount, _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._info += ESP32_MAIL_STR_70;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ imapData._cbData._info = ESP32_MAIL_STR_71;
+ memset(_val, 0, bufSize);
+ itoa(imapData._msgNum.size(), _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._info += ESP32_MAIL_STR_70;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ else
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_72;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ }
+ }
+ else
+ {
+
+ imapData._msgNum.push_back(imapData._totalMessage);
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_73;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ }
+ }
+ else
+ {
+
+ imapData._msgNum.push_back(atoi(imapData._fetchUID.c_str()));
+ }
+
+ for (int i = 0; i < imapData._messageDataInfo.size(); i++)
+ imapData._messageDataInfo[i].clear();
+
+ imapData._messageDataInfo.clear();
+
+ for (int i = 0; i < imapData._msgNum.size(); i++)
+ {
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_233);
+
+ if (imapData._readCallback)
+ {
+
+ imapData._cbData._info = ESP32_MAIL_STR_74;
+ memset(_val, 0, bufSize);
+ itoa(i + 1, _val, 10);
+ imapData._cbData._info += _val;
+
+ imapData._cbData._status = "";
+ if (imapData._uidSearch || imapData._fetchUID.length() > 0)
+ imapData._cbData._info += ESP32_MAIL_STR_75;
+ else
+ imapData._cbData._info += ESP32_MAIL_STR_76;
+
+ memset(_val, 0, bufSize);
+ itoa(imapData._msgNum[i], _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._status = ESP32_MAIL_STR_77;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ imapData._date.push_back(std::string());
+ imapData._subject.push_back(std::string());
+ imapData._subject_charset.push_back(std::string());
+ imapData._from.push_back(std::string());
+ imapData._from_charset.push_back(std::string());
+ imapData._to.push_back(std::string());
+ imapData._to_charset.push_back(std::string());
+ imapData._cc.push_back(std::string());
+ imapData._attachmentCount.push_back(0);
+ imapData._totalAttachFileSize.push_back(0);
+ imapData._downloadedByte.push_back(0);
+ imapData._messageDataCount.push_back(0);
+ imapData._error.push_back(false);
+ imapData._errorMsg.push_back(std::string());
+ imapData._cc_charset.push_back(std::string());
+ imapData._msgID.push_back(std::string());
+ imapData._acceptLanguage.push_back(std::string());
+ imapData._contentLanguage.push_back(std::string());
+
+ std::vector d = std::vector();
+
+ imapData._messageDataInfo.push_back(d);
+
+ std::vector().swap(d);
+
+ if (imapData._uidSearch || imapData._fetchUID.length() > 0)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142);
+ else
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143);
+
+ imapData._net->getStreamPtr()->print(imapData._msgNum[i]);
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_144);
+
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_HEADER, 0, mailIndex))
+ {
+ if (imapData._headerOnly)
+ _imapStatus = IMAP_STATUS_IMAP_RESPONSE_FAILED;
+ else
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (!imapData._headerOnly)
+ {
+
+ messageDataIndex = 0;
+ partID = 1;
+ _partID = 1;
+ res = false;
+ _res = false;
+
+ do
+ {
+
+ if (imapData._uidSearch || imapData._fetchUID.length() > 0)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142);
+ else
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143);
+
+ imapData._net->getStreamPtr()->print(imapData._msgNum[i]);
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147);
+ imapData._net->getStreamPtr()->print(partID);
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_148);
+
+ memset(_part, 0, bufSize);
+ memset(_val, 0, bufSize);
+ itoa(partID, _val, 10);
+ strcpy(_part, _val);
+ res = waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_MIME, 0, mailIndex, messageDataIndex, _part);
+ if (res)
+ {
+
+ if (imapData._messageDataInfo[mailIndex].size() < messageDataIndex + 1)
+ {
+ messageBodyData b;
+ imapData._messageDataInfo[mailIndex].push_back(b);
+ b.empty();
+ imapData._messageDataCount[mailIndex] = imapData._messageDataInfo[mailIndex].size();
+ }
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == "")
+ continue;
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType.find(ESP32_MAIL_STR_149) != std::string::npos)
+ {
+ do
+ {
+
+ if (imapData._uidSearch || imapData._fetchUID.length() > 0)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142);
+ else
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143);
+
+ imapData._net->getStreamPtr()->print(imapData._msgNum[i]);
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147);
+ imapData._net->getStreamPtr()->print(partID);
+ imapData._net->getStreamPtr()->print(".");
+ imapData._net->getStreamPtr()->print(_partID);
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_148);
+
+ memset(_part, 0, bufSize);
+ memset(_val, 0, bufSize);
+ itoa(partID, _val, 10);
+ strcpy(_part, _val);
+ strcat(_part, ".");
+ memset(_val, 0, bufSize);
+ itoa(_partID, _val, 10);
+ strcat(_part, _val);
+ _res = waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_MIME, 0, mailIndex, messageDataIndex, _part);
+
+ if (_res)
+ {
+ messageDataIndex++;
+ _partID++;
+ }
+
+ } while (_res);
+ }
+ else
+ {
+ messageDataIndex++;
+ }
+ partID++;
+ }
+
+ } while (res);
+
+ if (imapData._saveHTMLMsg || imapData._saveTextMsg || imapData._downloadAttachment)
+ {
+
+ if (!_sdOk)
+ {
+ if (imapData._storageType == MailClientStorageType::SD)
+ {
+ _sdOk = sdTest();
+ if (_sdOk)
+ if (!SD.exists(imapData._savePath.c_str()))
+ createDirs(imapData._savePath);
+ }
+ else if (imapData._storageType == MailClientStorageType::SPIFFS)
+ _sdOk = SPIFFS.begin(true);
+ }
+ }
+
+ if (imapData._messageDataInfo[mailIndex].size() > 0)
+ {
+ if (imapData._attachmentCount[mailIndex] > 0 && imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_78;
+ memset(_val, 0, bufSize);
+ itoa(imapData._attachmentCount[mailIndex], _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._info += ESP32_MAIL_STR_79;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ for (int j = 0; j < imapData._messageDataInfo[mailIndex].size(); j++)
+ {
+ if (imapData._messageDataInfo[mailIndex][j]._disposition == ESP32_MAIL_STR_153)
+ {
+ imapData._cbData._info = imapData._messageDataInfo[mailIndex][j]._filename;
+ imapData._cbData._info += ESP32_MAIL_STR_83;
+ memset(_val, 0, bufSize);
+ itoa(imapData._messageDataInfo[mailIndex][j]._size, _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._info += ESP32_MAIL_STR_82;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ }
+
+ if (imapData._downloadAttachment && _sdOk)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_80;
+ imapData._cbData._status = ESP32_MAIL_STR_81;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ }
+
+ for (int j = 0; j < imapData._messageDataInfo[mailIndex].size(); j++)
+ {
+
+ if (imapData._messageDataInfo[mailIndex][j]._disposition == "")
+ {
+
+ if (!imapData._textFormat && imapData._messageDataInfo[mailIndex][j]._contentType != ESP32_MAIL_STR_154)
+ continue;
+
+ if (!imapData._htmlFormat && imapData._messageDataInfo[mailIndex][j]._contentType != ESP32_MAIL_STR_155)
+ continue;
+
+ if (imapData._uidSearch || imapData._fetchUID.length() > 0)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142);
+ else
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143);
+
+ imapData._net->getStreamPtr()->print(imapData._msgNum[i]);
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147);
+ imapData._net->getStreamPtr()->print(imapData._messageDataInfo[mailIndex][j]._part.c_str());
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_156);
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_TEXT, imapData._message_buffer_size, mailIndex, j))
+ {
+ _imapStatus = IMAP_STATUS_IMAP_RESPONSE_FAILED;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ }
+ }
+ else if (imapData._messageDataInfo[mailIndex][j]._disposition == ESP32_MAIL_STR_153 && _sdOk)
+ {
+
+ if (imapData._downloadAttachment)
+ {
+ if (imapData._messageDataInfo[mailIndex][j]._size <= imapData._attacement_max_size)
+ {
+
+ if (_sdOk)
+ {
+
+ if (j < imapData._messageDataInfo[mailIndex].size() - 1)
+ if (imapData._messageDataInfo[mailIndex][j + 1]._size > imapData._attacement_max_size)
+ imapData._downloadedByte[mailIndex] += imapData._messageDataInfo[mailIndex][j + 1]._size;
+
+ if (imapData._uidSearch || imapData._fetchUID.length() > 0)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142);
+ else
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143);
+
+ imapData._net->getStreamPtr()->print(imapData._msgNum[i]);
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147);
+ imapData._net->getStreamPtr()->print(imapData._messageDataInfo[mailIndex][j]._part.c_str());
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_156);
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT, imapData._message_buffer_size, mailIndex, j))
+ {
+ _imapStatus = IMAP_STATUS_IMAP_RESPONSE_FAILED;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ }
+
+ delay(0);
+ }
+ }
+ else
+ {
+ if (j == imapData._messageDataInfo[mailIndex].size() - 1)
+ imapData._downloadedByte[mailIndex] += imapData._messageDataInfo[mailIndex][j]._size;
+ }
+ }
+ }
+ }
+ }
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ {
+ if (_sdOk)
+ SD.end();
+ }
+ else if (imapData._storageType == MailClientStorageType::SPIFFS)
+ {
+ if (_sdOk)
+ SPIFFS.end();
+ }
+
+ _sdOk = false;
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_84;
+ memset(_val, 0, bufSize);
+ itoa(ESP.getFreeHeap(), _val, 10);
+ imapData._cbData._info += _val;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ mailIndex++;
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_85;
+ imapData._cbData._status = ESP32_MAIL_STR_86;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_234);
+
+ if (imapData._net->connected())
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_146);
+
+ if (!waitIMAPResponse(imapData, 0))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_98;
+ imapData._cbData._status = ESP32_MAIL_STR_96;
+ imapData._cbData._success = true;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_235);
+
+ if (imapData._net->connected())
+ {
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+
+ imapData._net->getStreamPtr()->stop();
+ }
+
+ imapData._cbData.empty();
+ delete[] _val;
+ delete[] _part;
+ std::string().swap(command);
+ std::string().swap(buf);
+
+ return true;
+
+out:
+
+ if (connected)
+ {
+ if (imapData._net->connected())
+ {
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+ imapData._net->getStreamPtr()->stop();
+ }
+ }
+
+ imapData._cbData.empty();
+ delete[] _val;
+ delete[] _part;
+ std::string().swap(command);
+ std::string().swap(buf);
+
+ return false;
+}
+
+bool ESP32_MailClient::setFlag(IMAPData &imapData, int msgUID, const String &flag)
+{
+ return _setFlag(imapData, msgUID, flag, 0);
+}
+
+bool ESP32_MailClient::addFlag(IMAPData &imapData, int msgUID, const String &flag)
+{
+ return _setFlag(imapData, msgUID, flag, 1);
+}
+
+bool ESP32_MailClient::removeFlag(IMAPData &imapData, int msgUID, const String &flag)
+{
+ return _setFlag(imapData, msgUID, flag, 2);
+}
+
+bool ESP32_MailClient::_setFlag(IMAPData &imapData, int msgUID, const String &flag, uint8_t action)
+{
+
+ std::string buf;
+
+ bool starttls = imapData._starttls;
+ bool connected = false;
+
+ int bufSize = 50;
+
+ char *_val = new char[bufSize];
+ char *_part = new char[bufSize];
+
+ unsigned long dataTime = 0;
+
+ int count = 0;
+
+ imapData._net->setDebugCallback(NULL);
+
+ if (imapData._debug)
+ {
+ ESP32MailDebugInfo(ESP32_MAIL_STR_225);
+ ESP32MailDebug(imapData._host.c_str());
+ ESP32MailDebug(String(imapData._port).c_str());
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_50;
+ imapData._cbData._status = ESP32_MAIL_STR_51;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ imapData._net->setDebugCallback(ESP32MailDebug);
+
+ if (imapData._rootCA.size() > 0)
+ imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)imapData._rootCA.front());
+ else
+ imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)NULL);
+
+ while (!imapData._net->connected() && count < 10)
+ {
+
+ count++;
+
+ if (!imapData._net->connect(starttls))
+ {
+
+ _imapStatus = IMAP_STATUS_SERVER_CONNECT_FAILED;
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (!imapData._net->connect(starttls))
+ {
+ goto out;
+ }
+
+ connected = true;
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_54;
+ imapData._cbData._status = ESP32_MAIL_STR_55;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_228);
+
+ //Don't expect handshake from some servers
+ dataTime = millis();
+
+ while (imapData._net->connected() && !imapData._net->getStreamPtr()->available() && millis() - 500 < dataTime)
+ delay(0);
+
+ if (imapData._net->connected() && imapData._net->getStreamPtr()->available())
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+
+ imapData.clearMessageData();
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_56;
+ imapData._cbData._status = ESP32_MAIL_STR_57;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_229);
+
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_130);
+ imapData._net->getStreamPtr()->print(imapData._loginEmail.c_str());
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_131);
+ imapData._net->getStreamPtr()->println(imapData._loginPassword.c_str());
+
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LOGIN))
+ {
+ _imapStatus = IMAP_STATUS_LOGIN_FAILED;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_58;
+ imapData._cbData._status = ESP32_MAIL_STR_59;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_230);
+
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_133);
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LIST))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ imapData._cbData.empty();
+ }
+
+ if (imapData._readCallback)
+ {
+
+ imapData._cbData._info = ESP32_MAIL_STR_60;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+
+ for (size_t i = 0; i < imapData._folders.size(); i++)
+ {
+ imapData._cbData._info = imapData._folders[i];
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ imapData._cbData._info = ESP32_MAIL_STR_61 + imapData._currentFolder + ESP32_MAIL_STR_97;
+ imapData._cbData._status = "";
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_248);
+
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_247);
+ imapData._net->getStreamPtr()->print(imapData._currentFolder.c_str());
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_136);
+ if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::EXAMINE))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._debug)
+ {
+ if (action == 0)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_253);
+ else if (action == 1)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_254);
+ else
+ ESP32MailDebugInfo(ESP32_MAIL_STR_255);
+ }
+
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_249);
+ imapData._net->getStreamPtr()->print(msgUID);
+ if (action == 0)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_250);
+ else if (action == 1)
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_251);
+ else
+ imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_252);
+ imapData._net->getStreamPtr()->print(flag);
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_192);
+
+ if (!getIMAPResponse(imapData))
+ {
+ _imapStatus = IMAP_STATUS_PARSE_FLAG_FAILED;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_85;
+ imapData._cbData._status = ESP32_MAIL_STR_86;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_234);
+
+ if (imapData._net->connected())
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+
+ imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_146);
+
+ if (!waitIMAPResponse(imapData, 0))
+ {
+ _imapStatus = IMAP_STATUS_BAD_COMMAND;
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr();
+ imapData._cbData._status = ESP32_MAIL_STR_52;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+ if (imapData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(imapErrorReasonStr().c_str(), true);
+ }
+ goto out;
+ }
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = ESP32_MAIL_STR_98;
+ imapData._cbData._status = ESP32_MAIL_STR_96;
+ imapData._cbData._success = true;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ if (imapData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_235);
+
+ if (imapData._net->connected())
+ {
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+
+ imapData._net->getStreamPtr()->stop();
+ }
+
+ imapData._cbData.empty();
+ delete[] _val;
+ delete[] _part;
+ std::string().swap(buf);
+
+ return true;
+
+out:
+
+ if (connected)
+ {
+ if (imapData._net->connected())
+ {
+ while (imapData._net->getStreamPtr()->available())
+ imapData._net->getStreamPtr()->read();
+ imapData._net->getStreamPtr()->stop();
+ }
+ }
+
+ imapData._cbData.empty();
+ delete[] _val;
+ delete[] _part;
+ std::string().swap(buf);
+ return false;
+}
+
+
+bool ESP32_MailClient::smtpClientAvailable(SMTPData &smtpData, bool available)
+{
+
+ if (!smtpData._net->getStreamPtr())
+ return false;
+
+ if (available)
+ return smtpData._net->getStreamPtr()->connected() && smtpData._net->getStreamPtr()->available();
+ else
+ return smtpData._net->getStreamPtr()->connected() && !smtpData._net->getStreamPtr()->available();
+}
+
+bool ESP32_MailClient::imapClientAvailable(IMAPData &imapData, bool available)
+{
+
+ if (!imapData._net->getStreamPtr())
+ return false;
+
+ if (available)
+ return imapData._net->getStreamPtr()->connected() && imapData._net->getStreamPtr()->available();
+ else
+ return imapData._net->getStreamPtr()->connected() && !imapData._net->getStreamPtr()->available();
+}
+
+void ESP32_MailClient::createDirs(std::string dirs)
+{
+ std::string dir = "";
+ int count = 0;
+ for (int i = 0; i < dirs.length(); i++)
+ {
+ dir.append(1, dirs[i]);
+ count++;
+ if (dirs[i] == '/')
+ {
+ if (dir.length() > 0)
+ SD.mkdir(dir.substr(0, dir.length() - 1).c_str());
+ count = 0;
+ }
+ }
+ if (count > 0)
+ SD.mkdir(dir.c_str());
+ std::string().swap(dir);
+}
+
+bool ESP32_MailClient::sdTest()
+{
+
+ if (_sdConfigSet)
+ sdBegin(_sck, _miso, _mosi, _ss);
+ else
+ sdBegin();
+
+ File file = SD.open(ESP32_MAIL_STR_204, FILE_WRITE);
+ if (!file)
+ return false;
+
+ if (!file.write(32))
+ return false;
+ file.close();
+
+ file = SD.open(ESP32_MAIL_STR_204);
+ if (!file)
+ return false;
+
+ while (file.available())
+ {
+ if (file.read() != 32)
+ return false;
+ }
+ file.close();
+
+ SD.remove(ESP32_MAIL_STR_204);
+
+ return true;
+}
+
+bool ESP32_MailClient::sendMail(SMTPData &smtpData)
+{
+
+ _smtpStatus = 0;
+ std::string buf;
+ std::string buf2;
+ int bufSize = 50;
+ bool starttls = smtpData._starttls;
+ bool connected = false;
+ char *_val = new char[bufSize];
+ int res = 0;
+
+ smtpData._net->setDebugCallback(NULL);
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_120;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ {
+ ESP32MailDebugInfo(ESP32_MAIL_STR_236);
+ ESP32MailDebug(smtpData._host.c_str());
+ ESP32MailDebug(String(smtpData._port).c_str());
+ }
+
+
+ if (smtpData._debug)
+ smtpData._net->setDebugCallback(ESP32MailDebug);
+
+ if (smtpData._rootCA.size() > 0)
+ smtpData._net->begin(smtpData._host.c_str(), smtpData._port, ESP32_MAIL_STR_202, (const char *)smtpData._rootCA.front());
+ else
+ smtpData._net->begin(smtpData._host.c_str(), smtpData._port, ESP32_MAIL_STR_202, (const char *)NULL);
+
+ if (smtpData._port == 587)
+ starttls = true;
+
+ if (!smtpData._net->connect(starttls))
+ {
+ _smtpStatus = SMTP_STATUS_SERVER_CONNECT_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_238);
+
+ connected = true;
+
+ if (!starttls)
+ {
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_121;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (waitSMTPResponse(smtpData) != 220)
+ {
+ _smtpStatus = SMTP_STATUS_SMTP_RESPONSE_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+ }
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_122;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_239);
+
+ smtpData._net->getStreamPtr()->println(ESP32_MAIL_STR_5);
+
+ if (waitSMTPResponse(smtpData) != 250)
+ {
+ _smtpStatus = SMTP_STATUS_IDENTIFICATION_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_123;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_240);
+
+ smtpData._net->getStreamPtr()->println(ESP32_MAIL_STR_4);
+
+ if (waitSMTPResponse(smtpData) != 334)
+ {
+ _smtpStatus = SMTP_STATUS_AUTHEN_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_124;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_241);
+
+ smtpData._net->getStreamPtr()->println(base64_encode_string((const unsigned char *)smtpData._loginEmail.c_str(), smtpData._loginEmail.length()).c_str());
+
+ if (waitSMTPResponse(smtpData) != 334)
+ {
+ _smtpStatus = SMTP_STATUS_USER_LOGIN_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ smtpData._net->getStreamPtr()->println(base64_encode_string((const unsigned char *)smtpData._loginPassword.c_str(), smtpData._loginPassword.length()).c_str());
+
+ if (waitSMTPResponse(smtpData) != 235)
+ {
+ _smtpStatus = SMTP_STATUS_PASSWORD_LOGIN_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_125;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_242);
+
+ if (smtpData._priority > 0 && smtpData._priority <= 5)
+ {
+ memset(_val, 0, bufSize);
+ itoa(smtpData._priority, _val, 10);
+
+ buf2 += ESP32_MAIL_STR_17;
+ buf2 += _val;
+ buf2 += ESP32_MAIL_STR_34;
+
+ if (smtpData._priority == 1)
+ {
+ buf2 += ESP32_MAIL_STR_18;
+ buf2 += ESP32_MAIL_STR_21;
+ }
+ else if (smtpData._priority == 3)
+ {
+ buf2 += ESP32_MAIL_STR_19;
+ buf2 += ESP32_MAIL_STR_22;
+ }
+ else if (smtpData._priority == 5)
+ {
+ buf2 += ESP32_MAIL_STR_20;
+ buf2 += ESP32_MAIL_STR_23;
+ }
+ }
+
+ buf2 += ESP32_MAIL_STR_10;
+
+ if (smtpData._fromName.length() > 0)
+ buf2 += smtpData._fromName;
+
+ buf2 += ESP32_MAIL_STR_14;
+ buf2 += smtpData._senderEmail;
+ buf2 += ESP32_MAIL_STR_15;
+ buf2 += ESP32_MAIL_STR_34;
+
+ buf += ESP32_MAIL_STR_8;
+ buf += ESP32_MAIL_STR_14;
+ buf += smtpData._senderEmail;
+ buf += ESP32_MAIL_STR_15;
+ smtpData._net->getStreamPtr()->println(buf.c_str());
+
+ if (waitSMTPResponse(smtpData) != 250)
+ {
+ _smtpStatus = SMTP_STATUS_SEND_HEADER_SENDER_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ for (uint8_t i = 0; i < smtpData._recipient.size(); i++)
+ {
+ if (i == 0)
+ {
+ buf2 += ESP32_MAIL_STR_11;
+ buf2 += ESP32_MAIL_STR_14;
+ buf2 += smtpData._recipient[i];
+ buf2 += ESP32_MAIL_STR_15;
+ }
+ else
+ {
+ buf2 += ESP32_MAIL_STR_13;
+ buf2 += smtpData._recipient[i];
+ buf2 += ESP32_MAIL_STR_15;
+ }
+
+ if (i == smtpData._recipient.size() - 1)
+ buf2 += ESP32_MAIL_STR_34;
+
+ buf.clear();
+
+ buf += ESP32_MAIL_STR_9;
+ buf += ESP32_MAIL_STR_14;
+ buf += smtpData._recipient[i];
+ buf += ESP32_MAIL_STR_15;
+
+ smtpData._net->getStreamPtr()->println(buf.c_str());
+
+ if (waitSMTPResponse(smtpData) != 250)
+ {
+ _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+ }
+
+ for (uint8_t i = 0; i < smtpData._cc.size(); i++)
+ {
+
+ if (i == 0)
+ {
+ buf2 += ESP32_MAIL_STR_12;
+ buf2 += ESP32_MAIL_STR_14;
+ buf2 += smtpData._cc[i];
+ buf2 += ESP32_MAIL_STR_15;
+ }
+ else
+ {
+ buf2 += ESP32_MAIL_STR_13;
+ buf2 += smtpData._cc[i];
+ buf2 += ESP32_MAIL_STR_15;
+ }
+
+ if (i == smtpData.ccCount() - 1)
+ buf2 += ESP32_MAIL_STR_34;
+
+ buf.clear();
+
+ buf += ESP32_MAIL_STR_9;
+ buf += ESP32_MAIL_STR_14;
+ buf += smtpData._cc[i];
+ buf += ESP32_MAIL_STR_15;
+ smtpData._net->getStreamPtr()->println(buf.c_str());
+
+ if (waitSMTPResponse(smtpData) != 250)
+ {
+ _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+ }
+
+ for (uint8_t i = 0; i < smtpData._bcc.size(); i++)
+ {
+ buf.clear();
+ buf += ESP32_MAIL_STR_9;
+ buf += ESP32_MAIL_STR_14;
+ buf += smtpData._bcc[i];
+ buf += ESP32_MAIL_STR_15;
+ smtpData._net->getStreamPtr()->println(buf.c_str());
+
+ if (waitSMTPResponse(smtpData) != 250)
+ {
+ _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+ }
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_126;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_243);
+
+ smtpData._net->getStreamPtr()->println(ESP32_MAIL_STR_16);
+
+ if (waitSMTPResponse(smtpData) != 354)
+ {
+ _smtpStatus = SMTP_STATUS_SEND_BODY_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ smtpData._net->getStreamPtr()->print(buf2.c_str());
+
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_24);
+ smtpData._net->getStreamPtr()->println(smtpData._subject.c_str());
+
+ if (smtpData._customMessageHeader.size() > 0)
+ for (uint8_t k = 0; k < smtpData._customMessageHeader.size(); k++)
+ smtpData._net->getStreamPtr()->println(smtpData._customMessageHeader[k].c_str());
+
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_3);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_1);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_2);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_35);
+
+ buf.clear();
+
+ set_message_header(buf, smtpData._message, smtpData._htmlFormat);
+
+ smtpData._net->getStreamPtr()->print(buf.c_str());
+
+ if (smtpData._attach._index > 0)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_127;
+ smtpData._cbData._success = false;
+ if (smtpData._sendCallback)
+ smtpData._sendCallback(smtpData._cbData);
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_244);
+ }
+
+ for (uint8_t i = 0; i < smtpData._attach._index; i++)
+ {
+ if (smtpData._attach._type[i] == 0)
+ {
+
+ smtpData._cbData._info = smtpData._attach._filename[i];
+ smtpData._cbData._success = false;
+ if (smtpData._sendCallback)
+ smtpData._sendCallback(smtpData._cbData);
+ if (smtpData._debug)
+ ESP32MailDebug(smtpData._attach._filename[i].c_str());
+
+ buf.clear();
+ set_attachment_header(i, buf, smtpData._attach);
+ smtpData._net->getStreamPtr()->print(buf.c_str());
+ send_base64_encode_mime_data(smtpData._net->getStreamPtr(), smtpData._attach._buf[i].front(), smtpData._attach._size[i]);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_34);
+ }
+ else
+ {
+
+ if (!_sdOk)
+ {
+ if (smtpData._storageType == MailClientStorageType::SD)
+ _sdOk = sdTest();
+ else if (smtpData._storageType == MailClientStorageType::SPIFFS)
+ _sdOk = SPIFFS.begin(true);
+ }
+
+ if (!_sdOk)
+ continue;
+
+ bool file_existed = false;
+ if (smtpData._storageType == MailClientStorageType::SD)
+ file_existed = SD.exists(smtpData._attach._filename[i].c_str());
+ else if (smtpData._storageType == MailClientStorageType::SPIFFS)
+ file_existed = SPIFFS.exists(smtpData._attach._filename[i].c_str());
+
+ if (file_existed)
+ {
+ smtpData._cbData._info = smtpData._attach._filename[i];
+ smtpData._cbData._success = false;
+ if (smtpData._sendCallback)
+ smtpData._sendCallback(smtpData._cbData);
+
+ if (smtpData._debug)
+ ESP32MailDebug(smtpData._attach._filename[i].c_str());
+
+ buf.clear();
+ set_attachment_header(i, buf, smtpData._attach);
+ smtpData._net->getStreamPtr()->print(buf.c_str());
+
+ File file;
+ if (smtpData._storageType == MailClientStorageType::SD)
+ file = SD.open(smtpData._attach._filename[i].c_str(), FILE_READ);
+ else if (smtpData._storageType == MailClientStorageType::SPIFFS)
+ file = SPIFFS.open(smtpData._attach._filename[i].c_str(), FILE_READ);
+
+ send_base64_encode_mime_file(smtpData._net->getStreamPtr(), file);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_34);
+ }
+ }
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_245);
+
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_33);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_2);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_33);
+ smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_37);
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_128;
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ res = waitSMTPResponse(smtpData);
+
+ if (res != 250 && res != -1000)
+ {
+ _smtpStatus = SMTP_STATUS_SEND_BODY_FAILED;
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr();
+ smtpData._cbData._success = false;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+ if (smtpData._debug)
+ {
+ ESP32MailDebugError();
+ ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true);
+ }
+ goto failed;
+ }
+
+ if (smtpData._sendCallback)
+ {
+ smtpData._cbData._info = ESP32_MAIL_STR_129;
+ smtpData._cbData._success = true;
+ smtpData._sendCallback(smtpData._cbData);
+ }
+
+ if (smtpData._debug)
+ ESP32MailDebugInfo(ESP32_MAIL_STR_246);
+
+ if (smtpData._net->connected())
+ smtpData._net->getStreamPtr()->stop();
+
+ smtpData._cbData.empty();
+
+ std::string().swap(buf);
+ std::string().swap(buf2);
+ delete[] _val;
+
+ return true;
+
+failed:
+
+ if (connected)
+ {
+ if (smtpData._net->connected())
+ smtpData._net->getStreamPtr()->stop();
+ }
+
+ smtpData._cbData.empty();
+ std::string().swap(buf);
+ std::string().swap(buf2);
+ delete[] _val;
+ return false;
+}
+
+String ESP32_MailClient::smtpErrorReason()
+{
+ return smtpErrorReasonStr().c_str();
+}
+
+std::string ESP32_MailClient::smtpErrorReasonStr()
+{
+ std::string res = "";
+ switch (_smtpStatus)
+ {
+ case SMTP_STATUS_SERVER_CONNECT_FAILED:
+ res = ESP32_MAIL_STR_38;
+ break;
+ case SMTP_STATUS_SMTP_RESPONSE_FAILED:
+ res = ESP32_MAIL_STR_39;
+ break;
+ case SMTP_STATUS_IDENTIFICATION_FAILED:
+ res = ESP32_MAIL_STR_41;
+ break;
+ case SMTP_STATUS_AUTHEN_NOT_SUPPORT:
+ res = ESP32_MAIL_STR_42;
+ break;
+ case SMTP_STATUS_AUTHEN_FAILED:
+ res = ESP32_MAIL_STR_43;
+ break;
+ case SMTP_STATUS_USER_LOGIN_FAILED:
+ res = ESP32_MAIL_STR_44;
+ break;
+ case SMTP_STATUS_PASSWORD_LOGIN_FAILED:
+ res = ESP32_MAIL_STR_47;
+ break;
+ case SMTP_STATUS_SEND_HEADER_SENDER_FAILED:
+ res = ESP32_MAIL_STR_48;
+ break;
+ case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED:
+ res = ESP32_MAIL_STR_222;
+ break;
+ case SMTP_STATUS_SEND_BODY_FAILED:
+ res = ESP32_MAIL_STR_49;
+ break;
+ case MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL:
+ res = ESP32_MAIL_STR_221;
+ break;
+ default:
+ res = "";
+ }
+ return res;
+}
+
+String ESP32_MailClient::imapErrorReason()
+{
+ std::string res = "";
+ switch (_imapStatus)
+ {
+ case IMAP_STATUS_SERVER_CONNECT_FAILED:
+ res = ESP32_MAIL_STR_38;
+ break;
+ case IMAP_STATUS_IMAP_RESPONSE_FAILED:
+ res = ESP32_MAIL_STR_40;
+ break;
+ case IMAP_STATUS_LOGIN_FAILED:
+ res = ESP32_MAIL_STR_45;
+ break;
+ case IMAP_STATUS_BAD_COMMAND:
+ res = ESP32_MAIL_STR_46;
+ break;
+ case IMAP_STATUS_PARSE_FLAG_FAILED:
+ res = ESP32_MAIL_STR_256;
+ break;
+ case MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL:
+ res = ESP32_MAIL_STR_221;
+ break;
+ default:
+ res = "";
+ }
+ return res.c_str();
+}
+
+std::string ESP32_MailClient::imapErrorReasonStr()
+{
+ std::string res = "";
+
+ switch (_imapStatus)
+ {
+ case IMAP_STATUS_SERVER_CONNECT_FAILED:
+ res = ESP32_MAIL_STR_38;
+ break;
+ case IMAP_STATUS_IMAP_RESPONSE_FAILED:
+ res = ESP32_MAIL_STR_40;
+ break;
+ case IMAP_STATUS_LOGIN_FAILED:
+ res = ESP32_MAIL_STR_45;
+ break;
+ case IMAP_STATUS_BAD_COMMAND:
+ res = ESP32_MAIL_STR_46;
+ break;
+ case IMAP_STATUS_PARSE_FLAG_FAILED:
+ res = ESP32_MAIL_STR_256;
+ break;
+ case MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL:
+ res = ESP32_MAIL_STR_221;
+ break;
+ default:
+ res = "";
+ }
+ return res;
+}
+
+void ESP32_MailClient::ESP32MailDebugError()
+{
+ size_t dbgInfoLen = strlen_P(ESP32_MAIL_STR_227) + 1;
+ char *dbgInfo = new char[dbgInfoLen];
+ memset(dbgInfo, 0, dbgInfoLen);
+ strcpy_P(dbgInfo, ESP32_MAIL_STR_227);
+ ESP32MailDebugLine(dbgInfo, false);
+ delete[] dbgInfo;
+}
+
+void ESP32_MailClient::ESP32MailDebugInfo(PGM_P info)
+{
+ size_t dbgInfoLen = strlen_P(info) + 1;
+ char *dbgInfo = new char[dbgInfoLen];
+ memset(dbgInfo, 0, dbgInfoLen);
+ strcpy_P(dbgInfo, info);
+ ESP32MailDebug(dbgInfo);
+ delete[] dbgInfo;
+}
+
+bool ESP32_MailClient::sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss)
+{
+ _sck = sck;
+ _miso = miso;
+ _mosi = mosi;
+ _ss = ss;
+ _sdConfigSet = true;
+ SPI.begin(_sck, _miso, _mosi, _ss);
+ return SD.begin(_ss, SPI);
+}
+
+bool ESP32_MailClient::sdBegin(void)
+{
+ _sdConfigSet = false;
+ return SD.begin();
+}
+
+void ESP32_MailClient::set_message_header(string &header, string &message, bool htmlFormat)
+{
+ header += ESP32_MAIL_STR_33;
+ header += ESP32_MAIL_STR_2;
+ header += ESP32_MAIL_STR_34;
+ if (!htmlFormat)
+ header += ESP32_MAIL_STR_27;
+ else
+ header += ESP32_MAIL_STR_28;
+
+ header += ESP32_MAIL_STR_29;
+ header += ESP32_MAIL_STR_34;
+
+ header += message;
+ header += ESP32_MAIL_STR_34;
+ header += ESP32_MAIL_STR_34;
+}
+
+void ESP32_MailClient::set_attachment_header(uint8_t index, std::string &header, attachmentData &attach)
+{
+
+ header += ESP32_MAIL_STR_33;
+ header += ESP32_MAIL_STR_2;
+ header += ESP32_MAIL_STR_34;
+
+ header += ESP32_MAIL_STR_25;
+
+ if (attach._mime_type[index].length() == 0)
+ header += ESP32_MAIL_STR_32;
+ else
+ header += attach._mime_type[index];
+
+ header += ESP32_MAIL_STR_26;
+
+ std::string filename(attach._filename[index]);
+
+ size_t found = filename.find_last_of("/\\");
+
+ if (found != std::string::npos)
+ {
+ filename.clear();
+ filename += attach._filename[index].substr(found + 1);
+ }
+
+ header += filename;
+ header += ESP32_MAIL_STR_36;
+
+ header += ESP32_MAIL_STR_30;
+ header += filename;
+ header += ESP32_MAIL_STR_36;
+
+ header += ESP32_MAIL_STR_31;
+ header += ESP32_MAIL_STR_34;
+
+ std::string().swap(filename);
+}
+
+int ESP32_MailClient::waitSMTPResponse(SMTPData &smtpData)
+{
+
+ long dataTime = millis();
+ char c = '\0';
+ std::string lineBuf = "";
+ int lfCount = 0;
+ size_t p1 = 0;
+ int resCode = -1000;
+
+ while (smtpClientAvailable(smtpData, false) && millis() - dataTime < smtpData._net->tcpTimeout)
+ delay(0);
+
+ dataTime = millis();
+ if (smtpClientAvailable(smtpData, true))
+ {
+ while (smtpClientAvailable(smtpData, true))
+ {
+ int r = smtpData._net->getStreamPtr()->read();
+
+ if (r < 0)
+ continue;
+
+ c = (char)r;
+
+ lineBuf.append(1, c);
+ if (c == '\n')
+ {
+ dataTime = millis();
+ if (lfCount == 0)
+ {
+ p1 = lineBuf.find(" ");
+ if (p1 != std::string::npos)
+ resCode = atoi(lineBuf.substr(0, p1).c_str());
+ }
+ if (smtpData._debug)
+ ESP32MailDebug(lineBuf.c_str());
+ lineBuf.clear();
+ lfCount++;
+ }
+
+ if (millis() - dataTime > smtpData._net->tcpTimeout + 30000)
+ break;
+ }
+ }
+ std::string().swap(lineBuf);
+ return resCode;
+}
+
+bool ESP32_MailClient::getIMAPResponse(IMAPData &imapData)
+{
+ long dataTime = millis();
+ char c = '\0';
+ bool success = false;
+ std::string str = "";
+ while (imapClientAvailable(imapData, false) && millis() - dataTime < imapData._net->tcpTimeout)
+ delay(0);
+
+ dataTime = millis();
+ if (imapClientAvailable(imapData, true))
+ {
+ while (imapClientAvailable(imapData, true))
+ {
+ int r = imapData._net->getStreamPtr()->read();
+ if (r < 0)
+ continue;
+ c = (char)r;
+ if (c == '\n')
+ {
+ if (imapData._debug)
+ ESP32MailDebug(str.c_str());
+ str.clear();
+ }
+ else
+ str += c;
+
+ if (str.find(ESP32_MAIL_STR_132) != std::string::npos)
+ success = true;
+ }
+ }
+
+ std::string().swap(str);
+ return success;
+}
+
+bool ESP32_MailClient::waitIMAPResponse(IMAPData &imapData, uint8_t imapCommandType, int maxChar, int mailIndex, int messageDataIndex, std::string part)
+{
+
+ long dataTime = millis();
+
+ char c = 0;
+ std::string lineBuf = "";
+ std::string msgNumBuf = "";
+ std::string filepath = "";
+ std::string hpath = "";
+ std::string tmp = "";
+ std::string msgID = "";
+ std::string from = "";
+ std::string to = "";
+ std::string subject = "";
+ std::string date = "";
+ std::string cc = "";
+ std::string from_charset = "";
+ std::string to_charset = "";
+ std::string cc_charset = "";
+ std::string subject_charset = "";
+ std::string acceptLanguage = "";
+ std::string contentLanguage = "";
+
+ int bufSize = 100;
+ char *dest = new char[bufSize];
+ char *buf = new char[bufSize];
+
+ int readCount = 0;
+ int lfCount = 0;
+ int charCount = 0;
+ size_t p1 = 0;
+ size_t p2 = 0;
+ size_t p3 = 0;
+ size_t payloadLength = 0;
+ size_t outputLength;
+
+ bool completeResp = false;
+ bool validResponse = false;
+ bool downloadReq = false;
+ size_t currentDownloadByte = 0;
+
+ int max = imapData._emailNumMax;
+ if (!imapData._recentSort)
+ max = max - 1;
+
+ uint8_t headerType = 0;
+
+ File file;
+ int reportState = 0;
+ int downloadedByte = 0;
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::LIST)
+ std::vector()
+ .swap(imapData._folders);
+
+ while (imapClientAvailable(imapData, false) && millis() - dataTime < imapData._net->tcpTimeout)
+ delay(0);
+
+ dataTime = millis();
+ if (imapClientAvailable(imapData, true))
+ {
+ while (imapClientAvailable(imapData, true) || !completeResp)
+ {
+
+ int r = imapData._net->getStreamPtr()->read();
+
+ if (r < 0)
+ continue;
+
+ c = (char)r;
+
+ if (payloadLength > 0 && !completeResp)
+ charCount++;
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount == 0)
+ {
+ delay(0);
+ if (c == ' ')
+ {
+ p3 = msgNumBuf.find(ESP32_MAIL_STR_257);
+ if (p3 != std::string::npos)
+ {
+ validResponse = false;
+ break;
+ }
+
+ if (msgNumBuf != ESP32_MAIL_STR_183 && msgNumBuf != ESP32_MAIL_STR_141 && imapData._msgNum.size() <= max)
+ {
+ imapData._msgNum.push_back(atoi(msgNumBuf.c_str()));
+
+ if (imapData._msgNum.size() > imapData._emailNumMax && imapData._recentSort)
+ imapData._msgNum.erase(imapData._msgNum.begin());
+ imapData._searchCount++;
+ }
+
+ msgNumBuf.clear();
+ }
+ else if (c != '\r' && c != '\n')
+ {
+ msgNumBuf.append(1, c);
+ }
+ }
+
+ if (c != '\r' && c != '\n' && imapCommandType != IMAP_COMMAND_TYPE::SEARCH)
+ lineBuf.append(1, c);
+
+ if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT && lfCount > 0)
+ {
+
+ if (payloadLength > 0 && charCount < payloadLength - 1)
+ {
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding != ESP32_MAIL_STR_160)
+ {
+ if (charCount < maxChar)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._text.append(1, c);
+
+ if (imapData._saveHTMLMsg || imapData._saveTextMsg)
+ {
+
+ if (!imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true;
+
+ if (_sdOk)
+ {
+ downloadReq = true;
+
+ filepath.clear();
+
+ filepath = imapData._savePath;
+ filepath += ESP32_MAIL_STR_202;
+
+ char *midx = new char[50];
+ memset(midx, 0, 50);
+ itoa(imapData._msgNum[mailIndex], midx, 10);
+
+ filepath += midx;
+
+ delete[] midx;
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ if (!SD.exists(filepath.c_str()))
+ createDirs(filepath);
+
+ if (!imapData._headerSaved)
+ hpath = filepath + ESP32_MAIL_STR_203;
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_155)
+ {
+ if (imapData._saveDecodedText)
+ filepath += ESP32_MAIL_STR_161;
+ else
+ filepath += ESP32_MAIL_STR_162;
+ }
+ else if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_154)
+ {
+ if (imapData._saveDecodedHTML)
+ filepath += ESP32_MAIL_STR_163;
+ else
+ filepath += ESP32_MAIL_STR_164;
+ }
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ file = SD.open(filepath.c_str(), FILE_WRITE);
+ else if (imapData._storageType == MailClientStorageType::SPIFFS)
+ file = SPIFFS.open(filepath.c_str(), FILE_WRITE);
+ }
+ else
+ {
+
+ if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true;
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear();
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_89;
+ }
+ }
+ }
+ if (_sdOk)
+ file.write(c);
+ }
+ }
+ }
+
+ if (millis() - dataTime > imapData._net->tcpTimeout + (30 * 1000) || (payloadLength > 0 && charCount == payloadLength && completeResp))
+ {
+
+ if (charCount < payloadLength || !completeResp)
+ clientReadAll(imapData._net->getStreamPtr());
+
+ break;
+ }
+ }
+
+ if (c == '\n')
+ {
+ dataTime = millis();
+
+ if (lfCount == 0)
+ {
+ if (imapData._debug)
+ ESP32MailDebug(lineBuf.c_str());
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT ||
+ imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME ||
+ imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER ||
+ imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT)
+ {
+
+ p1 = lineBuf.find(ESP32_MAIL_STR_165);
+ if (p1 != std::string::npos)
+ validResponse = true;
+ }
+
+ p1 = lineBuf.find(ESP32_MAIL_STR_166);
+ if (p1 != std::string::npos)
+ validResponse = true;
+ }
+
+ p1 = lineBuf.find(ESP32_MAIL_STR_211);
+ p2 = lineBuf.find(ESP32_MAIL_STR_158);
+ p3 = lineBuf.find(ESP32_MAIL_STR_159);
+
+ if (p1 != std::string::npos || p2 != std::string::npos || p3 != std::string::npos)
+ {
+
+ validResponse = true;
+
+ if (p2 != std::string::npos || p3 != std::string::npos)
+ validResponse = false;
+
+ if (payloadLength == 0)
+ {
+ if (imapCommandType == IMAP_COMMAND_TYPE::LOGIN ||
+ imapCommandType == IMAP_COMMAND_TYPE::LIST ||
+ imapCommandType == IMAP_COMMAND_TYPE::EXAMINE ||
+ imapCommandType == IMAP_COMMAND_TYPE::SEARCH ||
+ imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME ||
+ imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER)
+ {
+
+ //Cyrus server 3.0 does not comply to rfc3501 as it resonses the CAPABILITY after received LOGIN command with no CAPABILITY command requested.
+ if (lineBuf.find(ESP32_MAIL_STR_134) == std::string::npos && lineBuf.find(ESP32_MAIL_STR_145) == std::string::npos)
+ completeResp = true;
+
+ //Some servers e.g. STRATO E-Mail-Server does not reply any error when fetching none existing MIME header part at defined index.
+ if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME)
+ validResponse = false;
+ }
+ }
+ else
+ {
+
+ if ((payloadLength > 0 && charCount >= payloadLength) || imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME)
+ {
+ completeResp = true;
+ }
+ }
+ }
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount > 0)
+ {
+ completeResp = true;
+ validResponse = true;
+ }
+
+ tmp = lineBuf;
+ std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME && lfCount > 0)
+ {
+
+ if (payloadLength > 0 && validResponse)
+ {
+
+ if (imapData._messageDataInfo[mailIndex].size() < messageDataIndex + 1)
+ {
+ messageBodyData b;
+ imapData._messageDataInfo[mailIndex].push_back(b);
+ imapData._messageDataCount[mailIndex] = imapData._messageDataInfo[mailIndex].size();
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_167);
+ if (p1 != std::string::npos)
+ {
+
+ p2 = lineBuf.find(";", p1 + strlen(ESP32_MAIL_STR_167));
+ if (p2 != std::string::npos)
+ {
+
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_167), p2 - p1 - strlen(ESP32_MAIL_STR_167));
+
+ p1 = tmp.find(ESP32_MAIL_STR_168, p2);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_168));
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._charset = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_168), p2 - p1 - strlen(ESP32_MAIL_STR_168));
+ }
+ else if (tmp.find(ESP32_MAIL_STR_169, p2) != std::string::npos)
+ {
+ p1 = tmp.find(ESP32_MAIL_STR_169, p2);
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._charset = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_169));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_170, p2);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_170));
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._name = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_170), p2 - p1 - strlen(ESP32_MAIL_STR_170));
+ }
+ else if (tmp.find(ESP32_MAIL_STR_171, p2) != std::string::npos)
+ {
+ p1 = tmp.find(ESP32_MAIL_STR_171, p2);
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._name = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_171));
+ }
+ }
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_172);
+ if (p1 != std::string::npos)
+ {
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + strlen(ESP32_MAIL_STR_172));
+
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_172), p2 - p1 - strlen(ESP32_MAIL_STR_172));
+ else
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_172));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_174);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + strlen(ESP32_MAIL_STR_174));
+
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._descr = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_174), p2 - p1 - strlen(ESP32_MAIL_STR_174));
+ else
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._descr = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_174));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_175);
+ if (p1 != std::string::npos)
+ {
+
+ p2 = lineBuf.find(";", p1 + strlen(ESP32_MAIL_STR_175));
+
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_175), p2 - p1 - strlen(ESP32_MAIL_STR_175));
+ else
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_175));
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition == ESP32_MAIL_STR_153)
+ imapData._attachmentCount[mailIndex]++;
+ }
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition != "")
+ {
+
+ p1 = tmp.find(ESP32_MAIL_STR_176);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_176));
+
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._filename = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_176), p2 - p1 - strlen(ESP32_MAIL_STR_176));
+ }
+ else if (tmp.find(ESP32_MAIL_STR_177) != std::string::npos)
+ {
+
+ p1 = tmp.find(ESP32_MAIL_STR_177);
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._filename = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_177));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_178);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(";", p1 + strlen(ESP32_MAIL_STR_178) + 1);
+ if (p2 != std::string::npos)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._size = atoi(lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_178), p2 - p1 - strlen(ESP32_MAIL_STR_178)).c_str());
+ imapData._totalAttachFileSize[mailIndex] += imapData._messageDataInfo[mailIndex][messageDataIndex]._size;
+ }
+ else
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._size = atoi(lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_178)).c_str());
+ imapData._totalAttachFileSize[mailIndex] += imapData._messageDataInfo[mailIndex][messageDataIndex]._size;
+ }
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_179);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_179));
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._creation_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_179), p2 - p1 - strlen(ESP32_MAIL_STR_179));
+ }
+ else if (tmp.find(ESP32_MAIL_STR_180) != std::string::npos)
+ {
+ p1 = tmp.find(ESP32_MAIL_STR_180);
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._creation_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_180));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_181);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_181));
+ if (p2 != std::string::npos)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._modification_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_181), p2 - p1 - strlen(ESP32_MAIL_STR_181));
+ }
+ else if (tmp.find(ESP32_MAIL_STR_182) != std::string::npos)
+ {
+ p1 = tmp.find(ESP32_MAIL_STR_182);
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._modification_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_182));
+ }
+ }
+
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._part = part;
+ }
+ }
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount == 0)
+ {
+
+ if (msgNumBuf.length() > 0 && msgNumBuf != ESP32_MAIL_STR_183 && msgNumBuf != ESP32_MAIL_STR_141 && imapData._msgNum.size() <= max)
+ {
+ imapData._msgNum.push_back(atoi(msgNumBuf.c_str()));
+ imapData._searchCount++;
+
+ if (imapData._msgNum.size() > imapData._emailNumMax && imapData._recentSort)
+ imapData._msgNum.erase(imapData._msgNum.begin());
+ }
+
+ if (imapData._recentSort)
+ std::sort(imapData._msgNum.begin(), imapData._msgNum.end(), compFunc);
+ }
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER)
+ {
+
+ uint8_t _headerType = 0;
+
+ p1 = tmp.find(ESP32_MAIL_STR_184);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::FROM;
+ _headerType = IMAP_HEADER_TYPE::FROM;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + strlen(ESP32_MAIL_STR_184));
+ if (p2 != std::string::npos)
+ from = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_184), p2 - p1 - strlen(ESP32_MAIL_STR_184));
+ else
+ from = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_184));
+
+ if (from[0] == '=' && from[1] == '?')
+ {
+ p1 = from.find("?", 2);
+
+ if (p1 != std::string::npos)
+ from_charset = from.substr(2, p1 - 2);
+ }
+
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, from.c_str(), bufSize);
+ from = dest;
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_185);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::TO;
+ _headerType = IMAP_HEADER_TYPE::TO;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+ if (p2 != std::string::npos)
+ to = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_185), p2 - p1 - strlen(ESP32_MAIL_STR_185));
+ else
+ to = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_185));
+
+ if (to[0] == '=' && to[1] == '?')
+ {
+ p1 = to.find("?", 2);
+
+ if (p1 != std::string::npos)
+ to_charset = to.substr(2, p1 - 2);
+ }
+
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, to.c_str(), bufSize);
+ to = dest;
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_186);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::CC;
+ _headerType = IMAP_HEADER_TYPE::CC;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+ if (p2 != std::string::npos)
+ cc = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_186), p2 - p1 - strlen(ESP32_MAIL_STR_186));
+ else
+ cc = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_186));
+
+ if (cc[0] == '=' && cc[1] == '?')
+ {
+ p1 = cc.find("?", 2);
+
+ if (p1 != std::string::npos)
+ cc_charset = cc.substr(2, p1 - 2);
+ }
+
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, cc.c_str(), bufSize);
+ cc = dest;
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_187);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::SUBJECT;
+ _headerType = IMAP_HEADER_TYPE::SUBJECT;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+
+ memset(dest, 0, bufSize);
+ if (p2 != std::string::npos)
+ subject = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_187), p2 - p1 - strlen(ESP32_MAIL_STR_187));
+ else
+ subject = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_187));
+
+ if (subject[0] == '=' && subject[1] == '?')
+ {
+ p1 = subject.find("?", 2);
+ if (p1 != std::string::npos)
+ subject_charset = subject.substr(2, p1 - 2);
+ }
+
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, subject.c_str(), bufSize);
+ subject = dest;
+ }
+ p1 = tmp.find(ESP32_MAIL_STR_188);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::DATE;
+ _headerType = IMAP_HEADER_TYPE::DATE;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+ if (p2 != std::string::npos)
+ date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_188), p2 - p1 - strlen(ESP32_MAIL_STR_188));
+ else
+ date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_188));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_189);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::MSG_ID;
+ _headerType = IMAP_HEADER_TYPE::MSG_ID;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+ if (p2 != std::string::npos)
+ msgID = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_189), p2 - p1 - strlen(ESP32_MAIL_STR_189));
+ else
+ msgID = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_189));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_190);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::ACCEPT_LANG;
+ _headerType = IMAP_HEADER_TYPE::ACCEPT_LANG;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+ if (p2 != std::string::npos)
+ acceptLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_190), p2 - p1 - strlen(ESP32_MAIL_STR_190));
+ else
+ acceptLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_190));
+ }
+
+ p1 = tmp.find(ESP32_MAIL_STR_191);
+ if (p1 != std::string::npos)
+ {
+ headerType = IMAP_HEADER_TYPE::CONT_LANG;
+ _headerType = IMAP_HEADER_TYPE::CONT_LANG;
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1);
+ if (p2 != std::string::npos)
+ contentLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_191), p2 - p1 - strlen(ESP32_MAIL_STR_191));
+ else
+ contentLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_191));
+ }
+
+ if (_headerType == 0 && charCount < payloadLength && payloadLength > 0)
+ {
+ if (headerType == IMAP_HEADER_TYPE::FROM)
+ {
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize);
+ from += dest;
+ }
+ else if (headerType == IMAP_HEADER_TYPE::TO)
+ {
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize);
+ to += dest;
+ }
+ else if (headerType == IMAP_HEADER_TYPE::CC)
+ {
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize);
+ cc += dest;
+ }
+ else if (headerType == IMAP_HEADER_TYPE::SUBJECT)
+ {
+ memset(dest, 0, bufSize);
+ RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize);
+ subject += dest;
+ }
+ }
+ }
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::LIST)
+ {
+ p1 = lineBuf.find(ESP32_MAIL_STR_195);
+ p2 = lineBuf.find(ESP32_MAIL_STR_196);
+
+ if (p1 != std::string::npos && p2 == std::string::npos)
+ {
+ p2 = lineBuf.find_last_of(ESP32_MAIL_STR_136);
+ if (p2 != std::string::npos)
+ {
+ p1 = lineBuf.find_last_of(ESP32_MAIL_STR_136, p2 - 1);
+ if (p1 != std::string::npos)
+ imapData._folders.push_back(lineBuf.substr(p1 + 1, p2 - p1 - 1));
+ }
+ }
+ }
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::SELECT || imapCommandType == IMAP_COMMAND_TYPE::EXAMINE)
+ {
+
+ p1 = lineBuf.find(ESP32_MAIL_STR_197);
+ if (p1 != std::string::npos)
+ {
+ p1 = lineBuf.find(ESP32_MAIL_STR_198);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_192);
+ if (p2 != std::string::npos)
+ {
+ string _tmp;
+
+ _tmp = lineBuf.substr(p1 + 1, p2 - p1 - 1).c_str();
+ msgNumBuf.clear();
+
+ for (size_t i = 0; i < _tmp.length(); i++)
+ {
+ if (_tmp[i] != '\\' && _tmp[i] != ' ' && _tmp[i] != '\r' && _tmp[i] != '\n')
+ msgNumBuf.append(1, _tmp[i]);
+
+ if (_tmp[i] == ' ')
+ {
+ imapData._flag.push_back(msgNumBuf);
+ msgNumBuf.clear();
+ }
+ }
+ if (msgNumBuf.length() > 0)
+ {
+ imapData._flag.push_back(msgNumBuf);
+ }
+
+ std::string().swap(_tmp);
+ }
+ }
+ }
+
+ p2 = lineBuf.find(ESP32_MAIL_STR_199);
+ if (p2 != std::string::npos)
+ imapData._totalMessage = atoi(lineBuf.substr(2, p2 - 2).c_str());
+
+ p1 = lineBuf.find(ESP32_MAIL_STR_200);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_156, p1 + 10);
+ if (p2 != std::string::npos)
+ imapData._nextUID = lineBuf.substr(p1 + 10, p2 - p1 - 10);
+ }
+ }
+
+ if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT && lfCount > 0 && (charCount < maxChar || imapData._saveHTMLMsg || imapData._saveTextMsg))
+ {
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding == ESP32_MAIL_STR_160)
+ {
+
+ unsigned char *decoded = base64_decode_char((const unsigned char *)lineBuf.c_str(), lineBuf.length(), &outputLength);
+
+ if (decoded)
+ {
+ if (charCount < maxChar)
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._text.append((char *)decoded, outputLength);
+
+ if (imapData._saveHTMLMsg || imapData._saveTextMsg)
+ {
+
+ if (!imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite)
+ {
+
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true;
+
+ if (_sdOk)
+ {
+
+ downloadReq = true;
+
+ filepath.clear();
+ filepath += imapData._savePath;
+ filepath += ESP32_MAIL_STR_202;
+
+ char *midx = new char[50];
+ memset(midx, 0, 50);
+ itoa(imapData._msgNum[mailIndex], midx, 10);
+
+ filepath += midx;
+
+ delete[] midx;
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ if (!SD.exists(filepath.c_str()))
+ createDirs(filepath);
+
+ if (!imapData._headerSaved)
+ hpath = filepath + ESP32_MAIL_STR_203;
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_155)
+ {
+ if (imapData._saveDecodedText)
+ filepath += ESP32_MAIL_STR_161;
+ else
+ filepath += ESP32_MAIL_STR_162;
+ }
+ else if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_154)
+ {
+ if (imapData._saveDecodedHTML)
+ filepath += ESP32_MAIL_STR_163;
+ else
+ filepath += ESP32_MAIL_STR_164;
+ }
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ file = SD.open(filepath.c_str(), FILE_WRITE);
+ else if (imapData._storageType == MailClientStorageType::SPIFFS)
+ file = SPIFFS.open(filepath.c_str(), FILE_WRITE);
+ }
+ else
+ {
+ if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true;
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear();
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_89;
+ }
+ }
+ }
+
+ if (_sdOk)
+ {
+ if ((imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_155 && imapData._saveDecodedText) ||
+ (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_154 && imapData._saveDecodedHTML))
+ file.write((const uint8_t *)decoded, outputLength);
+ else
+ file.write((const uint8_t *)lineBuf.c_str(), lineBuf.length());
+ }
+ }
+
+ delete[] decoded;
+ }
+ }
+ }
+
+ if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT && lfCount > 0)
+ {
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding == ESP32_MAIL_STR_160)
+ {
+
+ if (!imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite)
+ {
+
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true;
+
+ if (_sdOk)
+ {
+
+ downloadReq = true;
+
+ filepath.clear();
+ filepath += imapData._savePath;
+ filepath += ESP32_MAIL_STR_202;
+
+ char *midx = new char[50];
+ memset(midx, 0, 50);
+ itoa(imapData._msgNum[mailIndex], midx, 10);
+
+ filepath += midx;
+
+ delete[] midx;
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ if (!SD.exists(filepath.c_str()))
+ createDirs(filepath);
+
+ filepath += ESP32_MAIL_STR_202;
+
+ filepath += imapData._messageDataInfo[mailIndex][messageDataIndex]._filename;
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ file = SD.open(filepath.c_str(), FILE_WRITE);
+ else if (imapData._storageType == MailClientStorageType::SPIFFS)
+ file = SPIFFS.open(filepath.c_str(), FILE_WRITE);
+ }
+ else
+ {
+ if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true;
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear();
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_89;
+ }
+ }
+ }
+
+ if (_sdOk)
+ {
+
+ unsigned char *decoded = base64_decode_char((const unsigned char *)lineBuf.c_str(), lineBuf.length(), &outputLength);
+
+ downloadedByte += outputLength;
+
+ if (downloadedByte > imapData._messageDataInfo[mailIndex][messageDataIndex]._size)
+ continue;
+
+ if (decoded)
+ {
+ file.write((const uint8_t *)decoded, outputLength);
+
+ if (imapData._storageType == MailClientStorageType::SPIFFS)
+ delayMicroseconds(1);
+ else
+ yield();
+
+ if (imapData._downloadReport)
+ {
+ imapData._downloadedByte[mailIndex] += outputLength;
+ currentDownloadByte += outputLength;
+
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._size == 0)
+ {
+ if (payloadLength > 36)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._size = base64DecodeSize(lineBuf, payloadLength - (payloadLength / 36));
+ imapData._totalAttachFileSize[mailIndex] += imapData._messageDataInfo[mailIndex][messageDataIndex]._size;
+ }
+ }
+
+ int p = 0;
+
+ if (imapData._totalAttachFileSize[mailIndex] > 0)
+ p = 100 * imapData._downloadedByte[mailIndex] / imapData._totalAttachFileSize[mailIndex];
+
+ if ((p % 5 == 0) && (p <= 100))
+ {
+
+ if (imapData._readCallback && reportState != -1)
+ {
+ memset(buf, 0, bufSize);
+ itoa(p, buf, 10);
+
+ std::string dl = ESP32_MAIL_STR_90 + imapData._messageDataInfo[mailIndex][messageDataIndex]._filename + ESP32_MAIL_STR_91 + buf + ESP32_MAIL_STR_92;
+
+ if (imapData._readCallback)
+ {
+ imapData._cbData._info = dl;
+ imapData._cbData._status = dl;
+ imapData._cbData._success = false;
+ imapData._readCallback(imapData._cbData);
+ }
+
+ std::string().swap(dl);
+ }
+ reportState = -1;
+ }
+ else
+ reportState = 0;
+ }
+
+ delete[] decoded;
+ }
+
+ if (millis() - dataTime > imapData._net->tcpTimeout + 1000 * 60 * 5)
+ break;
+ }
+ }
+ }
+
+ if (lfCount == 0)
+ {
+ p1 = lineBuf.find_last_of(ESP32_MAIL_STR_193);
+ if (p1 != std::string::npos)
+ {
+ p2 = lineBuf.find(ESP32_MAIL_STR_194, p1 + 1);
+ if (p2 != std::string::npos)
+ payloadLength = atoi(lineBuf.substr(p1 + 1, p2 - p1 - 1).c_str());
+ }
+ }
+
+ lineBuf.clear();
+ lfCount++;
+ std::string().swap(tmp);
+ }
+
+ readCount++;
+ }
+
+ if (imapData._error.size() > 0 && mailIndex > -1)
+ {
+ if (validResponse && !imapData._error[mailIndex])
+ {
+ imapData._errorMsg[mailIndex].clear();
+ imapData._errorMsg[mailIndex] = "";
+ }
+ }
+
+ if (millis() - dataTime > imapData._net->tcpTimeout)
+ {
+
+ if (downloadReq)
+ {
+ if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true;
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear();
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_93;
+ }
+ }
+ else
+ {
+
+ if (imapData._error.size() > 0 && mailIndex > -1)
+ {
+ imapData._error[mailIndex] = true;
+ imapData._errorMsg[mailIndex].clear();
+ imapData._errorMsg[mailIndex] = ESP32_MAIL_STR_95;
+ }
+ }
+ }
+ }
+
+ if (validResponse && (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT || imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT) && messageDataIndex != -1)
+ {
+ if (imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite)
+ file.close();
+ }
+
+ if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT && imapData._messageDataInfo[mailIndex][messageDataIndex]._size != currentDownloadByte)
+ {
+ imapData._messageDataInfo[mailIndex][messageDataIndex]._size = currentDownloadByte;
+ }
+
+ if (hpath != "")
+ {
+
+ if (imapData._storageType == MailClientStorageType::SD)
+ file = SD.open(hpath.c_str(), FILE_WRITE);
+ else if (imapData._storageType == MailClientStorageType::SPIFFS)
+ file = SPIFFS.open(hpath.c_str(), FILE_WRITE);
+
+ file.print(ESP32_MAIL_STR_99);
+ file.println(imapData._date[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_100);
+ if (imapData._uidSearch)
+ file.println(imapData._msgNum[mailIndex]);
+ else
+ file.println();
+
+ file.print(ESP32_MAIL_STR_101);
+ file.println(imapData._msgNum[mailIndex]);
+
+ file.print(ESP32_MAIL_STR_102);
+ file.println(imapData._acceptLanguage[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_103);
+ file.println(imapData._contentLanguage[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_104);
+ file.println(imapData._from[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_105);
+ file.println(imapData._from_charset[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_106);
+ file.println(imapData._to[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_107);
+ file.println(imapData._to_charset[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_108);
+ file.println(imapData._cc[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_109);
+ file.println(imapData._cc_charset[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_110);
+ file.println(imapData._subject[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_111);
+ file.println(imapData._subject_charset[mailIndex].c_str());
+
+ file.print(ESP32_MAIL_STR_112);
+ file.println(imapData._messageDataInfo[mailIndex][messageDataIndex]._charset.c_str());
+
+ if (imapData._attachmentCount[mailIndex] > 0)
+ {
+
+ file.print(ESP32_MAIL_STR_113);
+ file.println(imapData._attachmentCount[mailIndex]);
+
+ for (int j = 0; j < imapData._attachmentCount[mailIndex]; j++)
+ {
+ file.print(ESP32_MAIL_STR_114);
+ file.println(j + 1);
+
+ file.print(ESP32_MAIL_STR_115);
+ file.println(imapData.getAttachmentFileName(mailIndex, j));
+
+ file.print(ESP32_MAIL_STR_116);
+ file.println(imapData.getAttachmentName(mailIndex, j));
+
+ file.print(ESP32_MAIL_STR_117);
+ file.println(imapData.getAttachmentFileSize(mailIndex, j));
+
+ file.print(ESP32_MAIL_STR_118);
+ file.println(imapData.getAttachmentType(mailIndex, j));
+
+ file.print(ESP32_MAIL_STR_119);
+ file.println(imapData.getAttachmentCreationDate(mailIndex, j));
+ }
+ }
+
+ file.close();
+ imapData._headerSaved = true;
+ }
+
+ if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER)
+ {
+ if (from != "")
+ {
+ imapData._msgID[mailIndex] = msgID;
+ imapData._from[mailIndex] = from;
+ imapData._to[mailIndex] = to;
+ imapData._cc[mailIndex] = cc;
+ imapData._subject[mailIndex] = subject;
+ imapData._date[mailIndex] = date;
+ imapData._from_charset[mailIndex] = from_charset;
+ imapData._to_charset[mailIndex] = to_charset;
+ imapData._cc_charset[mailIndex] = cc_charset;
+ imapData._subject_charset[mailIndex] = subject_charset;
+ imapData._contentLanguage[mailIndex] = contentLanguage;
+ imapData._acceptLanguage[mailIndex] = acceptLanguage;
+ }
+ }
+
+ delete[] buf;
+ delete[] dest;
+
+ std::string().swap(lineBuf);
+ std::string().swap(msgNumBuf);
+ std::string().swap(filepath);
+ std::string().swap(hpath);
+ std::string().swap(tmp);
+
+ std::string().swap(msgID);
+ std::string().swap(from);
+ std::string().swap(to);
+ std::string().swap(subject);
+ std::string().swap(date);
+ std::string().swap(cc);
+ std::string().swap(from_charset);
+ std::string().swap(to_charset);
+ std::string().swap(cc_charset);
+ std::string().swap(subject_charset);
+ std::string().swap(contentLanguage);
+ std::string().swap(acceptLanguage);
+
+ return validResponse;
+}
+
+void ESP32_MailClient::clientReadAll(WiFiClient *client)
+{
+ if (client)
+ {
+ if (client->available() > 0)
+ client->read();
+ }
+}
+
+double ESP32_MailClient::base64DecodeSize(std::string lastBase64String, int length)
+{
+ double result = 0;
+ int padding = 0;
+ if (lastBase64String != "")
+ {
+
+ if (lastBase64String[lastBase64String.length() - 1] == '=' && lastBase64String[lastBase64String.length() - 2] == '=')
+ padding = 2;
+ else if (lastBase64String[lastBase64String.length() - 1] == '=')
+ padding = 1;
+ }
+ result = (ceil(length / 4) * 3) - padding;
+ return result;
+}
+
+unsigned char *ESP32_MailClient::base64_decode_char(const unsigned char *src, size_t len, size_t *out_len)
+{
+
+ unsigned char *out, *pos, block[4], tmp;
+ size_t i, count, olen;
+ int pad = 0;
+ size_t extra_pad;
+
+ unsigned char *dtable = new unsigned char[256];
+
+ memset(dtable, 0x80, 256);
+
+ for (i = 0; i < sizeof(base64_table) - 1; i++)
+ dtable[base64_table[i]] = (unsigned char)i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (dtable[src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0)
+ goto exit;
+ extra_pad = (4 - count % 4) % 4;
+
+ olen = (count + extra_pad) / 4 * 3;
+ pos = out = (unsigned char *)malloc(olen);
+ if (out == NULL)
+ goto exit;
+
+ count = 0;
+ for (i = 0; i < len + extra_pad; i++)
+ {
+ unsigned char val;
+
+ if (i >= len)
+ val = '=';
+ else
+ val = src[i];
+ tmp = dtable[val];
+ if (tmp == 0x80)
+ continue;
+
+ if (val == '=')
+ pad++;
+ block[count] = tmp;
+ count++;
+ if (count == 4)
+ {
+ *pos++ = (block[0] << 2) | (block[1] >> 4);
+ *pos++ = (block[1] << 4) | (block[2] >> 2);
+ *pos++ = (block[2] << 6) | block[3];
+ count = 0;
+ if (pad)
+ {
+ if (pad == 1)
+ pos--;
+ else if (pad == 2)
+ pos -= 2;
+ else
+ {
+ free(out);
+ goto exit;
+ }
+ break;
+ }
+ }
+ }
+
+ *out_len = pos - out;
+ delete[] dtable;
+ return out;
+
+exit:
+ delete[] dtable;
+ return NULL;
+}
+
+std::string ESP32_MailClient::base64_encode_string(const unsigned char *src, size_t len)
+{
+ unsigned char *out, *pos;
+ const unsigned char *end, *in;
+
+ size_t olen;
+
+ olen = 4 * ((len + 2) / 3);
+
+ if (olen < len)
+ return std::string();
+
+ std::string outStr = "";
+ outStr.resize(olen);
+ out = (unsigned char *)&outStr[0];
+
+ end = src + len;
+ in = src;
+ pos = out;
+
+ while (end - in >= 3)
+ {
+ *pos++ = base64_table[in[0] >> 2];
+ *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ *pos++ = base64_table[in[2] & 0x3f];
+ in += 3;
+ }
+
+ if (end - in)
+ {
+ *pos++ = base64_table[in[0] >> 2];
+ if (end - in == 1)
+ {
+ *pos++ = base64_table[(in[0] & 0x03) << 4];
+ *pos++ = '=';
+ }
+ else
+ {
+ *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ *pos++ = base64_table[(in[1] & 0x0f) << 2];
+ }
+ *pos++ = '=';
+ }
+
+ return outStr;
+}
+
+void ESP32_MailClient::send_base64_encode_mime_data(WiFiClient *client, const unsigned char *src, size_t len)
+{
+
+ const unsigned char *end, *in;
+
+ size_t olen;
+
+ olen = 4 * ((len + 2) / 3);
+
+ if (olen < len)
+ return;
+
+ end = src + len;
+ in = src;
+
+ size_t chunkSize = 936;
+ size_t byteAdd = 0;
+ size_t byteSent = 0;
+
+ int dByte = 0;
+ unsigned char *buf = new unsigned char[chunkSize];
+ memset(buf, 0, chunkSize);
+
+ while (end - in >= 3)
+ {
+ buf[byteAdd++] = base64_table[in[0] >> 2];
+ buf[byteAdd++] = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ buf[byteAdd++] = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ buf[byteAdd++] = base64_table[in[2] & 0x3f];
+ dByte += 4;
+ if (dByte == 76)
+ {
+ if(byteAdd + 1 < chunkSize)
+ {
+ buf[byteAdd++] = 0x0d;
+ buf[byteAdd++] = 0x0a;
+ }
+ dByte = 0;
+ }
+ if (byteAdd >= chunkSize - 4)
+ {
+ byteSent += byteAdd;
+ client->write(buf, byteAdd);
+ memset(buf, 0, chunkSize);
+ byteAdd = 0;
+ }
+ in += 3;
+ }
+
+ if (byteAdd > 0)
+ client->write(buf, byteAdd);
+
+ if (end - in)
+ {
+ memset(buf, 0, chunkSize);
+ byteAdd = 0;
+
+ buf[byteAdd++] = base64_table[in[0] >> 2];
+ if (end - in == 1)
+ {
+ buf[byteAdd++] = base64_table[(in[0] & 0x03) << 4];
+ buf[byteAdd++] = '=';
+ }
+ else
+ {
+ buf[byteAdd++] = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ buf[byteAdd++] = base64_table[(in[1] & 0x0f) << 2];
+ }
+ buf[byteAdd++] = '=';
+
+ client->write(buf, byteAdd);
+ memset(buf, 0, chunkSize);
+ }
+ delete[] buf;
+}
+
+void ESP32_MailClient::send_base64_encode_mime_file(WiFiClient *client, File file)
+{
+
+ if (!file)
+ return;
+
+ size_t chunkSize = 936;
+ size_t byteAdd = 0;
+ size_t byteSent = 0;
+
+ unsigned char *buf = new unsigned char[chunkSize];
+ memset(buf, 0, chunkSize);
+
+ size_t len = file.size();
+ size_t fbufIndex = 0;
+ unsigned char *fbuf = new unsigned char[3];
+
+ int dByte = 0;
+
+ while (file.available())
+ {
+ memset(fbuf, 0, 3);
+ if (len - fbufIndex >= 3)
+ {
+ file.read(fbuf, 3);
+ buf[byteAdd++] = base64_table[fbuf[0] >> 2];
+ buf[byteAdd++] = base64_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)];
+ buf[byteAdd++] = base64_table[((fbuf[1] & 0x0f) << 2) | (fbuf[2] >> 6)];
+ buf[byteAdd++] = base64_table[fbuf[2] & 0x3f];
+ dByte += 4;
+ if (dByte == 76)
+ {
+ if(byteAdd + 1 < chunkSize)
+ {
+ buf[byteAdd++] = 0x0d;
+ buf[byteAdd++] = 0x0a;
+ }
+ dByte = 0;
+ }
+ if (byteAdd >= chunkSize - 4)
+ {
+ byteSent += byteAdd;
+ client->write(buf, byteAdd);
+ memset(buf, 0, chunkSize);
+ byteAdd = 0;
+ }
+ fbufIndex += 3;
+ }
+ else
+ {
+ if (len - fbufIndex == 1)
+ {
+ fbuf[0] = file.read();
+ }
+ else if (len - fbufIndex == 2)
+ {
+ fbuf[0] = file.read();
+ fbuf[1] = file.read();
+ }
+ break;
+ }
+ }
+
+ file.close();
+ if (byteAdd > 0)
+ client->write(buf, byteAdd);
+
+ if (len - fbufIndex > 0)
+ {
+ memset(buf, 0, chunkSize);
+ byteAdd = 0;
+ buf[byteAdd++] = base64_table[fbuf[0] >> 2];
+ if (len - fbufIndex == 1)
+ {
+ buf[byteAdd++] = base64_table[(fbuf[0] & 0x03) << 4];
+ buf[byteAdd++] = '=';
+ }
+ else
+ {
+ buf[byteAdd++] = base64_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)];
+ buf[byteAdd++] = base64_table[(fbuf[1] & 0x0f) << 2];
+ }
+ buf[byteAdd++] = '=';
+ client->write(buf, byteAdd);
+ }
+ delete[] buf;
+ delete[] fbuf;
+}
+
+IMAPData::IMAPData() {}
+IMAPData::~IMAPData()
+{
+ empty();
+ _net.reset();
+ _net.release();
+}
+
+void IMAPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA)
+{
+
+ _host.clear();
+ _port = port;
+ _loginEmail.clear();
+ _loginPassword.clear();
+
+ _host = host.c_str();
+ _loginEmail = loginEmail.c_str();
+ _loginPassword = loginPassword.c_str();
+
+ _rootCA.clear();
+ if (strlen(rootCA) > 0)
+ _rootCA.push_back((char *)rootCA);
+}
+
+void IMAPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword)
+{
+ _host.clear();
+ _port = port;
+ _loginEmail.clear();
+ _loginPassword.clear();
+
+ _host = host.c_str();
+ _loginEmail = loginEmail.c_str();
+ _loginPassword = loginPassword.c_str();
+}
+
+void IMAPData::setSTARTTLS(bool starttls)
+{
+ _starttls = starttls;
+}
+
+void IMAPData::setDebug(bool debug)
+{
+ _debug = debug;
+}
+
+void IMAPData::setFolder(const String &folderName)
+{
+ _currentFolder.clear();
+ _currentFolder = folderName.c_str();
+}
+void IMAPData::setMessageBufferSize(size_t size)
+{
+ _message_buffer_size = size;
+}
+
+void IMAPData::setAttachmentSizeLimit(size_t size)
+{
+ _attacement_max_size = size;
+}
+
+void IMAPData::setSearchCriteria(const String &criteria)
+{
+ _searchCriteria.clear();
+ _searchCriteria = criteria.c_str();
+}
+
+void IMAPData::setSearchUnseenMessage(bool unseenSearch)
+{
+ _unseen = unseenSearch;
+}
+
+void IMAPData::setSaveFilePath(const String &path)
+{
+ _savePath.clear();
+ if (path.c_str()[0] != '/')
+ {
+ _savePath = "/";
+ _savePath += path.c_str();
+ }
+ else
+ _savePath = path.c_str();
+}
+
+void IMAPData::setFetchUID(const String &fetchUID)
+{
+ _fetchUID.clear();
+ string tmp = fetchUID.c_str();
+ std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
+ if (tmp.find(ESP32_MAIL_STR_140) != std::string::npos || tmp.find(ESP32_MAIL_STR_212) != std::string::npos ||
+ tmp.find(ESP32_MAIL_STR_213) != std::string::npos || tmp.find(ESP32_MAIL_STR_214) != std::string::npos || tmp.find(ESP32_MAIL_STR_215) != std::string::npos ||
+ tmp.find(ESP32_MAIL_STR_216) != std::string::npos || tmp.find(ESP32_MAIL_STR_217) != std::string::npos || tmp.find(ESP32_MAIL_STR_218) != std::string::npos ||
+ tmp.find(ESP32_MAIL_STR_219) != std::string::npos || tmp.find(ESP32_MAIL_STR_220) != std::string::npos)
+ _fetchUID = ESP32_MAIL_STR_183;
+ else
+ _fetchUID = fetchUID.c_str();
+
+ std::string().swap(tmp);
+}
+
+void IMAPData::setFileStorageType(uint8_t storageType)
+{
+ _storageType = storageType;
+}
+
+void IMAPData::setDownloadAttachment(bool download)
+{
+ _downloadAttachment = download;
+}
+void IMAPData::setRecentSort(bool recentSort)
+{
+ _recentSort = recentSort;
+}
+
+void IMAPData::setHTMLMessage(bool htmlFormat)
+{
+ _htmlFormat = htmlFormat;
+}
+void IMAPData::setTextMessage(bool textFormat)
+{
+ _textFormat = textFormat;
+}
+
+void IMAPData::setSearchLimit(uint16_t limit)
+{
+ if (limit <= MAX_EMAIL_SEARCH_LIMIT)
+ _emailNumMax = limit;
+}
+
+bool IMAPData::isHeaderOnly()
+{
+ return _headerOnly;
+}
+
+void IMAPData::saveHTMLMessage(bool download, bool decoded)
+{
+ _saveDecodedHTML = decoded;
+ _saveHTMLMsg = download;
+}
+void IMAPData::saveTextMessage(bool download, bool decoded)
+{
+ _saveDecodedText = decoded;
+ _saveTextMsg = download;
+}
+
+void IMAPData::setReadCallback(readStatusCallback readCallback)
+{
+ _readCallback = std::move(readCallback);
+}
+
+void IMAPData::setDownloadReport(bool report)
+{
+ _downloadReport = report;
+}
+
+uint16_t IMAPData::getFolderCount()
+{
+ return _folders.size();
+}
+String IMAPData::getFolder(uint16_t folderIndex)
+{
+ if (folderIndex < _folders.size())
+ return _folders[folderIndex].c_str();
+ return std::string().c_str();
+}
+
+uint16_t IMAPData::getFlagCount()
+{
+ return _flag.size();
+}
+String IMAPData::getFlag(uint16_t flagIndex)
+{
+ if (flagIndex < _flag.size())
+ return _flag[flagIndex].c_str();
+ return std::string().c_str();
+}
+
+size_t IMAPData::totalMessages()
+{
+ return _totalMessage;
+}
+
+size_t IMAPData::searchCount()
+{
+ return _searchCount;
+}
+
+size_t IMAPData::availableMessages()
+{
+ return _msgNum.size();
+}
+
+size_t IMAPData::getAttachmentCount(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _attachmentCount[messageIndex];
+ return 0;
+}
+
+String IMAPData::getAttachmentFileName(size_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._filename.c_str();
+ id++;
+ }
+ }
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+String IMAPData::getAttachmentName(size_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._name.c_str();
+ id++;
+ }
+ }
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+int IMAPData::getAttachmentFileSize(size_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._size;
+ id++;
+ }
+ }
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+
+ return 0;
+}
+
+String IMAPData::getAttachmentCreationDate(size_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._creation_date.c_str();
+ id++;
+ }
+ }
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+String IMAPData::getAttachmentType(size_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._contentType.c_str();
+ id++;
+ }
+ }
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+String IMAPData::getFrom(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _from[messageIndex].c_str();
+ return std::string().c_str();
+}
+
+String IMAPData::getFromCharset(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _from_charset[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getTo(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _to[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getToCharset(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _to_charset[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getCC(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _cc[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getCCCharset(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _cc_charset[messageIndex].c_str();
+ return std::string().c_str();
+}
+
+String IMAPData::getSubject(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _subject[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getSubjectCharset(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _subject_charset[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getHTMLMessage(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return getMessage(messageIndex, true);
+ return std::string().c_str();
+}
+
+String IMAPData::getTextMessage(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return getMessage(messageIndex, false);
+ return std::string().c_str();
+}
+
+String IMAPData::getMessage(uint16_t messageIndex, bool htmlFormat)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_155 && !htmlFormat)
+ return _messageDataInfo[messageIndex][i]._text.c_str();
+ else if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_154 && htmlFormat)
+ return _messageDataInfo[messageIndex][i]._text.c_str();
+ }
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+String IMAPData::getHTMLMessgaeCharset(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_154)
+ return _messageDataInfo[messageIndex][i]._charset.c_str();
+ }
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+String IMAPData::getTextMessgaeCharset(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_155)
+ return _messageDataInfo[messageIndex][i]._charset.c_str();
+ }
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+String IMAPData::getDate(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _date[messageIndex].c_str();
+ return std::string().c_str();
+}
+
+String IMAPData::getUID(uint16_t messageIndex)
+{
+ char *buf = new char[50];
+ memset(buf, 0, 50);
+ if (_uidSearch)
+ {
+ if (messageIndex < _msgNum.size())
+ itoa(_msgNum[messageIndex], buf, 10);
+ }
+
+ String v = buf;
+ delete[] buf;
+ return v;
+}
+
+String IMAPData::getNumber(uint16_t messageIndex)
+{
+ char *buf = new char[50];
+ memset(buf, 0, 50);
+
+ if (messageIndex < _msgNum.size())
+ {
+ if (!_uidSearch)
+ itoa(_msgNum[messageIndex], buf, 10);
+ else
+ itoa(_msgNum[messageIndex] + 1, buf, 10);
+ }
+
+ String v = buf;
+ delete[] buf;
+ return v;
+}
+
+String IMAPData::getMessageID(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _msgID[messageIndex].c_str();
+ return std::string().c_str();
+}
+
+String IMAPData::getAcceptLanguage(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _acceptLanguage[messageIndex].c_str();
+ return std::string().c_str();
+}
+String IMAPData::getContentLanguage(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _contentLanguage[messageIndex].c_str();
+ return std::string().c_str();
+}
+
+bool IMAPData::isFetchMessageFailed(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _error[messageIndex];
+ return false;
+}
+String IMAPData::getFetchMessageFailedReason(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ return _errorMsg[messageIndex].c_str();
+ return std::string().c_str();
+}
+
+bool IMAPData::isDownloadAttachmentFailed(uint16_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._error;
+ id++;
+ }
+ }
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+
+ return false;
+}
+
+String IMAPData::getDownloadAttachmentFailedReason(uint16_t messageIndex, size_t attachmentIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ int id = 0;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153)
+ {
+ if (attachmentIndex == id)
+ return _messageDataInfo[messageIndex][i]._downloadError.c_str();
+ id++;
+ }
+ }
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+ return std::string().c_str();
+}
+
+bool IMAPData::isDownloadMessageFailed(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ bool res = false;
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == "")
+ {
+ res |= _messageDataInfo[messageIndex][i]._error;
+ }
+ }
+
+ return res;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+
+ return false;
+}
+String IMAPData::getDownloadMessageFailedReason(uint16_t messageIndex)
+{
+ if (messageIndex < _msgNum.size())
+ {
+ int s = _messageDataInfo[messageIndex].size();
+ string res = "";
+ if (s > 0)
+ {
+ for (int i = 0; i < s; i++)
+ {
+ if (_messageDataInfo[messageIndex][i]._disposition == "")
+ {
+ if (_messageDataInfo[messageIndex][i]._downloadError != "")
+ res = _messageDataInfo[messageIndex][i]._downloadError;
+ }
+ }
+
+ return res.c_str();
+ }
+ else
+ return std::string().c_str();
+ }
+ else
+ return std::string().c_str();
+
+ return std::string().c_str();
+}
+
+void IMAPData::empty()
+{
+ std::string().swap(_host);
+ std::string().swap(_loginEmail);
+ std::string().swap(_loginPassword);
+ std::string().swap(_currentFolder);
+ std::string().swap(_nextUID);
+ std::string().swap(_searchCriteria);
+ std::vector().swap(_date);
+ std::vector().swap(_subject);
+ std::vector().swap(_subject_charset);
+ std::vector().swap(_from);
+ std::vector().swap(_from_charset);
+ std::vector().swap(_to);
+ std::vector().swap(_to_charset);
+ std::vector().swap(_cc);
+ std::vector().swap(_cc_charset);
+ std::vector().swap(_msgNum);
+ std::vector().swap(_folders);
+ std::vector().swap(_flag);
+ std::vector().swap(_msgID);
+ std::vector().swap(_acceptLanguage);
+ std::vector().swap(_contentLanguage);
+ std::vector().swap(_attachmentCount);
+ std::vector().swap(_totalAttachFileSize);
+ std::vector().swap(_downloadedByte);
+ std::vector().swap(_error);
+ std::vector>().swap(_messageDataInfo);
+ std::vector().swap(_errorMsg);
+}
+
+void IMAPData::clearMessageData()
+{
+ std::vector().swap(_date);
+ std::vector().swap(_subject);
+ std::vector().swap(_subject_charset);
+ std::vector().swap(_from);
+ std::vector().swap(_from_charset);
+ std::vector().swap(_to);
+ std::vector().swap(_to_charset);
+ std::vector().swap(_cc);
+ std::vector().swap(_cc_charset);
+ std::vector().swap(_msgNum);
+ std::vector().swap(_msgID);
+ std::vector().swap(_contentLanguage);
+ std::vector().swap(_acceptLanguage);
+ std::vector().swap(_folders);
+ std::vector().swap(_flag);
+ std::vector().swap(_attachmentCount);
+ std::vector>().swap(_messageDataInfo);
+ std::vector().swap(_totalAttachFileSize);
+ std::vector().swap(_downloadedByte);
+ std::vector().swap(_messageDataCount);
+ std::vector().swap(_errorMsg);
+ std::vector().swap(_error);
+ _searchCount = 0;
+}
+
+messageBodyData::messageBodyData()
+{
+}
+messageBodyData::~messageBodyData()
+{
+ empty();
+}
+
+void messageBodyData::empty()
+{
+ std::string().swap(_text);
+ std::string().swap(_filename);
+ std::string().swap(_savePath);
+ std::string().swap(_name);
+ std::string().swap(_disposition);
+ std::string().swap(_contentType);
+ std::string().swap(_descr);
+ std::string().swap(_transfer_encoding);
+ std::string().swap(_creation_date);
+ std::string().swap(_modification_date);
+ std::string().swap(_charset);
+ std::string().swap(_part);
+ std::string().swap(_downloadError);
+}
+
+attachmentData::attachmentData() {}
+attachmentData::~attachmentData()
+{
+
+ std::vector>().swap(_buf);
+ std::vector().swap(_filename);
+ std::vector().swap(_id);
+ std::vector().swap(_type);
+ std::vector().swap(_size);
+ std::vector().swap(_mime_type);
+}
+
+void attachmentData::add(const String &fileName, const String &mimeType, uint8_t *data, size_t size)
+{
+ _filename.push_back(fileName.c_str());
+ _mime_type.push_back(mimeType.c_str());
+
+ if (size > 0)
+ {
+ std::vector d = std::vector();
+ d.push_back(data);
+ _buf.push_back(d);
+ _size.push_back(size);
+ _type.push_back(0);
+ }
+ else
+ {
+ _buf.push_back(std::vector());
+ _size.push_back(0);
+ _type.push_back(1);
+ }
+
+ _id.push_back(_index);
+ _index++;
+}
+
+void attachmentData::remove(uint8_t index)
+{
+ _buf.erase(_buf.begin() + index);
+ _filename.erase(_filename.begin() + index);
+ _type.erase(_type.begin() + index);
+ _size.erase(_size.begin() + index);
+ _mime_type.erase(_mime_type.begin() + index);
+ _id.erase(_id.begin() + index);
+}
+
+void attachmentData::free()
+{
+ std::vector>().swap(_buf);
+ std::vector().swap(_filename);
+ std::vector().swap(_id);
+ std::vector().swap(_type);
+ std::vector().swap(_size);
+ std::vector().swap(_mime_type);
+ _index = 0;
+}
+
+String attachmentData::getFileName(uint8_t index)
+{
+ return _filename[index].c_str();
+}
+
+String attachmentData::getMimeType(uint8_t index)
+{
+ return _mime_type[index].c_str();
+}
+
+uint8_t *attachmentData::getData(uint8_t index)
+{
+ uint8_t *ptr = _buf[index].front();
+ return ptr;
+}
+
+uint16_t attachmentData::getSize(uint8_t index)
+{
+ return _size[index];
+}
+
+uint8_t attachmentData::getCount()
+{
+ return _index;
+}
+
+uint8_t attachmentData::getType(uint8_t index)
+{
+ return _type[index];
+}
+
+SMTPData::SMTPData() {}
+
+SMTPData::~SMTPData()
+{
+ empty();
+ _net.reset();
+ _net.release();
+}
+
+void SMTPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA)
+{
+
+ _host.clear();
+ _port = port;
+ _loginEmail.clear();
+ _loginPassword.clear();
+
+ _host = host.c_str();
+ _loginEmail = loginEmail.c_str();
+ _loginPassword = loginPassword.c_str();
+
+ _rootCA.clear();
+ if (strlen(rootCA) > 0)
+ _rootCA.push_back((char *)rootCA);
+}
+
+void SMTPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword)
+{
+
+ _host.clear();
+ _port = port;
+ _loginEmail.clear();
+ _loginPassword.clear();
+
+ _host = host.c_str();
+ _loginEmail = loginEmail.c_str();
+ _loginPassword = loginPassword.c_str();
+
+ _rootCA.clear();
+}
+
+void SMTPData::setSTARTTLS(bool starttls)
+{
+ _starttls = starttls;
+}
+
+void SMTPData::setDebug(bool debug)
+{
+ _debug = debug;
+}
+
+void SMTPData::setSender(const String &fromName, const String &senderEmail)
+{
+
+ _fromName.clear();
+ _senderEmail.clear();
+
+ _fromName += fromName.c_str();
+ _senderEmail += senderEmail.c_str();
+}
+
+String SMTPData::getFromName()
+{
+ return _fromName.c_str();
+}
+
+String SMTPData::getSenderEmail()
+{
+ return _senderEmail.c_str();
+}
+
+void SMTPData::setPriority(int priority)
+{
+ _priority = priority;
+}
+void SMTPData::setPriority(const String &priority)
+{
+ if (priority == ESP32_MAIL_STR_205 || priority == ESP32_MAIL_STR_206)
+ _priority = 1;
+ else if (priority == ESP32_MAIL_STR_207 || priority == ESP32_MAIL_STR_208)
+ _priority = 3;
+ else if (priority == ESP32_MAIL_STR_209 || priority == ESP32_MAIL_STR_210)
+ _priority = 5;
+}
+
+uint8_t SMTPData::getPriority()
+{
+ return _priority;
+}
+
+void SMTPData::addRecipient(const String &email)
+{
+ _recipient.insert(_recipient.end(), email.c_str());
+}
+
+void SMTPData::removeRecipient(const String &email)
+{
+ for (uint8_t i = 0; i < _recipient.size(); i++)
+ if (_recipient[i].c_str() == email.c_str())
+ _recipient.erase(_recipient.begin() + i);
+}
+
+void SMTPData::removeRecipient(uint8_t index)
+{
+ _recipient.erase(_recipient.begin() + index);
+}
+
+void SMTPData::clearRecipient()
+{
+ std::vector().swap(_recipient);
+}
+
+uint8_t SMTPData::recipientCount()
+{
+ return _recipient.size();
+}
+
+String SMTPData::getRecipient(uint8_t index)
+{
+ if (index >= _recipient.size())
+ return std::string().c_str();
+ return _recipient[index].c_str();
+}
+
+void SMTPData::setSubject(const String &subject)
+{
+ _subject = subject.c_str();
+}
+
+String SMTPData::getSubject()
+{
+ return _subject.c_str();
+}
+
+void SMTPData::setMessage(const String &message, bool htmlFormat)
+{
+ _message.clear();
+ _message += message.c_str();
+ _htmlFormat = htmlFormat;
+}
+
+void SMTPData::clrMessage(bool htmlFormat)
+{
+ _message.clear();
+ _htmlFormat = htmlFormat;
+}
+
+void SMTPData::addMessage(const String &message)
+{
+ _message += message.c_str();
+}
+
+String SMTPData::getMessage()
+{
+ return _message.c_str();
+}
+
+bool SMTPData::htmlFormat()
+{
+ return _htmlFormat;
+}
+void SMTPData::addCC(const String &email)
+{
+ _cc.push_back(email.c_str());
+}
+
+void SMTPData::removeCC(const String &email)
+{
+ for (uint8_t i = 0; i < _cc.size(); i++)
+ if (_cc[i].c_str() == email.c_str())
+ _cc.erase(_cc.begin() + i);
+}
+
+void SMTPData::removeCC(uint8_t index)
+{
+ _cc.erase(_cc.begin() + index);
+}
+void SMTPData::clearCC()
+{
+ std::vector().swap(_cc);
+}
+
+uint8_t SMTPData::ccCount()
+{
+ return _cc.size();
+}
+
+String SMTPData::getCC(uint8_t index)
+{
+ if (index >= _cc.size())
+ return std::string().c_str();
+ return _cc[index].c_str();
+}
+
+void SMTPData::addBCC(const String &email)
+{
+ _bcc.push_back(email.c_str());
+}
+
+void SMTPData::removeBCC(const String &email)
+{
+ for (uint8_t i = 0; i < _bcc.size(); i++)
+ if (_bcc[i].c_str() == email.c_str())
+ _bcc.erase(_bcc.begin() + i);
+}
+
+void SMTPData::removeBCC(uint8_t index)
+{
+ _bcc.erase(_bcc.begin() + index);
+}
+
+void SMTPData::clearBCC()
+{
+ std::vector().swap(_bcc);
+}
+
+uint8_t SMTPData::bccCount()
+{
+ return _bcc.size();
+}
+
+String SMTPData::getBCC(uint8_t index)
+{
+ if (index >= _bcc.size())
+ return std::string().c_str();
+ return _bcc[index].c_str();
+}
+
+void SMTPData::addAttachData(const String &fileName, const String &mimeType, uint8_t *data, size_t size)
+{
+ _attach.add(fileName, mimeType, data, size);
+}
+
+void SMTPData::removeAttachData(const String &fileName)
+{
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getFileName(i) == fileName && _attach.getType(i) == 0)
+ {
+ _attach.remove(i);
+ }
+}
+
+void SMTPData::removeAttachData(uint8_t index)
+{
+ uint8_t id = 0;
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getType(i) == 0)
+ {
+ if (id == index)
+ {
+ _attach.remove(i);
+ break;
+ }
+ id++;
+ }
+}
+
+uint8_t SMTPData::attachDataCount()
+{
+ uint8_t count = 0;
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getType(i) == 0)
+ count++;
+
+ return count;
+}
+
+void SMTPData::addAttachFile(const String &filePath, const String &mimeType)
+{
+ _attach.add(filePath, mimeType, NULL, 0);
+}
+
+void SMTPData::removeAttachFile(const String &filePath)
+{
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getFileName(i) == filePath && _attach.getType(i) == 1)
+ {
+ _attach.remove(i);
+ }
+}
+
+void SMTPData::removeAttachFile(uint8_t index)
+{
+ uint8_t id = 0;
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getType(i) == 1)
+ {
+ if (id == index)
+ {
+ _attach.remove(i);
+ break;
+ }
+ id++;
+ }
+}
+
+void SMTPData::setFileStorageType(uint8_t storageType)
+{
+ _storageType = storageType;
+}
+
+void SMTPData::clearAttachData()
+{
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getType(i) == 0)
+ _attach.remove(i);
+}
+
+void SMTPData::clearAttachFile()
+{
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getType(i) == 1)
+ _attach.remove(i);
+}
+
+void SMTPData::clearAttachment()
+{
+ _attach.free();
+}
+
+uint8_t SMTPData::attachFileCount()
+{
+ uint8_t count = 0;
+ for (uint8_t i = 0; i < _attach.getCount(); i++)
+ if (_attach.getType(i) == 1)
+ count++;
+
+ return count;
+}
+
+void SMTPData::addCustomMessageHeader(const String &commmand)
+{
+ _customMessageHeader.insert(_customMessageHeader.end(), commmand.c_str());
+}
+
+void SMTPData::removeCustomMessageHeader(const String &commmand)
+{
+ for (uint8_t i = 0; i < _customMessageHeader.size(); i++)
+ if (_customMessageHeader[i].c_str() == commmand.c_str())
+ _customMessageHeader.erase(_customMessageHeader.begin() + i);
+}
+
+void SMTPData::removeCustomMessageHeader(uint8_t index)
+{
+ _customMessageHeader.erase(_customMessageHeader.begin() + index);
+}
+
+void SMTPData::clearCustomMessageHeader()
+{
+ std::vector().swap(_customMessageHeader);
+}
+
+uint8_t SMTPData::CustomMessageHeaderCount()
+{
+ return _customMessageHeader.size();
+}
+
+String SMTPData::getCustomMessageHeader(uint8_t index)
+{
+ if (index >= _customMessageHeader.size())
+ return std::string().c_str();
+ return _customMessageHeader[index].c_str();
+}
+
+void SMTPData::empty()
+{
+ std::string().swap(_host);
+ std::string().swap(_loginEmail);
+ std::string().swap(_loginPassword);
+ std::string().swap(_fromName);
+ std::string().swap(_senderEmail);
+ std::string().swap(_subject);
+ std::string().swap(_message);
+ clearRecipient();
+ clearCustomMessageHeader();
+ clearCC();
+ clearBCC();
+ clearAttachment();
+}
+
+void SMTPData::setSendCallback(sendStatusCallback sendCallback)
+{
+ _sendCallback = std::move(sendCallback);
+}
+
+ReadStatus::ReadStatus()
+{
+}
+ReadStatus::~ReadStatus()
+{
+ empty();
+}
+
+String ReadStatus::status()
+{
+ return _status.c_str();
+}
+String ReadStatus::info()
+{
+ return _info.c_str();
+}
+
+bool ReadStatus::success()
+{
+ return _success;
+}
+void ReadStatus::empty()
+{
+ std::string().swap(_info);
+ std::string().swap(_status);
+}
+
+SendStatus::SendStatus()
+{
+}
+
+SendStatus::~SendStatus()
+{
+ empty();
+}
+
+String SendStatus::info()
+{
+ return _info.c_str();
+}
+bool SendStatus::success()
+{
+ return _success;
+}
+void SendStatus::empty()
+{
+ std::string().swap(_info);
+}
+
+ESP32_MailClient MailClient = ESP32_MailClient();
+
+#endif //ESP32
+
+#endif //ESP32_MailClient_CPP
diff --git a/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h b/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h
new file mode 100755
index 000000000..943cd62f7
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h
@@ -0,0 +1,1908 @@
+/*
+ *Mail Client Arduino Library for ESP32, version 2.1.4
+ *
+ * April 12, 2020
+ *
+ * This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers.
+ *
+ * The library supports all ESP32 MCU based modules.
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+
+#ifndef ESP32_MailClient_H
+#define ESP32_MailClient_H
+
+#ifdef ESP32
+
+#include
+#include "WiFiClientSecureESP32.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "RFC2047.h"
+#include "ESP32MailHTTPClient.h"
+#include "ESP32TimeHelper.h"
+
+#define FORMAT_SPIFFS_IF_FAILED true
+
+static RFC2047 RFC2047Decoder;
+
+using namespace std;
+
+#define SMTP_STATUS_SERVER_CONNECT_FAILED 1
+#define SMTP_STATUS_SMTP_RESPONSE_FAILED 2
+#define SMTP_STATUS_IDENTIFICATION_FAILED 3
+#define SMTP_STATUS_AUTHEN_NOT_SUPPORT 4
+#define SMTP_STATUS_AUTHEN_FAILED 5
+#define SMTP_STATUS_USER_LOGIN_FAILED 6
+#define SMTP_STATUS_PASSWORD_LOGIN_FAILED 7
+#define SMTP_STATUS_SEND_HEADER_SENDER_FAILED 8
+#define SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED 9
+#define SMTP_STATUS_SEND_BODY_FAILED 10
+
+#define IMAP_STATUS_SERVER_CONNECT_FAILED 1
+#define IMAP_STATUS_IMAP_RESPONSE_FAILED 2
+#define IMAP_STATUS_LOGIN_FAILED 3
+#define IMAP_STATUS_BAD_COMMAND 4
+#define IMAP_STATUS_PARSE_FLAG_FAILED 5
+
+#define MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL 100
+
+#define MAX_EMAIL_SEARCH_LIMIT 1000
+
+static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+class IMAPData;
+class SMTPData;
+class attachmentData;
+class SendStatus;
+class messageBodyData;
+class DownloadProgress;
+class MessageData;
+
+struct MailClientStorageType
+{
+ static const uint8_t SPIFFS = 0;
+ static const uint8_t SD = 1;
+};
+
+static const char ESP32_MAIL_STR_1[] PROGMEM = "Content-Type: multipart/mixed; boundary=\"";
+static const char ESP32_MAIL_STR_2[] PROGMEM = "{BOUNDARY}";
+static const char ESP32_MAIL_STR_3[] PROGMEM = "Mime-Version: 1.0\r\n";
+static const char ESP32_MAIL_STR_4[] PROGMEM = "AUTH LOGIN";
+static const char ESP32_MAIL_STR_5[] PROGMEM = "HELO dude";
+static const char ESP32_MAIL_STR_6[] PROGMEM = "EHLO dude";
+static const char ESP32_MAIL_STR_7[] PROGMEM = "QUIT";
+static const char ESP32_MAIL_STR_8[] PROGMEM = "MAIL FROM:";
+static const char ESP32_MAIL_STR_9[] PROGMEM = "RCPT TO:";
+static const char ESP32_MAIL_STR_10[] PROGMEM = "From: ";
+static const char ESP32_MAIL_STR_11[] PROGMEM = "To: ";
+static const char ESP32_MAIL_STR_12[] PROGMEM = "Cc: ";
+static const char ESP32_MAIL_STR_13[] PROGMEM = ",<";
+static const char ESP32_MAIL_STR_14[] PROGMEM = "<";
+static const char ESP32_MAIL_STR_15[] PROGMEM = ">";
+static const char ESP32_MAIL_STR_16[] PROGMEM = "DATA";
+static const char ESP32_MAIL_STR_17[] PROGMEM = "X-Priority: ";
+static const char ESP32_MAIL_STR_18[] PROGMEM = "X-MSMail-Priority: High\r\n";
+static const char ESP32_MAIL_STR_19[] PROGMEM = "X-MSMail-Priority: Normal\r\n";
+static const char ESP32_MAIL_STR_20[] PROGMEM = "X-MSMail-Priority: Low\r\n";
+static const char ESP32_MAIL_STR_21[] PROGMEM = "Importance: High\r\n";
+static const char ESP32_MAIL_STR_22[] PROGMEM = "Importance: Normal\r\n";
+static const char ESP32_MAIL_STR_23[] PROGMEM = "Importance: Low\r\n";
+static const char ESP32_MAIL_STR_24[] PROGMEM = "Subject: ";
+static const char ESP32_MAIL_STR_25[] PROGMEM = "Content-Type: ";
+static const char ESP32_MAIL_STR_26[] PROGMEM = "; Name=\"";
+static const char ESP32_MAIL_STR_27[] PROGMEM = "Content-type: text/plain; charset=us-ascii\r\n";
+static const char ESP32_MAIL_STR_28[] PROGMEM = "Content-type: text/html; charset=\"UTF-8\"\r\n";
+static const char ESP32_MAIL_STR_29[] PROGMEM = "Content-transfer-encoding: 7bit\r\n";
+static const char ESP32_MAIL_STR_30[] PROGMEM = "Content-Disposition: attachment; filename=\"";
+static const char ESP32_MAIL_STR_31[] PROGMEM = "Content-transfer-encoding: base64\r\n";
+static const char ESP32_MAIL_STR_32[] PROGMEM = "application/octet-stream";
+static const char ESP32_MAIL_STR_33[] PROGMEM = "--";
+static const char ESP32_MAIL_STR_34[] PROGMEM = "\r\n";
+static const char ESP32_MAIL_STR_35[] PROGMEM = "\"\r\n\r\n";
+static const char ESP32_MAIL_STR_36[] PROGMEM = "\"\r\n";
+static const char ESP32_MAIL_STR_37[] PROGMEM = "\r\n.\r\n";
+static const char ESP32_MAIL_STR_38[] PROGMEM = "could not connect to server";
+static const char ESP32_MAIL_STR_39[] PROGMEM = "could not handle SMTP server response";
+static const char ESP32_MAIL_STR_40[] PROGMEM = "could not handle IMAP server response";
+static const char ESP32_MAIL_STR_41[] PROGMEM = "identification failed";
+static const char ESP32_MAIL_STR_42[] PROGMEM = "authentication is not support";
+static const char ESP32_MAIL_STR_43[] PROGMEM = "authentication failed";
+static const char ESP32_MAIL_STR_44[] PROGMEM = "login account is not valid";
+static const char ESP32_MAIL_STR_45[] PROGMEM = "could not sigin";
+static const char ESP32_MAIL_STR_46[] PROGMEM = "could not parse command";
+static const char ESP32_MAIL_STR_47[] PROGMEM = "login password is not valid";
+static const char ESP32_MAIL_STR_48[] PROGMEM = "send header failed";
+static const char ESP32_MAIL_STR_49[] PROGMEM = "send body failed";
+static const char ESP32_MAIL_STR_50[] PROGMEM = "Connecting to IMAP server...";
+static const char ESP32_MAIL_STR_51[] PROGMEM = "initialize";
+static const char ESP32_MAIL_STR_52[] PROGMEM = "failed";
+static const char ESP32_MAIL_STR_53[] PROGMEM = "Error, ";
+static const char ESP32_MAIL_STR_54[] PROGMEM = "IMAP server connected";
+static const char ESP32_MAIL_STR_55[] PROGMEM = "server_connected";
+static const char ESP32_MAIL_STR_56[] PROGMEM = "Sign in...";
+static const char ESP32_MAIL_STR_57[] PROGMEM = "signin";
+static const char ESP32_MAIL_STR_58[] PROGMEM = "Lising folders...";
+static const char ESP32_MAIL_STR_59[] PROGMEM = "listing";
+static const char ESP32_MAIL_STR_60[] PROGMEM = ":::::::Message folders:::::::";
+static const char ESP32_MAIL_STR_61[] PROGMEM = "Reading ";
+static const char ESP32_MAIL_STR_62[] PROGMEM = "Predicted next UID: ";
+static const char ESP32_MAIL_STR_63[] PROGMEM = "Total Message: ";
+static const char ESP32_MAIL_STR_64[] PROGMEM = "::::::::::::Flags::::::::::::";
+static const char ESP32_MAIL_STR_65[] PROGMEM = "::::::::::Messages:::::::::::";
+static const char ESP32_MAIL_STR_66[] PROGMEM = "Searching messages...";
+static const char ESP32_MAIL_STR_67[] PROGMEM = "searching";
+static const char ESP32_MAIL_STR_68[] PROGMEM = "Search limit:";
+static const char ESP32_MAIL_STR_69[] PROGMEM = "Found ";
+static const char ESP32_MAIL_STR_70[] PROGMEM = " messages";
+static const char ESP32_MAIL_STR_71[] PROGMEM = "Show ";
+static const char ESP32_MAIL_STR_72[] PROGMEM = "Could not found any Email for defined criteria";
+static const char ESP32_MAIL_STR_73[] PROGMEM = "Search criteria is not set, fetch the recent message";
+static const char ESP32_MAIL_STR_74[] PROGMEM = "Feching message ";
+static const char ESP32_MAIL_STR_75[] PROGMEM = ", UID: ";
+static const char ESP32_MAIL_STR_76[] PROGMEM = ", Number: ";
+static const char ESP32_MAIL_STR_77[] PROGMEM = "fetching";
+static const char ESP32_MAIL_STR_78[] PROGMEM = "Attachment (";
+static const char ESP32_MAIL_STR_79[] PROGMEM = ")";
+static const char ESP32_MAIL_STR_80[] PROGMEM = "Downloading attachments...";
+static const char ESP32_MAIL_STR_81[] PROGMEM = "downloading";
+static const char ESP32_MAIL_STR_82[] PROGMEM = " bytes";
+static const char ESP32_MAIL_STR_83[] PROGMEM = " - ";
+static const char ESP32_MAIL_STR_84[] PROGMEM = "Free Heap: ";
+static const char ESP32_MAIL_STR_85[] PROGMEM = "Sign out...";
+static const char ESP32_MAIL_STR_86[] PROGMEM = "signout";
+static const char ESP32_MAIL_STR_87[] PROGMEM = "Finished";
+static const char ESP32_MAIL_STR_88[] PROGMEM = "finished";
+static const char ESP32_MAIL_STR_89[] PROGMEM = "SD card mount failed";
+static const char ESP32_MAIL_STR_90[] PROGMEM = "download ";
+static const char ESP32_MAIL_STR_91[] PROGMEM = ", ";
+static const char ESP32_MAIL_STR_92[] PROGMEM = "%";
+static const char ESP32_MAIL_STR_93[] PROGMEM = "connection timeout";
+static const char ESP32_MAIL_STR_94[] PROGMEM = "WiFi connection lost";
+static const char ESP32_MAIL_STR_95[] PROGMEM = "no server response";
+static const char ESP32_MAIL_STR_96[] PROGMEM = "finished";
+static const char ESP32_MAIL_STR_97[] PROGMEM = " folder...";
+static const char ESP32_MAIL_STR_98[] PROGMEM = "Finished";
+static const char ESP32_MAIL_STR_99[] PROGMEM = "Date: ";
+static const char ESP32_MAIL_STR_100[] PROGMEM = "Messsage UID: ";
+static const char ESP32_MAIL_STR_101[] PROGMEM = "Messsage ID: ";
+static const char ESP32_MAIL_STR_102[] PROGMEM = "Accept Language: ";
+static const char ESP32_MAIL_STR_103[] PROGMEM = "Content Language: ";
+static const char ESP32_MAIL_STR_104[] PROGMEM = "From: ";
+static const char ESP32_MAIL_STR_105[] PROGMEM = "From Charset: ";
+static const char ESP32_MAIL_STR_106[] PROGMEM = "To: ";
+static const char ESP32_MAIL_STR_107[] PROGMEM = "To Charset: ";
+static const char ESP32_MAIL_STR_108[] PROGMEM = "CC: ";
+static const char ESP32_MAIL_STR_109[] PROGMEM = "CC Charset: ";
+static const char ESP32_MAIL_STR_110[] PROGMEM = "Subject: ";
+static const char ESP32_MAIL_STR_111[] PROGMEM = "Subject Charset: ";
+static const char ESP32_MAIL_STR_112[] PROGMEM = "Message Charset: ";
+static const char ESP32_MAIL_STR_113[] PROGMEM = "Attachment: ";
+static const char ESP32_MAIL_STR_114[] PROGMEM = "File Index: ";
+static const char ESP32_MAIL_STR_115[] PROGMEM = "Filename: ";
+static const char ESP32_MAIL_STR_116[] PROGMEM = "Name: ";
+static const char ESP32_MAIL_STR_117[] PROGMEM = "Size: ";
+static const char ESP32_MAIL_STR_118[] PROGMEM = "Type: ";
+static const char ESP32_MAIL_STR_119[] PROGMEM = "Creation Date: ";
+static const char ESP32_MAIL_STR_120[] PROGMEM = "Connecting to SMTP server...";
+static const char ESP32_MAIL_STR_121[] PROGMEM = "SMTP server connected, wait for response...";
+static const char ESP32_MAIL_STR_122[] PROGMEM = "Identification...";
+static const char ESP32_MAIL_STR_123[] PROGMEM = "Authentication...";
+static const char ESP32_MAIL_STR_124[] PROGMEM = "Sign in...";
+static const char ESP32_MAIL_STR_125[] PROGMEM = "Sending Email header...";
+static const char ESP32_MAIL_STR_126[] PROGMEM = "Sending Email body...";
+static const char ESP32_MAIL_STR_127[] PROGMEM = "Sending attachments...";
+static const char ESP32_MAIL_STR_128[] PROGMEM = "Finalize...";
+static const char ESP32_MAIL_STR_129[] PROGMEM = "Finished\r\nEmail sent successfully";
+static const char ESP32_MAIL_STR_130[] PROGMEM = "$ LOGIN ";
+static const char ESP32_MAIL_STR_131[] PROGMEM = " ";
+static const char ESP32_MAIL_STR_132[] PROGMEM = " OK ";
+static const char ESP32_MAIL_STR_133[] PROGMEM = "$ LIST \"\" \"*\"";
+static const char ESP32_MAIL_STR_134[] PROGMEM = "CAPABILITY";
+static const char ESP32_MAIL_STR_135[] PROGMEM = "$ EXAMINE \"";
+static const char ESP32_MAIL_STR_136[] PROGMEM = "\"";
+static const char ESP32_MAIL_STR_137[] PROGMEM = "UID ";
+static const char ESP32_MAIL_STR_138[] PROGMEM = " UID";
+static const char ESP32_MAIL_STR_139[] PROGMEM = " SEARCH";
+static const char ESP32_MAIL_STR_140[] PROGMEM = "UID";
+static const char ESP32_MAIL_STR_141[] PROGMEM = "SEARCH";
+static const char ESP32_MAIL_STR_142[] PROGMEM = "$ UID FETCH ";
+static const char ESP32_MAIL_STR_143[] PROGMEM = "$ FETCH ";
+static const char ESP32_MAIL_STR_144[] PROGMEM = " BODY.PEEK[HEADER.FIELDS (SUBJECT FROM TO DATE Message-ID Accept-Language Content-Language)]";
+static const char ESP32_MAIL_STR_145[] PROGMEM = "IMAP";
+static const char ESP32_MAIL_STR_146[] PROGMEM = "$ LOGOUT";
+static const char ESP32_MAIL_STR_147[] PROGMEM = " BODY.PEEK[";
+static const char ESP32_MAIL_STR_148[] PROGMEM = ".MIME]";
+static const char ESP32_MAIL_STR_149[] PROGMEM = "multipart/";
+static const char ESP32_MAIL_STR_150[] PROGMEM = "$ UID FETCH ";
+static const char ESP32_MAIL_STR_151[] PROGMEM = " BODY.PEEK[";
+static const char ESP32_MAIL_STR_152[] PROGMEM = ".";
+static const char ESP32_MAIL_STR_153[] PROGMEM = "attachment";
+static const char ESP32_MAIL_STR_154[] PROGMEM = "text/html";
+static const char ESP32_MAIL_STR_155[] PROGMEM = "text/plain";
+static const char ESP32_MAIL_STR_156[] PROGMEM = "]";
+static const char ESP32_MAIL_STR_157[] PROGMEM = "* ESEARCH";
+static const char ESP32_MAIL_STR_158[] PROGMEM = "$ NO ";
+static const char ESP32_MAIL_STR_159[] PROGMEM = "$ BAD ";
+static const char ESP32_MAIL_STR_160[] PROGMEM = "base64";
+static const char ESP32_MAIL_STR_161[] PROGMEM = "/decoded_msg.txt";
+static const char ESP32_MAIL_STR_162[] PROGMEM = "/raw_msg.txt";
+static const char ESP32_MAIL_STR_163[] PROGMEM = "/decoded_msg.html";
+static const char ESP32_MAIL_STR_164[] PROGMEM = "/raw_msg.html";
+static const char ESP32_MAIL_STR_165[] PROGMEM = " FETCH ";
+static const char ESP32_MAIL_STR_166[] PROGMEM = "* OK ";
+static const char ESP32_MAIL_STR_167[] PROGMEM = "content-type: ";
+static const char ESP32_MAIL_STR_168[] PROGMEM = "charset=\"";
+static const char ESP32_MAIL_STR_169[] PROGMEM = "charset=";
+static const char ESP32_MAIL_STR_170[] PROGMEM = "name=\"";
+static const char ESP32_MAIL_STR_171[] PROGMEM = "name=";
+static const char ESP32_MAIL_STR_172[] PROGMEM = "content-transfer-encoding: ";
+static const char ESP32_MAIL_STR_173[] PROGMEM = "\r";
+static const char ESP32_MAIL_STR_174[] PROGMEM = "content-description: ";
+static const char ESP32_MAIL_STR_175[] PROGMEM = "content-disposition: ";
+static const char ESP32_MAIL_STR_176[] PROGMEM = "filename=\"";
+static const char ESP32_MAIL_STR_177[] PROGMEM = "filename=";
+static const char ESP32_MAIL_STR_178[] PROGMEM = "size=";
+static const char ESP32_MAIL_STR_179[] PROGMEM = "creation-date=\"";
+static const char ESP32_MAIL_STR_180[] PROGMEM = "creation-date=";
+static const char ESP32_MAIL_STR_181[] PROGMEM = "modification-date=\"";
+static const char ESP32_MAIL_STR_182[] PROGMEM = "modification-date=";
+static const char ESP32_MAIL_STR_183[] PROGMEM = "*";
+static const char ESP32_MAIL_STR_184[] PROGMEM = "from: ";
+static const char ESP32_MAIL_STR_185[] PROGMEM = "to: ";
+static const char ESP32_MAIL_STR_186[] PROGMEM = "cc: ";
+static const char ESP32_MAIL_STR_187[] PROGMEM = "subject: ";
+static const char ESP32_MAIL_STR_188[] PROGMEM = "date: ";
+static const char ESP32_MAIL_STR_189[] PROGMEM = "message-id: ";
+static const char ESP32_MAIL_STR_190[] PROGMEM = "accept-language: ";
+static const char ESP32_MAIL_STR_191[] PROGMEM = "content-language: ";
+static const char ESP32_MAIL_STR_192[] PROGMEM = ")";
+static const char ESP32_MAIL_STR_193[] PROGMEM = "{";
+static const char ESP32_MAIL_STR_194[] PROGMEM = "}";
+static const char ESP32_MAIL_STR_195[] PROGMEM = " LIST ";
+static const char ESP32_MAIL_STR_196[] PROGMEM = "\\Noselect";
+static const char ESP32_MAIL_STR_197[] PROGMEM = " FLAGS ";
+static const char ESP32_MAIL_STR_198[] PROGMEM = "(";
+static const char ESP32_MAIL_STR_199[] PROGMEM = " EXISTS";
+static const char ESP32_MAIL_STR_200[] PROGMEM = " [UIDNEXT ";
+static const char ESP32_MAIL_STR_201[] PROGMEM = "]";
+static const char ESP32_MAIL_STR_202[] PROGMEM = "/";
+static const char ESP32_MAIL_STR_203[] PROGMEM = "/header.txt";
+static const char ESP32_MAIL_STR_204[] PROGMEM = "/esp.32";
+static const char ESP32_MAIL_STR_205[] PROGMEM = "high";
+static const char ESP32_MAIL_STR_206[] PROGMEM = "High";
+static const char ESP32_MAIL_STR_207[] PROGMEM = "normal";
+static const char ESP32_MAIL_STR_208[] PROGMEM = "Normal";
+static const char ESP32_MAIL_STR_209[] PROGMEM = "low";
+static const char ESP32_MAIL_STR_210[] PROGMEM = "Low";
+static const char ESP32_MAIL_STR_211[] PROGMEM = "$ OK ";
+static const char ESP32_MAIL_STR_212[] PROGMEM = "FLAGS";
+static const char ESP32_MAIL_STR_213[] PROGMEM = "BODY";
+static const char ESP32_MAIL_STR_214[] PROGMEM = "PEEK";
+static const char ESP32_MAIL_STR_215[] PROGMEM = "TEXT";
+static const char ESP32_MAIL_STR_216[] PROGMEM = "HEADER";
+static const char ESP32_MAIL_STR_217[] PROGMEM = "FIELDS";
+static const char ESP32_MAIL_STR_218[] PROGMEM = "[";
+static const char ESP32_MAIL_STR_219[] PROGMEM = "]";
+static const char ESP32_MAIL_STR_220[] PROGMEM = "MIME";
+static const char ESP32_MAIL_STR_221[] PROGMEM = "connection lost";
+static const char ESP32_MAIL_STR_222[] PROGMEM = "set recipient failed";
+static const char ESP32_MAIL_STR_223[] PROGMEM = " NEW";
+static const char ESP32_MAIL_STR_224[] PROGMEM = "ALL";
+
+static const char ESP32_MAIL_STR_225[] PROGMEM = "INFO: connecting to IMAP server...";
+static const char ESP32_MAIL_STR_226[] PROGMEM = "ERROR: could not connect to internet";
+static const char ESP32_MAIL_STR_227[] PROGMEM = "ERROR: ";
+static const char ESP32_MAIL_STR_228[] PROGMEM = "INFO: server connected";
+static const char ESP32_MAIL_STR_229[] PROGMEM = "INFO: send imap command LOGIN";
+static const char ESP32_MAIL_STR_230[] PROGMEM = "INFO: send imap command LIST";
+static const char ESP32_MAIL_STR_231[] PROGMEM = "INFO: send imap command EXAMINE";
+static const char ESP32_MAIL_STR_232[] PROGMEM = "INFO: search message";
+static const char ESP32_MAIL_STR_233[] PROGMEM = "INFO: fetch message";
+static const char ESP32_MAIL_STR_234[] PROGMEM = "INFO: send imap command LOGOUT";
+static const char ESP32_MAIL_STR_235[] PROGMEM = "INFO: message fetch completed";
+static const char ESP32_MAIL_STR_236[] PROGMEM = "INFO: connecting to SMTP server...";
+static const char ESP32_MAIL_STR_237[] PROGMEM = "ERROR: could not connect to internet";
+static const char ESP32_MAIL_STR_238[] PROGMEM = "INFO: smtp server connected";
+static const char ESP32_MAIL_STR_239[] PROGMEM = "INFO: send smtp HELO command";
+static const char ESP32_MAIL_STR_240[] PROGMEM = "INFO: send smtp AUTH LOGIN command";
+static const char ESP32_MAIL_STR_241[] PROGMEM = "INFO: log in with username and password";
+static const char ESP32_MAIL_STR_242[] PROGMEM = "INFO: send email header";
+static const char ESP32_MAIL_STR_243[] PROGMEM = "INFO: send email body";
+static const char ESP32_MAIL_STR_244[] PROGMEM = "INFO: send attachment...";
+static const char ESP32_MAIL_STR_245[] PROGMEM = "INFO: finalize...";
+static const char ESP32_MAIL_STR_246[] PROGMEM = "INFO: email sent successfully";
+static const char ESP32_MAIL_STR_247[] PROGMEM = "$ SELECT \"";
+static const char ESP32_MAIL_STR_248[] PROGMEM = "INFO: send imap command SELECT";
+static const char ESP32_MAIL_STR_249[] PROGMEM = "$ UID STORE ";
+static const char ESP32_MAIL_STR_250[] PROGMEM = " FLAGS (";
+static const char ESP32_MAIL_STR_251[] PROGMEM = " +FLAGS (";
+static const char ESP32_MAIL_STR_252[] PROGMEM = " -FLAGS (";
+static const char ESP32_MAIL_STR_253[] PROGMEM = "INFO: set FLAG";
+static const char ESP32_MAIL_STR_254[] PROGMEM = "INFO: add FLAG";
+static const char ESP32_MAIL_STR_255[] PROGMEM = "INFO: remove FLAG";
+static const char ESP32_MAIL_STR_256[] PROGMEM = "could not parse flag";
+static const char ESP32_MAIL_STR_257[] PROGMEM = "BAD";
+
+__attribute__((used)) static bool compFunc(uint32_t i, uint32_t j)
+{
+ return (i > j);
+}
+
+class ReadStatus
+{
+public:
+ ReadStatus();
+ ~ReadStatus();
+ String status();
+ String info();
+ bool success();
+ void empty();
+ friend IMAPData;
+
+ std::string _status = "";
+ std::string _info = "";
+ bool _success = false;
+};
+
+class SendStatus
+{
+public:
+ SendStatus();
+ ~SendStatus();
+ String info();
+ bool success();
+ void empty();
+ friend SMTPData;
+
+ std::string _info = "";
+ bool _success = false;
+};
+
+typedef void (*readStatusCallback)(ReadStatus);
+typedef void (*sendStatusCallback)(SendStatus);
+
+
+
+class ESP32_MailClient
+{
+
+public:
+ /*
+
+ Sending Email through SMTP server
+
+ @param net - HTTPClientESP32 WiFi client.
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool sendMail(SMTPData &smtpData);
+
+ /*
+
+ Reading Email through IMAP server.
+
+ @param imapData - IMAP Data object to hold data and instances.
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool readMail(IMAPData &imapData);
+
+ /*
+
+ Set the argument to the Flags for message.
+
+ @param imapData - IMAP Data object to hold data and instances.
+
+ @param msgUID - The UID of message.
+
+ @param flags - The flag list.
+
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool setFlag(IMAPData &imapData, int msgUID, const String &flags);
+
+
+
+ /*
+
+ Add the argument to the Flags for message.
+
+ @param imapData - IMAP Data object to hold data and instances.
+
+ @param msgUID - The UID of message.
+
+ @param flags - The flag list.
+
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool addFlag(IMAPData &imapData, int msgUID, const String &flags);
+
+ /*
+
+ Remove the argument from the Flags for message.
+
+ @param imapData - IMAP Data object to hold data and instances.
+
+ @param msgUID - The UID of message.
+
+ @param flags - The flag list.
+
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool removeFlag(IMAPData &imapData, int msgUID, const String &flags);
+
+ /*
+
+ Get the Email sending error details.
+
+ @return Error details string (String object).
+
+ */
+ String smtpErrorReason();
+
+ /*
+
+ Get the Email reading error details.
+
+ @return Error details string (String object).
+
+ */
+ String imapErrorReason();
+
+ /*
+
+ Init SD card with GPIO pins.
+
+ @param sck - SPI Clock pin.
+ @param miso - SPI MISO pin.
+ @param mosi - SPI MOSI pin.
+ @param ss - SPI Chip/Slave Select pin.
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss);
+
+ /*
+
+ Init SD card with default GPIO pins.
+
+ @return Boolean type status indicates the success of operation.
+
+ */
+ bool sdBegin(void);
+
+ struct IMAP_COMMAND_TYPE;
+ struct IMAP_HEADER_TYPE;
+
+
+ESP32TimeHelper Time;
+
+private:
+ int _smtpStatus = 0;
+ int _imapStatus = 0;
+ bool _sdOk = false;
+ bool _sdConfigSet = false;
+ uint8_t _sck, _miso, _mosi, _ss;
+ unsigned long _lastReconnectMillis = 0;
+ uint16_t _reconnectTimeout = 10000;
+
+
+ std::string smtpErrorReasonStr();
+ std::string imapErrorReasonStr();
+ void ESP32MailDebugError();
+ void ESP32MailDebugInfo(PGM_P info);
+ void set_message_header(string &header, std::string &message, bool htmlFormat);
+ void set_attachment_header(uint8_t index, std::string &header, attachmentData &attach);
+ void clientReadAll(WiFiClient *client);
+ double base64DecodeSize(std::string lastBase64String, int length);
+ unsigned char *base64_decode_char(const unsigned char *src, size_t len, size_t *out_len);
+ std::string base64_encode_string(const unsigned char *src, size_t len);
+ void send_base64_encode_mime_data(WiFiClient *client, const unsigned char *src, size_t len);
+ void send_base64_encode_mime_file(WiFiClient *client, File file);
+ int waitSMTPResponse(SMTPData &smtpData);
+ bool waitIMAPResponse(IMAPData &imapData, uint8_t imapCommandType = 0, int maxChar = 0, int mailIndex = -1, int messageDataIndex = -1, std ::string part = "");
+ bool _setFlag(IMAPData &imapData, int msgUID, const String &flags, uint8_t action);
+ bool getIMAPResponse(IMAPData &imapData);
+ void createDirs(std::string dirs);
+ bool smtpClientAvailable(SMTPData &smtpData, bool available);
+ bool imapClientAvailable(IMAPData &imapData, bool available);
+ bool sdTest();
+};
+
+class messageBodyData
+{
+public:
+ messageBodyData();
+ ~messageBodyData();
+ void empty();
+
+ friend ESP32_MailClient;
+ friend IMAPData;
+
+protected:
+ uint8_t _index = 0;
+ size_t _size = 0;
+ std::string _text = "";
+ std::string _filename = "";
+ std::string _savePath = "";
+ std::string _name = "";
+ std::string _disposition = "";
+ std::string _contentType = "";
+ std::string _descr = "";
+ std::string _transfer_encoding = "";
+ std::string _creation_date = "";
+ std::string _modification_date = "";
+ std::string _charset = "";
+ std::string _part = "";
+ std::string _downloadError = "";
+ bool _sdFileOpenWrite = false;
+ bool _error = false;
+};
+
+class attachmentData
+{
+public:
+ attachmentData();
+ ~attachmentData();
+
+ friend ESP32_MailClient;
+ friend SMTPData;
+
+protected:
+ uint8_t _index = 0;
+ std::vector> _buf = std::vector>();
+ std::vector _filename = std::vector();
+ std::vector _id = std::vector();
+ std::vector _type = std::vector();
+ std::vector _size = std::vector();
+ std::vector _mime_type = std::vector();
+
+ void add(const String &fileName, const String &mimeType, uint8_t *data, size_t size);
+ void remove(uint8_t index);
+ void free();
+ String getFileName(uint8_t index);
+ String getMimeType(uint8_t index);
+ uint8_t *getData(uint8_t index);
+ uint16_t getSize(uint8_t index);
+ uint8_t getCount();
+ uint8_t getType(uint8_t index);
+};
+
+class IMAPData
+{
+public:
+ IMAPData();
+ ~IMAPData();
+
+ /*
+ Set the IMAP server login credentials.
+
+ @param host - IMAP server e.g. imap.gmail.com.
+ @param port - IMAP port e.g. 993 for gmail.
+ @param loginEmail - The Email address of account.
+ @param loginPassword - The account password.
+ @rootCA - Root CA certificate base64 string
+
+ */
+ void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA);
+ void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword);
+
+ /*
+
+ Set STARTTLS mode to enable STARTTLS protocol
+
+ @param starttls - bool flag that enables STARTTLS mode
+
+ */
+ void setSTARTTLS(bool starttls);
+
+ /*
+
+ Set debug print to serial
+
+ @param debug - bool flag to enable debug
+
+ */
+ void setDebug(bool debug);
+
+ /*
+
+ Set the mailbox folder to search or fetch.
+
+ @param folderName - Known mailbox folder. Ddefault value is INBOX
+
+ */
+ void setFolder(const String &folderName);
+
+ /*
+
+ Set the maximum message buffer size for text/html result from search or fetch the message.
+
+ @param size - The message size in byte.
+
+ */
+ void setMessageBufferSize(size_t size);
+
+ /*
+
+ Set the maximum attachment file size to be downloaded.
+
+ @param size - The attachement file size in byte.
+
+ */
+ void setAttachmentSizeLimit(size_t size);
+
+ /*
+ Set the search criteria used in selected mailbox search.
+
+ In case of message UID was set through setFetchUID function, search operation will not process,
+ you need to clear message UID by calling imapData.setFetchUID("") to clear.
+
+ @param criteria - Search criteria String.
+
+ If folder is not set, the INBOX folder will be used
+
+ Example:
+
+ "SINCE 10-Feb-2019" will search all messages that received since 10 Feb 2019
+ "UID SEARCH ALL" will seach all message which will return the message UID that can be use later for fetch one or more messages.
+
+
+ Search criteria can be consisted these keywords
+
+ ALL - All messages in the mailbox; the default initial key for ANDing.
+ ANSWERED - Messages with the \Answered flag set.
+ BCC - Messages that contain the specified string in the envelope structure's BCC field.
+ BEFORE - Messages whose internal date (disregarding time and timezone) is earlier than the specified date.
+ BODY - Messages that contain the specified string in the body of the message.
+ CC - Messages that contain the specified string in the envelope structure's CC field.
+ DELETED - Messages with the \Deleted flag set.
+ DRAFT - Messages with the \Draft flag set.
+ FLAGGED - Messages with the \Flagged flag set.
+ FROM - Messages that contain the specified string in the envelope structure's FROM field.
+ HEADER - Messages that have a header with the specified field-name (as defined in [RFC-2822])
+ and that contains the specified string in the text of the header (what comes after the colon).
+
+ If the string to search is zero-length, this matches all messages that have a header line with
+ the specified field-name regardless of the contents.
+
+ KEYWORD - Messages with the specified keyword flag set.
+ LARGER - Messages with an [RFC-2822] size larger than the specified number of octets.
+ NEW - Messages that have the \Recent flag set but not the \Seen flag.
+ This is functionally equivalent to "(RECENT UNSEEN)".
+ NOT - Messages that do not match the specified search key.
+ OLD - Messages that do not have the \Recent flag set. This is functionally equivalent to
+ "NOT RECENT" (as opposed to "NOT NEW").
+ ON - Messages whose internal date (disregarding time and timezone) is within the specified date.
+ OR - Messages that match either search key.
+ RECENT - Messages that have the \Recent flag set.
+ SEEN - Messages that have the \Seen flag set.
+ SENTBEFORE - Messages whose [RFC-2822] Date: header (disregarding time and timezone) is earlier than the specified date.
+ SENTON - Messages whose [RFC-2822] Date: header (disregarding time and timezone) is within the specified date.
+ SENTSINCE - Messages whose [RFC-2822] Date: header (disregarding time and timezone) is within or later than the specified date.
+ SINCE - Messages whose internal date (disregarding time and timezone) is within or later than the specified date.
+ SMALLER - Messages with an [RFC-2822] size smaller than the specified number of octets.
+ SUBJECT - Messages that contain the specified string in the envelope structure's SUBJECT field.
+ TEXT - Messages that contain the specified string in the header or body of the message.
+ TO - Messages that contain the specified string in the envelope structure's TO field.
+ UID - Messages with unique identifiers corresponding to the specified unique identifier set.
+ Sequence set ranges are permitted.
+ UNANSWERED - Messages that do not have the \Answered flag set.
+ UNDELETED - Messages that do not have the \Deleted flag set.
+ UNDRAFT - Messages that do not have the \Draft flag set.
+ UNFLAGGED - Messages that do not have the \Flagged flag set.
+ UNKEYWORD - Messages that do not have the specified keyword flag set.
+ UNSEEN - Messages that do not have the \Seen flag set.
+
+ */
+ void setSearchCriteria(const String &criteria);
+
+ /*
+ Set to search the unseen message.
+
+ @param unseenSearch - Boolean flag to enable unseen message search.
+
+ This function will be overridden (omitted) by setFetchUID as setSearchCriteria.
+
+ */
+ void setSearchUnseenMessage(bool unseenSearch);
+
+ /*
+ Set the download folder.
+
+ @param path - Path in SD card.
+
+ All text/html message and attachemnts will be saved to message UID folder which created in defined path
+ e.g. "/{DEFINED_PATH}/{MESSAGE_UID}/{ATTACHMENT_FILE...}".
+
+ */
+ void setSaveFilePath(const String &path);
+
+ /*
+
+ Specify message UID to fetch or read.
+
+ @param fetchUID - The message UID.
+
+ Specify the message UID to fetch (read) only specific message instead of search.
+
+ */
+ void setFetchUID(const String &fetchUID);
+
+ /*
+
+ Set storage type to save download attached file or messages.
+
+ @param storageType - The storage type to save file, MailClientStorageType::SD or MailClientStorageType::SPIFFS
+
+ */
+ void setFileStorageType(uint8_t storageType);
+
+ /*
+
+ Enable/disable attachment download.
+
+ @param download - Boolean flag to enable/disable attachment download.
+
+ */
+ void setDownloadAttachment(bool download);
+
+ /*
+
+ Enable/disable html message result.
+
+ @param htmlFormat - Boolean flag to enable/disable html message result.
+
+ The default value is false.
+
+ */
+ void setHTMLMessage(bool htmlFormat);
+
+ /*
+
+ Enable/disable plain text message result.
+
+ @param textFormat - Boolean flag to enable/disable plain text message result.
+
+ The default value is true.
+
+ */
+ void setTextMessage(bool textFormat);
+
+ /*
+
+ Set the maximum message to search.
+
+ @param limit - Any number from 0 to 65535.
+
+ The default value is 20.
+
+ */
+ void setSearchLimit(uint16_t limit);
+
+ /*
+
+ Enable/disable recent sort result.
+
+ @param recentSort - Boolean flag to enable/disable recent message sort result.
+
+ The default value is true.
+
+ */
+ void setRecentSort(bool recentSort);
+
+ /*
+
+ Assign callback function that return status of message fetching or reading.
+
+ @param readCallback - The function that accept readStatusCallback as parameter.
+
+ */
+ void setReadCallback(readStatusCallback readCallback);
+
+ /*
+
+ Enable/disable attachement download progress while fetching or receiving message.
+
+ @param report - Boolean flag to enable/disable attachement download progress while fetching or receiving message.
+
+ To get the download status, Callback function should be set through setReadCallback.
+
+ */
+ void setDownloadReport(bool report);
+
+ /*
+
+ Determine only message header is return when search.
+
+ */
+ bool isHeaderOnly();
+
+ /*
+
+ Get the sender name/Email for selected message from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Sender name/Email String.
+
+ */
+ String getFrom(uint16_t messageIndex);
+
+ /*
+
+ Get the sender name/Email charactor encoding.
+
+ @param messageIndex - The index of message.
+
+ @return Sender name/Email charactor encoding which use for decoding.
+
+ */
+ String getFromCharset(uint16_t messageIndex);
+
+ /*
+
+ Get the recipient name/Email for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Recipient name/Email String.
+
+ */
+ String getTo(uint16_t messageIndex);
+
+ /*
+
+ Get the recipient name/Email charactor encoding.
+
+ @param messageIndex - The index of message.
+
+ @return Recipient name/Email charactor encoding which use in decoding to local language.
+
+ */
+ String getToCharset(uint16_t messageIndex);
+
+ /*
+
+ Get the CC name/Email for selected message index of IMAPData result.
+
+ @param messageIndex - The index of message.
+
+ @return CC name/Email String.
+
+ */
+ String getCC(uint16_t messageIndex);
+
+ /*
+
+ Get the CC name/Email charactor encoding.
+
+ @param messageIndex - The index of message.
+
+ @return CC name/Email charactor encoding which use in decoding to local language.
+
+ */
+ String getCCCharset(uint16_t messageIndex);
+
+ /*
+
+ Get the message subject for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Message subject name/Email String.
+
+ */
+ String getSubject(uint16_t messageIndex);
+
+ /*
+
+ Get the message subject charactor encoding.
+
+ @param messageIndex - The index of message.
+
+ @return Message subject charactor encoding which use in decoding to local language.
+
+ */
+ String getSubjectCharset(uint16_t messageIndex);
+
+ /*
+
+ Get the html message for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The html message String or empty String upon the setHTMLMessage was set.
+
+ */
+ String getHTMLMessage(uint16_t messageIndex);
+
+ /*
+
+ Get the plain text message for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The plain text message String or empty String upon the setTextMessage was set.
+
+ */
+ String getTextMessage(uint16_t messageIndex);
+
+ /*
+
+ Get the html message charactor encoding.
+
+ @param messageIndex - The index of message.
+
+ @return Html message charactor encoding which use in decoding to local language.
+
+ */
+ String getHTMLMessgaeCharset(uint16_t messageIndex);
+
+ /*
+
+ Get the text message charactor encoding.
+
+ @param messageIndex - The index of message.
+
+ @return The text message charactor encoding which use in decoding to local language.
+
+ */
+ String getTextMessgaeCharset(uint16_t messageIndex);
+
+ /*
+
+ Get the date of received message for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The date String.
+
+ */
+ String getDate(uint16_t messageIndex);
+
+ /*
+
+ Get the message UID for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return UID String that can be use in setFetchUID.
+
+ */
+ String getUID(uint16_t messageIndex);
+
+ /*
+
+ Get the message number for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The message number which vary upon search criteria and sorting.
+
+ */
+ String getNumber(uint16_t messageIndex);
+
+ /*
+
+ Get the message ID for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The message ID String.
+
+ */
+ String getMessageID(uint16_t messageIndex);
+
+ /*
+
+ Get the accept language for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The accept language String.
+
+ */
+ String getAcceptLanguage(uint16_t messageIndex);
+
+ /*
+
+ Get the content language of text or html for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return The content language String.
+
+ */
+ String getContentLanguage(uint16_t messageIndex);
+
+ /*
+
+ Determine fetch error status for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Fetch error status.
+
+ */
+ bool isFetchMessageFailed(uint16_t messageIndex);
+
+ /*
+ Get fetch error reason for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Fetch error reason String for selected message index.
+
+ */
+ String getFetchMessageFailedReason(uint16_t messageIndex);
+
+ /*
+ Determine the attachment download error for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Fetch status.
+
+ */
+ bool isDownloadAttachmentFailed(uint16_t messageIndex, size_t attachmentIndex);
+
+ /*
+
+ Get the attachment download error reason for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Download error reason String for selected message index.
+
+ */
+ String getDownloadAttachmentFailedReason(uint16_t messageIndex, size_t attachmentIndex);
+
+ /*
+
+ Determine the downloaded/saved text message error status for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Text message download status.
+
+ */
+ bool isDownloadMessageFailed(uint16_t messageIndex);
+
+ /*
+
+ Get the attachment or message downloadeds error reason for selected message index from search result.
+
+ @param messageIndex - The index of message.
+
+ @return Downloaded error reason String for selected message index.
+
+ */
+ String getDownloadMessageFailedReason(uint16_t messageIndex);
+
+ /*
+
+ Assign the download and decode flags for html message download.
+
+ @param download - Boolean flag to enable/disable message download.
+
+ @param decoded - Boolean flag to enable/disable html message decoding (support utf8 and base64 encoding).
+
+ */
+ void saveHTMLMessage(bool download, bool decoded);
+
+ /*
+
+ Assign the download and decode flags for plain text message download.
+
+ @param download - Boolean flag to enable/disable message download.
+
+ @param decoded - Boolean flag to enable/disable plain text message decoding (support utf8 and base64 encoding).
+
+ */
+ void saveTextMessage(bool download, bool decoded);
+
+ /*
+
+ Determine the mailbox folder count.
+
+ @return Folder count number.
+
+ */
+ uint16_t getFolderCount();
+
+ /*
+ Get the mailbox folder name at selected index.
+
+ @param folderIndex - Index of folder.
+
+ @return Folder name String.
+
+ Use folder name from this function for fetch or search.
+
+ */
+ String getFolder(uint16_t folderIndex);
+
+ /*
+
+ Determin the number of supported flags count.
+
+ @return Flag count number.
+
+ */
+ uint16_t getFlagCount();
+
+ /*
+ Get the flag name for selected index.
+
+ @param folderIndex - Index of folder.
+
+ @return Flag name String.
+
+ Use flags from this function for fetch or search.
+
+ */
+ String getFlag(uint16_t flagIndex);
+
+ /*
+
+ Get the number of message in selected mailbox folder.
+
+ @return Total message number.
+
+ */
+ size_t totalMessages();
+
+ /*
+
+ Get the number of message from search result.
+
+ @return Search result number.
+
+ */
+ size_t searchCount();
+
+ /*
+
+ Get the number of message available from search result which less than search limit.
+
+ @return Available message number.
+
+ */
+ size_t availableMessages();
+
+ /*
+
+ Get the number of attachments for selected message index from search result.
+
+ @param messageIndex - Index of message.
+
+ @return Number of attachments
+
+ */
+ size_t getAttachmentCount(uint16_t messageIndex);
+
+ /*
+
+ Get file name of attachment for selected attachment index and message index from search result.
+
+ @param messageIndex - Index of message.
+ @param attachmentIndex - Index of attachment.
+
+ @return The attachment file name String at the selected index.
+
+ */
+ String getAttachmentFileName(size_t messageIndex, size_t attachmentIndex);
+
+ /*
+
+ Get the name of attachment for selected attachment index and message index from search result.
+
+ @param messageIndex - Index of message.
+ @param attachmentIndex - Index of attachment.
+
+ @return The attachment name String at the selected index.
+
+ */
+ String getAttachmentName(size_t messageIndex, size_t attachmentIndex);
+
+ /*
+
+ Get attachment file size for selected attachment index and message index from search result.
+
+ @param messageIndex - Index of message.
+ @param attachmentIndex - Index of attachment.
+
+ @return The attachment file size in byte at the selected index.
+
+ */
+ int getAttachmentFileSize(size_t messageIndex, size_t attachmentIndex);
+
+ /*
+
+ Get creation date of attachment for selected attachment index and message index from search result.
+
+ @param messageIndex - Index of message.
+ @param attachmentIndex - Index of attachment.
+
+ @return The attachment creation date String at the selected index.
+
+ */
+ String getAttachmentCreationDate(size_t messageIndex, size_t attachmentIndex);
+
+ /*
+ Get attachment file type for selected attachment index and message index from search result.
+
+ @param messageIndex - Index of message.
+ @param attachmentIndex - Index of attachment.
+
+ @return File MIME String at the selected index e.g. image/jpeg.
+
+ */
+ String getAttachmentType(size_t messageIndex, size_t attachmentIndex);
+
+ /*
+
+ Clear all IMAPData object data.
+
+ */
+ void empty();
+
+ /*
+
+ Clear IMAPData object message data.
+
+ */
+ void clearMessageData();
+
+ friend ESP32_MailClient;
+
+private:
+ String getMessage(uint16_t messageIndex, bool htmlFormat);
+
+
+ size_t _totalMessage = 0;
+ std::string _host = "";
+ uint16_t _port = 993;
+ uint8_t _storageType = 1;
+ bool _unseen = false;
+ std::string _loginEmail = "";
+ std::string _loginPassword = "";
+ std::string _currentFolder = "INBOX";
+ std::string _nextUID = "";
+ std::string _searchCriteria = "ALL*";
+ std::string _fetchUID = "";
+ std::string _savePath = "";
+
+ bool _downloadAttachment = false;
+ bool _recentSort = true;
+ bool _htmlFormat = false;
+ bool _textFormat = false;
+ bool _headerOnly = true;
+ bool _uidSearch = false;
+ bool _saveHTMLMsg = false;
+ bool _saveTextMsg = false;
+ bool _saveDecodedHTML = false;
+ bool _saveDecodedText = false;
+ bool _downloadReport = false;
+ bool _headerSaved = false;
+
+ size_t _message_buffer_size = 200;
+ size_t _attacement_max_size = 1024 * 1024;
+ uint16_t _emailNumMax = 20;
+ int _searchCount;
+ bool _starttls = false;
+ bool _debug = false;
+ readStatusCallback _readCallback = NULL;
+
+ std::vector _date = std::vector();
+ std::vector _subject = std::vector();
+ std::vector _subject_charset = std::vector();
+ std::vector _from = std::vector();
+ std::vector _from_charset = std::vector();
+ std::vector _to = std::vector();
+ std::vector _to_charset = std::vector();
+ std::vector _cc = std::vector();
+ std::vector _cc_charset = std::vector();
+ std::vector _msgNum = std::vector();
+ std::vector _msgID = std::vector();
+ std::vector _contentLanguage = std::vector();
+ std::vector _acceptLanguage = std::vector();
+
+ std::vector _folders = std::vector();
+ std::vector _flag = std::vector();
+ std::vector _attachmentCount = std::vector();
+ std::vector> _messageDataInfo = std::vector>();
+ std::vector _totalAttachFileSize = std::vector();
+ std::vector _downloadedByte = std::vector();
+ std::vector _messageDataCount = std::vector();
+ std::vector _errorMsg = std::vector();
+ std::vector _error = std::vector();
+ std::vector _rootCA = std::vector();
+
+
+ std::unique_ptr _net = std::unique_ptr(new ESP32MailHTTPClient());
+
+ ReadStatus _cbData;
+};
+
+class SMTPData
+{
+public:
+ SMTPData();
+ ~SMTPData();
+
+ /*
+
+ Set SMTP server login credentials
+
+ @param host - SMTP server e.g. smtp.gmail.com
+ @param port - SMTP port.
+ @param loginEmail - The account Email.
+ @param loginPassword - The account password.
+ @rootCA - Root CA certificate base64 string
+
+ */
+ void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA);
+ void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword);
+
+ /*
+
+ Set STARTTLS mode to enable STARTTLS protocol
+
+ @param starttls - bool flag that enables STARTTLS mode
+
+ */
+ void setSTARTTLS(bool starttls);
+
+ /*
+
+ Set debug print to serial
+
+ @param debug - bool flag to enable debug
+
+ */
+ void setDebug(bool debug);
+ /*
+
+ Set Sender info
+
+ @param fromName - Sender's name
+ @param senderEmail - Sender's Email.
+
+ */
+ void setSender(const String &fromName, const String &senderEmail);
+
+ /*
+
+ Get Sender's name
+
+ @return Sender's name String.
+
+ */
+ String getFromName();
+
+ /*
+
+ Get Sender's Email
+
+ @return Sender's Email String.
+
+ */
+ String getSenderEmail();
+
+ /*
+
+ Set Email priority or importance
+
+ @param priority - Number from 1 to 5, 1 for highest, 3 for normal and 5 for lowest priority
+
+ */
+ void setPriority(int priority);
+
+ /*
+
+ Set Email priority or importance
+
+ @param priority - String (High, Normal or Low)
+
+ */
+ void setPriority(const String &priority);
+
+ /*
+
+ Get Email priority
+
+ @return number represents Email priority (1 for highest, 3 for normal, 5 for low priority).
+
+ */
+ uint8_t getPriority();
+
+ /*
+
+ Add one or more recipient
+
+ @param email - Recipient Email String of one recipient.
+
+ To add multiple recipients, call addRecipient for each recipient.
+
+ */
+ void addRecipient(const String &email);
+
+ /*
+
+ Remove recipient
+
+ @param email - Recipient Email String.
+
+ */
+ void removeRecipient(const String &email);
+
+ /*
+
+ Remove recipient
+
+ @param index - Index of recipients in Email object that previously added.
+
+ */
+ void removeRecipient(uint8_t index);
+
+ /*
+ Clear all recipients.
+ */
+ void clearRecipient();
+
+ /*
+
+ Get one recipient
+
+ @param index - Index of recipients.
+
+ @return Recipient Email String at the index.
+
+ */
+ String getRecipient(uint8_t index);
+
+ /*
+
+ Get number of recipients
+
+ @return Number of recipients.
+
+ */
+ uint8_t recipientCount();
+
+ /*
+
+ Set the Email subject
+
+ @param subject - The subject.
+
+ */
+ void setSubject(const String &subject);
+
+ /*
+
+ Get the Email subject
+
+ @return Subject String.
+
+ */
+ String getSubject();
+
+ /*
+
+ Set the Email message
+
+ @param message - The message can be in normal text or html format.
+ @param htmlFormat - The html format flag, True for send the message as html format
+
+ */
+ void setMessage(const String &message, bool htmlFormat);
+
+ void clrMessage(bool htmlFormat);
+
+ void addMessage(const String &message);
+
+
+ /*
+
+ Get the message
+
+ @return Message String.
+
+ */
+ String getMessage();
+
+ /*
+
+ Determine message is being send in html format
+
+ @return Boolean status.
+
+ */
+ bool htmlFormat();
+
+ /*
+
+ Add Carbon Copy (CC) Email
+
+ @param email - The CC Email String.
+
+ */
+ void addCC(const String &email);
+
+ /*
+
+ Remove specified Carbon Copy (CC) Email
+
+ @param email - The CC Email String to remove.
+
+ */
+ void removeCC(const String &email);
+
+ /*
+
+ Remove specified Carbon Copy (CC) Email
+
+ @param index - The CC Email index to remove.
+
+ */
+ void removeCC(uint8_t index);
+
+ /*
+
+ Clear all Carbon Copy (CC) Emails
+
+ */
+ void clearCC();
+
+ /*
+
+ Get Carbon Copy (CC) Email at specified index
+
+ @param index - The CC Email index to get.
+ @return The CC Email string at the index.
+
+ */
+ String getCC(uint8_t index);
+
+ /*
+
+ Get the number of Carbon Copy (CC) Email
+
+ @return Number of CC Emails.
+
+ */
+ uint8_t ccCount();
+
+ /*
+ Add Blind Carbon Copy (BCC) Email
+
+ @param email - The BCC Email String.
+
+ */
+ void addBCC(const String &email);
+
+ /*
+
+ Remove specified Blind Carbon Copy (BCC) Email
+
+ @param email - The BCC Email String to remove.
+
+ */
+ void removeBCC(const String &email);
+
+ /*
+
+ Remove specified Blind Carbon Copy (BCC) Email
+
+ @param index - The BCC Email index to remove.
+
+ */
+ void removeBCC(uint8_t index);
+
+ /*
+
+ Clear all Blind Carbon Copy (BCC) Emails
+
+ */
+ void clearBCC();
+
+ /*
+
+ Get Blind Carbon Copy (BCC) Email at specified index
+
+ @param index - The BCC Email index to get.
+
+ @return The BCC Email string at the index.
+
+ */
+ String getBCC(uint8_t index);
+
+ /*
+
+ Get the number of Blind Carbon Copy (BCC) Email
+
+ @return Number of BCC Emails.
+
+ */
+ uint8_t bccCount();
+
+ /*
+
+ Add attchement data (binary) from internal memory (flash or ram)
+
+ @param fileName - The file name String that recipient can be saved.
+ @param mimeType - The MIME type of file (image/jpeg, image/png, text/plain...). Can be empty String.
+ @param data - The byte array of data (uint8_t)
+ @param size - The data length in byte.
+
+ */
+ void addAttachData(const String &fileName, const String &mimeType, uint8_t *data, size_t size);
+
+ /*
+
+ Remove specified attachment data
+
+ @param fileName - The file name of the attachment data to remove.
+
+ */
+ void removeAttachData(const String &fileName);
+
+ /*
+
+ Remove specified attachment data
+
+ @param index - The index of the attachment data (count only data type attachment) to remove.
+
+ */
+ void removeAttachData(uint8_t index);
+
+ /*
+
+ Get the number of attachment data
+
+ @return Number of attach data.
+
+ */
+ uint8_t attachDataCount();
+
+ /*
+
+ Add attchement file from SD card
+
+ @param fileName - The file name String that recipient can be saved.
+ @param mimeType - The MIME type of file (image/jpeg, image/png, text/plain...). Can be omitted.
+
+ */
+ void addAttachFile(const String &filePath, const String &mimeType = "");
+
+ /*
+
+ Remove specified attachment file from Email object
+
+ @param fileName - The file name of the attachment file to remove.
+
+ */
+ void removeAttachFile(const String &filePath);
+
+ /*
+
+ Remove specified attachment file
+
+ @param index - The index of the attachment file (count only file type attachment) to remove.
+
+ */
+ void removeAttachFile(uint8_t index);
+
+ /*
+
+ Set storage type for all attach files.
+
+ @param storageType - The storage type to read attach file, MailClientStorageType::SD or MailClientStorageType::SPIFFS
+
+ */
+ void setFileStorageType(uint8_t storageType);
+
+ /*
+
+ Clear all attachment data
+
+ */
+ void clearAttachData();
+
+ /*
+
+ Clear all attachment file.
+
+ */
+ void clearAttachFile();
+
+ /*
+
+ Clear all attachments (both data and file type attachments).
+
+ */
+ void clearAttachment();
+
+ /*
+
+ Get number of attachments (both data and file type attachments).
+
+ @return Number of all attachemnts.
+
+ */
+ uint8_t attachFileCount();
+
+ /*
+
+ Add one or more custom message header field.
+
+ @param field - custom header String inform of FIELD: VALUE
+
+ This header field will add to message header.
+
+
+ */
+ void addCustomMessageHeader(const String &field);
+
+ /*
+
+ Remove one custom message header field that previously added.
+
+ @param field - custom custom message header field String to remove.
+
+
+ */
+ void removeCustomMessageHeader(const String &field);
+
+ /*
+
+ Remove one custom message header field that previously added by its index.
+
+ @param index - custom message header field index (number) to remove.
+
+
+ */
+ void removeCustomMessageHeader(uint8_t index);
+
+ /*
+
+ Clear all ccustom message header field that previously added.
+
+ */
+ void clearCustomMessageHeader();
+
+ /*
+
+ Get the number of custom message header field that previously added.
+
+ @return Number of custom message header field.
+
+ */
+ uint8_t CustomMessageHeaderCount();
+
+ /*
+
+ Get custom message header field that previously added by index
+
+ @param index - The custom message header field index to get.
+
+ @return The custom message header field string at the index.
+
+ */
+ String getCustomMessageHeader(uint8_t index);
+
+
+
+ /*
+
+ Clear all data from Email object to free memory.
+
+ */
+ void empty();
+
+ /*
+
+ Set the Email sending status callback function to Email object.
+
+ @param sendCallback - The callback function that accept the sendStatusCallback param.
+
+ */
+ void setSendCallback(sendStatusCallback sendCallback);
+
+ friend ESP32_MailClient;
+ friend attachmentData;
+
+protected:
+ int _priority = -1;
+ string _loginEmail = "";
+ string _loginPassword = "";
+ string _host = "";
+ uint16_t _port = 0;
+ uint8_t _storageType = 1;
+
+ string _fromName = "";
+ string _senderEmail = "";
+ string _subject = "";
+ string _message = "";
+ bool _htmlFormat = false;
+ bool _starttls = false;
+ bool _debug = false;
+ sendStatusCallback _sendCallback = NULL;
+
+ std::vector _recipient = std::vector();
+ std::vector _customMessageHeader = std::vector();
+ std::vector _cc = std::vector();
+ std::vector _bcc = std::vector();
+ attachmentData _attach;
+ SendStatus _cbData;
+ std::vector _rootCA = std::vector();
+ std::unique_ptr _net = std::unique_ptr(new ESP32MailHTTPClient());
+
+};
+
+
+static void __attribute__((used)) ESP32MailDebug(const char *msg)
+{
+
+ Serial.print(FPSTR("[DEBUG] - "));
+ Serial.println(msg);
+
+}
+
+static void __attribute__((used)) ESP32MailDebugLine(const char *msg, bool newline)
+{
+ if (!newline)
+ Serial.print(FPSTR("[DEBUG] - "));
+
+ if (newline)
+ Serial.println(msg);
+ else
+ Serial.print(msg);
+}
+
+
+extern ESP32_MailClient MailClient;
+
+#endif //ESP32
+
+#endif //ESP32_MailClient_H
diff --git a/libesp32/ESP32-Mail-Client/src/RFC2047.cpp b/libesp32/ESP32-Mail-Client/src/RFC2047.cpp
new file mode 100755
index 000000000..993c132e3
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/RFC2047.cpp
@@ -0,0 +1,240 @@
+#ifndef RFC2047_CPP
+#define RFC2047_CPP
+
+#ifdef ESP32
+
+#include "RFC2047.h"
+
+RFC2047::RFC2047(){}
+
+
+void RFC2047::rfc2047Decode(char *d, const char *s, size_t dlen){
+
+ const char *p, *q;
+ size_t n;
+ int found_encoded = 0;
+
+ dlen--; /* save room for the terminal nul */
+
+ while (*s && dlen > 0)
+ {
+ if ((p = strstr (s, "=?")) == NULL ||
+ (q = strchr (p + 2, '?')) == NULL ||
+ (q = strchr (q + 1, '?')) == NULL ||
+ (q = strstr (q + 1, "?=")) == NULL)
+ {
+ /* no encoded words */
+ if (d != s)
+ strfcpy (d, s, dlen + 1);
+ return;
+ }
+
+ if (p != s)
+ {
+ n = (size_t) (p - s);
+ /* ignore spaces between encoded words */
+ if (!found_encoded || strspn (s, " \t\r\n") != n)
+ {
+ if (n > dlen)
+ n = dlen;
+ if (d != s)
+ memcpy (d, s, n);
+ d += n;
+ dlen -= n;
+ }
+ }
+
+ rfc2047DecodeWord (d, p, dlen);
+ found_encoded = 1;
+ s = q + 2;
+ n = strlen (d);
+ dlen -= n;
+ d += n;
+ }
+ *d = 0;
+
+}
+
+void RFC2047::rfc2047DecodeWord(char *d, const char *s, size_t dlen){
+
+ char *p = safe_strdup (s);
+ char *pp = p;
+ char *pd = d;
+ size_t len = dlen;
+ int enc = 0, filter = 0, count = 0, c1, c2, c3, c4;
+
+ while ((pp = strtok (pp, "?")) != NULL)
+ {
+ count++;
+ switch (count)
+ {
+ case 2:
+ if (strcasecmp (pp, Charset) != 0)
+ {
+ filter = 1;
+ }
+ break;
+ case 3:
+ if (toupper (*pp) == 'Q')
+ enc = ENCQUOTEDPRINTABLE;
+ else if (toupper (*pp) == 'B')
+ enc = ENCBASE64;
+ else
+ return;
+ break;
+ case 4:
+ if (enc == ENCQUOTEDPRINTABLE)
+ {
+ while (*pp && len > 0)
+ {
+ if (*pp == '_')
+ {
+ *pd++ = ' ';
+ len--;
+ }
+ else if (*pp == '=')
+ {
+ *pd++ = (hexval(pp[1]) << 4) | hexval(pp[2]);
+ len--;
+ pp += 2;
+ }
+ else
+ {
+ *pd++ = *pp;
+ len--;
+ }
+ pp++;
+ }
+ *pd = 0;
+ }
+ else if (enc == ENCBASE64)
+ {
+ while (*pp && len > 0)
+ {
+ c1 = base64val(pp[0]);
+ c2 = base64val(pp[1]);
+ *pd++ = (c1 << 2) | ((c2 >> 4) & 0x3);
+ if (--len == 0) break;
+
+ if (pp[2] == '=') break;
+
+ c3 = base64val(pp[2]);
+ *pd++ = ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf);
+ if (--len == 0)
+ break;
+
+ if (pp[3] == '=')
+ break;
+
+ c4 = base64val(pp[3]);
+ *pd++ = ((c3 & 0x3) << 6) | c4;
+ if (--len == 0)
+ break;
+
+ pp += 4;
+ }
+ *pd = 0;
+ }
+ break;
+ }
+ pp = 0;
+ }
+ safe_free (&p);
+ if (filter)
+ {
+
+ pd = d;
+ while (*pd)
+ {
+ if (!IsPrint (*pd))
+ *pd = '?';
+ pd++;
+ }
+ }
+ return;
+}
+
+
+void *RFC2047::safe_calloc (size_t nmemb, size_t size)
+{
+ void *p;
+
+ if (!nmemb || !size)
+ return NULL;
+ if (!(p = calloc (nmemb, size)))
+ {
+ //out of memory
+ return NULL;
+ }
+ return p;
+}
+
+void *RFC2047::safe_malloc (unsigned int siz)
+{
+ void *p;
+
+ if (siz == 0)
+ return 0;
+ if ((p = (void *) malloc (siz)) == 0)
+ {
+ //out of memory
+ return NULL;
+ }
+ return (p);
+}
+
+void RFC2047::safe_realloc (void **p, size_t siz)
+{
+ void *r;
+
+ if (siz == 0)
+ {
+ if (*p)
+ {
+ free (*p);
+ *p = NULL;
+ }
+ return;
+ }
+
+ if (*p)
+ r = (void *) realloc (*p, siz);
+ else
+ {
+ r = (void *) malloc (siz);
+ }
+
+ if (!r)
+ {
+ //out of memory
+ return;
+ }
+
+ *p = r;
+}
+
+void RFC2047::safe_free (void *ptr)
+{
+ void **p = (void **)ptr;
+ if (*p)
+ {
+ free (*p);
+ *p = 0;
+ }
+}
+
+char *RFC2047::safe_strdup (const char *s)
+{
+ char *p;
+ size_t l;
+
+ if (!s || !*s) return 0;
+ l = strlen (s) + 1;
+ p = (char *)safe_malloc (l);
+ memcpy (p, s, l);
+ return (p);
+}
+
+#endif //ESP32
+
+#endif //RFC2047_CPP
\ No newline at end of file
diff --git a/libesp32/ESP32-Mail-Client/src/RFC2047.h b/libesp32/ESP32-Mail-Client/src/RFC2047.h
new file mode 100755
index 000000000..aeee0e12c
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/RFC2047.h
@@ -0,0 +1,70 @@
+
+#ifndef RFC2047_H
+#define RFC2047_H
+
+#ifdef ESP32
+
+#include
+
+
+#define strfcpy(A,B,C) strncpy(A,B,C), *(A+(C)-1)=0
+
+enum
+{
+ ENCOTHER,
+ ENC7BIT,
+ ENC8BIT,
+ ENCQUOTEDPRINTABLE,
+ ENCBASE64,
+ ENCBINARY
+};
+
+__attribute__((used)) static const char *Charset = "utf-8";
+
+__attribute__((used)) static int Index_hex[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+__attribute__((used)) static int Index_64[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1};
+
+#define IsPrint(c) (isprint((unsigned char)(c)) || \
+ ((unsigned char)(c) >= 0xa0))
+
+#define hexval(c) Index_hex[(unsigned int)(c)]
+#define base64val(c) Index_64[(unsigned int)(c)]
+
+class RFC2047{
+
+ public:
+ RFC2047();
+ void rfc2047Decode(char *d, const char *s, size_t dlen);
+
+
+ private:
+ void rfc2047DecodeWord(char *d, const char *s, size_t dlen);
+ void *safe_calloc (size_t nmemb, size_t size);
+ void *safe_malloc (unsigned int siz);
+ void safe_realloc (void **p, size_t siz);
+ void safe_free (void *ptr);
+ char *safe_strdup (const char *s);
+
+
+};
+
+#endif //ESP32
+
+#endif //RFC2047_H
\ No newline at end of file
diff --git a/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp b/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp
new file mode 100755
index 000000000..26460a604
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp
@@ -0,0 +1,397 @@
+/*
+ *Customized WiFiClientSecure.cpp to support STARTTLS protocol, version 1.0.1
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/*
+ WiFiClientSecureESP32.cpp - Client Secure class for ESP32
+ Copyright (c) 2016 Hristo Gochkov All right reserved.
+ Additions Copyright (C) 2017 Evandro Luis Copercini.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef WiFiClientSecureESP32_CPP
+#define WiFiClientSecureESP32_CPP
+
+#ifdef ESP32
+
+#include "WiFiClientSecureESP32.h"
+#include
+#include
+#include
+
+#undef connect
+#undef write
+#undef read
+
+
+WiFiClientSecureESP32::WiFiClientSecureESP32()
+{
+ _connected = false;
+
+ sslclient = new sslclient_context32;
+ ssl_init(sslclient);
+ sslclient->socket = -1;
+ sslclient->handshake_timeout = 120000;
+ _CA_cert = NULL;
+ _cert = NULL;
+ _private_key = NULL;
+ _pskIdent = NULL;
+ _psKey = NULL;
+ next = NULL;
+}
+
+
+WiFiClientSecureESP32::WiFiClientSecureESP32(int sock)
+{
+ _connected = false;
+ _timeout = 0;
+
+ sslclient = new sslclient_context32;
+ ssl_init(sslclient);
+ sslclient->socket = sock;
+ sslclient->handshake_timeout = 120000;
+
+ if (sock >= 0) {
+ _connected = true;
+ }
+
+ _CA_cert = NULL;
+ _cert = NULL;
+ _private_key = NULL;
+ _pskIdent = NULL;
+ _psKey = NULL;
+ next = NULL;
+}
+
+WiFiClientSecureESP32::WiFiClientSecureESP32(bool starttls)
+{
+ _connected = false;
+
+ sslclient = new sslclient_context32;
+ ssl_init(sslclient);
+ sslclient->socket = -1;
+ sslclient->handshake_timeout = 120000;
+ sslclient->starttls = true;
+ _CA_cert = NULL;
+ _cert = NULL;
+ _private_key = NULL;
+ _pskIdent = NULL;
+ _psKey = NULL;
+ next = NULL;
+}
+
+WiFiClientSecureESP32::~WiFiClientSecureESP32()
+{
+ stop();
+ delete sslclient;
+}
+
+WiFiClientSecureESP32 &WiFiClientSecureESP32::operator=(const WiFiClientSecureESP32 &other)
+{
+ stop();
+ sslclient->socket = other.sslclient->socket;
+ _connected = other._connected;
+ return *this;
+}
+
+void WiFiClientSecureESP32::stop()
+{
+ if (sslclient->socket >= 0) {
+ close(sslclient->socket);
+ sslclient->socket = -1;
+ _connected = false;
+ _peek = -1;
+ }
+ stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
+}
+
+int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port)
+{
+ if (_pskIdent && _psKey)
+ return connect(ip, port, _pskIdent, _psKey);
+ return connect(ip, port, _CA_cert, _cert, _private_key);
+}
+
+int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, int32_t timeout){
+ _timeout = timeout;
+ return connect(ip, port);
+}
+
+int WiFiClientSecureESP32::connect(const char *host, uint16_t port)
+{
+ if (_pskIdent && _psKey)
+ return connect(host, port, _pskIdent, _psKey);
+ return connect(host, port, _CA_cert, _cert, _private_key);
+}
+
+int WiFiClientSecureESP32::connect(const char *host, uint16_t port, int32_t timeout){
+ _timeout = timeout;
+ return connect(host, port);
+}
+
+int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
+{
+ return connect(ip.toString().c_str(), port, _CA_cert, _cert, _private_key);
+}
+
+int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
+{
+ if(_timeout > 0){
+ sslclient->handshake_timeout = _timeout;
+ }
+ int ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL);
+ _lastError = ret;
+ if (ret < 0) {
+ log_e("start_ssl_client: %d", ret);
+ stop();
+ return 0;
+ }
+ _connected = true;
+ return 1;
+}
+
+int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) {
+ return connect(ip.toString().c_str(), port,_pskIdent, _psKey);
+}
+
+int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) {
+ log_v("start_ssl_client with PSK");
+ if(_timeout > 0){
+ sslclient->handshake_timeout = _timeout;
+ }
+ int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
+ _lastError = ret;
+ if (ret < 0) {
+ log_e("start_ssl_client: %d", ret);
+ stop();
+ return 0;
+ }
+ _connected = true;
+ return 1;
+}
+
+int WiFiClientSecureESP32::peek(){
+ if(_peek >= 0){
+ return _peek;
+ }
+ _peek = timedRead();
+ return _peek;
+}
+
+size_t WiFiClientSecureESP32::write(uint8_t data)
+{
+ return write(&data, 1);
+}
+
+int WiFiClientSecureESP32::read()
+{
+ uint8_t data = -1;
+ int res = read(&data, 1);
+ if (res < 0) {
+ return res;
+ }
+ return data;
+}
+
+size_t WiFiClientSecureESP32::write(const uint8_t *buf, size_t size)
+{
+ if (!_connected) {
+ return 0;
+ }
+ int res = send_ssl_data(sslclient, buf, size);
+ if (res < 0) {
+ stop();
+ res = 0;
+ }
+ return res;
+}
+
+int WiFiClientSecureESP32::read(uint8_t *buf, size_t size)
+{
+ int peeked = 0;
+ int avail = available();
+ if ((!buf && size) || avail <= 0) {
+ return -1;
+ }
+ if(!size){
+ return 0;
+ }
+ if(_peek >= 0){
+ buf[0] = _peek;
+ _peek = -1;
+ size--;
+ avail--;
+ if(!size || !avail){
+ return 1;
+ }
+ buf++;
+ peeked = 1;
+ }
+
+ int res = get_ssl_receive(sslclient, buf, size);
+ if (res < 0) {
+ stop();
+ return peeked?peeked:res;
+ }
+ return res + peeked;
+}
+
+int WiFiClientSecureESP32::available()
+{
+ int peeked = (_peek >= 0);
+ if (!_connected) {
+ return peeked;
+ }
+ int res = data_to_read(sslclient);
+ if (res < 0) {
+ stop();
+ return peeked?peeked:res;
+ }
+ return res+peeked;
+}
+
+uint8_t WiFiClientSecureESP32::connected()
+{
+ uint8_t dummy = 0;
+ read(&dummy, 0);
+
+ return _connected;
+}
+
+void WiFiClientSecureESP32::setCACert (const char *rootCA)
+{
+ _CA_cert = rootCA;
+}
+
+void WiFiClientSecureESP32::setCertificate (const char *client_ca)
+{
+ _cert = client_ca;
+}
+
+void WiFiClientSecureESP32::setPrivateKey (const char *private_key)
+{
+ _private_key = private_key;
+}
+
+void WiFiClientSecureESP32::setPreSharedKey(const char *pskIdent, const char *psKey) {
+ _pskIdent = pskIdent;
+ _psKey = psKey;
+}
+
+bool WiFiClientSecureESP32::verify(const char* fp, const char* domain_name)
+{
+ if (!sslclient)
+ return false;
+
+ return verify_ssl_fingerprint(sslclient, fp, domain_name);
+}
+
+char *WiFiClientSecureESP32::_streamLoad(Stream& stream, size_t size) {
+ static char *dest = nullptr;
+ if(dest) {
+ free(dest);
+ }
+ dest = (char*)malloc(size);
+ if (!dest) {
+ return nullptr;
+ }
+ if (size != stream.readBytes(dest, size)) {
+ free(dest);
+ dest = nullptr;
+ }
+ return dest;
+}
+
+bool WiFiClientSecureESP32::loadCACert(Stream& stream, size_t size) {
+ char *dest = _streamLoad(stream, size);
+ bool ret = false;
+ if (dest) {
+ setCACert(dest);
+ ret = true;
+ }
+ return ret;
+}
+
+bool WiFiClientSecureESP32::loadCertificate(Stream& stream, size_t size) {
+ char *dest = _streamLoad(stream, size);
+ bool ret = false;
+ if (dest) {
+ setCertificate(dest);
+ ret = true;
+ }
+ return ret;
+}
+
+bool WiFiClientSecureESP32::loadPrivateKey(Stream& stream, size_t size) {
+ char *dest = _streamLoad(stream, size);
+ bool ret = false;
+ if (dest) {
+ setPrivateKey(dest);
+ ret = true;
+ }
+ return ret;
+}
+
+int WiFiClientSecureESP32::lastError(char *buf, const size_t size)
+{
+ if (!_lastError) {
+ return 0;
+ }
+ char error_buf[100];
+ mbedtls_strerror(_lastError, error_buf, 100);
+ snprintf(buf, size, "%s", error_buf);
+ return _lastError;
+}
+
+void WiFiClientSecureESP32::setHandshakeTimeout(unsigned long handshake_timeout)
+{
+ sslclient->handshake_timeout = handshake_timeout * 1000;
+}
+
+void WiFiClientSecureESP32::setSTARTTLS(bool starttls)
+{
+ sslclient->starttls = starttls;
+}
+
+void WiFiClientSecureESP32::setDebugCB(DebugMsgCallback cb)
+{
+ sslclient->_debugCallback = std::move(cb);
+}
+
+#endif //ESP32
+
+#endif //WiFiClientSecureESP32_CPP
\ No newline at end of file
diff --git a/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h b/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h
new file mode 100755
index 000000000..2a940c391
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h
@@ -0,0 +1,145 @@
+
+/*
+ *Customized WiFiClientSecure.h to support STARTTLS protocol, version 1.0.1
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/*
+ WiFiClientSecureESP32.h - Base class that provides Client SSL to ESP32
+ Copyright (c) 2011 Adrian McEwen. All right reserved.
+ Additions Copyright (C) 2017 Evandro Luis Copercini.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef WiFiClientSecureESP32_H
+#define WiFiClientSecureESP32_H
+
+#ifdef ESP32
+
+#include "Arduino.h"
+#include "IPAddress.h"
+#include
+#include "ssl_client32.h"
+
+typedef void (*DebugMsgCallback)(const char* msg);
+
+class WiFiClientSecureESP32 : public WiFiClient
+{
+protected:
+ sslclient_context32 *sslclient;
+
+ int _lastError = 0;
+ int _peek = -1;
+ int _timeout = 0;
+ const char *_CA_cert;
+ const char *_cert;
+ const char *_private_key;
+ const char *_pskIdent; // identity for PSK cipher suites
+ const char *_psKey; // key in hex for PSK cipher suites
+ DebugMsgCallback _debugCallback = NULL;
+
+public:
+ WiFiClientSecureESP32 *next;
+ WiFiClientSecureESP32();
+ WiFiClientSecureESP32(int socket);
+ WiFiClientSecureESP32(bool starttls);
+ ~WiFiClientSecureESP32();
+ int connect(IPAddress ip, uint16_t port);
+ int connect(IPAddress ip, uint16_t port, int32_t timeout);
+ int connect(const char *host, uint16_t port);
+ int connect(const char *host, uint16_t port, int32_t timeout);
+ int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
+ int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
+ int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
+ int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
+ int peek();
+ size_t write(uint8_t data);
+ size_t write(const uint8_t *buf, size_t size);
+ int available();
+ int read();
+ int read(uint8_t *buf, size_t size);
+ void flush() {}
+ void stop();
+ uint8_t connected();
+ int lastError(char *buf, const size_t size);
+ void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
+ void setCACert(const char *rootCA);
+ void setCertificate(const char *client_ca);
+ void setPrivateKey (const char *private_key);
+ bool loadCACert(Stream& stream, size_t size);
+ bool loadCertificate(Stream& stream, size_t size);
+ bool loadPrivateKey(Stream& stream, size_t size);
+ bool verify(const char* fingerprint, const char* domain_name);
+ void setHandshakeTimeout(unsigned long handshake_timeout);
+ void setSTARTTLS(bool starttls);
+ void setDebugCB(DebugMsgCallback cb);
+
+ operator bool()
+ {
+ return connected();
+ }
+ WiFiClientSecureESP32 &operator=(const WiFiClientSecureESP32 &other);
+ bool operator==(const bool value)
+ {
+ return bool() == value;
+ }
+ bool operator!=(const bool value)
+ {
+ return bool() != value;
+ }
+ bool operator==(const WiFiClientSecureESP32 &);
+ bool operator!=(const WiFiClientSecureESP32 &rhs)
+ {
+ return !this->operator==(rhs);
+ };
+
+ int socket()
+ {
+ return sslclient->socket = -1;
+ }
+
+private:
+ char *_streamLoad(Stream& stream, size_t size);
+
+ //friend class WiFiServer;
+ using Print::write;
+};
+
+#endif //ESP32
+
+#endif //WiFiClientSecureESP32_H
+
+
diff --git a/libesp32/ESP32-Mail-Client/src/ssl_client32.cpp b/libesp32/ESP32-Mail-Client/src/ssl_client32.cpp
new file mode 100755
index 000000000..06e3f11b1
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ssl_client32.cpp
@@ -0,0 +1,853 @@
+/*
+ *Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.3
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Provide SSL/TLS functions to ESP32 with Arduino IDE
+*
+* Adapted from the ssl_client1 example of mbedtls.
+*
+* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License.
+* Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License.
+*/
+
+#ifndef SSL_CLIENT32_CPP
+#define SSL_CLIENT32_CPP
+
+#ifdef ESP32
+
+#include "Arduino.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "ssl_client32.h"
+#include "WiFi.h"
+
+const char *pers32 = "esp32-tls";
+
+static int handle_error(int err)
+{
+ if (err == -30848)
+ {
+ return err;
+ }
+#ifdef MBEDTLS_ERROR_C
+ char error_buf[100];
+ mbedtls_strerror(err, error_buf, 100);
+ log_e("%s", error_buf);
+#endif
+ log_e("MbedTLS message code: %d", err);
+ return err;
+}
+
+void ssl_init(sslclient_context32 *ssl_client)
+{
+ mbedtls_ssl_init(&ssl_client->ssl_ctx);
+ mbedtls_ssl_config_init(&ssl_client->ssl_conf);
+ mbedtls_ctr_drbg_init(&ssl_client->drbg_ctx);
+ mbedtls_net_init(&ssl_client->server_fd);
+}
+
+int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey)
+{
+ char buf[512];
+ int ret, flags;
+ int enable = 1;
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_2, ssl_client);
+
+ log_v("Free internal heap before TLS %u", ESP.getFreeHeap());
+
+ log_v("Starting socket");
+ ssl_client->socket = -1;
+
+ ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (ssl_client->socket < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_3, ssl_client);
+ log_e("ERROR opening socket");
+ return ssl_client->socket;
+ }
+
+ IPAddress srv((uint32_t)0);
+ if (!WiFiGenericClass::hostByName(host, srv))
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_4, ssl_client);
+ return -1;
+ }
+
+ struct sockaddr_in serv_addr;
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = srv;
+ serv_addr.sin_port = htons(port);
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_5, ssl_client);
+
+ if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0)
+ {
+ if (timeout <= 0)
+ {
+ timeout = 30000;
+ }
+ lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+ lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
+ lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_6, ssl_client);
+ }
+ else
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_7, ssl_client);
+ log_e("Connect to Server failed!");
+ return -1;
+ }
+
+ fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK);
+
+ if (ssl_client->starttls && (port == 25 || port == 587 || port == 143))
+ {
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_8, ssl_client);
+
+ if ((ret = starttlsHandshake(ssl_client, port)) != 0)
+ {
+ log_e("STARTTLS failed!");
+ return -1;
+ }
+ }
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_9, ssl_client);
+
+ log_v("Seeding the random number generator");
+ mbedtls_entropy_init(&ssl_client->entropy_ctx);
+
+ ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func,
+ &ssl_client->entropy_ctx, (const unsigned char *)pers32, strlen(pers32));
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+
+ return handle_error(ret);
+ }
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_10, ssl_client);
+
+ log_v("Setting up the SSL/TLS structure...");
+
+ if ((ret = mbedtls_ssl_config_defaults(&ssl_client->ssl_conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+ return handle_error(ret);
+ }
+
+ // MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and
+ // MBEDTLS_SSL_VERIFY_NONE if not.
+
+ if (rootCABuff != NULL)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_11, ssl_client);
+ log_v("Loading CA cert");
+ mbedtls_x509_crt_init(&ssl_client->ca_cert);
+ mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+ ret = mbedtls_x509_crt_parse(&ssl_client->ca_cert, (const unsigned char *)rootCABuff, strlen(rootCABuff) + 1);
+ mbedtls_ssl_conf_ca_chain(&ssl_client->ssl_conf, &ssl_client->ca_cert, NULL);
+ //mbedtls_ssl_conf_verify(&ssl_client->ssl_ctx, my_verify, NULL );
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+ return handle_error(ret);
+ }
+ }
+ else if (pskIdent != NULL && psKey != NULL)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_12, ssl_client);
+ log_v("Setting up PSK");
+ // convert PSK from hex to binary
+ if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2 * MBEDTLS_PSK_MAX_LEN)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_13, ssl_client);
+ log_e("pre-shared key not valid hex or too long");
+ return -1;
+ }
+ unsigned char psk[MBEDTLS_PSK_MAX_LEN];
+ size_t psk_len = strlen(psKey) / 2;
+ for (int j = 0; j < strlen(psKey); j += 2)
+ {
+ char c = psKey[j];
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'F')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else
+ return -1;
+ psk[j / 2] = c << 4;
+ c = psKey[j + 1];
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'F')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else
+ return -1;
+ psk[j / 2] |= c;
+ }
+ // set mbedtls config
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_14, ssl_client);
+ ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len,
+ (const unsigned char *)pskIdent, strlen(pskIdent));
+ if (ret != 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+ log_e("mbedtls_ssl_conf_psk returned %d", ret);
+ return handle_error(ret);
+ }
+ }
+ else
+ {
+
+ mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
+ log_i("WARNING: Use certificates for a more secure communication!");
+ }
+
+ if (cli_cert != NULL && cli_key != NULL)
+ {
+
+ mbedtls_x509_crt_init(&ssl_client->client_cert);
+ mbedtls_pk_init(&ssl_client->client_key);
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_15, ssl_client);
+
+ log_v("Loading CRT cert");
+
+ ret = mbedtls_x509_crt_parse(&ssl_client->client_cert, (const unsigned char *)cli_cert, strlen(cli_cert) + 1);
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+ return handle_error(ret);
+ }
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_16, ssl_client);
+
+ log_v("Loading private key");
+ ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0);
+
+ if (ret != 0)
+ {
+ return handle_error(ret);
+ }
+
+ mbedtls_ssl_conf_own_cert(&ssl_client->ssl_conf, &ssl_client->client_cert, &ssl_client->client_key);
+ }
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_17, ssl_client);
+
+ log_v("Setting hostname for TLS session...");
+
+ // Hostname set here should match CN in server certificate
+ if ((ret = mbedtls_ssl_set_hostname(&ssl_client->ssl_ctx, host)) != 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+ return handle_error(ret);
+ }
+
+ mbedtls_ssl_conf_rng(&ssl_client->ssl_conf, mbedtls_ctr_drbg_random, &ssl_client->drbg_ctx);
+
+ if ((ret = mbedtls_ssl_setup(&ssl_client->ssl_ctx, &ssl_client->ssl_conf)) != 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+
+ return handle_error(ret);
+ }
+
+ mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_18, ssl_client);
+
+ log_v("Performing the SSL/TLS handshake...");
+ unsigned long handshake_start_time = millis();
+ while ((ret = mbedtls_ssl_handshake(&ssl_client->ssl_ctx)) != 0)
+ {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ }
+ return handle_error(ret);
+ }
+ if ((millis() - handshake_start_time) > ssl_client->handshake_timeout)
+ return -1;
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ }
+
+ if (cli_cert != NULL && cli_key != NULL)
+ {
+ log_d("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_client->ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_client->ssl_ctx));
+ if ((ret = mbedtls_ssl_get_record_expansion(&ssl_client->ssl_ctx)) >= 0)
+ {
+
+ log_d("Record expansion is %d", ret);
+ }
+ else
+ {
+ log_w("Record expansion is unknown (compression)");
+ }
+ }
+
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_19, ssl_client);
+
+ log_v("Verifying peer X.509 certificate...");
+
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl_client->ssl_ctx)) != 0)
+ {
+ bzero(buf, sizeof(buf));
+ mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_20, ssl_client);
+ log_e("Failed to verify peer certificate! verification info: %s", buf);
+ stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue.
+ return handle_error(ret);
+ }
+ else
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_21, ssl_client);
+ log_v("Certificate verified.");
+ }
+
+ if (rootCABuff != NULL)
+ {
+ mbedtls_x509_crt_free(&ssl_client->ca_cert);
+ }
+
+ if (cli_cert != NULL)
+ {
+ mbedtls_x509_crt_free(&ssl_client->client_cert);
+ }
+
+ if (cli_key != NULL)
+ {
+ mbedtls_pk_free(&ssl_client->client_key);
+ }
+
+ log_v("Free internal heap after TLS %u", ESP.getFreeHeap());
+
+ return ssl_client->socket;
+}
+
+void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key)
+{
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_22, ssl_client);
+ log_v("Cleaning SSL connection.");
+
+ if (ssl_client->socket >= 0)
+ {
+ close(ssl_client->socket);
+ ssl_client->socket = -1;
+ }
+
+ mbedtls_ssl_free(&ssl_client->ssl_ctx);
+ mbedtls_ssl_config_free(&ssl_client->ssl_conf);
+ mbedtls_ctr_drbg_free(&ssl_client->drbg_ctx);
+ mbedtls_entropy_free(&ssl_client->entropy_ctx);
+}
+
+int data_to_read(sslclient_context32 *ssl_client)
+{
+ int ret, res;
+ ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0);
+ //log_e("RET: %i",ret); //for low level debug
+ res = mbedtls_ssl_get_bytes_avail(&ssl_client->ssl_ctx);
+ //log_e("RES: %i",res); //for low level debug
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ {
+ char *buf = new char[512];
+ char *error_buf = new char[100];
+ memset(buf, 0, 512);
+ strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
+ mbedtls_strerror(ret, error_buf, 100);
+ strcat(buf, error_buf);
+ ssl_client->_debugCallback(buf);
+ delete[] error_buf;
+ delete[] buf;
+ }
+ return handle_error(ret);
+ }
+
+ return res;
+}
+
+int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len)
+{
+
+ log_v("Writing HTTP request..."); //for low level debug
+ int ret = -1;
+
+ while ((ret = mbedtls_ssl_write(&ssl_client->ssl_ctx, data, len)) <= 0)
+ {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+ {
+ return handle_error(ret);
+ }
+ }
+
+ len = ret;
+ //log_v("%d bytes written", len); //for low level debug
+ return ret;
+}
+
+int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length)
+{
+
+ //log_d( "Reading HTTP response..."); //for low level debug
+ int ret = -1;
+
+ ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, data, length);
+
+ //log_v( "%d bytes read", ret); //for low level debug
+ return ret;
+}
+
+static bool parseHexNibble(char pb, uint8_t *res)
+{
+ if (pb >= '0' && pb <= '9')
+ {
+ *res = (uint8_t)(pb - '0');
+ return true;
+ }
+ else if (pb >= 'a' && pb <= 'f')
+ {
+ *res = (uint8_t)(pb - 'a' + 10);
+ return true;
+ }
+ else if (pb >= 'A' && pb <= 'F')
+ {
+ *res = (uint8_t)(pb - 'A' + 10);
+ return true;
+ }
+ return false;
+}
+
+// Compare a name from certificate and domain name, return true if they match
+static bool matchName(const std::string &name, const std::string &domainName)
+{
+ size_t wildcardPos = name.find('*');
+ if (wildcardPos == std::string::npos)
+ {
+ // Not a wildcard, expect an exact match
+ return name == domainName;
+ }
+
+ size_t firstDotPos = name.find('.');
+ if (wildcardPos > firstDotPos)
+ {
+ // Wildcard is not part of leftmost component of domain name
+ // Do not attempt to match (rfc6125 6.4.3.1)
+ return false;
+ }
+ if (wildcardPos != 0 || firstDotPos != 1)
+ {
+ // Matching of wildcards such as baz*.example.com and b*z.example.com
+ // is optional. Maybe implement this in the future?
+ return false;
+ }
+ size_t domainNameFirstDotPos = domainName.find('.');
+ if (domainNameFirstDotPos == std::string::npos)
+ {
+ return false;
+ }
+ return domainName.substr(domainNameFirstDotPos) == name.substr(firstDotPos);
+}
+
+// Verifies certificate provided by the peer to match specified SHA256 fingerprint
+bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, const char *domain_name)
+{
+ // Convert hex string to byte array
+ uint8_t fingerprint_local[32];
+ int len = strlen(fp);
+ int pos = 0;
+ for (size_t i = 0; i < sizeof(fingerprint_local); ++i)
+ {
+ while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':')))
+ {
+ ++pos;
+ }
+ if (pos > len - 2)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_23, ssl_client);
+ log_d("pos:%d len:%d fingerprint too short", pos, len);
+ return false;
+ }
+ uint8_t high, low;
+ if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low))
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_24, ssl_client);
+ log_d("pos:%d len:%d invalid hex sequence: %c%c", pos, len, fp[pos], fp[pos + 1]);
+ return false;
+ }
+ pos += 2;
+ fingerprint_local[i] = low | (high << 4);
+ }
+
+ // Get certificate provided by the peer
+ const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx);
+
+ if (!crt)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_25, ssl_client);
+ log_d("could not fetch peer certificate");
+ return false;
+ }
+
+ // Calculate certificate's SHA256 fingerprint
+ uint8_t fingerprint_remote[32];
+ mbedtls_sha256_context sha256_ctx;
+ mbedtls_sha256_init(&sha256_ctx);
+ mbedtls_sha256_starts(&sha256_ctx, false);
+ mbedtls_sha256_update(&sha256_ctx, crt->raw.p, crt->raw.len);
+ mbedtls_sha256_finish(&sha256_ctx, fingerprint_remote);
+
+ // Check if fingerprints match
+ if (memcmp(fingerprint_local, fingerprint_remote, 32))
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_26, ssl_client);
+ log_d("fingerprint doesn't match");
+ return false;
+ }
+
+ // Additionally check if certificate has domain name if provided
+ if (domain_name)
+ return verify_ssl_dn(ssl_client, domain_name);
+ else
+ return true;
+}
+
+// Checks if peer certificate has specified domain in CN or SANs
+bool verify_ssl_dn(sslclient_context32 *ssl_client, const char *domain_name)
+{
+ log_d("domain name: '%s'", (domain_name) ? domain_name : "(null)");
+ std::string domain_name_str(domain_name);
+ std::transform(domain_name_str.begin(), domain_name_str.end(), domain_name_str.begin(), ::tolower);
+
+ // Get certificate provided by the peer
+ const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx);
+
+ // Check for domain name in SANs
+ const mbedtls_x509_sequence *san = &crt->subject_alt_names;
+ while (san != nullptr)
+ {
+ std::string san_str((const char *)san->buf.p, san->buf.len);
+ std::transform(san_str.begin(), san_str.end(), san_str.begin(), ::tolower);
+
+ if (matchName(san_str, domain_name_str))
+ return true;
+
+ log_d("SAN '%s': no match", san_str.c_str());
+
+ // Fetch next SAN
+ san = san->next;
+ }
+
+ // Check for domain name in CN
+ const mbedtls_asn1_named_data *common_name = &crt->subject;
+ while (common_name != nullptr)
+ {
+ // While iterating through DN objects, check for CN object
+ if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &common_name->oid))
+ {
+ std::string common_name_str((const char *)common_name->val.p, common_name->val.len);
+
+ if (matchName(common_name_str, domain_name_str))
+ return true;
+
+ log_d("CN '%s': not match", common_name_str.c_str());
+ }
+
+ // Fetch next DN object
+ common_name = common_name->next;
+ }
+
+ return false;
+}
+
+int starttlsHandshake(sslclient_context32 *ssl_client, int port)
+{
+
+ int ret = 0;
+ size_t msgLen = 100;
+ size_t bufLen = 512;
+ char *buf = new char[bufLen];
+ char *hMsg = new char[msgLen];
+
+ fd_set readset;
+ fd_set writeset;
+ fd_set errset;
+
+ struct timeval tv;
+
+ FD_ZERO(&readset);
+ FD_SET(ssl_client->socket, &readset);
+ FD_ZERO(&writeset);
+ FD_SET(ssl_client->socket, &writeset);
+
+ FD_ZERO(&errset);
+ FD_SET(ssl_client->socket, &errset);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_27, ssl_client);
+
+ goto starttls_exit;
+ }
+
+ ret = read(ssl_client->socket, buf, bufLen);
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_28, ssl_client);
+ goto starttls_exit;
+ }
+ else
+ {
+ if (ssl_client->_debugCallback)
+ ssl_client->_debugCallback(buf);
+ }
+
+ if (port == 587 || port == 25)
+ {
+
+ memset(hMsg, 0, msgLen);
+ strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_29);
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_30, ssl_client);
+ ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg));
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_31, ssl_client);
+ goto starttls_exit;
+ }
+
+ ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_32, ssl_client);
+ goto starttls_exit;
+ }
+
+ memset(buf, 0, bufLen);
+ ret = lwip_read(ssl_client->socket, buf, bufLen);
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_33, ssl_client);
+ goto starttls_exit;
+ }
+ else
+ {
+ if (ssl_client->_debugCallback)
+ ssl_client->_debugCallback(buf);
+ }
+ }
+
+ memset(hMsg, 0, msgLen);
+ strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_34);
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_35, ssl_client);
+ ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg));
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_36, ssl_client);
+ goto starttls_exit;
+ }
+
+ ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_37, ssl_client);
+ goto starttls_exit;
+ }
+
+ memset(buf, 0, bufLen);
+ ret = lwip_read(ssl_client->socket, buf, bufLen);
+
+ if (ret < 0)
+ {
+ if (ssl_client->_debugCallback)
+ ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_38, ssl_client);
+ goto starttls_exit;
+ }
+ else
+ {
+ if (ssl_client->_debugCallback)
+ ssl_client->_debugCallback(buf);
+ }
+
+ delete[] buf;
+ delete[] hMsg;
+
+ return 0;
+
+starttls_exit:
+
+ delete[] buf;
+ delete[] hMsg;
+
+ return -1;
+}
+
+void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client)
+{
+ size_t dbgInfoLen = strlen_P(info) + 1;
+ char *dbgInfo = new char[dbgInfoLen];
+ memset(dbgInfo, 0, dbgInfoLen);
+ strcpy_P(dbgInfo, info);
+ ssl_client->_debugCallback(dbgInfo);
+ delete[] dbgInfo;
+}
+
+#endif //ESP32
+
+#endif //SSL_CLIENT32_CPP
\ No newline at end of file
diff --git a/libesp32/ESP32-Mail-Client/src/ssl_client32.h b/libesp32/ESP32-Mail-Client/src/ssl_client32.h
new file mode 100755
index 000000000..3e2d3b09a
--- /dev/null
+++ b/libesp32/ESP32-Mail-Client/src/ssl_client32.h
@@ -0,0 +1,116 @@
+/*
+ *Customized ssl_client.h to support STARTTLS protocol, version 1.0.3
+ *
+ * The MIT License (MIT)
+ * Copyright (c) 2019 K. Suwatchai (Mobizt)
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* Provide SSL/TLS functions to ESP32 with Arduino IDE
+ * by Evandro Copercini - 2017 - Apache 2.0 License
+ */
+
+#ifndef SSL_CLIENT32_H
+#define SSL_CLIENT32_H
+
+#ifdef ESP32
+
+#include "mbedtls/platform.h"
+#include "mbedtls/net.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+
+static const char ESP32_SSL_CLIENT_STR_1[] PROGMEM = "ERROR: ";
+static const char ESP32_SSL_CLIENT_STR_2[] PROGMEM = "INFO: starting socket";
+static const char ESP32_SSL_CLIENT_STR_3[] PROGMEM = "ERROR: opening socket";
+static const char ESP32_SSL_CLIENT_STR_4[] PROGMEM = "ERROR: could not get ip from host";
+static const char ESP32_SSL_CLIENT_STR_5[] PROGMEM = "INFO: connecting to Server...";
+static const char ESP32_SSL_CLIENT_STR_6[] PROGMEM = "INFO: server connected";
+static const char ESP32_SSL_CLIENT_STR_7[] PROGMEM = "ERROR: connect to Server failed!";
+static const char ESP32_SSL_CLIENT_STR_8[] PROGMEM = "INFO: begin STARTTLS handshake";
+static const char ESP32_SSL_CLIENT_STR_9[] PROGMEM = "INFO: seeding the random number generator";
+static const char ESP32_SSL_CLIENT_STR_10[] PROGMEM = "INFO: setting up the SSL/TLS structure...";
+static const char ESP32_SSL_CLIENT_STR_11[] PROGMEM = "INFO: loading CA cert";
+static const char ESP32_SSL_CLIENT_STR_12[] PROGMEM = "INFO: setting up PSK";
+static const char ESP32_SSL_CLIENT_STR_13[] PROGMEM = "ERROR: pre-shared key not valid hex or too long";
+static const char ESP32_SSL_CLIENT_STR_14[] PROGMEM = "INFO: set mbedtls config";
+static const char ESP32_SSL_CLIENT_STR_15[] PROGMEM = "INFO: loading CRT cert";
+static const char ESP32_SSL_CLIENT_STR_16[] PROGMEM = "INFO: loading private key";
+static const char ESP32_SSL_CLIENT_STR_17[] PROGMEM = "INFO: setting hostname for TLS session...";
+static const char ESP32_SSL_CLIENT_STR_18[] PROGMEM = "INFO: performing the SSL/TLS handshake...";
+static const char ESP32_SSL_CLIENT_STR_19[] PROGMEM = "INFO: verifying peer X.509 certificate...";
+static const char ESP32_SSL_CLIENT_STR_20[] PROGMEM = "ERROR: failed to verify peer certificate!";
+static const char ESP32_SSL_CLIENT_STR_21[] PROGMEM = "INFO: certificate verified";
+static const char ESP32_SSL_CLIENT_STR_22[] PROGMEM = "INFO: cleaning SSL connection";
+static const char ESP32_SSL_CLIENT_STR_23[] PROGMEM = "ERROR: fingerprint too short";
+static const char ESP32_SSL_CLIENT_STR_24[] PROGMEM = "ERROR: invalid hex sequence";
+static const char ESP32_SSL_CLIENT_STR_25[] PROGMEM = "ERROR: could not fetch peer certificate";
+static const char ESP32_SSL_CLIENT_STR_26[] PROGMEM = "ERROR: fingerprint doesn't match";
+static const char ESP32_SSL_CLIENT_STR_27[] PROGMEM = "ERROR: waiting incoming data failed!";
+static const char ESP32_SSL_CLIENT_STR_28[] PROGMEM = "ERROR: reading incoming data failed!";
+static const char ESP32_SSL_CLIENT_STR_29[] PROGMEM = "EHLO DUDE\r\n";
+static const char ESP32_SSL_CLIENT_STR_30[] PROGMEM = "INFO: send SMTP command extended HELO";
+static const char ESP32_SSL_CLIENT_STR_31[] PROGMEM = "ERROR: send SMTP command failed!";
+static const char ESP32_SSL_CLIENT_STR_32[] PROGMEM = "ERROR: waiting incoming data failed!";
+static const char ESP32_SSL_CLIENT_STR_33[] PROGMEM = "ERROR: reading incoming data failed!";
+static const char ESP32_SSL_CLIENT_STR_34[] PROGMEM = "STARTTLS\r\n";
+static const char ESP32_SSL_CLIENT_STR_35[] PROGMEM = "INFO: send STARTTLS protocol command";
+static const char ESP32_SSL_CLIENT_STR_36[] PROGMEM = "ERROR: send STARTTLS protocol command failed!";
+static const char ESP32_SSL_CLIENT_STR_37[] PROGMEM = "ERROR: waiting incoming data failed!";
+static const char ESP32_SSL_CLIENT_STR_38[] PROGMEM = "ERROR: reading incoming data failed!";
+
+typedef void (*DebugMsgCallback)(const char *msg);
+
+typedef struct sslclient_context32 {
+ int socket;
+ bool starttls;
+ mbedtls_ssl_context ssl_ctx;
+ mbedtls_ssl_config ssl_conf;
+ mbedtls_net_context server_fd;
+
+ mbedtls_ctr_drbg_context drbg_ctx;
+ mbedtls_entropy_context entropy_ctx;
+
+ mbedtls_x509_crt ca_cert;
+ mbedtls_x509_crt client_cert;
+ mbedtls_pk_context client_key;
+ DebugMsgCallback _debugCallback;
+
+ unsigned long handshake_timeout;
+} sslclient_context32;
+
+
+void ssl_init(sslclient_context32 *ssl_client);
+int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey);
+void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
+int data_to_read(sslclient_context32 *ssl_client);
+int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len);
+int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length);
+bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char* fp, const char* domain_name);
+bool verify_ssl_dn(sslclient_context32 *ssl_client, const char* domain_name);
+int starttlsHandshake(sslclient_context32 *ssl_client, int port);
+void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client);
+
+#endif //ESP32
+
+#endif //SSL_CLIENT32_H
diff --git a/libesp32/ESP32-to-ESP8266-compat/README.adoc b/libesp32/ESP32-to-ESP8266-compat/README.adoc
new file mode 100644
index 000000000..abf17a277
--- /dev/null
+++ b/libesp32/ESP32-to-ESP8266-compat/README.adoc
@@ -0,0 +1,19 @@
+Library for ESP32 with Tasmota
+
+This Class is for compatibility with esp8266 code
+
+== License ==
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
diff --git a/libesp32/ESP32-to-ESP8266-compat/keywords.txt b/libesp32/ESP32-to-ESP8266-compat/keywords.txt
new file mode 100644
index 000000000..3422d1305
--- /dev/null
+++ b/libesp32/ESP32-to-ESP8266-compat/keywords.txt
@@ -0,0 +1,24 @@
+#######################################
+# Syntax Coloring Map For Test
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+A4988_ESP32Compat KEYWORD1 A4988_ESP32Compat
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+doMove KEYWORD2
+doRotate KEYWORD2
+setRPM KEYWORD2
+setSPR KEYWORD2
+setMIS KEYWORD2
+version KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
diff --git a/libesp32/ESP32-to-ESP8266-compat/library.properties b/libesp32/ESP32-to-ESP8266-compat/library.properties
new file mode 100644
index 000000000..5d5e39166
--- /dev/null
+++ b/libesp32/ESP32-to-ESP8266-compat/library.properties
@@ -0,0 +1,9 @@
+name=ESP32-to-ESP8266-compat
+version=0.0.2
+author=Jörg Schüler-Maroldt
+maintainer=Jörg Schüler-Maroldt
+sentence=Allows Tasmota to compile for esp32
+paragraph=Allows Tasmota to compile for esp32
+category=ESP32
+url=
+architectures=*
diff --git a/libesp32/ESP32-to-ESP8266-compat/src/AddrList.h b/libesp32/ESP32-to-ESP8266-compat/src/AddrList.h
new file mode 100644
index 000000000..cc32ea232
--- /dev/null
+++ b/libesp32/ESP32-to-ESP8266-compat/src/AddrList.h
@@ -0,0 +1,233 @@
+/*
+ AddrList.h - cycle through lwIP netif's ip addresses like a c++ list
+ Copyright (c) 2018 david gauchard. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ This class allows to explore all configured IP addresses
+ in lwIP netifs, with that kind of c++ loop:
+
+ for (auto a: addrList)
+ out.printf("IF='%s' index=%d legacy=%d IPv4=%d local=%d hostname='%s' addr= %s\n",
+ a.iface().c_str(),
+ a.ifnumber(),
+ a.addr().isLegacy(),
+ a.addr().isV4(),
+ a.addr().isLocal(),
+ a.hostname().c_str(),
+ a.addr().toString().c_str());
+
+ This loop:
+
+ while (WiFi.status() != WL_CONNECTED()) {
+ Serial.print('.');
+ delay(500);
+ }
+
+ can be replaced by:
+
+ for (bool configured = false; !configured; ) {
+ for (auto iface: addrList)
+ if ((configured = !iface.addr().isLocal())
+ break;
+ Serial.print('.');
+ delay(500);
+ }
+
+ waiting for an IPv6 global address:
+
+ for (bool configured = false; !configured; ) {
+ for (auto iface: addrList)
+ if ((configured = ( !iface.addr().isV4()
+ && !iface.addr().isLocal())))
+ break;
+ Serial.print('.');
+ delay(500);
+ }
+
+ waiting for an IPv6 global address, on a specific interface:
+
+ for (bool configured = false; !configured; ) {
+ for (auto iface: addrList)
+ if ((configured = ( !iface.addr().isV4()
+ && !iface.addr().isLocal()
+ && iface.ifnumber() == STATION_IF)))
+ break;
+ Serial.print('.');
+ delay(500);
+ }
+*/
+
+#ifndef __ADDRLIST_H
+#define __ADDRLIST_H
+
+#include
+#include |