buf(new char[size]);
+
+ configFile.readBytes(buf.get(), size);
+ DynamicJsonBuffer jsonBuffer;
+ JsonObject& json = jsonBuffer.parseObject(buf.get());
+ if (json.success()) {
+ debug("Json config file parsed ok.");
+#if MQTT_ENABLE
+ strncpy(MqttServer, json[kMqttServerKey] | "", kHostnameLength);
+ strncpy(MqttPort, json[kMqttPortKey] | "1883", kPortLength);
+ strncpy(MqttUsername, json[kMqttUserKey] | "", kUsernameLength);
+ strncpy(MqttPassword, json[kMqttPassKey] | "", kPasswordLength);
+ strncpy(MqttPrefix, json[kMqttPrefixKey] | "", kHostnameLength);
+#endif // MQTT_ENABLE
+ strncpy(Hostname, json[kHostnameKey] | "", kHostnameLength);
+ strncpy(HttpUsername, json[kHttpUserKey] | "", kUsernameLength);
+ strncpy(HttpPassword, json[kHttpPassKey] | "", kPasswordLength);
+ debug("Recovered Json fields.");
+ } else {
+ debug("Failed to load json config");
+ }
+ debug("Closing the config file.");
+ configFile.close();
+ }
+ } else {
+ debug("Config file doesn't exist!");
+ }
+ debug("Unmounting SPIFFS.");
+ SPIFFS.end();
+ } else {
+ debug("Failed to mount SPIFFS");
+ }
+}
+
+String msToHumanString(uint32_t const msecs) {
+ uint32_t totalseconds = msecs / 1000;
+ if (totalseconds == 0) return "Now";
+
+ // Note: millis() can only count up to 45 days, so uint8_t is safe.
+ uint8_t days = totalseconds / (60 * 60 * 24);
+ uint8_t hours = (totalseconds / (60 * 60)) % 24;
+ uint8_t minutes = (totalseconds / 60) % 60;
+ uint8_t seconds = totalseconds % 60;
+
+ String result = "";
+ if (days) result += String(days) + " day";
+ if (days > 1) result += 's';
+ if (hours) result += ' ' + String(hours) + " hour";
+ if (hours > 1) result += 's';
+ if (minutes) result += ' ' + String(minutes) + " minute";
+ if (minutes > 1) result += 's';
+ if (seconds) result += ' ' + String(seconds) + " second";
+ if (seconds > 1) result += 's';
+ result.trim();
+ return result;
+}
+
+String timeElapsed(uint32_t const msec) {
+ String result = msToHumanString(msec);
+ if (result.equalsIgnoreCase("Now"))
+ return result;
+ else
+ return result + " ago";
+}
+
+String timeSince(uint32_t const start) {
+ if (start == 0)
+ return "Never";
+ uint32_t diff = 0;
+ uint32_t now = millis();
+ if (start < now)
+ diff = now - start;
+ else
+ diff = UINT32_MAX - start + now;
+ return msToHumanString(diff) + " ago";
+}
+
+// Return a string containing the comma separated list of sending gpios.
+String listOfSendGpios(void) {
+ String result = String(gpioTable[0]);
+ if (kSendTableSize > 1) result += " (default)";
+ for (uint8_t i = 1; i < kSendTableSize; i++) {
+ result += ", " + String(gpioTable[i]);
+ }
+ return result;
+}
+
+String htmlMenu(void) {
+ return F(
+ ""
+ ""
+ "Home"
+ " "
+ ""
+ "Aircon"
+ " "
+ ""
+ "Examples"
+ " "
+ ""
+ "System Info"
+ " "
+ ""
+ "Admin"
+ " "
+ " "
+ " ");
+}
+
+// Root web page with example usage etc.
+void handleRoot(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /.");
+ return server.requestAuthentication();
+ }
+#endif
+ String html = F(
+ "IR MQTT server "
+ ""
+ "ESP8266 IR MQTT Server "
+ "" _MY_VERSION_ " ");
+ html += htmlMenu();
+ html += F(
+ "Send a simple IR message "
+ "
"
+ " "
+ "Send a complex (Air Conditioner) IR message "
+ "
"
+ " "
+ "Send an IRremote Raw IR message "
+ "
"
+ " "
+ "Send a GlobalCache "
+ " IR message "
+ "
"
+ " "
+ ""
+ "
"
+ " ");
+ server.send(200, "text/html", html);
+}
+
+String addJsReloadUrl(const String url, const uint16_t timeout_s,
+ const bool notify) {
+ String html = F(
+ "\n");
+ return html;
+}
+
+// Web page with hardcoded example usage etc.
+void handleExamples(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /examples.");
+ return server.requestAuthentication();
+ }
+#endif
+ String html = F(
+ "IR MQTT examples "
+ ""
+ "ESP8266 IR MQTT Server "
+ "" _MY_VERSION_ " ");
+ html += htmlMenu();
+ html += F(
+ "Hardcoded examples "
+ ""
+ "Sherwood Amp On (GlobalCache)
"
+ ""
+ "Sherwood Amp Off (Raw)
"
+ ""
+ "Sherwood Amp Input TAPE (Pronto)
"
+ "TV on (Samsung)
"
+ "Power Off (Sony 12bit)
"
+ ""
+ "Panasonic A/C LKE model, On, Auto mode, Min fan, 23C"
+ " (via HTTP aircon interface)
"
+ ""
+ "Change just the temp to 27C (via HTTP aircon interface)
"
+ ""
+ "Turn OFF the current A/C (via HTTP aircon interface)
"
+ " ");
+ server.send(200, "text/html", html);
+}
+
+String boolToString(const bool value) {
+ return value ? F("on") : F("off");
+}
+
+
+String opmodeToString(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kOff:
+ return F("off");
+ case stdAc::opmode_t::kAuto:
+ return F("auto");
+ case stdAc::opmode_t::kCool:
+ return F("cool");
+ case stdAc::opmode_t::kHeat:
+ return F("heat");
+ case stdAc::opmode_t::kDry:
+ return F("dry");
+ case stdAc::opmode_t::kFan:
+ return F("fan_only");
+ default:
+ return F("unknown");
+ }
+}
+
+String fanspeedToString(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kAuto:
+ return F("auto");
+ case stdAc::fanspeed_t::kMax:
+ return F("max");
+ case stdAc::fanspeed_t::kHigh:
+ return F("high");
+ case stdAc::fanspeed_t::kMedium:
+ return F("medium");
+ case stdAc::fanspeed_t::kLow:
+ return F("low");
+ case stdAc::fanspeed_t::kMin:
+ return F("min");
+ default:
+ return F("unknown");
+ }
+}
+
+String swingvToString(const stdAc::swingv_t swingv) {
+ switch (swingv) {
+ case stdAc::swingv_t::kOff:
+ return F("off");
+ case stdAc::swingv_t::kAuto:
+ return F("auto");
+ case stdAc::swingv_t::kHighest:
+ return F("highest");
+ case stdAc::swingv_t::kHigh:
+ return F("high");
+ case stdAc::swingv_t::kMiddle:
+ return F("middle");
+ case stdAc::swingv_t::kLow:
+ return F("low");
+ case stdAc::swingv_t::kLowest:
+ return F("lowest");
+ default:
+ return F("unknown");
+ }
+}
+
+String swinghToString(const stdAc::swingh_t swingh) {
+ switch (swingh) {
+ case stdAc::swingh_t::kOff:
+ return F("off");
+ case stdAc::swingh_t::kAuto:
+ return F("auto");
+ case stdAc::swingh_t::kLeftMax:
+ return F("leftmax");
+ case stdAc::swingh_t::kLeft:
+ return F("left");
+ case stdAc::swingh_t::kMiddle:
+ return F("middle");
+ case stdAc::swingh_t::kRight:
+ return F("right");
+ case stdAc::swingh_t::kRightMax:
+ return F("rightmax");
+ default:
+ return F("unknown");
+ }
+}
+
+String htmlSelectBool(const String name, const bool def) {
+ String html = "";
+ for (uint16_t i = 0; i < 2; i++) {
+ html += F("';
+ html += boolToString(i);
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectProtocol(const String name, const decode_type_t def) {
+ String html = "";
+ for (uint8_t i = 1; i <= decode_type_t::kLastDecodeType; i++) {
+ if (IRac::isProtocolSupported((decode_type_t)i)) {
+ html += F("';
+ html += typeToString((decode_type_t)i);
+ html += F(" ");
+ }
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectModel(const String name, const int16_t def) {
+ String html = "";
+ for (int16_t i = -1; i <= 6; i++) {
+ String num = String(i);
+ html += F("';
+ if (i == -1)
+ html += F("Default");
+ else if (i == 0)
+ html += F("Unknown");
+ else
+ html += num;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectMode(const String name, const stdAc::opmode_t def) {
+ String html = "";
+ for (int8_t i = -1; i <= 4; i++) {
+ String mode = opmodeToString((stdAc::opmode_t)i);
+ html += F("';
+ html += mode;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
+ String html = "";
+ for (int8_t i = 0; i <= 5; i++) {
+ String speed = fanspeedToString((stdAc::fanspeed_t)i);
+ html += F("';
+ html += speed;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
+ String html = "";
+ for (int8_t i = -1; i <= 5; i++) {
+ String swing = swingvToString((stdAc::swingv_t)i);
+ html += F("';
+ html += swing;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+String htmlSelectSwingh(const String name, const stdAc::swingh_t def) {
+ String html = "";
+ for (int8_t i = -1; i <= 5; i++) {
+ String swing = swinghToString((stdAc::swingh_t)i);
+ html += F("';
+ html += swing;
+ html += F(" ");
+ }
+ html += F(" ");
+ return html;
+}
+
+// Admin web page
+void handleAirCon(void) {
+ String html = F(
+ "AirCon control "
+ ""
+ "Air Conditioner Control ");
+ html += htmlMenu();
+ html += "Current Settings "
+ "";
+ // Display the current settings.
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+// Parse the URL args to find the Common A/C arguments.
+void handleAirConSet(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /aircon/set.");
+ return server.requestAuthentication();
+ }
+#endif
+ commonAcState_t result = climate;
+ debug("New common a/c received via HTTP");
+ for (uint16_t i = 0; i < server.args(); i++)
+ result = updateClimate(result, server.argName(i), "", server.arg(i));
+
+#if MQTT_ENABLE
+ sendClimate(climate, result, MqttClimateStat,
+ true, false, false);
+#else // MQTT_ENABLE
+ sendClimate(climate, result, "", false, false, false);
+#endif // MQTT_ENABLE
+ // Update the old climate state with the new one.
+ climate = result;
+ // Redirect back to the aircon page.
+ String html = F(
+ "Update Aircon "
+ ""
+ "Aircon updated! ");
+ html += addJsReloadUrl("/aircon", 2, false);
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+// Admin web page
+void handleAdmin(void) {
+ String html = F(
+ "IR MQTT server admin "
+ ""
+ "Administration ");
+ html += htmlMenu();
+ html += F(
+ "Special commands "
+#if MQTT_ENABLE
+ ""
+ "Send MQTT Discovery"
+ " "
+ "Send a Climate MQTT discovery message to Home Assistant. "
+#endif // MQTT_ENABLE
+ ""
+ "Reboot"
+ " A simple reboot of the ESP8266. "
+ "ie. No changes "
+ ""
+ "Wipe Settings"
+ " Warning: "
+ "Resets the device back to original settings. "
+ "ie. Goes back to AP/Setup mode. ");
+#if FIRMWARE_OTA
+ html += F("Update firmware "
+ "Warning: ");
+ if (!strlen(HttpPassword)) // Deny if password not set
+ html += F("OTA firmware is disabled until you set a password. "
+ "You will need to wipe & reset to set one."
+ " ");
+ else // default password has been changed, so allow it.
+ html += F(
+ "Updating your firmware may screw up your access to the device. "
+ "If you are going to use this, know what you are doing first "
+ "(and you probably do). "
+ "
");
+#endif // FIRMWARE_OTA
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+// Info web page
+void handleInfo(void) {
+ String html =
+ "IR MQTT server info "
+ ""
+ "Information ";
+ html += htmlMenu();
+ html +=
+ "General "
+ "Hostname: " + String(Hostname) + " "
+ "IP address: " + WiFi.localIP().toString() + " "
+ "Booted: " + timeSince(1) + " " +
+ "Version: " _MY_VERSION_ " "
+ "Built: " __DATE__
+ " " __TIME__ " "
+ "Period Offset: " + String(offset) + "us "
+ "IR Lib Version: " _IRREMOTEESP8266_VERSION_ " "
+ "ESP8266 Core Version: " + ESP.getCoreVersion() + " "
+ "IR Send GPIO(s): " + listOfSendGpios() + " "
+ "Total send requests: " + String(sendReqCounter) + " "
+ "Last message sent: " + String(lastSendSucceeded ? "Ok" : "FAILED") +
+ " (" + timeSince(lastSendTime) + ") "
+#ifdef IR_RX
+ "IR Recv GPIO: " + String(IR_RX) +
+#if IR_RX_PULLUP
+ " (pullup)"
+#endif // IR_RX_PULLUP
+ " "
+ "Total IR Received: " + String(irRecvCounter) + " "
+ "Last IR Received: " + lastIrReceived +
+ " (" + timeSince(lastIrReceivedTime) + ") "
+#endif // IR_RX
+ "Duplicate Wifi networks: " +
+ String(HIDE_DUPLIATE_NETWORKS ? "Hide" : "Show") + " "
+ "Min Wifi signal required: "
+#ifdef MIN_SIGNAL_STRENGTH
+ + String(static_cast(MIN_SIGNAL_STRENGTH)) +
+#else // MIN_SIGNAL_STRENGTH
+ "8"
+#endif // MIN_SIGNAL_STRENGTH
+ "% "
+ "Serial debugging: "
+#if DEBUG
+ + String(isSerialGpioUsedByIr() ? "Off" : "On") +
+#else // DEBUG
+ "Off"
+#endif // DEBUG
+ " "
+ "
"
+#if MQTT_ENABLE
+ "MQTT Information "
+ "Server: " + String(MqttServer) + ":" + String(MqttPort) + " (" +
+ (mqtt_client.connected() ? "Connected " + timeSince(lastDisconnectedTime)
+ : "Disconnected " + timeSince(lastConnectedTime)) +
+ ") "
+ "Disconnections: " + String(mqttDisconnectCounter - 1) + " "
+ "Client id: " + MqttClientId + " "
+ "Command topic(s): " + listOfCommandTopics() + " "
+ "Acknowledgements topic: " + MqttAck + " "
+#ifdef IR_RX
+ "IR Received topic: " + MqttRecv + " "
+#endif // IR_RX
+ "Log topic: " + MqttLog + " "
+ "LWT topic: " + MqttLwt + " "
+ "QoS: " + String(QOS) + " "
+ // lastMqttCmd* is unescaped untrusted input.
+ // Avoid any possible HTML/XSS when displaying it.
+ "Last MQTT command seen: (topic) '" + htmlEscape(lastMqttCmdTopic) +
+ "' (payload) '" + htmlEscape(lastMqttCmd) + "' (" +
+ timeSince(lastMqttCmdTime) + ") "
+ "Total published: " + String(mqttSentCounter) + " "
+ "Total received: " + String(mqttRecvCounter) + " "
+ "
"
+#endif // MQTT_ENABLE
+ "Climate Information "
+ ""
+ "IR Send GPIO: " + String(gpioTable[0]) + " "
+ "Total sent: " + String(irClimateCounter) + " "
+ "Last send: " + String(hasClimateBeenSent ?
+ (String(lastClimateSucceeded ? "Ok" : "FAILED") +
+ " (" + timeElapsed(lastClimateIr.elapsed()) + ") ") :
+ "Never ") + " "
+#if MQTT_ENABLE
+ "State listen period: " + msToHumanString(kStatListenPeriodMs) + " "
+ "State broadcast period: " + msToHumanString(kBroadcastPeriodMs) + " "
+ "Last state broadcast: " + (hasBroadcastBeenSent ?
+ timeElapsed(lastBroadcast.elapsed()) :
+ String("Never ")) + " "
+ "Last discovery sent: " + (lockMqttBroadcast ?
+ String("Locked ") :
+ (hasDiscoveryBeenSent ?
+ timeElapsed(lastDiscovery.elapsed()) :
+ String("Never "))) +
+ " "
+ "Command topics: " + MqttClimateCmnd +
+ "(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|"
+ KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|"
+ KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|"
+ KEY_CLOCK "|" KEY_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS ") "
+ "State topics: " + MqttClimateStat +
+ "(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|"
+ KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|"
+ KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|"
+ KEY_CLOCK "|" KEY_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS ") "
+#endif // MQTT_ENABLE
+ "
"
+ // Page footer
+ ""
+ "(Note: Page will refresh every 60 seconds.) "
+ "
";
+ html += addJsReloadUrl("/info", 60, false);
+ html += "";
+ server.send(200, "text/html", html);
+}
+// Reset web page
+void handleReset(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /reset.");
+ return server.requestAuthentication();
+ }
+#endif
+ server.send(200, "text/html",
+ "Reset WiFi Config "
+ ""
+ "Resetting the WiFiManager config back to defaults. "
+ "Device restarting. Try connecting in a few seconds.
" +
+ addJsReloadUrl("/", 10, true) +
+ "");
+ // Do the reset.
+#if MQTT_ENABLE
+ mqttLog("Wiping all saved config settings.");
+#endif // MQTT_ENABLE
+ debug("Trying to mount SPIFFS");
+ if (SPIFFS.begin()) {
+ debug("Removing JSON config file");
+ SPIFFS.remove(kConfigFile);
+ SPIFFS.end();
+ }
+ delay(1000);
+ debug("Reseting wifiManager's settings.");
+ wifiManager.resetSettings();
+ delay(1000);
+ debug("rebooting...");
+ ESP.restart();
+ delay(1000);
+}
+
+// Reboot web page
+void handleReboot() {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /quitquitquit.");
+ return server.requestAuthentication();
+ }
+#endif
+ server.send(200, "text/html",
+ "Rebooting "
+ ""
+ "Device restarting. "
+ "Try connecting in a few seconds.
" +
+ addJsReloadUrl("/", 15, true) +
+ "");
+#if MQTT_ENABLE
+ mqttLog("Reboot requested");
+#endif // MQTT_ENABLE
+ // Do the reset.
+ delay(1000);
+ ESP.restart();
+ delay(1000);
+}
+
+// Parse an Air Conditioner A/C Hex String/code and send it.
+// Args:
+// irsend: A Ptr to the IRsend object to transmit via.
+// irType: Nr. of the protocol we need to send.
+// str: A hexadecimal string containing the state to be sent.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendAirCon(IRsend *irsend, const uint16_t irType,
+ const String str) {
+ uint8_t strOffset = 0;
+ uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0.
+ uint16_t stateSize = 0;
+
+ if (str.startsWith("0x") || str.startsWith("0X"))
+ strOffset = 2;
+ // Calculate how many hexadecimal characters there are.
+ uint16_t inputLength = str.length() - strOffset;
+ if (inputLength == 0) {
+ debug("Zero length AirCon code encountered. Ignored.");
+ return false; // No input. Abort.
+ }
+
+ switch (irType) { // Get the correct state size for the protocol.
+ case KELVINATOR:
+ stateSize = kKelvinatorStateLength;
+ break;
+ case TOSHIBA_AC:
+ stateSize = kToshibaACStateLength;
+ break;
+ case DAIKIN:
+ // Daikin has 2 different possible size states.
+ // (The correct size, and a legacy shorter size.)
+ // 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.
+ // This should provide backward compatiblity with legacy messages.
+ stateSize = inputLength / 2; // Every two hex chars is a byte.
+ // Use at least the minimum size.
+ stateSize = std::max(stateSize, kDaikinStateLengthShort);
+ // If we think it isn't a "short" message.
+ if (stateSize > kDaikinStateLengthShort)
+ // Then it has to be at least the version of the "normal" size.
+ stateSize = std::max(stateSize, kDaikinStateLength);
+ // Lastly, it should never exceed the "normal" size.
+ stateSize = std::min(stateSize, kDaikinStateLength);
+ break;
+ case DAIKIN2:
+ stateSize = kDaikin2StateLength;
+ break;
+ case DAIKIN216:
+ stateSize = kDaikin216StateLength;
+ break;
+ case ELECTRA_AC:
+ stateSize = kElectraAcStateLength;
+ break;
+ case MITSUBISHI_AC:
+ stateSize = kMitsubishiACStateLength;
+ break;
+ case MITSUBISHI_HEAVY_88:
+ stateSize = kMitsubishiHeavy88StateLength;
+ break;
+ case MITSUBISHI_HEAVY_152:
+ stateSize = kMitsubishiHeavy152StateLength;
+ break;
+ case PANASONIC_AC:
+ stateSize = kPanasonicAcStateLength;
+ break;
+ case TROTEC:
+ stateSize = kTrotecStateLength;
+ break;
+ case ARGO:
+ stateSize = kArgoStateLength;
+ break;
+ case GREE:
+ stateSize = kGreeStateLength;
+ break;
+ case FUJITSU_AC:
+ // Fujitsu has four 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) (kFujitsuAcStateLengthShort - 1));
+ // If we think it isn't a "short" message.
+ if (stateSize > kFujitsuAcStateLengthShort)
+ // Then it has to be at least the smaller version of the "normal" size.
+ stateSize = std::max(stateSize, (uint16_t) (kFujitsuAcStateLength - 1));
+ // Lastly, it should never exceed the maximum "normal" size.
+ stateSize = std::min(stateSize, kFujitsuAcStateLength);
+ break;
+ case HAIER_AC:
+ stateSize = kHaierACStateLength;
+ break;
+ case HAIER_AC_YRW02:
+ stateSize = kHaierACYRW02StateLength;
+ break;
+ case HITACHI_AC:
+ stateSize = kHitachiAcStateLength;
+ break;
+ case HITACHI_AC1:
+ stateSize = kHitachiAc1StateLength;
+ break;
+ case HITACHI_AC2:
+ stateSize = kHitachiAc2StateLength;
+ break;
+ case WHIRLPOOL_AC:
+ stateSize = kWhirlpoolAcStateLength;
+ break;
+ case SAMSUNG_AC:
+ // Samsung 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) (kSamsungAcStateLength));
+ // If we think it isn't a "normal" message.
+ if (stateSize > kSamsungAcStateLength)
+ // Then it probably the extended size.
+ stateSize = std::max(stateSize,
+ (uint16_t) (kSamsungAcExtendedStateLength));
+ // Lastly, it should never exceed the maximum "extended" size.
+ stateSize = std::min(stateSize, kSamsungAcExtendedStateLength);
+ 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
+ // 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) 3);
+ // Cap the maximum size.
+ stateSize = std::min(stateSize, kStateSizeMax);
+ break;
+ case TCL112AC:
+ stateSize = kTcl112AcStateLength;
+ break;
+ default: // Not a protocol we expected. Abort.
+ debug("Unexpected AirCon protocol detected. Ignoring.");
+ return false;
+ }
+ if (inputLength > stateSize * 2) {
+ debug("AirCon code to large for the given protocol.");
+ return false;
+ }
+
+ // Ptr to the least significant byte of the resulting state for this protocol.
+ uint8_t *statePtr = &state[stateSize - 1];
+
+ // Convert the string into a state array of the correct length.
+ for (uint16_t i = 0; i < inputLength; i++) {
+ // Grab the next least sigificant hexadecimal digit from the string.
+ uint8_t c = tolower(str[inputLength + strOffset - i - 1]);
+ if (isxdigit(c)) {
+ if (isdigit(c))
+ c -= '0';
+ else
+ c = c - 'a' + 10;
+ } else {
+ debug("Aborting! Non-hexadecimal char found in AirCon state:");
+ debug(str.c_str());
+ return false;
+ }
+ if (i % 2 == 1) { // Odd: Upper half of the byte.
+ *statePtr += (c << 4);
+ statePtr--; // Advance up to the next least significant byte of state.
+ } else { // Even: Lower half of the byte.
+ *statePtr = c;
+ }
+ }
+
+ // Make the appropriate call for the protocol type.
+ switch (irType) {
+#if SEND_KELVINATOR
+ case KELVINATOR:
+ irsend->sendKelvinator(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_TOSHIBA_AC
+ case TOSHIBA_AC:
+ irsend->sendToshibaAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_DAIKIN
+ case DAIKIN:
+ irsend->sendDaikin(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_DAIKIN2
+ case DAIKIN2:
+ irsend->sendDaikin2(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_DAIKIN216
+ case DAIKIN216:
+ irsend->sendDaikin216(reinterpret_cast(state));
+ break;
+#endif // SEND_DAIKIN216
+#if SEND_MITSUBISHI_AC
+ case MITSUBISHI_AC:
+ irsend->sendMitsubishiAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_MITSUBISHIHEAVY
+ case MITSUBISHI_HEAVY_88: // 59
+ irsend->sendMitsubishiHeavy88(reinterpret_cast(state));
+ break;
+ case MITSUBISHI_HEAVY_152: // 60
+ irsend->sendMitsubishiHeavy152(reinterpret_cast(state));
+ break;
+#endif // SEND_MITSUBISHIHEAVY
+#if SEND_TROTEC
+ case TROTEC:
+ irsend->sendTrotec(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_ARGO
+ case ARGO:
+ irsend->sendArgo(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_GREE
+ case GREE:
+ irsend->sendGree(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_FUJITSU_AC
+ case FUJITSU_AC:
+ irsend->sendFujitsuAC(reinterpret_cast(state), stateSize);
+ break;
+#endif
+#if SEND_HAIER_AC
+ case HAIER_AC:
+ irsend->sendHaierAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_HAIER_AC_YRW02
+ case HAIER_AC_YRW02:
+ irsend->sendHaierACYRW02(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_HITACHI_AC
+ case HITACHI_AC:
+ irsend->sendHitachiAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_HITACHI_AC1
+ case HITACHI_AC1:
+ irsend->sendHitachiAC1(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_HITACHI_AC2
+ case HITACHI_AC2:
+ irsend->sendHitachiAC2(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_WHIRLPOOL_AC
+ case WHIRLPOOL_AC:
+ irsend->sendWhirlpoolAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_SAMSUNG_AC
+ case SAMSUNG_AC:
+ irsend->sendSamsungAC(reinterpret_cast(state), stateSize);
+ break;
+#endif
+#if SEND_ELECTRA_AC
+ case ELECTRA_AC:
+ irsend->sendElectraAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_PANASONIC_AC
+ case PANASONIC_AC:
+ irsend->sendPanasonicAC(reinterpret_cast(state));
+ break;
+#endif
+#if SEND_MWM
+ case MWM:
+ irsend->sendMWM(reinterpret_cast(state), stateSize);
+ break;
+#endif
+#if SEND_TCL112AC
+ case TCL112AC:
+ irsend->sendTcl112Ac(reinterpret_cast(state));
+ break;
+#endif
+ default:
+ debug("Unexpected AirCon type in send request. Not sent.");
+ return false;
+ }
+ return true; // We were successful as far as we can tell.
+}
+
+// Count how many values are in the String.
+// Args:
+// str: String containing the values.
+// sep: Character that separates the values.
+// Returns:
+// The number of values found in the String.
+uint16_t countValuesInStr(const String str, char sep) {
+ int16_t index = -1;
+ uint16_t count = 1;
+ do {
+ index = str.indexOf(sep, index + 1);
+ count++;
+ } while (index != -1);
+ return count;
+}
+
+// Dynamically allocate an array of uint16_t's.
+// Args:
+// size: Nr. of uint16_t's need to be in the new array.
+// Returns:
+// A Ptr to the new array. Restarts the ESP8266 if it fails.
+uint16_t * newCodeArray(const uint16_t size) {
+ uint16_t *result;
+
+ result = reinterpret_cast(malloc(size * sizeof(uint16_t)));
+ // Check we malloc'ed successfully.
+ if (result == NULL) { // malloc failed, so give up.
+ Serial.printf("\nCan't allocate %d bytes. (%d bytes free)\n",
+ size * sizeof(uint16_t), ESP.getFreeHeap());
+ Serial.println("Giving up & forcing a reboot.");
+ ESP.restart(); // Reboot.
+ delay(500); // Wait for the restart to happen.
+ return result; // Should never get here, but just in case.
+ }
+ return result;
+}
+
+#if SEND_GLOBALCACHE
+// Parse a GlobalCache String/code and send it.
+// Args:
+// irsend: A ptr to the IRsend object to transmit via.
+// str: A GlobalCache formatted String of comma separated numbers.
+// e.g. "38000,1,1,170,170,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,
+// 20,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,
+// 20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20,
+// 63,20,63,20,63,20,63,20,1798"
+// Note: The leading "1:1,1," of normal GC codes should be removed.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendGC(IRsend *irsend, const String str) {
+ uint16_t count;
+ uint16_t *code_array;
+ String tmp_str;
+
+ // Remove the leading "1:1,1," if present.
+ if (str.startsWith("1:1,1,"))
+ tmp_str = str.substring(6);
+ else
+ tmp_str = str;
+
+ // Find out how many items there are in the string.
+ count = countValuesInStr(tmp_str, ',');
+
+ // Now we know how many there are, allocate the memory to store them all.
+ code_array = newCodeArray(count);
+
+ // Now convert the strings to integers and place them in code_array.
+ count = 0;
+ uint16_t start_from = 0;
+ int16_t index = -1;
+ do {
+ index = tmp_str.indexOf(',', start_from);
+ code_array[count] = tmp_str.substring(start_from, index).toInt();
+ start_from = index + 1;
+ count++;
+ } while (index != -1);
+
+ irsend->sendGC(code_array, count); // All done. Send it.
+ free(code_array); // Free up the memory allocated.
+ if (count > 0)
+ return true; // We sent something.
+ return false; // We probably didn't.
+}
+#endif // SEND_GLOBALCACHE
+
+#if SEND_PRONTO
+// Parse a Pronto Hex String/code and send it.
+// Args:
+// irsend: A ptr to the IRsend object to transmit via.
+// str: A comma-separated String of nr. of repeats, then hexadecimal numbers.
+// e.g. "R1,0000,0067,0000,0015,0060,0018,0018,0018,0030,0018,0030,0018,
+// 0030,0018,0018,0018,0030,0018,0018,0018,0018,0018,0030,0018,
+// 0018,0018,0030,0018,0030,0018,0030,0018,0018,0018,0018,0018,
+// 0030,0018,0018,0018,0018,0018,0030,0018,0018,03f6"
+// or
+// "0000,0067,0000,0015,0060,0018". i.e. without the Repeat value
+// Requires at least kProntoMinLength comma-separated values.
+// sendPronto() only supports raw pronto code types, thus so does this.
+// repeats: Nr. of times the message is to be repeated.
+// This value is ignored if an embeddd repeat is found in str.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendPronto(IRsend *irsend, const String str,
+ uint16_t repeats) {
+ uint16_t count;
+ uint16_t *code_array;
+ int16_t index = -1;
+ uint16_t start_from = 0;
+
+ // Find out how many items there are in the string.
+ count = countValuesInStr(str, ',');
+
+ // Check if we have the optional embedded repeats value in the code string.
+ if (str.startsWith("R") || str.startsWith("r")) {
+ // Grab the first value from the string, as it is the nr. of repeats.
+ index = str.indexOf(',', start_from);
+ repeats = str.substring(start_from + 1, index).toInt(); // Skip the 'R'.
+ start_from = index + 1;
+ count--; // We don't count the repeats value as part of the code array.
+ }
+
+ // We need at least kProntoMinLength values for the code part.
+ if (count < kProntoMinLength) return false;
+
+ // Now we know how many there are, allocate the memory to store them all.
+ code_array = newCodeArray(count);
+
+ // Rest of the string are values for the code array.
+ // Now convert the hex strings to integers and place them in code_array.
+ count = 0;
+ do {
+ index = str.indexOf(',', start_from);
+ // Convert the hexadecimal value string to an unsigned integer.
+ code_array[count] = strtoul(str.substring(start_from, index).c_str(),
+ NULL, 16);
+ start_from = index + 1;
+ count++;
+ } while (index != -1);
+
+ irsend->sendPronto(code_array, count, repeats); // All done. Send it.
+ free(code_array); // Free up the memory allocated.
+ if (count > 0)
+ return true; // We sent something.
+ return false; // We probably didn't.
+}
+#endif // SEND_PRONTO
+
+#if SEND_RAW
+// Parse an IRremote Raw Hex String/code and send it.
+// Args:
+// irsend: A ptr to the IRsend object to transmit via.
+// str: A comma-separated String containing the freq and raw IR data.
+// e.g. "38000,9000,4500,600,1450,600,900,650,1500,..."
+// Requires at least two comma-separated values.
+// First value is the transmission frequency in Hz or kHz.
+// Returns:
+// bool: Successfully sent or not.
+bool parseStringAndSendRaw(IRsend *irsend, const String str) {
+ uint16_t count;
+ uint16_t freq = 38000; // Default to 38kHz.
+ uint16_t *raw_array;
+
+ // Find out how many items there are in the string.
+ count = countValuesInStr(str, ',');
+
+ // We expect the frequency as the first comma separated value, so we need at
+ // least two values. If not, bail out.
+ if (count < 2) return false;
+ count--; // We don't count the frequency value as part of the raw array.
+
+ // Now we know how many there are, allocate the memory to store them all.
+ raw_array = newCodeArray(count);
+
+ // Grab the first value from the string, as it is the frequency.
+ int16_t index = str.indexOf(',', 0);
+ freq = str.substring(0, index).toInt();
+ uint16_t start_from = index + 1;
+ // Rest of the string are values for the raw array.
+ // Now convert the strings to integers and place them in raw_array.
+ count = 0;
+ do {
+ index = str.indexOf(',', start_from);
+ raw_array[count] = str.substring(start_from, index).toInt();
+ start_from = index + 1;
+ count++;
+ } while (index != -1);
+
+ irsend->sendRaw(raw_array, count, freq); // All done. Send it.
+ free(raw_array); // Free up the memory allocated.
+ if (count > 0)
+ return true; // We sent something.
+ return false; // We probably didn't.
+}
+#endif // SEND_RAW
+
+// Parse the URL args to find the IR code.
+void handleIr(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /ir.");
+ return server.requestAuthentication();
+ }
+#endif
+ uint64_t data = 0;
+ String data_str = "";
+ int16_t ir_type = decode_type_t::NEC; // Default to NEC codes.
+ uint16_t nbits = 0;
+ uint16_t repeat = 0;
+
+ for (uint16_t i = 0; i < server.args(); i++) {
+ if (server.argName(i).equals(KEY_TYPE) ||
+ server.argName(i).equals(KEY_PROTOCOL)) {
+ ir_type = strToDecodeType(server.arg(i).c_str());
+ } else if (server.argName(i).equals(KEY_CODE)) {
+ data = getUInt64fromHex(server.arg(i).c_str());
+ data_str = server.arg(i);
+ } else if (server.argName(i).equals(KEY_BITS)) {
+ nbits = server.arg(i).toInt();
+ } else if (server.argName(i).equals(KEY_REPEAT)) {
+ repeat = server.arg(i).toInt();
+ }
+ }
+ debug("New code received via HTTP");
+ lastSendSucceeded = sendIRCode(IrSendTable[0], ir_type, data,
+ data_str.c_str(), nbits, repeat);
+ String html = F(
+ "Send IR command "
+ ""
+ "IR command sent! ");
+ html += addJsReloadUrl("/", 2, true);
+ html += F("");
+ server.send(200, "text/html", html);
+}
+
+void handleNotFound(void) {
+ String message = "File Not Found\n\n";
+ message += "URI: ";
+ message += server.uri();
+ message += "\nMethod: ";
+ message += (server.method() == HTTP_GET)?"GET":"POST";
+ message += "\nArguments: ";
+ message += server.args();
+ message += "\n";
+ for (uint8_t i=0; i < server.args(); i++)
+ message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
+ server.send(404, "text/plain", message);
+}
+
+void setup_wifi(void) {
+ delay(10);
+ loadWifiConfigFile();
+ // We start by connecting to a WiFi network
+ wifiManager.setTimeout(300); // Time out after 5 mins.
+ // Set up additional parameters for WiFiManager config menu page.
+ wifiManager.setSaveConfigCallback(saveWifiConfigCallback);
+ WiFiManagerParameter custom_hostname_text(
+ "Hostname ");
+ wifiManager.addParameter(&custom_hostname_text);
+ WiFiManagerParameter custom_hostname(
+ kHostnameKey, kHostnameKey, Hostname, kHostnameLength);
+ wifiManager.addParameter(&custom_hostname);
+ WiFiManagerParameter custom_authentication_text(
+ "Web/OTA authentication ");
+ wifiManager.addParameter(&custom_authentication_text);
+ WiFiManagerParameter custom_http_username(
+ kHttpUserKey, "username", HttpUsername, kUsernameLength);
+ wifiManager.addParameter(&custom_http_username);
+ WiFiManagerParameter custom_http_password(
+ kHttpPassKey, "password (No OTA if blank)", HttpPassword, kPasswordLength,
+ " type='password'");
+ wifiManager.addParameter(&custom_http_password);
+#if MQTT_ENABLE
+ WiFiManagerParameter custom_mqtt_text(
+ "MQTT Broker details ");
+ wifiManager.addParameter(&custom_mqtt_text);
+ WiFiManagerParameter custom_mqtt_server(
+ kMqttServerKey, "mqtt server", MqttServer, kHostnameLength);
+ wifiManager.addParameter(&custom_mqtt_server);
+ WiFiManagerParameter custom_mqtt_port(
+ kMqttPortKey, "mqtt port", MqttPort, kPortLength,
+ " input type='number' min='1' max='65535'");
+ wifiManager.addParameter(&custom_mqtt_port);
+ WiFiManagerParameter custom_mqtt_user(
+ kMqttUserKey, "mqtt username", MqttUsername, kUsernameLength);
+ wifiManager.addParameter(&custom_mqtt_user);
+ WiFiManagerParameter custom_mqtt_pass(
+ kMqttPassKey, "mqtt password", MqttPassword, kPasswordLength,
+ " type='password'");
+ wifiManager.addParameter(&custom_mqtt_pass);
+ WiFiManagerParameter custom_prefix_text(
+ "MQTT Prefix ");
+ wifiManager.addParameter(&custom_prefix_text);
+ WiFiManagerParameter custom_mqtt_prefix(
+ kMqttPrefixKey, "Leave empty to use Hostname", MqttPrefix,
+ kHostnameLength);
+ wifiManager.addParameter(&custom_mqtt_prefix);
+ #endif // MQTT_ENABLE
+#if USE_STATIC_IP
+ // Use a static IP config rather than the one supplied via DHCP.
+ wifiManager.setSTAStaticIPConfig(kIPAddress, kGateway, kSubnetMask);
+#endif // USE_STATIC_IP
+#if MIN_SIGNAL_STRENGTH
+ wifiManager.setMinimumSignalQuality(MIN_SIGNAL_STRENGTH);
+#endif // MIN_SIGNAL_STRENGTH
+ wifiManager.setRemoveDuplicateAPs(HIDE_DUPLIATE_NETWORKS);
+
+ if (!wifiManager.autoConnect()) {
+ debug("Wifi failed to connect and hit timeout. Rebooting...");
+ delay(3000);
+ // Reboot. A.k.a. "Have you tried turning it Off and On again?"
+ ESP.reset();
+ delay(5000);
+ }
+
+#if MQTT_ENABLE
+ strncpy(MqttServer, custom_mqtt_server.getValue(), kHostnameLength);
+ strncpy(MqttPort, custom_mqtt_port.getValue(), kPortLength);
+ strncpy(MqttUsername, custom_mqtt_user.getValue(), kUsernameLength);
+ strncpy(MqttPassword, custom_mqtt_pass.getValue(), kPasswordLength);
+ strncpy(MqttPrefix, custom_mqtt_prefix.getValue(), kHostnameLength);
+#endif // MQTT_ENABLE
+ strncpy(Hostname, custom_hostname.getValue(), kHostnameLength);
+ strncpy(HttpUsername, custom_http_username.getValue(), kUsernameLength);
+ strncpy(HttpPassword, custom_http_password.getValue(), kPasswordLength);
+ if (flagSaveWifiConfig) {
+ saveWifiConfig();
+ }
+ debug("WiFi connected. IP address:");
+ debug(WiFi.localIP().toString().c_str());
+}
+
+void init_vars(void) {
+#if MQTT_ENABLE
+ // If we have a prefix already, use it. Otherwise use the hostname.
+ if (!strlen(MqttPrefix)) strncpy(MqttPrefix, Hostname, kHostnameLength);
+ // Topic we send back acknowledgements on.
+ MqttAck = String(MqttPrefix) + '/' + MQTT_ACK;
+ // Sub-topic we get new commands from.
+ MqttSend = String(MqttPrefix) + '/' + MQTT_SEND;
+ // Topic we send received IRs to.
+ MqttRecv = String(MqttPrefix) + '/' + MQTT_RECV;
+ // Topic we send log messages to.
+ MqttLog = String(MqttPrefix) + '/' + MQTT_LOG;
+ // Topic for the Last Will & Testament.
+ MqttLwt = String(MqttPrefix) + '/' + MQTT_LWT;
+ // Sub-topic for the climate topics.
+ MqttClimate = String(MqttPrefix) + '/' + MQTT_CLIMATE;
+ // Sub-topic for the climate command topics.
+ MqttClimateCmnd = MqttClimate + '/' + MQTT_CLIMATE_CMND + '/';
+ // Sub-topic for the climate stat topics.
+ MqttClimateStat = MqttClimate + '/' + MQTT_CLIMATE_STAT + '/';
+ MqttDiscovery = "homeassistant/climate/" + String(Hostname) + "/config";
+ MqttHAName = String(Hostname) + "_aircon";
+ // Create a unique MQTT client id.
+ MqttClientId = String(Hostname) + String(ESP.getChipId(), HEX);
+#endif // MQTT_ENABLE
+}
+
+void setup(void) {
+ // Set the default climate settings.
+ climate.protocol = decode_type_t::UNKNOWN;
+ climate.model = -1; // Unknown.
+ climate.power = false;
+ climate.mode = stdAc::opmode_t::kAuto;
+ climate.celsius = true;
+ climate.degrees = 25; // 25C
+ climate.fanspeed = stdAc::fanspeed_t::kAuto;
+ climate.swingv = stdAc::swingv_t::kAuto;
+ climate.swingh = stdAc::swingh_t::kAuto;
+ climate.quiet = false;
+ climate.turbo = false;
+ climate.econo = false;
+ climate.light = false;
+ climate.filter = false;
+ climate.clean = false;
+ climate.beep = false;
+ climate.sleep = -1; // Off
+ climate.clock = -1; // Don't set.
+ climate_prev = climate;
+
+ // Initialise all the IR transmitters.
+ for (uint8_t i = 0; i < kSendTableSize; i++) {
+ IrSendTable[i] = new IRsend(gpioTable[i]);
+ IrSendTable[i]->begin();
+ offset = IrSendTable[i]->calibrate();
+ }
+#ifdef IR_RX
+#if IR_RX_PULLUP
+ pinMode(IR_RX, INPUT_PULLUP);
+#endif // IR_RX_PULLUP
+#if DECODE_HASH
+ // Ignore messages with less than minimum on or off pulses.
+ irrecv.setUnknownThreshold(kMinUnknownSize);
+#endif // DECODE_HASH
+ irrecv.enableIRIn(); // Start the receiver
+#endif // IR_RX
+
+#if DEBUG
+ if (!isSerialGpioUsedByIr()) {
+ // Use SERIAL_TX_ONLY so that the RX pin can be freed up for GPIO/IR use.
+ Serial.begin(BAUD_RATE, SERIAL_8N1, SERIAL_TX_ONLY);
+ while (!Serial) // Wait for the serial connection to be establised.
+ delay(50);
+ Serial.println();
+ debug("IRMQTTServer " _MY_VERSION_" has booted.");
+ }
+#endif // DEBUG
+
+ setup_wifi();
+
+ // Wait a bit for things to settle.
+ delay(500);
+
+ lastReconnectAttempt = 0;
+
+ if (mdns.begin(Hostname, WiFi.localIP())) {
+ debug("MDNS responder started");
+ }
+
+ // Setup the root web page.
+ server.on("/", handleRoot);
+ // Setup the examples web page.
+ server.on("/examples", handleExamples);
+ // Setup the page to handle web-based IR codes.
+ server.on("/ir", handleIr);
+ // Setup the aircon page.
+ server.on("/aircon", handleAirCon);
+ // Setup the aircon update page.
+ server.on("/aircon/set", handleAirConSet);
+ // Setup the info page.
+ server.on("/info", handleInfo);
+ // Setup the admin page.
+ server.on("/admin", handleAdmin);
+ // Setup a reset page to cause WiFiManager information to be reset.
+ server.on("/reset", handleReset);
+ // Reboot url
+ server.on("/quitquitquit", handleReboot);
+#if MQTT_ENABLE
+ // MQTT Discovery url
+ server.on("/send_discovery", handleSendMqttDiscovery);
+ // Finish setup of the mqtt clent object.
+ mqtt_client.setServer(MqttServer, atoi(MqttPort));
+ mqtt_client.setCallback(mqttCallback);
+ // Set various variables
+ init_vars();
+#endif // MQTT_ENABLE
+
+#if FIRMWARE_OTA
+ // Setup the URL to allow Over-The-Air (OTA) firmware updates.
+ if (strlen(HttpPassword)) { // Allow if password is set.
+ server.on("/update", HTTP_POST, [](){
+#if MQTT_ENABLE
+ mqttLog("Attempting firmware update & reboot");
+ delay(1000);
+#endif // MQTT_ENABLE
+ server.send(200, "text/html",
+ "Updating firmware. "
+ ""
+ "Updating firmware "
+ " "
+ "Warning! Don't power off the device for 60 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 " +
+ String(Update.hasError() ? "FAILED!" : "SUCCEEDED!") +
+ " Rebooting!
" +
+ addJsReloadUrl("/", 20, true) +
+ "");
+ delay(1000);
+ ESP.restart();
+ delay(1000);
+ }, [](){
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /update.");
+ return server.requestAuthentication();
+ }
+ HTTPUpload& upload = server.upload();
+ if (upload.status == UPLOAD_FILE_START) {
+ WiFiUDP::stopAll();
+ debug("Update:");
+ debug(upload.filename.c_str());
+ uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) &
+ 0xFFFFF000;
+ if (!Update.begin(maxSketchSpace)) { // start with max available size
+#if DEBUG
+ if (!isSerialGpioUsedByIr())
+ Update.printError(Serial);
+#endif // DEBUG
+ }
+ } else if (upload.status == UPLOAD_FILE_WRITE) {
+ if (Update.write(upload.buf, upload.currentSize) !=
+ upload.currentSize) {
+#if DEBUG
+ if (!isSerialGpioUsedByIr())
+ Update.printError(Serial);
+#endif // DEBUG
+ }
+ } else if (upload.status == UPLOAD_FILE_END) {
+ // true to set the size to the current progress
+ if (Update.end(true)) {
+ debug("Update Success:");
+ debug(String(upload.totalSize).c_str());
+ debug("Rebooting...");
+ }
+ }
+ yield();
+ });
+ }
+#endif // FIRMWARE_OTA
+
+ // Set up an error page.
+ server.onNotFound(handleNotFound);
+
+ server.begin();
+ debug("HTTP server started");
+}
+
+#if MQTT_ENABLE
+// MQTT subscribing to topic
+void subscribing(const String topic_name) {
+ // subscription to topic for receiving data with QoS.
+ if (mqtt_client.subscribe(topic_name.c_str(), QOS))
+ debug("Subscription OK to:");
+ else
+ debug("Subscription FAILED to:");
+ debug(topic_name.c_str());
+}
+
+// Un-subscribe from a MQTT topic
+void unsubscribing(const String topic_name) {
+ // subscription to topic for receiving data with QoS.
+ if (mqtt_client.unsubscribe(topic_name.c_str()))
+ debug("Unsubscribed OK from:");
+ else
+ debug("FAILED to unsubscribe from:");
+ debug(topic_name.c_str());
+}
+
+void mqttLog(const String mesg) {
+ debug(mesg.c_str());
+ mqtt_client.publish(MqttLog.c_str(), mesg.c_str());
+ mqttSentCounter++;
+}
+
+bool reconnect(void) {
+ // Loop a few times or until we're reconnected
+ uint16_t tries = 1;
+ while (!mqtt_client.connected() && tries <= 3) {
+ int connected = false;
+ // Attempt to connect
+ debug(("Attempting MQTT connection to " + String(MqttServer) + ":" +
+ String(MqttPort) + "... ").c_str());
+ if (strcmp(MqttUsername, "") && strcmp(MqttPassword, "")) {
+ debug("Using mqtt username/password to connect.");
+ connected = mqtt_client.connect(MqttClientId.c_str(),
+ MqttUsername, MqttPassword,
+ MqttLwt.c_str(),
+ QOS, true, kLwtOffline);
+
+ } else {
+ debug("Using password-less mqtt connection.");
+ connected = mqtt_client.connect(MqttClientId.c_str(), MqttLwt.c_str(),
+ QOS, true, kLwtOffline);
+ }
+ if (connected) {
+ // Once connected, publish an announcement...
+ mqttLog("(Re)Connected.");
+
+ // Update Last Will & Testament to say we are back online.
+ mqtt_client.publish(MqttLwt.c_str(), kLwtOnline, true);
+ mqttSentCounter++;
+
+ // Subscribing to topic(s)
+ subscribing(MqttSend);
+ for (uint8_t i = 0; i < kSendTableSize; i++) {
+ subscribing(MqttSend + '_' + String(static_cast(i)));
+ }
+ // Climate command topics.
+ subscribing(MqttClimateCmnd + '+');
+ } else {
+ debug(("failed, rc=" + String(mqtt_client.state()) +
+ " Try again in a bit.").c_str());
+ // Wait for a bit before retrying
+ delay(tries << 7); // Linear increasing back-off (x128)
+ }
+ tries++;
+ }
+ return mqtt_client.connected();
+}
+
+// Return a string containing the comma separated list of MQTT command topics.
+String listOfCommandTopics(void) {
+ String result = MqttSend;
+ for (uint16_t i = 0; i < kSendTableSize; i++) {
+ result += ", " + MqttSend + '_' + String(i);
+ }
+ return result;
+}
+
+// MQTT Discovery web page
+void handleSendMqttDiscovery(void) {
+#if HTML_PASSWORD_ENABLE
+ if (!server.authenticate(HttpUsername, HttpPassword)) {
+ debug("Basic HTTP authentication failure for /send_discovery.");
+ return server.requestAuthentication();
+ }
+#endif // HTML_PASSWORD_ENABLE
+ server.send(200, "text/html",
+ "Sending MQTT Discovery message "
+ ""
+ "Sending MQTT Discovery message. " +
+ htmlMenu() +
+ "The Home Assistant MQTT Discovery message is being sent to topic: " +
+ MqttDiscovery + ". It will show up in Home Assistant in a few seconds."
+ "
"
+ "Warning! "
+ "Home Assistant's config for this device is reset each time this is "
+ " is sent.
" +
+ addJsReloadUrl("/", 15, true) +
+ "");
+ sendMQTTDiscovery(MqttDiscovery.c_str());
+}
+
+void doBroadcast(TimerMs *timer, const uint32_t interval,
+ const commonAcState_t state, const bool retain,
+ const bool force) {
+ if (force || (!lockMqttBroadcast && timer->elapsed() > interval)) {
+ debug("Sending MQTT stat update broadcast.");
+ sendClimate(state, state, MqttClimateStat,
+ retain, true, false);
+ timer->reset(); // It's been sent, so reset the timer.
+ hasBroadcastBeenSent = true;
+ }
+}
+
+void receivingMQTT(String const topic_name, String const callback_str) {
+ char* tok_ptr;
+ uint64_t code = 0;
+ uint16_t nbits = 0;
+ uint16_t repeat = 0;
+ uint8_t channel = 0; // Default to the first channel. e.g. "*_0"
+
+ debug("Receiving data by MQTT topic:");
+ debug(topic_name.c_str());
+ debug("with payload:");
+ debug(callback_str.c_str());
+ // Save the message as the last command seen (global).
+ lastMqttCmdTopic = topic_name;
+ lastMqttCmd = callback_str;
+ lastMqttCmdTime = millis();
+ mqttRecvCounter++;
+
+ if (topic_name.startsWith(MqttClimate)) {
+ if (topic_name.startsWith(MqttClimateCmnd)) {
+ debug("It's a climate command topic");
+ commonAcState_t updated = updateClimate(
+ climate, topic_name, MqttClimateCmnd, callback_str);
+ sendClimate(climate, updated, MqttClimateStat,
+ true, false, false);
+ climate = updated;
+ } else if (topic_name.startsWith(MqttClimateStat)) {
+ debug("It's a climate state topic. Update internal state and DON'T send");
+ climate = updateClimate(
+ climate, topic_name, MqttClimateStat, callback_str);
+ }
+ return; // We are done for now.
+ }
+ // Check if a specific channel was requested by looking for a "*_[0-9]" suffix
+ for (uint8_t i = 0; i < kSendTableSize; i++) {
+ debug(("Checking if " + topic_name + " ends with _" + String(i)).c_str());
+ if (topic_name.endsWith("_" + String(i))) {
+ channel = i;
+ debug("It does!");
+ break;
+ }
+ }
+
+ debug(("Using transmit channel " + String(static_cast(channel)) +
+ " / GPIO " + String(static_cast(gpioTable[channel]))).c_str());
+ // Make a copy of the callback string as strtok destroys it.
+ char* callback_c_str = strdup(callback_str.c_str());
+ debug("MQTT Payload (raw):");
+ debug(callback_c_str);
+
+ // Get the numeric protocol type.
+ int ir_type = strtoul(strtok_r(callback_c_str, ",", &tok_ptr), NULL, 10);
+ char* next = strtok_r(NULL, ",", &tok_ptr);
+ // If there is unparsed string left, try to convert it assuming it's hex.
+ if (next != NULL) {
+ code = getUInt64fromHex(next);
+ next = strtok_r(NULL, ",", &tok_ptr);
+ } else {
+ // We require at least two value in the string. Give up.
+ return;
+ }
+ // If there is still string left, assume it is the bit size.
+ if (next != NULL) {
+ nbits = atoi(next);
+ next = strtok_r(NULL, ",", &tok_ptr);
+ }
+ // If there is still string left, assume it is the repeat count.
+ if (next != NULL)
+ repeat = atoi(next);
+
+ free(callback_c_str);
+
+ // send received MQTT value by IR signal
+ lastSendSucceeded = sendIRCode(
+ IrSendTable[channel], ir_type, code,
+ callback_str.substring(callback_str.indexOf(",") + 1).c_str(),
+ nbits, repeat);
+}
+
+// Callback function, when we receive an MQTT value on the topics
+// subscribed this function is called
+void mqttCallback(char* topic, byte* payload, unsigned int length) {
+ // In order to republish this payload, a copy must be made
+ // as the orignal payload buffer will be overwritten whilst
+ // constructing the PUBLISH packet.
+ // Allocate the correct amount of memory for the payload copy
+ byte* payload_copy = reinterpret_cast(malloc(length + 1));
+ // Copy the payload to the new buffer
+ memcpy(payload_copy, payload, length);
+
+ // Conversion to a printable string
+ payload_copy[length] = '\0';
+ String callback_string = String(reinterpret_cast(payload_copy));
+ String topic_name = String(reinterpret_cast(topic));
+
+ // launch the function to treat received data
+ receivingMQTT(topic_name, callback_string);
+
+ // Free the memory
+ free(payload_copy);
+}
+
+void sendMQTTDiscovery(const char *topic) {
+ if (mqtt_client.publish(
+ topic, String(
+ "{"
+ "\"~\":\"" + MqttClimate + "\","
+ "\"name\":\"" + MqttHAName + "\","
+ "\"pow_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_POWER "\","
+ "\"mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_MODE "\","
+ "\"mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/" KEY_MODE
+ "\","
+ "\"modes\":[\"off\",\"auto\",\"cool\",\"heat\",\"dry\",\"fan_only\"],"
+ "\"temp_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/" KEY_TEMP "\","
+ "\"temp_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/" KEY_TEMP
+ "\","
+ "\"min_temp\":\"16\","
+ "\"max_temp\":\"30\","
+ "\"temp_step\":\"1\","
+ "\"fan_mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/"
+ KEY_FANSPEED "\","
+ "\"fan_mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/"
+ KEY_FANSPEED "\","
+ "\"fan_modes\":[\"auto\",\"min\",\"low\",\"medium\",\"high\",\"max\"],"
+ "\"swing_mode_cmd_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_CMND "/"
+ KEY_SWINGV "\","
+ "\"swing_mode_stat_t\":\"~" MQTT_CLIMATE "/" MQTT_CLIMATE_STAT "/"
+ KEY_SWINGV "\","
+ "\"swing_modes\":["
+ "\"off\",\"auto\",\"highest\",\"high\",\"middle\",\"low\",\"lowest\""
+ "]"
+ "}").c_str())) {
+ mqttLog("MQTT climate discovery successful sent.");
+ hasDiscoveryBeenSent = true;
+ lastDiscovery.reset();
+ mqttSentCounter++;
+ } else {
+ mqttLog("MQTT climate discovery FAILED to send.");
+ }
+}
+#endif // MQTT_ENABLE
+
+void loop(void) {
+ server.handleClient(); // Handle any web activity
+
+#if MQTT_ENABLE
+ uint32_t now = millis();
+ // MQTT client connection management
+ if (!mqtt_client.connected()) {
+ if (wasConnected) {
+ lastDisconnectedTime = now;
+ wasConnected = false;
+ mqttDisconnectCounter++;
+ }
+ // Reconnect if it's longer than kMqttReconnectTime since we last tried.
+ if (now - lastReconnectAttempt > kMqttReconnectTime) {
+ lastReconnectAttempt = now;
+ debug("client mqtt not connected, trying to connect");
+ // Attempt to reconnect
+ if (reconnect()) {
+ lastReconnectAttempt = 0;
+ wasConnected = true;
+ if (boot) {
+ mqttLog("IR Server just booted");
+ boot = false;
+ } else {
+ mqttLog("IR Server just (re)connected to MQTT. "
+ "Lost connection about " + timeSince(lastConnectedTime));
+ }
+ lastConnectedTime = now;
+ debug("successful client mqtt connection");
+ if (lockMqttBroadcast) {
+ // Attempt to fetch back any Climate state stored in MQTT retained
+ // messages on the MQTT broker.
+ mqttLog("Started listening for previous state.");
+ climate_prev = climate; // Make a copy so we can compare afterwards.
+ subscribing(MqttClimateStat + '+');
+ statListenTime.reset();
+ }
+ }
+ }
+ } else {
+ // MQTT loop
+ lastConnectedTime = now;
+ mqtt_client.loop();
+ if (lockMqttBroadcast && statListenTime.elapsed() > kStatListenPeriodMs) {
+ unsubscribing(MqttClimateStat + '+');
+ mqttLog("Finished listening for previous state.");
+ if (cmpClimate(climate, climate_prev)) { // Something changed.
+ mqttLog("The state was recovered from MQTT broker. Updating.");
+ sendClimate(climate_prev, climate, MqttClimateStat,
+ true, false, false);
+ }
+ lockMqttBroadcast = false; // Release the lock so we can broadcast again.
+ }
+ // Periodically send all of the climate state via MQTT.
+ doBroadcast(&lastBroadcast, kBroadcastPeriodMs, climate, false, false);
+ }
+#endif // MQTT_ENABLE
+#ifdef IR_RX
+ // Check if an IR code has been received via the IR RX module.
+#if REPORT_UNKNOWNS
+ if (irrecv.decode(&capture)) {
+#else // REPORT_UNKNOWNS
+ if (irrecv.decode(&capture) && capture.decode_type != UNKNOWN) {
+#endif // REPORT_UNKNOWNS
+ lastIrReceivedTime = millis();
+ lastIrReceived = String(capture.decode_type) + "," +
+ resultToHexidecimal(&capture);
+#if REPORT_RAW_UNKNOWNS
+ if (capture.decode_type == UNKNOWN) {
+ lastIrReceived += ";";
+ for (uint16_t i = 1; i < capture.rawlen; i++) {
+ uint32_t usecs;
+ for (usecs = capture.rawbuf[i] * kRawTick; usecs > UINT16_MAX;
+ usecs -= UINT16_MAX) {
+ lastIrReceived += uint64ToString(UINT16_MAX);
+ lastIrReceived += ",0,";
+ }
+ lastIrReceived += uint64ToString(usecs, 10);
+ if (i < capture.rawlen - 1)
+ lastIrReceived += ",";
+ }
+ }
+#endif // REPORT_RAW_UNKNOWNS
+ // If it isn't an AC code, add the bits.
+ if (!hasACState(capture.decode_type))
+ lastIrReceived += "," + String(capture.bits);
+#if MQTT_ENABLE
+ mqtt_client.publish(MqttRecv.c_str(), lastIrReceived.c_str());
+ mqttSentCounter++;
+#endif // MQTT_ENABLE
+ irRecvCounter++;
+ debug("Incoming IR message sent to MQTT:");
+ debug(lastIrReceived.c_str());
+ }
+#endif // IR_RX
+ delay(100);
+}
+
+// Arduino framework doesn't support strtoull(), so make our own one.
+uint64_t getUInt64fromHex(char const *str) {
+ uint64_t result = 0;
+ uint16_t offset = 0;
+ // Skip any leading '0x' or '0X' prefix.
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ offset = 2;
+ for (; isxdigit((unsigned char)str[offset]); offset++) {
+ char c = str[offset];
+ result *= 16;
+ if (isdigit(c)) /* '0' .. '9' */
+ result += c - '0';
+ else if (isupper(c)) /* 'A' .. 'F' */
+ result += c - 'A' + 10;
+ else /* 'a' .. 'f'*/
+ result += c - 'a' + 10;
+ }
+ return result;
+}
+
+// Transmit the given IR message.
+//
+// Args:
+// irsend: A pointer to a IRsend object to transmit via.
+// ir_type: enum of the protocol to be sent.
+// code: Numeric payload of the IR message. Most protocols use this.
+// code_str: The unparsed code to be sent. Used by complex protocol encodings.
+// bits: Nr. of bits in the protocol. 0 means use the protocol's default.
+// repeat: Nr. of times the message is to be repeated. (Not all protcols.)
+// Returns:
+// bool: Successfully sent or not.
+bool sendIRCode(IRsend *irsend, int const ir_type,
+ uint64_t const code, char const * code_str, uint16_t bits,
+ uint16_t repeat) {
+ // Create a pseudo-lock so we don't try to send two codes at the same time.
+ while (lockIr)
+ delay(20);
+ lockIr = true;
+
+ bool success = true; // Assume success.
+
+ // send the IR message.
+ switch (ir_type) {
+#if SEND_RC5
+ case RC5: // 1
+ if (bits == 0)
+ bits = kRC5Bits;
+ irsend->sendRC5(code, bits, repeat);
+ break;
+#endif
+#if SEND_RC6
+ case RC6: // 2
+ if (bits == 0)
+ bits = kRC6Mode0Bits;
+ irsend->sendRC6(code, bits, repeat);
+ break;
+#endif
+#if SEND_NEC
+ case NEC: // 3
+ if (bits == 0)
+ bits = kNECBits;
+ irsend->sendNEC(code, bits, repeat);
+ break;
+#endif
+#if SEND_SONY
+ case SONY: // 4
+ if (bits == 0)
+ bits = kSony12Bits;
+ repeat = std::max(repeat, kSonyMinRepeat);
+ irsend->sendSony(code, bits, repeat);
+ break;
+#endif
+#if SEND_PANASONIC
+ case PANASONIC: // 5
+ if (bits == 0)
+ bits = kPanasonicBits;
+ irsend->sendPanasonic64(code, bits, repeat);
+ break;
+#endif
+#if SEND_JVC
+ case JVC: // 6
+ if (bits == 0)
+ bits = kJvcBits;
+ irsend->sendJVC(code, bits, repeat);
+ break;
+#endif
+#if SEND_SAMSUNG
+ case SAMSUNG: // 7
+ if (bits == 0)
+ bits = kSamsungBits;
+ irsend->sendSAMSUNG(code, bits, repeat);
+ break;
+#endif
+#if SEND_SAMSUNG36
+ case SAMSUNG36: // 56
+ if (bits == 0)
+ bits = kSamsung36Bits;
+ irsend->sendSamsung36(code, bits, repeat);
+ break;
+#endif
+#if SEND_WHYNTER
+ case WHYNTER: // 8
+ if (bits == 0)
+ bits = kWhynterBits;
+ irsend->sendWhynter(code, bits, repeat);
+ break;
+#endif
+#if SEND_AIWA_RC_T501
+ case AIWA_RC_T501: // 9
+ if (bits == 0)
+ bits = kAiwaRcT501Bits;
+ repeat = std::max(repeat, kAiwaRcT501MinRepeats);
+ irsend->sendAiwaRCT501(code, bits, repeat);
+ break;
+#endif
+#if SEND_LG
+ case LG: // 10
+ if (bits == 0)
+ bits = kLgBits;
+ irsend->sendLG(code, bits, repeat);
+ break;
+#endif
+#if SEND_MITSUBISHI
+ case MITSUBISHI: // 12
+ if (bits == 0)
+ bits = kMitsubishiBits;
+ repeat = std::max(repeat, kMitsubishiMinRepeat);
+ irsend->sendMitsubishi(code, bits, repeat);
+ break;
+#endif
+#if SEND_DISH
+ case DISH: // 13
+ if (bits == 0)
+ bits = kDishBits;
+ repeat = std::max(repeat, kDishMinRepeat);
+ irsend->sendDISH(code, bits, repeat);
+ break;
+#endif
+#if SEND_SHARP
+ case SHARP: // 14
+ if (bits == 0)
+ bits = kSharpBits;
+ irsend->sendSharpRaw(code, bits, repeat);
+ break;
+#endif
+#if SEND_COOLIX
+ case COOLIX: // 15
+ if (bits == 0)
+ bits = kCoolixBits;
+ irsend->sendCOOLIX(code, bits, repeat);
+ break;
+#endif
+ case DAIKIN: // 16
+ case DAIKIN2: // 53
+ case DAIKIN216: // 61
+ case KELVINATOR: // 18
+ case MITSUBISHI_AC: // 20
+ case GREE: // 24
+ case ARGO: // 27
+ case TROTEC: // 28
+ case TOSHIBA_AC: // 32
+ case FUJITSU_AC: // 33
+ case HAIER_AC: // 38
+ case HAIER_AC_YRW02: // 44
+ case HITACHI_AC: // 40
+ case HITACHI_AC1: // 41
+ case HITACHI_AC2: // 42
+ case WHIRLPOOL_AC: // 45
+ case SAMSUNG_AC: // 46
+ case ELECTRA_AC: // 48
+ case PANASONIC_AC: // 49
+ case MWM: // 52
+ success = parseStringAndSendAirCon(irsend, ir_type, code_str);
+ break;
+#if SEND_DENON
+ case DENON: // 17
+ if (bits == 0)
+ bits = DENON_BITS;
+ irsend->sendDenon(code, bits, repeat);
+ break;
+#endif
+#if SEND_SHERWOOD
+ case SHERWOOD: // 19
+ if (bits == 0)
+ bits = kSherwoodBits;
+ repeat = std::max(repeat, kSherwoodMinRepeat);
+ irsend->sendSherwood(code, bits, repeat);
+ break;
+#endif
+#if SEND_RCMM
+ case RCMM: // 21
+ if (bits == 0)
+ bits = kRCMMBits;
+ irsend->sendRCMM(code, bits, repeat);
+ break;
+#endif
+#if SEND_SANYO
+ case SANYO_LC7461: // 22
+ if (bits == 0)
+ bits = kSanyoLC7461Bits;
+ irsend->sendSanyoLC7461(code, bits, repeat);
+ break;
+#endif
+#if SEND_RC5
+ case RC5X: // 23
+ if (bits == 0)
+ bits = kRC5XBits;
+ irsend->sendRC5(code, bits, repeat);
+ break;
+#endif
+#if SEND_PRONTO
+ case PRONTO: // 25
+ success = parseStringAndSendPronto(irsend, code_str, repeat);
+ break;
+#endif
+#if SEND_NIKAI
+ case NIKAI: // 29
+ if (bits == 0)
+ bits = kNikaiBits;
+ irsend->sendNikai(code, bits, repeat);
+ break;
+#endif
+#if SEND_RAW
+ case RAW: // 30
+ success = parseStringAndSendRaw(irsend, code_str);
+ break;
+#endif
+#if SEND_GLOBALCACHE
+ case GLOBALCACHE: // 31
+ success = parseStringAndSendGC(irsend, code_str);
+ break;
+#endif
+#if SEND_MIDEA
+ case MIDEA: // 34
+ if (bits == 0)
+ bits = kMideaBits;
+ irsend->sendMidea(code, bits, repeat);
+ break;
+#endif
+#if SEND_MAGIQUEST
+ case MAGIQUEST: // 35
+ if (bits == 0)
+ bits = kMagiquestBits;
+ irsend->sendMagiQuest(code, bits, repeat);
+ break;
+#endif
+#if SEND_LASERTAG
+ case LASERTAG: // 36
+ if (bits == 0)
+ bits = kLasertagBits;
+ irsend->sendLasertag(code, bits, repeat);
+ break;
+#endif
+#if SEND_CARRIER_AC
+ case CARRIER_AC: // 37
+ if (bits == 0)
+ bits = kCarrierAcBits;
+ irsend->sendCarrierAC(code, bits, repeat);
+ break;
+#endif
+#if SEND_MITSUBISHI2
+ case MITSUBISHI2: // 39
+ if (bits == 0)
+ bits = kMitsubishiBits;
+ repeat = std::max(repeat, kMitsubishiMinRepeat);
+ irsend->sendMitsubishi2(code, bits, repeat);
+ break;
+#endif
+#if SEND_GICABLE
+ case GICABLE: // 43
+ if (bits == 0)
+ bits = kGicableBits;
+ repeat = std::max(repeat, kGicableMinRepeat);
+ irsend->sendGICable(code, bits, repeat);
+ break;
+#endif
+#if SEND_LUTRON
+ case LUTRON: // 47
+ if (bits == 0)
+ bits = kLutronBits;
+ irsend->sendLutron(code, bits, repeat);
+ break;
+#endif
+#if SEND_PIONEER
+ case PIONEER: // 50
+ if (bits == 0)
+ bits = kPioneerBits;
+ irsend->sendPioneer(code, bits, repeat);
+ break;
+#endif
+#if SEND_LG
+ case LG2: // 51
+ if (bits == 0)
+ bits = kLgBits;
+ irsend->sendLG2(code, bits, repeat);
+ break;
+#endif
+#if SEND_VESTEL_AC
+ case VESTEL_AC: // 54
+ if (bits == 0)
+ bits = kVestelAcBits;
+ irsend->sendVestelAc(code, bits, repeat);
+ break;
+#endif
+#if SEND_TECO
+ case TECO: // 55
+ if (bits == 0)
+ bits = kTecoBits;
+ irsend->sendTeco(code, bits, repeat);
+ break;
+#endif
+#if SEND_LEGOPF
+ case LEGOPF: // 58
+ if (bits == 0)
+ bits = kLegoPfBits;
+ irsend->sendLegoPf(code, bits, repeat);
+ break;
+#endif
+ default:
+ // If we got here, we didn't know how to send it.
+ success = false;
+ }
+ lastSendTime = millis();
+ // Release the lock.
+ lockIr = false;
+
+ // Indicate that we sent the message or not.
+ if (success) {
+ sendReqCounter++;
+ debug("Sent the IR message:");
+ } else {
+ debug("Failed to send IR Message:");
+ }
+ debug("Type:");
+ debug(String(ir_type).c_str());
+ // For "long" codes we basically repeat what we got.
+ if (hasACState((decode_type_t) ir_type) ||
+ ir_type == PRONTO ||
+ ir_type == RAW ||
+ ir_type == GLOBALCACHE) {
+ debug("Code: ");
+ debug(code_str);
+ // Confirm what we were asked to send was sent.
+#if MQTT_ENABLE
+ if (success) {
+ if (ir_type == PRONTO && repeat > 0)
+ mqtt_client.publish(MqttAck.c_str(), (String(ir_type) + ",R" +
+ String(repeat) + "," +
+ String(code_str)).c_str());
+ else
+ mqtt_client.publish(MqttAck.c_str(), (String(ir_type) + "," +
+ String(code_str)).c_str());
+ mqttSentCounter++;
+ }
+#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());
+#if MQTT_ENABLE
+ if (success) {
+ mqtt_client.publish(MqttAck.c_str(), (String(ir_type) + "," +
+ uint64ToString(code, 16)
+ + "," + String(bits) + "," +
+ String(repeat)).c_str());
+ mqttSentCounter++;
+ }
+#endif // MQTT_ENABLE
+ }
+ return success;
+}
+
+bool sendInt(const String topic, const int32_t num, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), String(num).c_str(), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+bool sendBool(const String topic, const bool on, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), (on ? "on" : "off"), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+bool sendString(const String topic, const String str, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), str.c_str(), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+bool sendFloat(const String topic, const float_t temp, const bool retain) {
+#if MQTT_ENABLE
+ mqttSentCounter++;
+ return mqtt_client.publish(topic.c_str(), String(temp, 1).c_str(), retain);
+#else // MQTT_ENABLE
+ return true;
+#endif // MQTT_ENABLE
+}
+
+commonAcState_t updateClimate(commonAcState_t current, const String str,
+ const String prefix, const String payload) {
+ commonAcState_t result = current;
+ String value = payload;
+ value.toUpperCase();
+ if (str.equals(prefix + KEY_PROTOCOL))
+ result.protocol = strToDecodeType(value.c_str());
+ else if (str.equals(prefix + KEY_MODEL))
+ result.model = IRac::strToModel(value.c_str());
+ else if (str.equals(prefix + KEY_POWER))
+ result.power = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_MODE))
+ result.mode = IRac::strToOpmode(value.c_str());
+ else if (str.equals(prefix + KEY_TEMP))
+ result.degrees = value.toFloat();
+ else if (str.equals(prefix + KEY_FANSPEED))
+ result.fanspeed = IRac::strToFanspeed(value.c_str());
+ else if (str.equals(prefix + KEY_SWINGV))
+ result.swingv = IRac::strToSwingV(value.c_str());
+ else if (str.equals(prefix + KEY_SWINGH))
+ result.swingh = IRac::strToSwingH(value.c_str());
+ else if (str.equals(prefix + KEY_QUIET))
+ result.quiet = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_TURBO))
+ result.turbo = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_ECONO))
+ result.econo = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_LIGHT))
+ result.light = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_BEEP))
+ result.beep = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_FILTER))
+ result.filter = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_CLEAN))
+ result.clean = IRac::strToBool(value.c_str());
+ else if (str.equals(prefix + KEY_SLEEP))
+ result.sleep = value.toInt();
+ else if (str.equals(prefix + KEY_CLOCK))
+ result.clock = value.toInt();
+ return result;
+}
+
+// Compare two AirCon states (climates).
+// Returns: True if they differ, False if they don't.
+bool cmpClimate(const commonAcState_t a, const commonAcState_t b) {
+ return a.protocol != b.protocol || a.model != b.model || a.power != b.power ||
+ a.mode != b.mode || a.degrees != b.degrees || a.celsius != b.celsius ||
+ a.fanspeed != b.fanspeed || a.swingv != b.swingv ||
+ a.swingh != b.swingh || a.quiet != b.quiet || a.turbo != b.turbo ||
+ a.econo != b.econo || a.light != b.light || a.filter != b.filter ||
+ a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep;
+}
+
+bool sendClimate(const commonAcState_t prev, const commonAcState_t next,
+ const String topic_prefix, const bool retain,
+ const bool forceMQTT, const bool forceIR) {
+ bool diff = false;
+ bool success = true;
+
+ if (prev.protocol != next.protocol || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_PROTOCOL,
+ typeToString(next.protocol), retain);
+ }
+ if (prev.model != next.model || forceMQTT) {
+ diff = true;
+ success &= sendInt(topic_prefix + KEY_MODEL, next.model, retain);
+ }
+ if (prev.power != next.power || prev.mode != next.mode || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_POWER, next.power, retain);
+ success &= sendString(topic_prefix + KEY_MODE,
+ (next.power ? opmodeToString(next.mode) : F("off")),
+ retain);
+ }
+ if (prev.degrees != next.degrees || forceMQTT) {
+ diff = true;
+ success &= sendFloat(topic_prefix + KEY_TEMP, next.degrees, retain);
+ }
+ if (prev.celsius != next.celsius || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_CELSIUS, next.celsius, retain);
+ }
+ if (prev.fanspeed != next.fanspeed || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_FANSPEED,
+ fanspeedToString(next.fanspeed), retain);
+ }
+ if (prev.swingv != next.swingv || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_SWINGV,
+ swingvToString(next.swingv), retain);
+ }
+ if (prev.swingh != next.swingh || forceMQTT) {
+ diff = true;
+ success &= sendString(topic_prefix + KEY_SWINGH,
+ swinghToString(next.swingh), retain);
+ }
+ if (prev.quiet != next.quiet || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_QUIET, next.quiet, retain);
+ }
+ if (prev.turbo != next.turbo || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_TURBO, next.turbo, retain);
+ }
+ if (prev.econo != next.econo || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_ECONO, next.econo, retain);
+ }
+ if (prev.light != next.light || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_LIGHT, next.light, retain);
+ }
+ if (prev.filter != next.filter || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_FILTER, next.filter, retain);
+ }
+ if (prev.clean != next.clean || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_CLEAN, next.clean, retain);
+ }
+ if (prev.beep != next.beep || forceMQTT) {
+ diff = true;
+ success &= sendBool(topic_prefix + KEY_BEEP, next.beep, retain);
+ }
+ if (prev.sleep != next.sleep || forceMQTT) {
+ diff = true;
+ success &= sendInt(topic_prefix + KEY_SLEEP, next.sleep, retain);
+ }
+ if (diff && !forceMQTT)
+ debug("Difference in common A/C state detected.");
+ else
+ debug("NO difference in common A/C state detected.");
+ // Only send an IR message if we need to.
+ if ((diff && !forceMQTT) || forceIR) {
+ debug("Sending common A/C state via IR.");
+ lastClimateSucceeded = commonAc.sendAc(
+ next.protocol, next.model, next.power, next.mode,
+ next.degrees, next.celsius, next.fanspeed, next.swingv, next.swingh,
+ next.quiet, next.turbo, next.econo, next.light, next.filter, next.clean,
+ next.beep, next.sleep, -1);
+ if (lastClimateSucceeded) hasClimateBeenSent = true;
+ success &= lastClimateSucceeded;
+ lastClimateIr.reset();
+ irClimateCounter++;
+ sendReqCounter++;
+ }
+ return success;
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRMQTTServer/platformio.ini
similarity index 55%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRMQTTServer/platformio.ini
rename to lib/IRremoteESP8266-2.6.0/examples/IRMQTTServer/platformio.ini
index 27b44ddca5fd..243b36a99fad 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRMQTTServer/platformio.ini
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRMQTTServer/platformio.ini
@@ -3,16 +3,19 @@ lib_extra_dirs = ../../
src_dir=.
[common]
-build_flags = -DMQTT_MAX_PACKET_SIZE=512
+build_flags = -DMQTT_MAX_PACKET_SIZE=768
+lib_ldf_mode = chain+
lib_deps_builtin =
lib_deps_external =
PubSubClient
WifiManager@0.14
+ ArduinoJson
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
@@ -22,7 +25,18 @@ lib_deps =
platform=espressif8266
framework=arduino
board=d1_mini
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
+
+[env:d1_mini_no_mqtt]
+platform=espressif8266
+framework=arduino
+board=d1_mini
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags} -DMQTT_ENABLE=false
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266-2.6.0/examples/IRServer/IRServer.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRServer/IRServer.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRServer/IRServer.ino
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRGCSendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRServer/platformio.ini
similarity index 83%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRGCSendDemo/platformio.ini
rename to lib/IRremoteESP8266-2.6.0/examples/IRServer/platformio.ini
index eeb8d1f2eb93..ec84f22f3b05 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRGCSendDemo/platformio.ini
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRServer/platformio.ini
@@ -6,11 +6,13 @@ src_dir=.
build_flags =
lib_deps_builtin =
lib_deps_external =
+lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/IRrecvDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDemo/IRrecvDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/IRrecvDemo.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/IRrecvDump.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDump/IRrecvDump.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/IRrecvDump.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDump/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDumpV2/IRrecvDumpV2.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino
index d72e0814ce45..2dee0597c17a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRrecvDumpV2/IRrecvDumpV2.ino
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino
@@ -35,9 +35,15 @@
#include
#include
#include
+#include
#include
#include
+#include
+#include
#include
+#include
+#include
+
// ==================== start of TUNEABLE PARAMETERS ====================
// An IR detector/demodulator is connected to GPIO pin 14
@@ -121,6 +127,20 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_DAIKIN
+#if DECODE_DAIKIN2
+ if (results->decode_type == DAIKIN2) {
+ IRDaikin2 ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_DAIKIN2
+#if DECODE_DAIKIN216
+ if (results->decode_type == DAIKIN216) {
+ IRDaikin216 ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_DAIKIN216
#if DECODE_FUJITSU_AC
if (results->decode_type == FUJITSU_AC) {
IRFujitsuAC ac(0);
@@ -142,6 +162,18 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_MITSUBISHI_AC
+#if DECODE_MITSUBISHIHEAVY
+ if (results->decode_type == MITSUBISHI_HEAVY_88) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+ if (results->decode_type == MITSUBISHI_HEAVY_152) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_MITSUBISHIHEAVY
#if DECODE_TOSHIBA_AC
if (results->decode_type == TOSHIBA_AC) {
IRToshibaAC ac(0);
@@ -180,7 +212,7 @@ void dumpACInfo(decode_results *results) {
#if DECODE_SAMSUNG_AC
if (results->decode_type == SAMSUNG_AC) {
IRSamsungAc ac(0);
- ac.setRaw(results->state);
+ ac.setRaw(results->state, results->bits / 8);
description = ac.toString();
}
#endif // DECODE_SAMSUNG_AC
@@ -206,6 +238,34 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_HITACHI_AC
+#if DECODE_WHIRLPOOL_AC
+ if (results->decode_type == WHIRLPOOL_AC) {
+ IRWhirlpoolAc ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_WHIRLPOOL_AC
+#if DECODE_VESTEL_AC
+ if (results->decode_type == VESTEL_AC) {
+ IRVestelAc ac(0);
+ ac.setRaw(results->value); // Like Coolix, use value instead of state.
+ description = ac.toString();
+ }
+#endif // DECODE_VESTEL_AC
+#if DECODE_TECO
+ if (results->decode_type == TECO) {
+ IRTecoAc ac(0);
+ ac.setRaw(results->value); // Like Coolix, use value instead of state.
+ description = ac.toString();
+ }
+#endif // DECODE_TECO
+#if DECODE_TCL112AC
+ if (results->decode_type == TCL112AC) {
+ IRTcl112Ac ac(0);
+ ac.setRaw(results->state);
+ description = ac.toString();
+ }
+#endif // DECODE_TCL112AC
// If we got a human-readable description of the message, display it.
if (description != "") Serial.println("Mesg Desc.: " + description);
}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRrecvDumpV2/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/IRsendDemo.ino
similarity index 85%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRsendDemo/IRsendDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/IRsendDemo.ino
index 892016b3eec1..19f118671e8c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/examples/IRsendDemo/IRsendDemo.ino
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/IRsendDemo.ino
@@ -1,6 +1,6 @@
/* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend.
*
- * Version 1.0 April, 2017
+ * Version 1.1 January, 2019
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009,
* Copyright 2009 Ken Shirriff, http://arcfn.com
*
@@ -46,6 +46,10 @@ uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
650, 1650, 650, 1650, 650, 1650, 600};
+// Example Samsung A/C state captured from IRrecvDumpV2.ino
+uint8_t samsungState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
void setup() {
irsend.begin();
@@ -53,19 +57,16 @@ void setup() {
}
void loop() {
-#if SEND_NEC
Serial.println("NEC");
- irsend.sendNEC(0x00FFE01FUL, 32);
-#endif // SEND_NEC
+ irsend.sendNEC(0x00FFE01FUL);
delay(2000);
-#if SEND_SONY
Serial.println("Sony");
- irsend.sendSony(0xa90, 12, 2);
-#endif // SEND_SONY
+ irsend.sendSony(0xa90, 12, 2); // 12 bits & 2 repeats
delay(2000);
-#if SEND_RAW
Serial.println("a rawData capture from IRrecvDumpV2");
irsend.sendRaw(rawData, 67, 38); // Send a raw data capture at 38kHz.
-#endif // SEND_RAW
+ delay(2000);
+ Serial.println("a Samsung A/C state from IRrecvDumpV2");
+ irsend.sendSamsungAC(samsungState);
delay(2000);
}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRsendDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/IRsendProntoDemo/IRsendProntoDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/IRsendProntoDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
rename to lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/JVCPanasonicSendDemo/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266-2.6.0/examples/LGACSend/LGACSend.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/LGACSend/LGACSend.ino
rename to lib/IRremoteESP8266-2.6.0/examples/LGACSend/LGACSend.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/LGACSend/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/LGACSend/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/TurnOnArgoAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnArgoAC/TurnOnArgoAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/TurnOnArgoAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnArgoAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnDaikinAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnFujitsuAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnKelvinatorAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
new file mode 100644
index 000000000000..2ad2d7bc303a
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
@@ -0,0 +1,72 @@
+/* Copyright 2019 David Conran
+*
+* 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/markszabo/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.
+*/
+#ifndef UNIT_TEST
+#include
+#endif
+#include
+#include
+#include
+
+const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
+IRMitsubishiHeavy152Ac ac(kIrLed); // Set the GPIO used for sending messages.
+
+void printState() {
+ // Display the settings.
+ Serial.println("Mitsubishi Heavy 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 < kMitsubishiHeavy152StateLength; 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_MitsubishiHeavy.(cpp|h) for all the
+ // options.
+ Serial.println("Default state of the remote.");
+ printState();
+ Serial.println("Setting desired state for A/C.");
+ ac.setPower(true); // Turn it on.
+ ac.setFan(kMitsubishiHeavy152FanMed); // Medium Fan
+ ac.setMode(kMitsubishiHeavyCool); // Cool mode
+ ac.setTemp(26); // Celsius
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto); // Swing vertically
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHMiddle); // Swing Horizontally
+}
+
+void loop() {
+ // Now send the IR signal.
+ Serial.println("Sending IR command to A/C ...");
+ ac.send();
+ printState();
+ delay(5000);
+}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
new file mode 100644
index 000000000000..ea39ac5e2b84
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
@@ -0,0 +1,74 @@
+/* Copyright 2017, 2018 David Conran
+*
+* 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/markszabo/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.
+*/
+#ifndef UNIT_TEST
+#include
+#endif
+#include
+#include
+#include
+
+const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
+IRPanasonicAc ac(kIrLed); // Set the GPIO used for sending messages.
+
+void printState() {
+ // Display the settings.
+ Serial.println("Panasonic 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 < kPanasonicAcStateLength; 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_Panasonic.cpp for all the options.
+ Serial.println("Default state of the remote.");
+ printState();
+ Serial.println("Setting desired state for A/C.");
+ ac.setModel(kPanasonicRkr);
+ ac.on();
+ ac.setFan(kPanasonicAcFanAuto);
+ ac.setMode(kPanasonicAcCool);
+ ac.setTemp(26);
+ ac.setSwingVertical(kPanasonicAcSwingVAuto);
+ ac.setSwingHorizontal(kPanasonicAcSwingHAuto);
+}
+
+void loop() {
+ // Now send the IR signal.
+#if SEND_PANASONIC_AC
+ Serial.println("Sending IR command to A/C ...");
+ ac.send();
+#endif // SEND_PANASONIC_AC
+ printState();
+ delay(5000);
+}
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnPanasonicAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnToshibaAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
rename to lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino
diff --git a/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/platformio.ini
new file mode 100644
index 000000000000..ec84f22f3b05
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/examples/TurnOnTrotecAC/platformio.ini
@@ -0,0 +1,19 @@
+[platformio]
+lib_extra_dirs = ../../
+src_dir=.
+
+[common]
+build_flags =
+lib_deps_builtin =
+lib_deps_external =
+lib_ldf_mode = chain+
+
+[env:nodemcuv2]
+platform = espressif8266
+framework = arduino
+board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
+build_flags = ${common.build_flags}
+lib_deps =
+ ${common.lib_deps_builtin}
+ ${common.lib_deps_external}
diff --git a/lib/IRremoteESP8266-2.5.2.03/keywords.txt b/lib/IRremoteESP8266-2.6.0/keywords.txt
similarity index 74%
rename from lib/IRremoteESP8266-2.5.2.03/keywords.txt
rename to lib/IRremoteESP8266-2.6.0/keywords.txt
index ac3f43fe1809..a498c5d61cae 100644
--- a/lib/IRremoteESP8266-2.5.2.03/keywords.txt
+++ b/lib/IRremoteESP8266-2.6.0/keywords.txt
@@ -22,21 +22,32 @@
IRArgoAC KEYWORD1
IRCoolixAC KEYWORD1
+IRDaikin2 KEYWORD1
+IRDaikin216 KEYWORD1
IRDaikinESP KEYWORD1
IRFujitsuAC KEYWORD1
IRGreeAC KEYWORD1
IRHaierAC KEYWORD1
IRHaierACYRW02 KEYWORD1
+IRHitachiAc KEYWORD1
IRKelvinatorAC KEYWORD1
IRMideaAC KEYWORD1
IRMitsubishiAC KEYWORD1
+IRMitsubishiHeavy152Ac KEYWORD1
+IRMitsubishiHeavy88Ac KEYWORD1
IRPanasonicAc KEYWORD1
IRSamsungAc KEYWORD1
+IRTcl112Ac KEYWORD1
+IRTecoAc KEYWORD1
IRToshibaAC KEYWORD1
IRTrotecESP KEYWORD1
+IRVestelAc KEYWORD1
+IRWhirlpoolAc KEYWORD1
+IRac KEYWORD1
IRrecv KEYWORD1
IRsend KEYWORD1
IRtimer KEYWORD1
+TimerMs KEYWORD1
decode_results KEYWORD1
ir_params_t KEYWORD1
match_result_t KEYWORD1
@@ -46,8 +57,10 @@ match_result_t KEYWORD1
#######################################
_delayMicroseconds KEYWORD2
+_setMode KEYWORD2
+_setTemp KEYWORD2
add KEYWORD2
-addbit KEYWORD2
+argo KEYWORD2
begin KEYWORD2
buildFromState KEYWORD2
buildState KEYWORD2
@@ -60,18 +73,27 @@ calibrate KEYWORD2
cancelOffTimer KEYWORD2
cancelOnTimer KEYWORD2
cancelTimers KEYWORD2
-checkheader KEYWORD2
+checkZjsSig KEYWORD2
+checkZmsSig KEYWORD2
checksum KEYWORD2
-clearBit KEYWORD2
+clearOnTimerFlag KEYWORD2
clearSensorTemp KEYWORD2
+clearSleepTimerFlag KEYWORD2
compare KEYWORD2
+coolix KEYWORD2
copyIrParams KEYWORD2
+countBits KEYWORD2
+daikin KEYWORD2
+daikin2 KEYWORD2
+daikin216 KEYWORD2
decode KEYWORD2
decodeAiwaRCT501 KEYWORD2
decodeCOOLIX KEYWORD2
decodeCarrierAC KEYWORD2
decodeDISH KEYWORD2
decodeDaikin KEYWORD2
+decodeDaikin2 KEYWORD2
+decodeDaikin216 KEYWORD2
decodeDenon KEYWORD2
decodeElectraAC KEYWORD2
decodeFujitsuAC KEYWORD2
@@ -85,6 +107,7 @@ decodeJVC KEYWORD2
decodeKelvinator KEYWORD2
decodeLG KEYWORD2
decodeLasertag KEYWORD2
+decodeLegoPf KEYWORD2
decodeLutron KEYWORD2
decodeMWM KEYWORD2
decodeMagiQuest KEYWORD2
@@ -92,6 +115,7 @@ decodeMidea KEYWORD2
decodeMitsubishi KEYWORD2
decodeMitsubishi2 KEYWORD2
decodeMitsubishiAC KEYWORD2
+decodeMitsubishiHeavy KEYWORD2
decodeNEC KEYWORD2
decodeNikai KEYWORD2
decodePanasonic KEYWORD2
@@ -101,22 +125,29 @@ decodeRC5 KEYWORD2
decodeRC6 KEYWORD2
decodeRCMM KEYWORD2
decodeSAMSUNG KEYWORD2
+decodeSamsung36 KEYWORD2
decodeSamsungAC KEYWORD2
decodeSanyo KEYWORD2
decodeSanyoLC7461 KEYWORD2
decodeSharp KEYWORD2
decodeSony KEYWORD2
+decodeTcl112Ac KEYWORD2
+decodeTeco KEYWORD2
decodeToshibaAC KEYWORD2
+decodeVestelAc KEYWORD2
decodeWhirlpoolAC KEYWORD2
decodeWhynter KEYWORD2
disableIRIn KEYWORD2
disableOffTimer KEYWORD2
disableOnTimer KEYWORD2
+disableSleepTimer KEYWORD2
elapsed KEYWORD2
enableIRIn KEYWORD2
enableIROut KEYWORD2
enableOffTimer KEYWORD2
enableOnTimer KEYWORD2
+enableSleepTimer KEYWORD2
+enableTimer KEYWORD2
encodeJVC KEYWORD2
encodeLG KEYWORD2
encodeMagiQuest KEYWORD2
@@ -131,15 +162,18 @@ encodeSanyoLC7461 KEYWORD2
encodeSharp KEYWORD2
encodeSony KEYWORD2
encodeTime KEYWORD2
+fanspeed_t KEYWORD2
fixChecksum KEYWORD2
fixup KEYWORD2
+fujitsu KEYWORD2
+get3D KEYWORD2
getBeep KEYWORD2
-getBit KEYWORD2
getBufSize KEYWORD2
getButton KEYWORD2
getClean KEYWORD2
getClock KEYWORD2
getCmd KEYWORD2
+getComfort KEYWORD2
getCommand KEYWORD2
getCoolMode KEYWORD2
getCorrectedRawLength KEYWORD2
@@ -147,11 +181,16 @@ getCurrTime KEYWORD2
getCurrentTime KEYWORD2
getEcono KEYWORD2
getEye KEYWORD2
+getEyeAuto KEYWORD2
getFan KEYWORD2
getFanSpeed KEYWORD2
+getFilter KEYWORD2
getFlap KEYWORD2
+getFreshAir KEYWORD2
+getFreshAirHigh KEYWORD2
getHealth KEYWORD2
getHeatMode KEYWORD2
+getIon KEYWORD2
getIonFilter KEYWORD2
getLed KEYWORD2
getLight KEYWORD2
@@ -159,6 +198,7 @@ getMax KEYWORD2
getMode KEYWORD2
getMold KEYWORD2
getNight KEYWORD2
+getNormalState KEYWORD2
getOffTime KEYWORD2
getOffTimer KEYWORD2
getOffTimerEnabled KEYWORD2
@@ -166,23 +206,30 @@ getOnTime KEYWORD2
getOnTimer KEYWORD2
getOnTimerEnabled KEYWORD2
getPower KEYWORD2
+getPowerToggle KEYWORD2
getPowerful KEYWORD2
+getPurify KEYWORD2
getQuiet KEYWORD2
getRClevel KEYWORD2
getRaw KEYWORD2
getSensor KEYWORD2
getSensorTemp KEYWORD2
+getSilent KEYWORD2
getSleep KEYWORD2
+getSleepTime KEYWORD2
+getSleepTimerEnabled KEYWORD2
getSpeed KEYWORD2
getStartClock KEYWORD2
getStateLength KEYWORD2
getStopClock KEYWORD2
+getSuper KEYWORD2
getSwing KEYWORD2
getSwingHorizontal KEYWORD2
getSwingVertical KEYWORD2
getSwingVerticalAuto KEYWORD2
getSwingVerticalPosition KEYWORD2
getTemp KEYWORD2
+getTempOffset KEYWORD2
getTempRaw KEYWORD2
getTime KEYWORD2
getTimer KEYWORD2
@@ -191,10 +238,23 @@ getVane KEYWORD2
getXFan KEYWORD2
getZoneFollow KEYWORD2
getiFeel KEYWORD2
+gree KEYWORD2
+haier KEYWORD2
+haierYrwo2 KEYWORD2
hasACState KEYWORD2
+hitachi KEYWORD2
+htmlEscape KEYWORD2
invertBits KEYWORD2
+isOffTimerActive KEYWORD2
isOffTimerEnabled KEYWORD2
+isOnTimerActive KEYWORD2
isOnTimerEnabled KEYWORD2
+isProtocolSupported KEYWORD2
+isSpecialState KEYWORD2
+isTimeCommand KEYWORD2
+isTimerActive KEYWORD2
+isTimerEnabled KEYWORD2
+kelvinator KEYWORD2
ledOff KEYWORD2
ledOn KEYWORD2
mark KEYWORD2
@@ -203,10 +263,17 @@ matchAtLeast KEYWORD2
matchData KEYWORD2
matchMark KEYWORD2
matchSpace KEYWORD2
+midea KEYWORD2
+mitsubishi KEYWORD2
+mitsubishiHeavy152 KEYWORD2
+mitsubishiHeavy88 KEYWORD2
+mode) KEYWORD2
off KEYWORD2
on KEYWORD2
-printState KEYWORD2
-readbits KEYWORD2
+opmode_t KEYWORD2
+panasonic KEYWORD2
+position) KEYWORD2
+recoverSavedState KEYWORD2
renderTime KEYWORD2
reset KEYWORD2
resultToHexidecimal KEYWORD2
@@ -215,13 +282,17 @@ resultToSourceCode KEYWORD2
resultToTimingInfo KEYWORD2
resume KEYWORD2
reverseBits KEYWORD2
+samsung KEYWORD2
send KEYWORD2
+sendAc KEYWORD2
sendAiwaRCT501 KEYWORD2
sendArgo KEYWORD2
sendCOOLIX KEYWORD2
sendCarrierAC KEYWORD2
sendDISH KEYWORD2
sendDaikin KEYWORD2
+sendDaikin2 KEYWORD2
+sendDaikin216 KEYWORD2
sendData KEYWORD2
sendDenon KEYWORD2
sendElectraAC KEYWORD2
@@ -241,6 +312,7 @@ sendKelvinator KEYWORD2
sendLG KEYWORD2
sendLG2 KEYWORD2
sendLasertag KEYWORD2
+sendLegoPf KEYWORD2
sendLutron KEYWORD2
sendMWM KEYWORD2
sendMagiQuest KEYWORD2
@@ -248,8 +320,12 @@ sendMidea KEYWORD2
sendMitsubishi KEYWORD2
sendMitsubishi2 KEYWORD2
sendMitsubishiAC KEYWORD2
+sendMitsubishiHeavy152 KEYWORD2
+sendMitsubishiHeavy88 KEYWORD2
sendNEC KEYWORD2
sendNikai KEYWORD2
+sendOff KEYWORD2
+sendOn KEYWORD2
sendPanasonic KEYWORD2
sendPanasonic64 KEYWORD2
sendPanasonicAC KEYWORD2
@@ -260,34 +336,45 @@ sendRC6 KEYWORD2
sendRCMM KEYWORD2
sendRaw KEYWORD2
sendSAMSUNG KEYWORD2
+sendSamsung36 KEYWORD2
sendSamsungAC KEYWORD2
sendSanyoLC7461 KEYWORD2
sendSharp KEYWORD2
sendSharpRaw KEYWORD2
sendSherwood KEYWORD2
sendSony KEYWORD2
+sendTcl112Ac KEYWORD2
+sendTeco KEYWORD2
sendToshibaAC KEYWORD2
sendTrotec KEYWORD2
+sendVestelAc KEYWORD2
sendWhirlpoolAC KEYWORD2
sendWhynter KEYWORD2
serialPrintUint64 KEYWORD2
+set3D KEYWORD2
+setAuto KEYWORD2
setBeep KEYWORD2
-setBit KEYWORD2
setButton KEYWORD2
setClean KEYWORD2
setClock KEYWORD2
setCmd KEYWORD2
+setComfort KEYWORD2
setCommand KEYWORD2
setCoolMode KEYWORD2
setCurrTime KEYWORD2
setCurrentTime KEYWORD2
setEcono KEYWORD2
setEye KEYWORD2
+setEyeAuto KEYWORD2
setFan KEYWORD2
setFanSpeed KEYWORD2
+setFilter KEYWORD2
setFlap KEYWORD2
+setFreshAir KEYWORD2
+setFreshAirHigh KEYWORD2
setHealth KEYWORD2
setHeatMode KEYWORD2
+setIon KEYWORD2
setIonFilter KEYWORD2
setLed KEYWORD2
setLight KEYWORD2
@@ -297,19 +384,25 @@ setModel KEYWORD2
setMold KEYWORD2
setNight KEYWORD2
setOffTimer KEYWORD2
+setOffTimerActive KEYWORD2
setOnTimer KEYWORD2
+setOnTimerActive KEYWORD2
setPower KEYWORD2
+setPowerToggle KEYWORD2
setPowerful KEYWORD2
+setPurify KEYWORD2
setQuiet KEYWORD2
setRaw KEYWORD2
setRoomTemp KEYWORD2
setSensor KEYWORD2
setSensorTemp KEYWORD2
setSensorTempRaw KEYWORD2
+setSilent KEYWORD2
setSleep KEYWORD2
setSpeed KEYWORD2
setStartClock KEYWORD2
setStopClock KEYWORD2
+setSuper KEYWORD2
setSwing KEYWORD2
setSwingHorizontal KEYWORD2
setSwingVertical KEYWORD2
@@ -317,6 +410,7 @@ setTemp KEYWORD2
setTempRaw KEYWORD2
setTime KEYWORD2
setTimer KEYWORD2
+setTimerActive KEYWORD2
setTurbo KEYWORD2
setUnknownThreshold KEYWORD2
setVane KEYWORD2
@@ -324,19 +418,33 @@ setXFan KEYWORD2
setZoneFollow KEYWORD2
setiFeel KEYWORD2
space KEYWORD2
+speed) KEYWORD2
stateReset KEYWORD2
stepHoriz KEYWORD2
stepVert KEYWORD2
+strToBool KEYWORD2
+strToModel KEYWORD2
sumBytes KEYWORD2
+swingh_t KEYWORD2
+swingv) KEYWORD2
+swingv_t KEYWORD2
+tcl112 KEYWORD2
+teco KEYWORD2
ticksHigh KEYWORD2
ticksLow KEYWORD2
timeToString KEYWORD2
toString KEYWORD2
toggleRC5 KEYWORD2
toggleRC6 KEYWORD2
+toshiba KEYWORD2
+trotec KEYWORD2
typeToString KEYWORD2
uint64ToString KEYWORD2
+updateSavedState KEYWORD2
validChecksum KEYWORD2
+vestel KEYWORD2
+whirlpool KEYWORD2
+xorBytes KEYWORD2
#######################################
# Constants (LITERAL1)
@@ -349,9 +457,9 @@ ARDB1 LITERAL1
ARGO LITERAL1
ARGO_COMMAND_LENGTH LITERAL1
ARGO_COOL_AUTO LITERAL1
+ARGO_COOL_HUM LITERAL1
ARGO_COOL_OFF LITERAL1
ARGO_COOL_ON LITERAL1
-ARGO_COOl_HUM LITERAL1
ARGO_FAN_1 LITERAL1
ARGO_FAN_2 LITERAL1
ARGO_FAN_3 LITERAL1
@@ -375,10 +483,11 @@ CARRIER_AC_BITS LITERAL1
COOLIX LITERAL1
COOLIX_BITS LITERAL1
DAIKIN LITERAL1
+DAIKIN2 LITERAL1
+DAIKIN216 LITERAL1
DAIKIN_AUTO LITERAL1
DAIKIN_COMMAND_LENGTH LITERAL1
DAIKIN_COOL LITERAL1
-DAIKIN_DEBUG LITERAL1
DAIKIN_DRY LITERAL1
DAIKIN_FAN LITERAL1
DAIKIN_FAN_AUTO LITERAL1
@@ -394,6 +503,8 @@ DECODE_ARGO LITERAL1
DECODE_CARRIER_AC LITERAL1
DECODE_COOLIX LITERAL1
DECODE_DAIKIN LITERAL1
+DECODE_DAIKIN2 LITERAL1
+DECODE_DAIKIN216 LITERAL1
DECODE_DENON LITERAL1
DECODE_DISH LITERAL1
DECODE_ELECTRA_AC LITERAL1
@@ -410,12 +521,14 @@ DECODE_HITACHI_AC2 LITERAL1
DECODE_JVC LITERAL1
DECODE_KELVINATOR LITERAL1
DECODE_LASERTAG LITERAL1
+DECODE_LEGOPF LITERAL1
DECODE_LG LITERAL1
DECODE_LUTRON LITERAL1
DECODE_MAGIQUEST LITERAL1
DECODE_MIDEA LITERAL1
DECODE_MITSUBISHI LITERAL1
DECODE_MITSUBISHI2 LITERAL1
+DECODE_MITSUBISHIHEAVY LITERAL1
DECODE_MITSUBISHI_AC LITERAL1
DECODE_MWM LITERAL1
DECODE_NEC LITERAL1
@@ -428,19 +541,25 @@ DECODE_RC5 LITERAL1
DECODE_RC6 LITERAL1
DECODE_RCMM LITERAL1
DECODE_SAMSUNG LITERAL1
+DECODE_SAMSUNG36 LITERAL1
DECODE_SAMSUNG_AC LITERAL1
DECODE_SANYO LITERAL1
DECODE_SHARP LITERAL1
DECODE_SHERWOOD LITERAL1
DECODE_SONY LITERAL1
+DECODE_TCL112AC LITERAL1
+DECODE_TECO LITERAL1
DECODE_TOSHIBA_AC LITERAL1
DECODE_TROTEC LITERAL1
+DECODE_VESTEL_AC LITERAL1
DECODE_WHIRLPOOL_AC LITERAL1
DECODE_WHYNTER LITERAL1
DENON LITERAL1
DENON_48_BITS LITERAL1
DENON_BITS LITERAL1
DENON_LEGACY_BITS LITERAL1
+DG11J13A LITERAL1
+DG11J191 LITERAL1
DISH LITERAL1
DISH_BITS LITERAL1
ELECTRA_AC LITERAL1
@@ -580,6 +699,7 @@ KELVINATOR_MIN_TEMP LITERAL1
KELVINATOR_STATE_LENGTH LITERAL1
LASERTAG LITERAL1
LASERTAG_BITS LITERAL1
+LEGOPF LITERAL1
LG LITERAL1
LG2 LITERAL1
LG32_BITS LITERAL1
@@ -623,6 +743,8 @@ MITSUBISHI_AC_STATE_LENGTH LITERAL1
MITSUBISHI_AC_VANE_AUTO LITERAL1
MITSUBISHI_AC_VANE_AUTO_MOVE LITERAL1
MITSUBISHI_BITS LITERAL1
+MITSUBISHI_HEAVY_152 LITERAL1
+MITSUBISHI_HEAVY_88 LITERAL1
MWM LITERAL1
NEC LITERAL1
NEC_BITS LITERAL1
@@ -647,6 +769,7 @@ RC6_MODE0_BITS LITERAL1
RCMM LITERAL1
RCMM_BITS LITERAL1
SAMSUNG LITERAL1
+SAMSUNG36 LITERAL1
SAMSUNG_AC LITERAL1
SAMSUNG_BITS LITERAL1
SANYO LITERAL1
@@ -658,6 +781,8 @@ SEND_ARGO LITERAL1
SEND_CARRIER_AC LITERAL1
SEND_COOLIX LITERAL1
SEND_DAIKIN LITERAL1
+SEND_DAIKIN2 LITERAL1
+SEND_DAIKIN216 LITERAL1
SEND_DENON LITERAL1
SEND_DISH LITERAL1
SEND_ELECTRA_AC LITERAL1
@@ -673,12 +798,14 @@ SEND_HITACHI_AC2 LITERAL1
SEND_JVC LITERAL1
SEND_KELVINATOR LITERAL1
SEND_LASERTAG LITERAL1
+SEND_LEGOPF LITERAL1
SEND_LG LITERAL1
SEND_LUTRON LITERAL1
SEND_MAGIQUEST LITERAL1
SEND_MIDEA LITERAL1
SEND_MITSUBISHI LITERAL1
SEND_MITSUBISHI2 LITERAL1
+SEND_MITSUBISHIHEAVY LITERAL1
SEND_MITSUBISHI_AC LITERAL1
SEND_MWM LITERAL1
SEND_NEC LITERAL1
@@ -692,13 +819,17 @@ SEND_RC5 LITERAL1
SEND_RC6 LITERAL1
SEND_RCMM LITERAL1
SEND_SAMSUNG LITERAL1
+SEND_SAMSUNG36 LITERAL1
SEND_SAMSUNG_AC LITERAL1
SEND_SANYO LITERAL1
SEND_SHARP LITERAL1
SEND_SHERWOOD LITERAL1
SEND_SONY LITERAL1
+SEND_TCL112AC LITERAL1
+SEND_TECO LITERAL1
SEND_TOSHIBA_AC LITERAL1
SEND_TROTEC LITERAL1
+SEND_VESTEL_AC LITERAL1
SEND_WHIRLPOOL_AC LITERAL1
SEND_WHYNTER LITERAL1
SHARP LITERAL1
@@ -709,6 +840,8 @@ SONY LITERAL1
SONY_12_BITS LITERAL1
SONY_15_BITS LITERAL1
SONY_20_BITS LITERAL1
+TCL112AC LITERAL1
+TECO LITERAL1
TIMEOUT_MS LITERAL1
TOSHIBA_AC LITERAL1
TOSHIBA_AC_AUTO LITERAL1
@@ -733,9 +866,9 @@ TROTEC_FAN_MED LITERAL1
TROTEC_MAX_TEMP LITERAL1
TROTEC_MAX_TIMER LITERAL1
TROTEC_MIN_TEMP LITERAL1
-TROTEC_MIN_TIMER LITERAL1
UNKNOWN LITERAL1
UNUSED LITERAL1
+VESTEL_AC LITERAL1
WHIRLPOOL_AC LITERAL1
WHYNTER LITERAL1
WHYNTER_BITS LITERAL1
@@ -750,6 +883,7 @@ kArgoCoolAuto LITERAL1
kArgoCoolHum LITERAL1
kArgoCoolOff LITERAL1
kArgoCoolOn LITERAL1
+kArgoDefaultRepeat LITERAL1
kArgoFan1 LITERAL1
kArgoFan2 LITERAL1
kArgoFan3 LITERAL1
@@ -772,6 +906,7 @@ kArgoMinTemp LITERAL1
kArgoOneSpace LITERAL1
kArgoStateLength LITERAL1
kArgoZeroSpace LITERAL1
+kAuto LITERAL1
kCarrierAcBitMark LITERAL1
kCarrierAcBits LITERAL1
kCarrierAcGap LITERAL1
@@ -780,16 +915,19 @@ kCarrierAcHdrSpace LITERAL1
kCarrierAcMinRepeat LITERAL1
kCarrierAcOneSpace LITERAL1
kCarrierAcZeroSpace LITERAL1
+kCool LITERAL1
kCoolixAuto LITERAL1
kCoolixBitMark LITERAL1
kCoolixBitMarkTicks LITERAL1
kCoolixBits LITERAL1
kCoolixClean LITERAL1
kCoolixCool LITERAL1
+kCoolixDefaultRepeat LITERAL1
kCoolixDefaultState LITERAL1
kCoolixDry LITERAL1
kCoolixFan LITERAL1
kCoolixFanAuto LITERAL1
+kCoolixFanAuto0 LITERAL1
kCoolixFanFixed LITERAL1
kCoolixFanMask LITERAL1
kCoolixFanMax LITERAL1
@@ -827,7 +965,70 @@ kCoolixUnknown LITERAL1
kCoolixZeroSpace LITERAL1
kCoolixZeroSpaceTicks LITERAL1
kCoolixZoneFollowMask LITERAL1
+kDaikin216BitMark LITERAL1
+kDaikin216Bits LITERAL1
+kDaikin216ByteFan LITERAL1
+kDaikin216ByteMode LITERAL1
+kDaikin216BytePower LITERAL1
+kDaikin216ByteSwingH LITERAL1
+kDaikin216ByteSwingV LITERAL1
+kDaikin216ByteTemp LITERAL1
+kDaikin216DefaultRepeat LITERAL1
+kDaikin216Freq LITERAL1
+kDaikin216Gap LITERAL1
+kDaikin216HdrMark LITERAL1
+kDaikin216HdrSpace LITERAL1
+kDaikin216MaskFan LITERAL1
+kDaikin216MaskMode LITERAL1
+kDaikin216MaskSwingH LITERAL1
+kDaikin216MaskSwingV LITERAL1
+kDaikin216MaskTemp LITERAL1
+kDaikin216OneSpace LITERAL1
+kDaikin216Section1Length LITERAL1
+kDaikin216Section2Length LITERAL1
+kDaikin216Sections LITERAL1
+kDaikin216StateLength LITERAL1
+kDaikin216ZeroSpace LITERAL1
+kDaikin2BeepMask LITERAL1
+kDaikin2BitClean LITERAL1
+kDaikin2BitEye LITERAL1
+kDaikin2BitEyeAuto LITERAL1
+kDaikin2BitFreshAir LITERAL1
+kDaikin2BitFreshAirHigh LITERAL1
+kDaikin2BitMark LITERAL1
+kDaikin2BitMold LITERAL1
+kDaikin2BitPower LITERAL1
+kDaikin2BitPurify LITERAL1
+kDaikin2BitSleepTimer LITERAL1
+kDaikin2Bits LITERAL1
+kDaikin2DefaultRepeat LITERAL1
+kDaikin2Freq LITERAL1
+kDaikin2Gap LITERAL1
+kDaikin2HdrMark LITERAL1
+kDaikin2HdrSpace LITERAL1
+kDaikin2LeaderMark LITERAL1
+kDaikin2LeaderSpace LITERAL1
+kDaikin2LightMask LITERAL1
+kDaikin2MinCoolTemp LITERAL1
+kDaikin2OneSpace LITERAL1
+kDaikin2Section1Length LITERAL1
+kDaikin2Section2Length LITERAL1
+kDaikin2Sections LITERAL1
+kDaikin2StateLength LITERAL1
+kDaikin2SwingHAuto LITERAL1
+kDaikin2SwingHSwing LITERAL1
+kDaikin2SwingVAuto LITERAL1
+kDaikin2SwingVBreeze LITERAL1
+kDaikin2SwingVCirculate LITERAL1
+kDaikin2SwingVHigh LITERAL1
+kDaikin2SwingVLow LITERAL1
+kDaikin2Tolerance LITERAL1
+kDaikin2ZeroSpace LITERAL1
kDaikinAuto LITERAL1
+kDaikinBeepLoud LITERAL1
+kDaikinBeepOff LITERAL1
+kDaikinBeepQuiet LITERAL1
+kDaikinBitComfort LITERAL1
kDaikinBitEcono LITERAL1
kDaikinBitEye LITERAL1
kDaikinBitMark LITERAL1
@@ -839,18 +1040,33 @@ kDaikinBitPowerful LITERAL1
kDaikinBitSensor LITERAL1
kDaikinBitSilent LITERAL1
kDaikinBits LITERAL1
+kDaikinBitsShort LITERAL1
+kDaikinByteChecksum1 LITERAL1
+kDaikinByteChecksum2 LITERAL1
+kDaikinByteChecksum3 LITERAL1
+kDaikinByteClockMinsHigh LITERAL1
+kDaikinByteClockMinsLow LITERAL1
+kDaikinByteComfort LITERAL1
kDaikinByteEcono LITERAL1
kDaikinByteEye LITERAL1
+kDaikinByteFan LITERAL1
kDaikinByteMold LITERAL1
kDaikinByteOffTimer LITERAL1
+kDaikinByteOffTimerMinsHigh LITERAL1
+kDaikinByteOffTimerMinsLow LITERAL1
kDaikinByteOnTimer LITERAL1
+kDaikinByteOnTimerMinsHigh LITERAL1
+kDaikinByteOnTimerMinsLow LITERAL1
kDaikinBytePower LITERAL1
kDaikinBytePowerful LITERAL1
kDaikinByteSensor LITERAL1
kDaikinByteSilent LITERAL1
+kDaikinByteSwingH LITERAL1
+kDaikinByteTemp LITERAL1
kDaikinCool LITERAL1
kDaikinCurBit LITERAL1
kDaikinCurIndex LITERAL1
+kDaikinDefaultRepeat LITERAL1
kDaikinDry LITERAL1
kDaikinFan LITERAL1
kDaikinFanAuto LITERAL1
@@ -861,15 +1077,25 @@ kDaikinFirstHeader64 LITERAL1
kDaikinGap LITERAL1
kDaikinHdrMark LITERAL1
kDaikinHdrSpace LITERAL1
+kDaikinHeaderLength LITERAL1
kDaikinHeat LITERAL1
+kDaikinLightBright LITERAL1
+kDaikinLightDim LITERAL1
+kDaikinLightOff LITERAL1
kDaikinMarkExcess LITERAL1
kDaikinMaxTemp LITERAL1
kDaikinMinTemp LITERAL1
kDaikinOneSpace LITERAL1
-kDaikinRawBits LITERAL1
+kDaikinSection1Length LITERAL1
+kDaikinSection2Length LITERAL1
+kDaikinSection3Length LITERAL1
+kDaikinSections LITERAL1
kDaikinStateLength LITERAL1
+kDaikinStateLengthShort LITERAL1
kDaikinTolerance LITERAL1
+kDaikinUnusedTime LITERAL1
kDaikinZeroSpace LITERAL1
+kDefaultMessageGap LITERAL1
kDenonBitMark LITERAL1
kDenonBitMarkTicks LITERAL1
kDenonBits LITERAL1
@@ -902,6 +1128,7 @@ kDishRptSpaceTicks LITERAL1
kDishTick LITERAL1
kDishZeroSpace LITERAL1
kDishZeroSpaceTicks LITERAL1
+kDry LITERAL1
kDutyDefault LITERAL1
kDutyMax LITERAL1
kElectraAcBitMark LITERAL1
@@ -912,6 +1139,7 @@ kElectraAcMessageGap LITERAL1
kElectraAcOneSpace LITERAL1
kElectraAcStateLength LITERAL1
kElectraAcZeroSpace LITERAL1
+kFan LITERAL1
kFnvBasis32 LITERAL1
kFnvPrime32 LITERAL1
kFooter LITERAL1
@@ -969,10 +1197,13 @@ kGreeBits LITERAL1
kGreeBlockFooter LITERAL1
kGreeBlockFooterBits LITERAL1
kGreeCool LITERAL1
+kGreeDefaultRepeat LITERAL1
kGreeDry LITERAL1
kGreeFan LITERAL1
+kGreeFanAuto LITERAL1
kGreeFanMask LITERAL1
kGreeFanMax LITERAL1
+kGreeFanMin LITERAL1
kGreeHdrMark LITERAL1
kGreeHdrSpace LITERAL1
kGreeHeat LITERAL1
@@ -1020,6 +1251,7 @@ kHaierAcCmdTimerCancel LITERAL1
kHaierAcCmdTimerSet LITERAL1
kHaierAcCool LITERAL1
kHaierAcDefTemp LITERAL1
+kHaierAcDefaultRepeat LITERAL1
kHaierAcDry LITERAL1
kHaierAcFan LITERAL1
kHaierAcFanAuto LITERAL1
@@ -1050,6 +1282,7 @@ kHaierAcYrw02ButtonTempDown LITERAL1
kHaierAcYrw02ButtonTempUp LITERAL1
kHaierAcYrw02ButtonTurbo LITERAL1
kHaierAcYrw02Cool LITERAL1
+kHaierAcYrw02DefaultRepeat LITERAL1
kHaierAcYrw02Dry LITERAL1
kHaierAcYrw02Fan LITERAL1
kHaierAcYrw02FanAuto LITERAL1
@@ -1071,17 +1304,32 @@ kHaierAcYrw02TurboLow LITERAL1
kHaierAcYrw02TurboOff LITERAL1
kHaierAcZeroSpace LITERAL1
kHeader LITERAL1
+kHeat LITERAL1
+kHigh LITERAL1
+kHighest LITERAL1
kHitachiAc1Bits LITERAL1
kHitachiAc1HdrMark LITERAL1
kHitachiAc1HdrSpace LITERAL1
kHitachiAc1StateLength LITERAL1
kHitachiAc2Bits LITERAL1
kHitachiAc2StateLength LITERAL1
+kHitachiAcAuto LITERAL1
+kHitachiAcAutoTemp LITERAL1
kHitachiAcBitMark LITERAL1
kHitachiAcBits LITERAL1
+kHitachiAcCool LITERAL1
+kHitachiAcDefaultRepeat LITERAL1
+kHitachiAcDry LITERAL1
+kHitachiAcFan LITERAL1
+kHitachiAcFanAuto LITERAL1
+kHitachiAcFanHigh LITERAL1
+kHitachiAcFanLow LITERAL1
kHitachiAcHdrMark LITERAL1
kHitachiAcHdrSpace LITERAL1
+kHitachiAcHeat LITERAL1
+kHitachiAcMaxTemp LITERAL1
kHitachiAcMinGap LITERAL1
+kHitachiAcMinTemp LITERAL1
kHitachiAcOneSpace LITERAL1
kHitachiAcStateLength LITERAL1
kHitachiAcZeroSpace LITERAL1
@@ -1113,6 +1361,7 @@ kKelvinatorChecksumStart LITERAL1
kKelvinatorCmdFooter LITERAL1
kKelvinatorCmdFooterBits LITERAL1
kKelvinatorCool LITERAL1
+kKelvinatorDefaultRepeat LITERAL1
kKelvinatorDry LITERAL1
kKelvinatorFan LITERAL1
kKelvinatorFanAuto LITERAL1
@@ -1159,6 +1408,16 @@ kLasertagMinRepeat LITERAL1
kLasertagMinSamples LITERAL1
kLasertagTick LITERAL1
kLasertagTolerance LITERAL1
+kLastDecodeType LITERAL1
+kLeft LITERAL1
+kLeftMax LITERAL1
+kLegoPfBitMark LITERAL1
+kLegoPfBits LITERAL1
+kLegoPfHdrSpace LITERAL1
+kLegoPfMinCommandLength LITERAL1
+kLegoPfMinRepeat LITERAL1
+kLegoPfOneSpace LITERAL1
+kLegoPfZeroSpace LITERAL1
kLg2BitMark LITERAL1
kLg2BitMarkTicks LITERAL1
kLg2HdrMark LITERAL1
@@ -1190,6 +1449,8 @@ kLgRptSpaceTicks LITERAL1
kLgTick LITERAL1
kLgZeroSpace LITERAL1
kLgZeroSpaceTicks LITERAL1
+kLow LITERAL1
+kLowest LITERAL1
kLutronBits LITERAL1
kLutronDelta LITERAL1
kLutronGap LITERAL1
@@ -1213,8 +1474,11 @@ kMagiquestBits LITERAL1
kMark LITERAL1
kMarkExcess LITERAL1
kMarkState LITERAL1
+kMax LITERAL1
kMaxAccurateUsecDelay LITERAL1
kMaxTimeoutMs LITERAL1
+kMedium LITERAL1
+kMiddle LITERAL1
kMideaACAuto LITERAL1
kMideaACChecksumMask LITERAL1
kMideaACCool LITERAL1
@@ -1251,6 +1515,7 @@ kMideaTick LITERAL1
kMideaTolerance LITERAL1
kMideaZeroSpace LITERAL1
kMideaZeroSpaceTicks LITERAL1
+kMin LITERAL1
kMitsubishi2BitMark LITERAL1
kMitsubishi2HdrMark LITERAL1
kMitsubishi2HdrSpace LITERAL1
@@ -1287,6 +1552,91 @@ kMitsubishiAcZeroSpace LITERAL1
kMitsubishiBitMark LITERAL1
kMitsubishiBitMarkTicks LITERAL1
kMitsubishiBits LITERAL1
+kMitsubishiHeavy152Bits LITERAL1
+kMitsubishiHeavy152FanAuto LITERAL1
+kMitsubishiHeavy152FanEcono LITERAL1
+kMitsubishiHeavy152FanHigh LITERAL1
+kMitsubishiHeavy152FanLow LITERAL1
+kMitsubishiHeavy152FanMax LITERAL1
+kMitsubishiHeavy152FanMed LITERAL1
+kMitsubishiHeavy152FanTurbo LITERAL1
+kMitsubishiHeavy152MinRepeat LITERAL1
+kMitsubishiHeavy152StateLength LITERAL1
+kMitsubishiHeavy152SwingHAuto LITERAL1
+kMitsubishiHeavy152SwingHLeft LITERAL1
+kMitsubishiHeavy152SwingHLeftMax LITERAL1
+kMitsubishiHeavy152SwingHLeftRight LITERAL1
+kMitsubishiHeavy152SwingHMask LITERAL1
+kMitsubishiHeavy152SwingHMiddle LITERAL1
+kMitsubishiHeavy152SwingHOff LITERAL1
+kMitsubishiHeavy152SwingHRight LITERAL1
+kMitsubishiHeavy152SwingHRightLeft LITERAL1
+kMitsubishiHeavy152SwingHRightMax LITERAL1
+kMitsubishiHeavy152SwingVAuto LITERAL1
+kMitsubishiHeavy152SwingVHigh LITERAL1
+kMitsubishiHeavy152SwingVHighest LITERAL1
+kMitsubishiHeavy152SwingVLow LITERAL1
+kMitsubishiHeavy152SwingVLowest LITERAL1
+kMitsubishiHeavy152SwingVMask LITERAL1
+kMitsubishiHeavy152SwingVMiddle LITERAL1
+kMitsubishiHeavy152SwingVOff LITERAL1
+kMitsubishiHeavy3DMask LITERAL1
+kMitsubishiHeavy88Bits LITERAL1
+kMitsubishiHeavy88CleanBit LITERAL1
+kMitsubishiHeavy88FanAuto LITERAL1
+kMitsubishiHeavy88FanEcono LITERAL1
+kMitsubishiHeavy88FanHigh LITERAL1
+kMitsubishiHeavy88FanLow LITERAL1
+kMitsubishiHeavy88FanMask LITERAL1
+kMitsubishiHeavy88FanMed LITERAL1
+kMitsubishiHeavy88FanTurbo LITERAL1
+kMitsubishiHeavy88MinRepeat LITERAL1
+kMitsubishiHeavy88StateLength LITERAL1
+kMitsubishiHeavy88SwingH3D LITERAL1
+kMitsubishiHeavy88SwingHAuto LITERAL1
+kMitsubishiHeavy88SwingHLeft LITERAL1
+kMitsubishiHeavy88SwingHLeftMax LITERAL1
+kMitsubishiHeavy88SwingHLeftRight LITERAL1
+kMitsubishiHeavy88SwingHMask LITERAL1
+kMitsubishiHeavy88SwingHMiddle LITERAL1
+kMitsubishiHeavy88SwingHOff LITERAL1
+kMitsubishiHeavy88SwingHRight LITERAL1
+kMitsubishiHeavy88SwingHRightLeft LITERAL1
+kMitsubishiHeavy88SwingHRightMax LITERAL1
+kMitsubishiHeavy88SwingVAuto LITERAL1
+kMitsubishiHeavy88SwingVHigh LITERAL1
+kMitsubishiHeavy88SwingVHighest LITERAL1
+kMitsubishiHeavy88SwingVLow LITERAL1
+kMitsubishiHeavy88SwingVLowest LITERAL1
+kMitsubishiHeavy88SwingVMask LITERAL1
+kMitsubishiHeavy88SwingVMaskByte5 LITERAL1
+kMitsubishiHeavy88SwingVMaskByte7 LITERAL1
+kMitsubishiHeavy88SwingVMiddle LITERAL1
+kMitsubishiHeavy88SwingVOff LITERAL1
+kMitsubishiHeavyAuto LITERAL1
+kMitsubishiHeavyBitMark LITERAL1
+kMitsubishiHeavyCleanBit LITERAL1
+kMitsubishiHeavyCool LITERAL1
+kMitsubishiHeavyDry LITERAL1
+kMitsubishiHeavyFan LITERAL1
+kMitsubishiHeavyFanMask LITERAL1
+kMitsubishiHeavyFilterBit LITERAL1
+kMitsubishiHeavyGap LITERAL1
+kMitsubishiHeavyHdrMark LITERAL1
+kMitsubishiHeavyHdrSpace LITERAL1
+kMitsubishiHeavyHeat LITERAL1
+kMitsubishiHeavyMaxTemp LITERAL1
+kMitsubishiHeavyMinTemp LITERAL1
+kMitsubishiHeavyModeMask LITERAL1
+kMitsubishiHeavyNightBit LITERAL1
+kMitsubishiHeavyOneSpace LITERAL1
+kMitsubishiHeavyPowerBit LITERAL1
+kMitsubishiHeavySigLength LITERAL1
+kMitsubishiHeavySilentBit LITERAL1
+kMitsubishiHeavyTempMask LITERAL1
+kMitsubishiHeavyZeroSpace LITERAL1
+kMitsubishiHeavyZjsSig LITERAL1
+kMitsubishiHeavyZmsSig LITERAL1
kMitsubishiMinCommandLength LITERAL1
kMitsubishiMinCommandLengthTicks LITERAL1
kMitsubishiMinGap LITERAL1
@@ -1331,10 +1681,12 @@ kNikaiTick LITERAL1
kNikaiZeroSpace LITERAL1
kNikaiZeroSpaceTicks LITERAL1
kNoRepeat LITERAL1
+kOff LITERAL1
kPanasonicAcAuto LITERAL1
kPanasonicAcBits LITERAL1
kPanasonicAcChecksumInit LITERAL1
kPanasonicAcCool LITERAL1
+kPanasonicAcDefaultRepeat LITERAL1
kPanasonicAcDry LITERAL1
kPanasonicAcExcess LITERAL1
kPanasonicAcFan LITERAL1
@@ -1393,6 +1745,7 @@ kPanasonicMinGapTicks LITERAL1
kPanasonicNke LITERAL1
kPanasonicOneSpace LITERAL1
kPanasonicOneSpaceTicks LITERAL1
+kPanasonicRkr LITERAL1
kPanasonicTick LITERAL1
kPanasonicUnknown LITERAL1
kPanasonicZeroSpace LITERAL1
@@ -1450,6 +1803,9 @@ kRcmmRptLengthTicks LITERAL1
kRcmmTick LITERAL1
kRcmmTolerance LITERAL1
kRepeat LITERAL1
+kRight LITERAL1
+kRightMax LITERAL1
+kSamsung36Bits LITERAL1
kSamsungACSectionLength LITERAL1
kSamsungAcAuto LITERAL1
kSamsungAcAutoTemp LITERAL1
@@ -1459,6 +1815,7 @@ kSamsungAcBits LITERAL1
kSamsungAcCleanMask10 LITERAL1
kSamsungAcCleanMask11 LITERAL1
kSamsungAcCool LITERAL1
+kSamsungAcDefaultRepeat LITERAL1
kSamsungAcDry LITERAL1
kSamsungAcExtendedBits LITERAL1
kSamsungAcExtendedStateLength LITERAL1
@@ -1569,6 +1926,65 @@ kSpaceState LITERAL1
kStartOffset LITERAL1
kStateSizeMax LITERAL1
kStopState LITERAL1
+kTcl112AcAuto LITERAL1
+kTcl112AcBitEcono LITERAL1
+kTcl112AcBitHealth LITERAL1
+kTcl112AcBitLight LITERAL1
+kTcl112AcBitMark LITERAL1
+kTcl112AcBitSwingH LITERAL1
+kTcl112AcBitSwingV LITERAL1
+kTcl112AcBitTurbo LITERAL1
+kTcl112AcBits LITERAL1
+kTcl112AcCool LITERAL1
+kTcl112AcDefaultRepeat LITERAL1
+kTcl112AcDry LITERAL1
+kTcl112AcFan LITERAL1
+kTcl112AcFanAuto LITERAL1
+kTcl112AcFanHigh LITERAL1
+kTcl112AcFanLow LITERAL1
+kTcl112AcFanMask LITERAL1
+kTcl112AcFanMed LITERAL1
+kTcl112AcGap LITERAL1
+kTcl112AcHalfDegree LITERAL1
+kTcl112AcHdrMark LITERAL1
+kTcl112AcHdrSpace LITERAL1
+kTcl112AcHeat LITERAL1
+kTcl112AcOneSpace LITERAL1
+kTcl112AcPowerMask LITERAL1
+kTcl112AcStateLength LITERAL1
+kTcl112AcTempMax LITERAL1
+kTcl112AcTempMin LITERAL1
+kTcl112AcZeroSpace LITERAL1
+kTecoAuto LITERAL1
+kTecoBitMark LITERAL1
+kTecoBits LITERAL1
+kTecoCool LITERAL1
+kTecoDefaultRepeat LITERAL1
+kTecoDry LITERAL1
+kTecoFan LITERAL1
+kTecoFanAuto LITERAL1
+kTecoFanHigh LITERAL1
+kTecoFanLow LITERAL1
+kTecoFanMask LITERAL1
+kTecoFanMed LITERAL1
+kTecoGap LITERAL1
+kTecoHdrMark LITERAL1
+kTecoHdrSpace LITERAL1
+kTecoHeat LITERAL1
+kTecoMaxTemp LITERAL1
+kTecoMinTemp LITERAL1
+kTecoModeMask LITERAL1
+kTecoOneSpace LITERAL1
+kTecoPower LITERAL1
+kTecoReset LITERAL1
+kTecoSleep LITERAL1
+kTecoSwing LITERAL1
+kTecoTempMask LITERAL1
+kTecoTimerHalfH LITERAL1
+kTecoTimerOn LITERAL1
+kTecoTimerTenHr LITERAL1
+kTecoTimerUniHr LITERAL1
+kTecoZeroSpace LITERAL1
kTimeoutMs LITERAL1
kTolerance LITERAL1
kToshibaACBits LITERAL1
@@ -1592,6 +2008,7 @@ kToshibaAcZeroSpace LITERAL1
kTrotecAuto LITERAL1
kTrotecCool LITERAL1
kTrotecDefTemp LITERAL1
+kTrotecDefaultRepeat LITERAL1
kTrotecDry LITERAL1
kTrotecFan LITERAL1
kTrotecFanHigh LITERAL1
@@ -1606,26 +2023,119 @@ kTrotecIntro2 LITERAL1
kTrotecMaxTemp LITERAL1
kTrotecMaxTimer LITERAL1
kTrotecMinTemp LITERAL1
-kTrotecMinTimer LITERAL1
-kTrotecOff LITERAL1
-kTrotecOn LITERAL1
kTrotecOneMark LITERAL1
kTrotecOneSpace LITERAL1
-kTrotecSleepOn LITERAL1
+kTrotecPowerBit LITERAL1
+kTrotecSleepBit LITERAL1
kTrotecStateLength LITERAL1
-kTrotecTimerOn LITERAL1
+kTrotecTimerBit LITERAL1
kTrotecZeroMark LITERAL1
kTrotecZeroSpace LITERAL1
kUnknownThreshold LITERAL1
+kVestelAcAuto LITERAL1
+kVestelAcBitMark LITERAL1
+kVestelAcBits LITERAL1
+kVestelAcCRCMask LITERAL1
+kVestelAcChecksumOffset LITERAL1
+kVestelAcCool LITERAL1
+kVestelAcDry LITERAL1
+kVestelAcFan LITERAL1
+kVestelAcFanAuto LITERAL1
+kVestelAcFanAutoCool LITERAL1
+kVestelAcFanAutoHot LITERAL1
+kVestelAcFanHigh LITERAL1
+kVestelAcFanLow LITERAL1
+kVestelAcFanMed LITERAL1
+kVestelAcFanOffset LITERAL1
+kVestelAcHdrMark LITERAL1
+kVestelAcHdrSpace LITERAL1
+kVestelAcHeat LITERAL1
+kVestelAcHourOffset LITERAL1
+kVestelAcIon LITERAL1
+kVestelAcIonOffset LITERAL1
+kVestelAcMaxTemp LITERAL1
+kVestelAcMinTempC LITERAL1
+kVestelAcMinTempH LITERAL1
+kVestelAcMinuteOffset LITERAL1
+kVestelAcModeOffset LITERAL1
+kVestelAcNormal LITERAL1
+kVestelAcOffTimeOffset LITERAL1
+kVestelAcOffTimerFlagOffset LITERAL1
+kVestelAcOnTimeOffset LITERAL1
+kVestelAcOnTimerFlagOffset LITERAL1
+kVestelAcOneSpace LITERAL1
+kVestelAcPowerOffset LITERAL1
+kVestelAcSleep LITERAL1
+kVestelAcStateDefault LITERAL1
+kVestelAcSwing LITERAL1
+kVestelAcSwingOffset LITERAL1
+kVestelAcTempOffset LITERAL1
+kVestelAcTimeStateDefault LITERAL1
+kVestelAcTimerFlagOffset LITERAL1
+kVestelAcTolerance LITERAL1
+kVestelAcTurbo LITERAL1
+kVestelAcTurboSleepOffset LITERAL1
+kVestelAcZeroSpace LITERAL1
+kWhirlpoolAcAltTempMask LITERAL1
+kWhirlpoolAcAltTempPos LITERAL1
+kWhirlpoolAcAuto LITERAL1
+kWhirlpoolAcAutoTemp LITERAL1
kWhirlpoolAcBitMark LITERAL1
kWhirlpoolAcBits LITERAL1
+kWhirlpoolAcChecksumByte1 LITERAL1
+kWhirlpoolAcChecksumByte2 LITERAL1
+kWhirlpoolAcClockPos LITERAL1
+kWhirlpoolAcCommand6thSense LITERAL1
+kWhirlpoolAcCommandFanSpeed LITERAL1
+kWhirlpoolAcCommandIFeel LITERAL1
+kWhirlpoolAcCommandLight LITERAL1
+kWhirlpoolAcCommandMode LITERAL1
+kWhirlpoolAcCommandOffTimer LITERAL1
+kWhirlpoolAcCommandOnTimer LITERAL1
+kWhirlpoolAcCommandPos LITERAL1
+kWhirlpoolAcCommandPower LITERAL1
+kWhirlpoolAcCommandSleep LITERAL1
+kWhirlpoolAcCommandSuper LITERAL1
+kWhirlpoolAcCommandSwing LITERAL1
+kWhirlpoolAcCommandTemp LITERAL1
+kWhirlpoolAcCool LITERAL1
+kWhirlpoolAcDefaultRepeat LITERAL1
+kWhirlpoolAcDry LITERAL1
+kWhirlpoolAcFan LITERAL1
+kWhirlpoolAcFanAuto LITERAL1
+kWhirlpoolAcFanHigh LITERAL1
+kWhirlpoolAcFanLow LITERAL1
+kWhirlpoolAcFanMask LITERAL1
+kWhirlpoolAcFanMedium LITERAL1
+kWhirlpoolAcFanPos LITERAL1
kWhirlpoolAcGap LITERAL1
kWhirlpoolAcHdrMark LITERAL1
kWhirlpoolAcHdrSpace LITERAL1
+kWhirlpoolAcHeat LITERAL1
+kWhirlpoolAcHourMask LITERAL1
+kWhirlpoolAcLightMask LITERAL1
+kWhirlpoolAcMaxTemp LITERAL1
kWhirlpoolAcMinGap LITERAL1
+kWhirlpoolAcMinTemp LITERAL1
+kWhirlpoolAcMinuteMask LITERAL1
+kWhirlpoolAcModeMask LITERAL1
+kWhirlpoolAcModePos LITERAL1
+kWhirlpoolAcOffTimerPos LITERAL1
+kWhirlpoolAcOnTimerPos LITERAL1
kWhirlpoolAcOneSpace LITERAL1
+kWhirlpoolAcPowerToggleMask LITERAL1
+kWhirlpoolAcPowerTogglePos LITERAL1
kWhirlpoolAcSections LITERAL1
+kWhirlpoolAcSleepMask LITERAL1
+kWhirlpoolAcSleepPos LITERAL1
kWhirlpoolAcStateLength LITERAL1
+kWhirlpoolAcSuperMask LITERAL1
+kWhirlpoolAcSuperPos LITERAL1
+kWhirlpoolAcSwing1Mask LITERAL1
+kWhirlpoolAcSwing2Mask LITERAL1
+kWhirlpoolAcTempMask LITERAL1
+kWhirlpoolAcTempPos LITERAL1
+kWhirlpoolAcTimerEnableMask LITERAL1
kWhirlpoolAcZeroSpace LITERAL1
kWhynterBitMark LITERAL1
kWhynterBitMarkTicks LITERAL1
diff --git a/lib/IRremoteESP8266-2.5.2.03/library.json b/lib/IRremoteESP8266-2.6.0/library.json
similarity index 97%
rename from lib/IRremoteESP8266-2.5.2.03/library.json
rename to lib/IRremoteESP8266-2.6.0/library.json
index 3fc14f027e16..95867de1db7f 100644
--- a/lib/IRremoteESP8266-2.5.2.03/library.json
+++ b/lib/IRremoteESP8266-2.6.0/library.json
@@ -1,6 +1,6 @@
{
"name": "IRremoteESP8266",
- "version": "2.5.2",
+ "version": "2.6.0",
"keywords": "infrared, ir, remote, esp8266",
"description": "Send and receive infrared signals with multiple protocols (ESP8266)",
"repository":
diff --git a/lib/IRremoteESP8266-2.5.2.03/library.properties b/lib/IRremoteESP8266-2.6.0/library.properties
similarity index 96%
rename from lib/IRremoteESP8266-2.5.2.03/library.properties
rename to lib/IRremoteESP8266-2.6.0/library.properties
index e71dc41542ef..f122067c5386 100644
--- a/lib/IRremoteESP8266-2.5.2.03/library.properties
+++ b/lib/IRremoteESP8266-2.6.0/library.properties
@@ -1,5 +1,5 @@
name=IRremoteESP8266
-version=2.5.2
+version=2.6.0
author=Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran
maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto
sentence=Send and receive infrared signals with multiple protocols (ESP8266)
diff --git a/lib/IRremoteESP8266-2.5.2.03/platformio.ini b/lib/IRremoteESP8266-2.6.0/platformio.ini
similarity index 83%
rename from lib/IRremoteESP8266-2.5.2.03/platformio.ini
rename to lib/IRremoteESP8266-2.6.0/platformio.ini
index 63c3781e1167..b6020c165c4e 100644
--- a/lib/IRremoteESP8266-2.5.2.03/platformio.ini
+++ b/lib/IRremoteESP8266-2.6.0/platformio.ini
@@ -6,11 +6,13 @@ src_dir = examples/IRrecvDumpV2
build_flags =
lib_deps_builtin =
lib_deps_external =
+lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
@@ -20,6 +22,7 @@ lib_deps =
platform = espressif8266
framework = arduino
board = d1_mini
+lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
diff --git a/lib/IRremoteESP8266-2.5.2.03/pylintrc b/lib/IRremoteESP8266-2.6.0/pylintrc
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/pylintrc
rename to lib/IRremoteESP8266-2.6.0/pylintrc
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/CPPLINT.cfg b/lib/IRremoteESP8266-2.6.0/src/CPPLINT.cfg
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/CPPLINT.cfg
rename to lib/IRremoteESP8266-2.6.0/src/CPPLINT.cfg
diff --git a/lib/IRremoteESP8266-2.6.0/src/IRac.cpp b/lib/IRremoteESP8266-2.6.0/src/IRac.cpp
new file mode 100644
index 000000000000..782c147c20d6
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/IRac.cpp
@@ -0,0 +1,1125 @@
+// Copyright 2019 David Conran
+
+// Provide a universal/standard interface for sending A/C nessages.
+// It does not provide complete and maximum granular control but tries
+// to off most common functionallity across all supported devices.
+
+#include "IRac.h"
+#ifndef UNIT_TEST
+#include
+#endif
+
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRsend.h"
+#include "IRremoteESP8266.h"
+#include "ir_Argo.h"
+#include "ir_Coolix.h"
+#include "ir_Daikin.h"
+#include "ir_Fujitsu.h"
+#include "ir_Haier.h"
+#include "ir_Hitachi.h"
+#include "ir_Kelvinator.h"
+#include "ir_Midea.h"
+#include "ir_Mitsubishi.h"
+#include "ir_MitsubishiHeavy.h"
+#include "ir_Panasonic.h"
+#include "ir_Samsung.h"
+#include "ir_Tcl.h"
+#include "ir_Teco.h"
+#include "ir_Toshiba.h"
+#include "ir_Trotec.h"
+#include "ir_Vestel.h"
+#include "ir_Whirlpool.h"
+
+IRac::IRac(uint8_t pin) { _pin = pin; }
+
+// Is the given protocol supported by the IRac class?
+bool IRac::isProtocolSupported(const decode_type_t protocol) {
+ switch (protocol) {
+#if SEND_ARGO
+ case decode_type_t::ARGO:
+#endif
+#if SEND_COOLIX
+ case decode_type_t::COOLIX:
+#endif
+#if SEND_DAIKIN
+ case decode_type_t::DAIKIN:
+#endif
+#if SEND_DAIKIN2
+ case decode_type_t::DAIKIN2:
+#endif
+#if SEND_DAIKIN216
+ case decode_type_t::DAIKIN216:
+#endif
+#if SEND_FUJITSU_AC
+ case decode_type_t::FUJITSU_AC:
+#endif
+#if SEND_GREE
+ case decode_type_t::GREE:
+#endif
+#if SEND_HAIER_AC
+ case decode_type_t::HAIER_AC:
+#endif
+#if SEND_HAIER_AC_YRW02
+ case decode_type_t::HAIER_AC_YRW02:
+#endif
+#if SEND_HITACHI_AC
+ case decode_type_t::HITACHI_AC:
+#endif
+#if SEND_KELVINATOR
+ case decode_type_t::KELVINATOR:
+#endif
+#if SEND_MIDEA
+ case decode_type_t::MIDEA:
+#endif
+#if SEND_MITSUBISHI_AC
+ case decode_type_t::MITSUBISHI_AC:
+#endif
+#if SEND_MITSUBISHIHEAVY
+ case decode_type_t::MITSUBISHI_HEAVY_88:
+ case decode_type_t::MITSUBISHI_HEAVY_152:
+#endif
+#if SEND_PANASONIC_AC
+ case decode_type_t::PANASONIC_AC:
+#endif
+#if SEND_SAMSUNG_AC
+ case decode_type_t::SAMSUNG_AC:
+#endif
+#if SEND_TCL112AC
+ case decode_type_t::TCL112AC:
+#endif
+#if SEND_TECO
+ case decode_type_t::TECO:
+#endif
+#if SEND_TOSHIBA_AC
+ case decode_type_t::TOSHIBA_AC:
+#endif
+#if SEND_TROTEC
+ case decode_type_t::TROTEC:
+#endif
+#if SEND_VESTEL_AC
+ case decode_type_t::VESTEL_AC:
+#endif
+#if SEND_WHIRLPOOL_AC
+ case decode_type_t::WHIRLPOOL_AC:
+#endif
+ return true;
+ default:
+ return false;
+ }
+}
+
+#if SEND_ARGO
+void IRac::argo(IRArgoAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const int16_t sleep) {
+ ac->setPower(on);
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ ac->setCoolMode(kArgoCoolOn);
+ break;
+ case stdAc::opmode_t::kHeat:
+ ac->setHeatMode(kArgoHeatOn);
+ break;
+ case stdAc::opmode_t::kDry:
+ ac->setCoolMode(kArgoCoolHum);
+ break;
+ default: // No idea how to set Fan mode.
+ ac->setCoolMode(kArgoCoolAuto);
+ }
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setFlap(ac->convertSwingV(swingv));
+ // No Quiet setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ ac->setMax(turbo);
+ // No Economy setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setNight(sleep >= 0); // Convert to a boolean.
+ ac->send();
+}
+#endif // SEND_ARGO
+
+#if SEND_COOLIX
+void IRac::coolix(IRCoolixAC *ac,
+ const bool on, 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 turbo, const bool light, const bool clean,
+ const int16_t sleep) {
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ // No Filter setting available.
+ // No Beep setting available.
+ // No Clock setting available.
+ // No Econo setting available.
+ // No Quiet setting available.
+ if (swingv != stdAc::swingv_t::kOff || swingh != stdAc::swingh_t::kOff) {
+ // Swing has a special command that needs to be sent independently.
+ ac->setSwing();
+ ac->send();
+ }
+ if (turbo) {
+ // Turbo has a special command that needs to be sent independently.
+ ac->setTurbo();
+ ac->send();
+ }
+ if (sleep > 0) {
+ // Sleep has a special command that needs to be sent independently.
+ ac->setSleep();
+ ac->send();
+ }
+ if (light) {
+ // Light has a special command that needs to be sent independently.
+ ac->setLed();
+ ac->send();
+ }
+ if (clean) {
+ // Clean has a special command that needs to be sent independently.
+ ac->setClean();
+ ac->send();
+ }
+ // Power gets done last, as off has a special command.
+ ac->setPower(on);
+ ac->send();
+}
+#endif // SEND_COOLIX
+
+#if SEND_DAIKIN
+void IRac::daikin(IRDaikinESP *ac,
+ const bool on, 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 quiet, const bool turbo, const bool econo,
+ const bool clean) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ // No Light setting available.
+ // No Filter setting available.
+ ac->setPowerful(turbo);
+ ac->setEcono(econo);
+ ac->setMold(clean);
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_DAIKIN
+
+#if SEND_DAIKIN2
+void IRac::daikin2(IRDaikin2 *ac,
+ const bool on, 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 quiet, const bool turbo, const bool light,
+ const bool econo, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep, const int16_t clock) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ ac->setLight(light);
+ ac->setPowerful(turbo);
+ ac->setEcono(econo);
+ ac->setPurify(filter);
+ ac->setMold(clean);
+ ac->setBeep(beep);
+ if (sleep > 0) ac->enableSleepTimer(sleep);
+ if (clock >= 0) ac->setCurrentTime(clock);
+ ac->send();
+}
+#endif // SEND_DAIKIN2
+
+#if SEND_DAIKIN216
+void IRac::daikin216(IRDaikin216 *ac,
+ const bool on, 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 quiet) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ ac->send();
+}
+#endif // SEND_DAIKIN216
+
+#if SEND_FUJITSU_AC
+void IRac::fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
+ const bool on, 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 quiet) {
+ ac->setModel(model);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFanSpeed(ac->convertFan(fan));
+ uint8_t swing = kFujitsuAcSwingOff;
+ if (swingv > stdAc::swingv_t::kOff) swing |= kFujitsuAcSwingVert;
+ if (swingh > stdAc::swingh_t::kOff) swing |= kFujitsuAcSwingHoriz;
+ ac->setSwing(swing);
+ if (quiet) ac->setFanSpeed(kFujitsuAcFanQuiet);
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Econo setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ if (!on) ac->off();
+ ac->send();
+}
+#endif // SEND_FUJITSU_AC
+
+#if SEND_GREE
+void IRac::gree(IRGreeAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light, const bool clean,
+ const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag.
+ ac->convertSwingV(swingv));
+ ac->setLight(light);
+ ac->setTurbo(turbo);
+ ac->setXFan(clean);
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ // No Horizontal Swing setting available.
+ // No Filter setting available.
+ // No Beep setting available.
+ // No Quiet setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_GREE
+
+#if SEND_HAIER_AC
+void IRac::haier(IRHaierAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool filter, const int16_t sleep, const int16_t clock) {
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(ac->convertSwingV(swingv));
+ // No Horizontal Swing setting available.
+ // No Quiet setting available.
+ // No Turbo setting available.
+ // No Light setting available.
+ ac->setHealth(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ if (clock >=0) ac->setCurrTime(clock);
+ if (on)
+ ac->setCommand(kHaierAcCmdOn);
+ else
+ ac->setCommand(kHaierAcCmdOff);
+ ac->send();
+}
+#endif // SEND_HAIER_AC
+
+#if SEND_HAIER_AC_YRW02
+void IRac::haierYrwo2(IRHaierACYRW02 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const bool turbo,
+ const bool filter, const int16_t sleep) {
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(ac->convertSwingV(swingv));
+ // No Horizontal Swing setting available.
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setHealth(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ ac->setPower(on);
+ ac->send();
+}
+#endif // SEND_HAIER_AC_YRW02
+
+#if SEND_HITACHI_AC
+void IRac::hitachi(IRHitachiAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(swingv != stdAc::swingv_t::kOff);
+ ac->setSwingHorizontal(swingh != stdAc::swingh_t::kOff);
+ // 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 Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_HITACHI_AC
+
+#if SEND_KELVINATOR
+void IRac::kelvinator(IRKelvinatorAC *ac,
+ const bool on, 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 quiet, const bool turbo, const bool light,
+ const bool filter, const bool clean) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan((uint8_t)fan); // No conversion needed.
+ ac->setSwingVertical((int8_t)swingv >= 0);
+ ac->setSwingHorizontal((int8_t)swingh >= 0);
+ ac->setQuiet(quiet);
+ ac->setTurbo(turbo);
+ ac->setLight(light);
+ ac->setIonFilter(filter);
+ ac->setXFan(clean);
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_KELVINATOR
+
+#if SEND_MIDEA
+void IRac::midea(IRMideaAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees, true); // true means use Celsius.
+ ac->setFan(ac->convertFan(fan));
+ // No Vertical swing setting available.
+ // No Horizontal swing 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.
+ ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_MIDEA
+
+#if SEND_MITSUBISHI_AC
+void IRac::mitsubishi(IRMitsubishiAC *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 int16_t clock) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setVane(ac->convertSwingV(swingv));
+ // No Horizontal swing setting available.
+ if (quiet) ac->setFan(kMitsubishiAcFanSilent);
+ // No Turbo setting available.
+ // No Light setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ if (clock >= 0) ac->setClock(clock / 10); // Clock is in 10 min increments.
+ ac->send();
+}
+#endif // SEND_MITSUBISHI_AC
+
+#if SEND_MITSUBISHIHEAVY
+void IRac::mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac,
+ const bool on, 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 turbo, const bool econo,
+ const bool clean) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal(ac->convertSwingH(swingh));
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setEcono(econo);
+ // No Filter setting available.
+ ac->setClean(clean);
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+
+void IRac::mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac,
+ const bool on, 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 quiet, const bool turbo,
+ const bool econo, const bool filter,
+ const bool clean, const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal(ac->convertSwingH(swingh));
+ ac->setSilent(quiet);
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setEcono(econo);
+ ac->setClean(clean);
+ ac->setFilter(filter);
+ // No Beep setting available.
+ ac->setNight(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+#if SEND_PANASONIC_AC
+void IRac::panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
+ const bool on, 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 quiet, const bool turbo, const int16_t clock) {
+ ac->setModel(model);
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(ac->convertSwingV(swingv));
+ ac->setSwingHorizontal(ac->convertSwingH(swingh));
+ ac->setQuiet(quiet);
+ ac->setPowerful(turbo);
+ // No Light setting available.
+ // No Econo setting available.
+ // No Filter setting available.
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ if (clock >= 0) ac->setClock(clock);
+ ac->send();
+}
+#endif // SEND_PANASONIC_AC
+
+#if SEND_SAMSUNG_AC
+void IRac::samsung(IRSamsungAc *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 bool clean,
+ const bool beep, const bool sendOnOffHack) {
+ if (sendOnOffHack) {
+ // Use a hack to for the unit on or off.
+ // See: https://github.com/markszabo/IRremoteESP8266/issues/604#issuecomment-475020036
+ if (on)
+ ac->sendOn();
+ else
+ ac->sendOff();
+ }
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ ac->setQuiet(quiet);
+ if (turbo) ac->setFan(kSamsungAcFanTurbo);
+ // No Light setting available.
+ // No Econo setting available.
+ // No Filter setting available.
+ ac->setClean(clean);
+ ac->setBeep(beep);
+ // No Sleep setting available.
+ // No Clock setting available.
+ // Do setMode() again as it can affect fan speed.
+ ac->setMode(ac->convertMode(mode));
+ ac->send();
+}
+#endif // SEND_SAMSUNG_AC
+
+#if SEND_TCL112AC
+void IRac::tcl112(IRTcl112Ac *ac,
+ const bool on, 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 turbo, const bool light, const bool econo,
+ const bool filter) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwingVertical(swingv != stdAc::swingv_t::kOff);
+ ac->setSwingHorizontal(swingh != stdAc::swingh_t::kOff);
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ ac->setLight(light);
+ ac->setEcono(econo);
+ ac->setHealth(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ // No Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TCL112AC
+
+#if SEND_TECO
+void IRac::teco(IRTecoAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing 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.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TECO
+
+#if SEND_TOSHIBA_AC
+void IRac::toshiba(IRToshibaAC *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ // No Vertical swing setting available.
+ // No Horizontal swing 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 Sleep setting available.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TOSHIBA_AC
+
+#if SEND_TROTEC
+void IRac::trotec(IRTrotecESP *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const int16_t sleep) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setSpeed(ac->convertFan(fan));
+ // No Vertical swing setting available.
+ // No Horizontal swing 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.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ // No Clock setting available.
+ ac->send();
+}
+#endif // SEND_TROTEC
+
+#if SEND_VESTEL_AC
+void IRac::vestel(IRVestelAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool filter, const int16_t sleep,
+ const int16_t clock, const bool sendNormal) {
+ ac->setPower(on);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ ac->setTurbo(turbo);
+ // No Light setting available.
+ ac->setIon(filter);
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ if (sendNormal) ac->send(); // Send the normal message.
+ if (clock >= 0) {
+ ac->setTime(clock);
+ ac->send(); // Setting the clock requires a different "timer" message.
+ }
+}
+#endif // SEND_VESTEL_AC
+
+#if SEND_WHIRLPOOL_AC
+void IRac::whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light,
+ const int16_t sleep, const int16_t clock) {
+ ac->setModel(model);
+ ac->setMode(ac->convertMode(mode));
+ ac->setTemp(degrees);
+ ac->setFan(ac->convertFan(fan));
+ ac->setSwing(swingv != stdAc::swingv_t::kOff);
+ // No Horizontal swing setting available.
+ // No Quiet setting available.
+ ac->setSuper(turbo);
+ ac->setLight(light);
+ // No Filter setting available
+ // No Clean setting available.
+ // No Beep setting available.
+ ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
+ if (clock >= 0) ac->setClock(clock);
+ ac->setPowerToggle(on);
+ ac->send();
+}
+#endif // SEND_WHIRLPOOL_AC
+
+// Send A/C message for a given device using common A/C settings.
+// Args:
+// vendor: The type of A/C protocol to use.
+// model: The specific model of A/C if supported/applicable.
+// on: Should the unit be powered on? (or in some cases, toggled)
+// mode: What operating mode should the unit perform? e.g. Cool, Heat etc.
+// degrees: What temperature should the unit be set to?
+// celsius: Use degreees Celsius, otherwise Fahrenheit.
+// fan: Fan speed.
+// The following args are all "if supported" by the underlying A/C classes.
+// swingv: Control the vertical swing of the vanes.
+// swingh: Control the horizontal swing of the vanes.
+// quiet: Set the unit to quiet (fan) operation mode.
+// turbo: Set the unit to turbo operating mode. e.g. Max fan & cooling etc.
+// econo: Set the unit to economical operating mode.
+// light: Turn on the display/LEDs etc.
+// filter: Turn on any particle/ion/allergy filter etc.
+// clean: Turn on any settings to reduce mold etc. (Not self-clean mode.)
+// beep: Control if the unit beeps upon receiving commands.
+// sleep: Nr. of mins of sleep mode, or use sleep mode. (< 0 means off.)
+// clock: Nr. of mins past midnight to set the clock to. (< 0 means off.)
+// Returns:
+// boolean: True, if accepted/converted/attempted. False, if unsupported.
+bool IRac::sendAc(const decode_type_t vendor, const int16_t model,
+ const bool power, const stdAc::opmode_t mode,
+ const float degrees, const bool celsius,
+ const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool light, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep, const int16_t clock) {
+ // Convert the temperature to Celsius.
+ float degC;
+ bool on = power;
+ if (celsius)
+ degC = degrees;
+ else
+ degC = (degrees - 32.0) * (5.0 / 9.0);
+ // A hack for Home Assistant, it appears to need/want an Off opmode.
+ if (mode == stdAc::opmode_t::kOff) on = false;
+ // Per vendor settings & setup.
+ switch (vendor) {
+#if SEND_ARGO
+ case ARGO:
+ {
+ IRArgoAC ac(_pin);
+ argo(&ac, on, mode, degC, fan, swingv, turbo, sleep);
+ break;
+ }
+#endif // SEND_DAIKIN
+#if SEND_COOLIX
+ case COOLIX:
+ {
+ IRCoolixAC ac(_pin);
+ coolix(&ac, on, mode, degC, fan, swingv, swingh,
+ quiet, turbo, econo, clean);
+ break;
+ }
+#endif // SEND_DAIKIN
+#if SEND_DAIKIN
+ case DAIKIN:
+ {
+ IRDaikinESP ac(_pin);
+ daikin(&ac, on, mode, degC, fan, swingv, swingh,
+ quiet, turbo, econo, clean);
+ break;
+ }
+#endif // SEND_DAIKIN
+#if SEND_DAIKIN2
+ case DAIKIN2:
+ {
+ IRDaikin2 ac(_pin);
+ daikin2(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo,
+ light, econo, filter, clean, beep, sleep, clock);
+ break;
+ }
+#endif // SEND_DAIKIN216
+#if SEND_DAIKIN216
+ case DAIKIN216:
+ {
+ IRDaikin216 ac(_pin);
+ daikin216(&ac, on, mode, degC, fan, swingv, swingh, quiet);
+ break;
+ }
+#endif // SEND_DAIKIN216
+#if SEND_FUJITSU_AC
+ case FUJITSU_AC:
+ {
+ IRFujitsuAC ac(_pin);
+ ac.begin();
+ fujitsu(&ac, (fujitsu_ac_remote_model_t)model, on, mode, degC, fan,
+ swingv, swingh, quiet);
+ break;
+ }
+#endif // SEND_FUJITSU_AC
+#if SEND_GREE
+ case GREE:
+ {
+ IRGreeAC ac(_pin);
+ ac.begin();
+ gree(&ac, on, mode, degC, fan, swingv, light, turbo, clean, sleep);
+ break;
+ }
+#endif // SEND_GREE
+#if SEND_HAIER_AC
+ case HAIER_AC:
+ {
+ IRHaierAC ac(_pin);
+ ac.begin();
+ haier(&ac, on, mode, degC, fan, swingv, filter, sleep, clock);
+ break;
+ }
+#endif // SEND_HAIER_AC
+#if SEND_HAIER_AC_YRW02
+ case HAIER_AC_YRW02:
+ {
+ IRHaierACYRW02 ac(_pin);
+ ac.begin();
+ haierYrwo2(&ac, on, mode, degC, fan, swingv, turbo, filter, sleep);
+ break;
+ }
+#endif // SEND_HAIER_AC_YRW02
+#if SEND_HITACHI_AC
+ case HITACHI_AC:
+ {
+ IRHitachiAc ac(_pin);
+ ac.begin();
+ hitachi(&ac, on, mode, degC, fan, swingv, swingh);
+ break;
+ }
+#endif // SEND_HITACHI_AC
+#if SEND_KELVINATOR
+ case KELVINATOR:
+ {
+ IRKelvinatorAC ac(_pin);
+ ac.begin();
+ kelvinator(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo,
+ light, filter, clean);
+ break;
+ }
+#endif // SEND_KELVINATOR
+#if SEND_MIDEA
+ case MIDEA:
+ {
+ IRMideaAC ac(_pin);
+ ac.begin();
+ midea(&ac, on, mode, degC, fan, sleep);
+ break;
+ }
+#endif // SEND_MIDEA
+#if SEND_MITSUBISHI_AC
+ case MITSUBISHI_AC:
+ {
+ IRMitsubishiAC ac(_pin);
+ ac.begin();
+ mitsubishi(&ac, on, mode, degC, fan, swingv, quiet, clock);
+ break;
+ }
+#endif // SEND_MITSUBISHI_AC
+#if SEND_MITSUBISHIHEAVY
+ case MITSUBISHI_HEAVY_88:
+ {
+ IRMitsubishiHeavy88Ac ac(_pin);
+ ac.begin();
+ mitsubishiHeavy88(&ac, on, mode, degC, fan, swingv, swingh,
+ turbo, econo, clean);
+ break;
+ }
+ case MITSUBISHI_HEAVY_152:
+ {
+ IRMitsubishiHeavy152Ac ac(_pin);
+ ac.begin();
+ mitsubishiHeavy152(&ac, on, mode, degC, fan, swingv, swingh,
+ quiet, turbo, econo, filter, clean, sleep);
+ break;
+ }
+#endif // SEND_MITSUBISHIHEAVY
+#if SEND_PANASONIC_AC
+ case PANASONIC_AC:
+ {
+ IRPanasonicAc ac(_pin);
+ ac.begin();
+ panasonic(&ac, (panasonic_ac_remote_model_t)model, on, mode, degC, fan,
+ swingv, swingh, quiet, turbo, clock);
+ break;
+ }
+#endif // SEND_PANASONIC_AC
+#if SEND_SAMSUNG_AC
+ case SAMSUNG_AC:
+ {
+ IRSamsungAc ac(_pin);
+ ac.begin();
+ samsung(&ac, on, mode, degC, fan, swingv, quiet, turbo, clean, beep);
+ break;
+ }
+#endif // SEND_SAMSUNG_AC
+#if SEND_TCL112AC
+ case TCL112AC:
+ {
+ IRTcl112Ac ac(_pin);
+ ac.begin();
+ tcl112(&ac, on, mode, degC, fan, swingv, swingh, turbo, light, econo,
+ filter);
+ break;
+ }
+#endif // SEND_TCL112AC
+#if SEND_TECO
+ case TECO:
+ {
+ IRTecoAc ac(_pin);
+ ac.begin();
+ teco(&ac, on, mode, degC, fan, swingv, sleep);
+ break;
+ }
+#endif // SEND_TECO
+#if SEND_TOSHIBA_AC
+ case TOSHIBA_AC:
+ {
+ IRToshibaAC ac(_pin);
+ ac.begin();
+ toshiba(&ac, on, mode, degC, fan);
+ break;
+ }
+#endif // SEND_TOSHIBA_AC
+#if SEND_TROTEC
+ case TROTEC:
+ {
+ IRTrotecESP ac(_pin);
+ ac.begin();
+ trotec(&ac, on, mode, degC, fan, sleep);
+ break;
+ }
+#endif // SEND_TROTEC
+#if SEND_VESTEL_AC
+ case VESTEL_AC:
+ {
+ IRVestelAc ac(_pin);
+ ac.begin();
+ vestel(&ac, on, mode, degC, fan, swingv, turbo, filter, sleep, clock);
+ break;
+ }
+#endif // SEND_VESTEL_AC
+#if SEND_WHIRLPOOL_AC
+ case WHIRLPOOL_AC:
+ {
+ IRWhirlpoolAc ac(_pin);
+ ac.begin();
+ whirlpool(&ac, (whirlpool_ac_remote_model_t)model, on, mode, degC, fan,
+ swingv, turbo, light, sleep, clock);
+ break;
+ }
+#endif // SEND_WHIRLPOOL_AC
+ default:
+ return false; // Fail, didn't match anything.
+ }
+ return true; // Success.
+}
+
+stdAc::opmode_t IRac::strToOpmode(const char *str,
+ const stdAc::opmode_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC"))
+ return stdAc::opmode_t::kAuto;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "STOP"))
+ return stdAc::opmode_t::kOff;
+ else if (!strcmp(str, "COOL") || !strcmp(str, "COOLING"))
+ return stdAc::opmode_t::kCool;
+ else if (!strcmp(str, "HEAT") || !strcmp(str, "HEATING"))
+ return stdAc::opmode_t::kHeat;
+ else if (!strcmp(str, "DRY") || !strcmp(str, "DRYING") ||
+ !strcmp(str, "DEHUMIDIFY"))
+ return stdAc::opmode_t::kDry;
+ else if (!strcmp(str, "FAN") || !strcmp(str, "FANONLY") ||
+ !strcmp(str, "FAN_ONLY"))
+ return stdAc::opmode_t::kFan;
+ else
+ return def;
+}
+
+stdAc::fanspeed_t IRac::strToFanspeed(const char *str,
+ const stdAc::fanspeed_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC"))
+ return stdAc::fanspeed_t::kAuto;
+ else if (!strcmp(str, "MIN") || !strcmp(str, "MINIMUM") ||
+ !strcmp(str, "LOWEST"))
+ return stdAc::fanspeed_t::kMin;
+ else if (!strcmp(str, "LOW"))
+ return stdAc::fanspeed_t::kLow;
+ else if (!strcmp(str, "MED") || !strcmp(str, "MEDIUM") ||
+ !strcmp(str, "MID"))
+ return stdAc::fanspeed_t::kMedium;
+ else if (!strcmp(str, "HIGH") || !strcmp(str, "HI"))
+ return stdAc::fanspeed_t::kHigh;
+ else if (!strcmp(str, "MAX") || !strcmp(str, "MAXIMUM") ||
+ !strcmp(str, "HIGHEST"))
+ return stdAc::fanspeed_t::kMax;
+ else
+ return def;
+}
+
+stdAc::swingv_t IRac::strToSwingV(const char *str,
+ const stdAc::swingv_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC") ||
+ !strcmp(str, "ON") || !strcmp(str, "SWING"))
+ return stdAc::swingv_t::kAuto;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "STOP"))
+ return stdAc::swingv_t::kOff;
+ else if (!strcmp(str, "MIN") || !strcmp(str, "MINIMUM") ||
+ !strcmp(str, "LOWEST") || !strcmp(str, "BOTTOM") ||
+ !strcmp(str, "DOWN"))
+ return stdAc::swingv_t::kLowest;
+ else if (!strcmp(str, "LOW"))
+ return stdAc::swingv_t::kLow;
+ else if (!strcmp(str, "MID") || !strcmp(str, "MIDDLE") ||
+ !strcmp(str, "MED") || !strcmp(str, "MEDIUM") ||
+ !strcmp(str, "CENTRE") || !strcmp(str, "CENTER"))
+ return stdAc::swingv_t::kMiddle;
+ else if (!strcmp(str, "HIGH") || !strcmp(str, "HI"))
+ return stdAc::swingv_t::kHigh;
+ else if (!strcmp(str, "HIGHEST") || !strcmp(str, "MAX") ||
+ !strcmp(str, "MAXIMUM") || !strcmp(str, "TOP") ||
+ !strcmp(str, "UP"))
+ return stdAc::swingv_t::kHighest;
+ else
+ return def;
+}
+
+stdAc::swingh_t IRac::strToSwingH(const char *str,
+ const stdAc::swingh_t def) {
+ if (!strcmp(str, "AUTO") || !strcmp(str, "AUTOMATIC") ||
+ !strcmp(str, "ON") || !strcmp(str, "SWING"))
+ return stdAc::swingh_t::kAuto;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "STOP"))
+ return stdAc::swingh_t::kOff;
+ else if (!strcmp(str, "LEFTMAX") || !strcmp(str, "LEFT MAX") ||
+ !strcmp(str, "MAXLEFT") || !strcmp(str, "MAX LEFT") ||
+ !strcmp(str, "FARLEFT") || !strcmp(str, "FAR LEFT"))
+ return stdAc::swingh_t::kLeftMax;
+ else if (!strcmp(str, "LEFT"))
+ return stdAc::swingh_t::kLeft;
+ else if (!strcmp(str, "MID") || !strcmp(str, "MIDDLE") ||
+ !strcmp(str, "MED") || !strcmp(str, "MEDIUM") ||
+ !strcmp(str, "CENTRE") || !strcmp(str, "CENTER"))
+ return stdAc::swingh_t::kMiddle;
+ else if (!strcmp(str, "RIGHT"))
+ return stdAc::swingh_t::kRight;
+ else if (!strcmp(str, "RIGHTMAX") || !strcmp(str, "RIGHT MAX") ||
+ !strcmp(str, "MAXRIGHT") || !strcmp(str, "MAX RIGHT") ||
+ !strcmp(str, "FARRIGHT") || !strcmp(str, "FAR RIGHT"))
+ return stdAc::swingh_t::kRightMax;
+ else
+ return def;
+}
+
+// Assumes str is upper case or an integer >= 1.
+int16_t IRac::strToModel(const char *str, const int16_t def) {
+ // Fujitsu A/C models
+ if (!strcmp(str, "ARRAH2E")) {
+ return fujitsu_ac_remote_model_t::ARRAH2E;
+ } else if (!strcmp(str, "ARDB1")) {
+ return fujitsu_ac_remote_model_t::ARDB1;
+ // Panasonic A/C families
+ } else if (!strcmp(str, "LKE") || !strcmp(str, "PANASONICLKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicLke;
+ } else if (!strcmp(str, "NKE") || !strcmp(str, "PANASONICNKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicNke;
+ } else if (!strcmp(str, "DKE") || !strcmp(str, "PANASONICDKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicDke;
+ } else if (!strcmp(str, "JKE") || !strcmp(str, "PANASONICJKE")) {
+ return panasonic_ac_remote_model_t::kPanasonicJke;
+ } else if (!strcmp(str, "CKP") || !strcmp(str, "PANASONICCKP")) {
+ return panasonic_ac_remote_model_t::kPanasonicCkp;
+ } else if (!strcmp(str, "RKR") || !strcmp(str, "PANASONICRKR")) {
+ return panasonic_ac_remote_model_t::kPanasonicRkr;
+ // Whirlpool A/C models
+ } else if (!strcmp(str, "DG11J13A") || !strcmp(str, "DG11J104") ||
+ !strcmp(str, "DG11J1-04")) {
+ return whirlpool_ac_remote_model_t::DG11J13A;
+ } else if (!strcmp(str, "DG11J191")) {
+ return whirlpool_ac_remote_model_t::DG11J191;
+ } else {
+ int16_t number = atoi(str);
+ if (number > 0)
+ return number;
+ else
+ return def;
+ }
+}
+
+// Assumes str is upper case.
+bool IRac::strToBool(const char *str, const bool def) {
+ if (!strcmp(str, "ON") || !strcmp(str, "1") || !strcmp(str, "YES") ||
+ !strcmp(str, "TRUE"))
+ return true;
+ else if (!strcmp(str, "OFF") || !strcmp(str, "0") ||
+ !strcmp(str, "NO") || !strcmp(str, "FALSE"))
+ return false;
+ else
+ return def;
+}
diff --git a/lib/IRremoteESP8266-2.6.0/src/IRac.h b/lib/IRremoteESP8266-2.6.0/src/IRac.h
new file mode 100644
index 000000000000..ce8d50507e9e
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/IRac.h
@@ -0,0 +1,248 @@
+#ifndef IRAC_H_
+#define IRAC_H_
+
+// Copyright 2019 David Conran
+
+#ifndef UNIT_TEST
+#include
+#endif
+#ifndef ARDUINO
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "ir_Argo.h"
+#include "ir_Coolix.h"
+#include "ir_Daikin.h"
+#include "ir_Fujitsu.h"
+#include "ir_Gree.h"
+#include "ir_Haier.h"
+#include "ir_Hitachi.h"
+#include "ir_Kelvinator.h"
+#include "ir_Midea.h"
+#include "ir_Mitsubishi.h"
+#include "ir_MitsubishiHeavy.h"
+#include "ir_Panasonic.h"
+#include "ir_Samsung.h"
+#include "ir_Tcl.h"
+#include "ir_Teco.h"
+#include "ir_Toshiba.h"
+#include "ir_Trotec.h"
+#include "ir_Vestel.h"
+#include "ir_Whirlpool.h"
+
+class IRac {
+ public:
+ explicit IRac(uint8_t pin);
+ static bool isProtocolSupported(const decode_type_t protocol);
+ bool sendAc(const decode_type_t vendor, const int16_t model,
+ const bool power, const stdAc::opmode_t mode, const float degrees,
+ const bool celsius, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+ const bool quiet, const bool turbo, const bool econo,
+ const bool light, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep = -1,
+ const int16_t clock = -1);
+
+ static bool strToBool(const char *str, const bool def = false);
+ static int16_t strToModel(const char *str, const int16_t def = -1);
+ static stdAc::opmode_t strToOpmode(
+ const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto);
+ static stdAc::fanspeed_t strToFanspeed(
+ const char *str,
+ const stdAc::fanspeed_t def = stdAc::fanspeed_t::kAuto);
+ static stdAc::swingv_t strToSwingV(
+ const char *str, const stdAc::swingv_t def = stdAc::swingv_t::kOff);
+ static stdAc::swingh_t strToSwingH(
+ const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff);
+#ifndef UNIT_TEST
+
+ private:
+#endif
+ uint8_t _pin;
+#if SEND_ARGO
+ void argo(IRArgoAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const int16_t sleep = -1);
+#endif // SEND_ARGO
+#if SEND_COOLIX
+ void coolix(IRCoolixAC *ac,
+ const bool on, 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 turbo, const bool light, const bool clean,
+ const int16_t sleep = -1);
+#endif // SEND_COOLIX
+#if SEND_DAIKIN
+ void daikin(IRDaikinESP *ac,
+ const bool on, 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 quiet, const bool turbo, const bool econo,
+ const bool clean);
+#endif // SEND_DAIKIN
+#if SEND_DAIKIN2
+ void daikin2(IRDaikin2 *ac,
+ const bool on, 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 quiet, const bool turbo, const bool light,
+ const bool econo, const bool filter, const bool clean,
+ const bool beep, const int16_t sleep = -1,
+ const int16_t clock = -1);
+#endif // SEND_DAIKIN2
+#if SEND_DAIKIN216
+void daikin216(IRDaikin216 *ac,
+ const bool on, 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 quiet);
+#endif // SEND_DAIKIN216
+#if SEND_FUJITSU_AC
+ void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
+ const bool on, 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 quiet);
+#endif // SEND_FUJITSU_AC
+#if SEND_GREE
+ void gree(IRGreeAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light, const bool clean,
+ const int16_t sleep = -1);
+#endif // SEND_GREE
+#if SEND_HAIER_AC
+ void haier(IRHaierAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool filter, const int16_t sleep = -1,
+ const int16_t clock = -1);
+#endif // SEND_HAIER_AC
+#if SEND_HAIER_AC_YRW02
+ void haierYrwo2(IRHaierACYRW02 *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv,
+ const bool turbo, const bool filter,
+ const int16_t sleep = -1);
+#endif // SEND_HAIER_AC_YRW02
+#if SEND_HITACHI_AC
+ void hitachi(IRHitachiAc *ac,
+ const bool on, const stdAc::opmode_t mode,
+ const float degrees, const stdAc::fanspeed_t fan,
+ const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
+#endif // SEND_HITACHI_AC
+#if SEND_KELVINATOR
+ void kelvinator(IRKelvinatorAC *ac,
+ const bool on, 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 quiet, const bool turbo, const bool light,
+ const bool filter, const bool clean);
+#endif // SEND_KELVINATOR
+#if SEND_MIDEA
+ void midea(IRMideaAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const int16_t sleep = -1);
+#endif // SEND_MIDEA
+#if SEND_MITSUBISHI_AC
+ void mitsubishi(IRMitsubishiAC *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 int16_t clock = -1);
+#endif // SEND_MITSUBISHI_AC
+#if SEND_MITSUBISHIHEAVY
+ void mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac,
+ const bool on, 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 turbo, const bool econo, const bool clean);
+ void mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac,
+ const bool on, 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 quiet, const bool turbo, const bool econo,
+ const bool filter, const bool clean,
+ const int16_t sleep = -1);
+#endif // SEND_MITSUBISHIHEAVY
+#if SEND_PANASONIC_AC
+ void panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
+ const bool on, 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 quiet, const bool turbo, const int16_t clock = -1);
+#endif // SEND_PANASONIC_AC
+#if SEND_SAMSUNG_AC
+ void samsung(IRSamsungAc *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 bool clean,
+ const bool beep, const bool sendOnOffHack = true);
+#endif // SEND_SAMSUNG_AC
+#if SEND_TCL112AC
+ void tcl112(IRTcl112Ac *ac,
+ const bool on, 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 turbo, const bool light, const bool econo,
+ const bool filter);
+#endif // SEND_TCL112AC
+#if SEND_TECO
+ void teco(IRTecoAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const int16_t sleep = -1);
+#endif // SEND_TECO
+#if SEND_TOSHIBA_AC
+ void toshiba(IRToshibaAC *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan);
+#endif // SEND_TOSHIBA_AC
+#if SEND_TROTEC
+ void trotec(IRTrotecESP *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const int16_t sleep = -1);
+#endif // SEND_TROTEC
+#if SEND_VESTEL_AC
+ void vestel(IRVestelAc *ac,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool filter,
+ const int16_t sleep = -1, const int16_t clock = -1,
+ const bool sendNormal = true);
+#endif // SEND_VESTEL_AC
+#if SEND_WHIRLPOOL_AC
+ void whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model,
+ const bool on, const stdAc::opmode_t mode, const float degrees,
+ const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+ const bool turbo, const bool light,
+ const int16_t sleep = -1, const int16_t clock = -1);
+#endif // SEND_WHIRLPOOL_AC
+}; // IRac class
+
+// Structure to hold a common A/C state.
+typedef struct {
+ decode_type_t protocol;
+ int16_t model;
+ bool power;
+ stdAc::opmode_t mode;
+ float degrees;
+ bool celsius;
+ stdAc::fanspeed_t fanspeed;
+ stdAc::swingv_t swingv;
+ stdAc::swingh_t swingh;
+ bool quiet;
+ bool turbo;
+ bool econo;
+ bool light;
+ bool filter;
+ bool clean;
+ bool beep;
+ int16_t sleep;
+ int16_t clock;
+} commonAcState_t;
+#endif // IRAC_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.cpp b/lib/IRremoteESP8266-2.6.0/src/IRrecv.cpp
similarity index 95%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRrecv.cpp
rename to lib/IRremoteESP8266-2.6.0/src/IRrecv.cpp
index b2c98439694b..eac86808415d 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/IRrecv.cpp
@@ -364,6 +364,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting SAMSUNG decode");
if (decodeSAMSUNG(results)) return true;
#endif
+#if DECODE_SAMSUNG36
+ DPRINTLN("Attempting Samsung36 decode");
+ if (decodeSamsung36(results)) return true;
+#endif
#if DECODE_WHYNTER
DPRINTLN("Attempting Whynter decode");
if (decodeWhynter(results)) return true;
@@ -394,6 +398,14 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting Daikin decode");
if (decodeDaikin(results)) return true;
#endif
+#if DECODE_DAIKIN2
+ DPRINTLN("Attempting Daikin2 decode");
+ if (decodeDaikin2(results)) return true;
+#endif
+#if DECODE_DAIKIN216
+ DPRINTLN("Attempting Daikin216 decode");
+ if (decodeDaikin216(results)) return true;
+#endif
#if DECODE_TOSHIBA_AC
DPRINTLN("Attempting Toshiba AC decode");
if (decodeToshibaAC(results)) return true;
@@ -489,6 +501,28 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting MWM decode");
if (decodeMWM(results)) return true;
#endif
+#if DECODE_VESTEL_AC
+ DPRINTLN("Attempting Vestel AC decode");
+ if (decodeVestelAc(results)) return true;
+#endif
+#if DECODE_TCL112AC
+ DPRINTLN("Attempting TCL112AC decode");
+ if (decodeTcl112Ac(results)) return true;
+#endif
+#if DECODE_TECO
+ DPRINTLN("Attempting Teco decode");
+ if (decodeTeco(results)) return true;
+#endif
+#if DECODE_LEGOPF
+ DPRINTLN("Attempting LEGOPF decode");
+ if (decodeLegoPf(results)) return true;
+#endif
+#if DECODE_MITSUBISHIHEAVY
+ DPRINTLN("Attempting MITSUBISHIHEAVY (152 bit) decode");
+ if (decodeMitsubishiHeavy(results, kMitsubishiHeavy152Bits)) return true;
+ DPRINTLN("Attempting MITSUBISHIHEAVY (88 bit) decode");
+ if (decodeMitsubishiHeavy(results, kMitsubishiHeavy88Bits)) return true;
+#endif
#if DECODE_HASH
// decodeHash returns a hash on any input.
// Thus, it needs to be last in the list.
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.h b/lib/IRremoteESP8266-2.6.0/src/IRrecv.h
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRrecv.h
rename to lib/IRremoteESP8266-2.6.0/src/IRrecv.h
index c0f5e781aa90..0659f093eb03 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRrecv.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRrecv.h
@@ -181,6 +181,10 @@ class IRrecv {
uint16_t nbits = kMitsubishiACBits,
bool strict = false);
#endif
+#if DECODE_MITSUBISHIHEAVY
+ bool decodeMitsubishiHeavy(decode_results *results, const uint16_t nbits,
+ const bool strict = true);
+#endif
#if (DECODE_RC5 || DECODE_R6 || DECODE_LASERTAG || DECODE_MWM)
int16_t getRClevel(decode_results *results, uint16_t *offset, uint16_t *used,
uint16_t bitTime, uint8_t tolerance = kTolerance,
@@ -216,6 +220,11 @@ class IRrecv {
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = kSamsungBits,
bool strict = true);
#endif
+#if DECODE_SAMSUNG
+ bool decodeSamsung36(decode_results *results,
+ const uint16_t nbits = kSamsung36Bits,
+ const bool strict = true);
+#endif
#if DECODE_SAMSUNG_AC
bool decodeSamsungAC(decode_results *results, uint16_t nbits = kSamsungAcBits,
bool strict = true);
@@ -257,8 +266,17 @@ class IRrecv {
uint16_t nbits = kKelvinatorBits, bool strict = true);
#endif
#if DECODE_DAIKIN
- bool decodeDaikin(decode_results *results, uint16_t nbits = kDaikinRawBits,
- bool strict = true);
+ bool decodeDaikin(decode_results *results, const uint16_t nbits = kDaikinBits,
+ const bool strict = true);
+#endif
+#if DECODE_DAIKIN2
+ bool decodeDaikin2(decode_results *results, uint16_t nbits = kDaikin2Bits,
+ bool strict = true);
+#endif
+#if DECODE_DAIKIN216
+ bool decodeDaikin216(decode_results *results,
+ const uint16_t nbits = kDaikin216Bits,
+ const bool strict = true);
#endif
#if DECODE_TOSHIBA_AC
bool decodeToshibaAC(decode_results *results,
@@ -330,6 +348,22 @@ class IRrecv {
bool decodeMWM(decode_results *results, uint16_t nbits = 24,
bool strict = true);
#endif
+#if DECODE_VESTEL_AC
+ bool decodeVestelAc(decode_results *results, uint16_t nbits = kVestelAcBits,
+ bool strict = true);
+#endif
+#if DECODE_TCL112AC
+ bool decodeTcl112Ac(decode_results *results, uint16_t nbits = kTcl112AcBits,
+ bool strict = true);
+#endif
+#if DECODE_TECO
+ bool decodeTeco(decode_results *results, uint16_t nbits = kTecoBits,
+ bool strict = false);
+#endif
+#if DECODE_LEGOPF
+ bool decodeLegoPf(decode_results *results, const uint16_t nbits = kLegoPfBits,
+ const bool strict = true);
+#endif
};
#endif // IRRECV_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.6.0/src/IRremoteESP8266.h
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRremoteESP8266.h
rename to lib/IRremoteESP8266-2.6.0/src/IRremoteESP8266.h
index e228cbcb0a4f..b532cb1c0ded 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRremoteESP8266.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRremoteESP8266.h
@@ -34,6 +34,8 @@
* Fujitsu A/C code added by jonnygraham
* Trotec AC code by stufisher
* Carrier & Haier AC code by crankyoldgit
+ * Vestel AC code by Erdem U. Altınyurt
+ * Teco AC code by Fabien Valthier (hcoohb)
*
* GPL license, all text above must be included in any redistribution
****************************************************/
@@ -48,7 +50,7 @@
#endif
// Library Version
-#define _IRREMOTEESP8266_VERSION_ "2.5.2"
+#define _IRREMOTEESP8266_VERSION_ "2.6.0"
// Supported IR protocols
// Each protocol you include costs memory and, during decode, costs time
// Disable (set to false) all the protocols you do not need/want!
@@ -86,6 +88,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
+#define DECODE_SAMSUNG36 true
+#define SEND_SAMSUNG36 true
+
#define DECODE_SAMSUNG_AC true
#define SEND_SAMSUNG_AC true
@@ -199,6 +204,27 @@
#define DECODE_PIONEER true
#define SEND_PIONEER true
+
+#define DECODE_DAIKIN2 true
+#define SEND_DAIKIN2 true
+
+#define DECODE_VESTEL_AC true
+#define SEND_VESTEL_AC true
+
+#define DECODE_TECO true
+#define SEND_TECO true
+
+#define DECODE_TCL112AC true
+#define SEND_TCL112AC true
+
+#define DECODE_LEGOPF true
+#define SEND_LEGOPF true
+
+#define DECODE_MITSUBISHIHEAVY true
+#define SEND_MITSUBISHIHEAVY true
+
+#define DECODE_DAIKIN216 true
+#define SEND_DAIKIN216 true
*/
// Tasmota supported protocols (less protocols is less code size)
@@ -233,6 +259,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
+#define DECODE_SAMSUNG36 false
+#define SEND_SAMSUNG36 false
+
#define DECODE_SAMSUNG_AC false
#define SEND_SAMSUNG_AC false
@@ -347,12 +376,35 @@
#define DECODE_PIONEER false
#define SEND_PIONEER false
+#define DECODE_DAIKIN2 false
+#define SEND_DAIKIN2 false
+
+#define DECODE_VESTEL_AC false
+#define SEND_VESTEL_AC false
+
+#define DECODE_TECO false
+#define SEND_TECO false
+
+#define DECODE_TCL112AC false
+#define SEND_TCL112AC false
+
+#define DECODE_LEGOPF false
+#define SEND_LEGOPF false
+
+#define DECODE_MITSUBISHIHEAVY false
+#define SEND_MITSUBISHIHEAVY false
+
+#define DECODE_DAIKIN216 false
+#define SEND_DAIKIN216 false
+
#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 || \
DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 || DECODE_HAIER_AC_YRW02 || \
DECODE_WHIRLPOOL_AC || DECODE_SAMSUNG_AC || DECODE_ELECTRA_AC || \
- DECODE_PANASONIC_AC || DECODE_MWM)
+ DECODE_PANASONIC_AC || DECODE_MWM || DECODE_DAIKIN2 || \
+ DECODE_VESTEL_AC || DECODE_TCL112AC || DECODE_MITSUBISHIHEAVY || \
+ DECODE_DAIKIN216)
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
#else
#define DECODE_AC false // We don't need that infrastructure.
@@ -376,54 +428,65 @@ enum decode_type_t {
RC6,
NEC,
SONY,
- PANASONIC,
+ PANASONIC, // (5)
JVC,
SAMSUNG,
WHYNTER,
AIWA_RC_T501,
- LG,
+ LG, // (10)
SANYO,
MITSUBISHI,
DISH,
SHARP,
- COOLIX,
+ COOLIX, // (15)
DAIKIN,
DENON,
KELVINATOR,
SHERWOOD,
- MITSUBISHI_AC,
+ MITSUBISHI_AC, // (20)
RCMM,
SANYO_LC7461,
RC5X,
GREE,
- PRONTO, // Technically not a protocol, but an encoding.
+ PRONTO, // Technically not a protocol, but an encoding. (25)
NEC_LIKE,
ARGO,
TROTEC,
NIKAI,
- RAW, // Technically not a protocol, but an encoding.
+ RAW, // Technically not a protocol, but an encoding. (30)
GLOBALCACHE, // Technically not a protocol, but an encoding.
TOSHIBA_AC,
FUJITSU_AC,
MIDEA,
- MAGIQUEST,
+ MAGIQUEST, // (35)
LASERTAG,
CARRIER_AC,
HAIER_AC,
MITSUBISHI2,
- HITACHI_AC,
+ HITACHI_AC, // (40)
HITACHI_AC1,
HITACHI_AC2,
GICABLE,
HAIER_AC_YRW02,
- WHIRLPOOL_AC,
+ WHIRLPOOL_AC, // (45)
SAMSUNG_AC,
LUTRON,
ELECTRA_AC,
PANASONIC_AC,
- PIONEER,
+ PIONEER, // (50)
LG2,
MWM,
+ DAIKIN2,
+ VESTEL_AC,
+ TECO, // (55)
+ SAMSUNG36,
+ TCL112AC,
+ LEGOPF,
+ MITSUBISHI_HEAVY_88,
+ MITSUBISHI_HEAVY_152, // 60
+ DAIKIN216,
+ // Add new entries before this one, and update it to point to the last entry.
+ kLastDecodeType = DAIKIN216,
};
// Message lengths & required repeat values
@@ -433,13 +496,22 @@ const uint16_t kSingleRepeat = 1;
const uint16_t kAiwaRcT501Bits = 15;
const uint16_t kAiwaRcT501MinRepeats = kSingleRepeat;
const uint16_t kArgoStateLength = 12;
+const uint16_t kArgoDefaultRepeat = kNoRepeat;
const uint16_t kCoolixBits = 24;
+const uint16_t kCoolixDefaultRepeat = 1;
const uint16_t kCarrierAcBits = 32;
const uint16_t kCarrierAcMinRepeat = kNoRepeat;
-// Daikin has a lot of static stuff that is discarded
-const uint16_t kDaikinRawBits = 583;
-const uint16_t kDaikinStateLength = 27;
+const uint16_t kDaikinStateLength = 35;
const uint16_t kDaikinBits = kDaikinStateLength * 8;
+const uint16_t kDaikinStateLengthShort = kDaikinStateLength - 8;
+const uint16_t kDaikinBitsShort = kDaikinStateLengthShort * 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 kDaikin216StateLength = 27;
+const uint16_t kDaikin216Bits = kDaikin216StateLength * 8;
+const uint16_t kDaikin216DefaultRepeat = kNoRepeat;
const uint16_t kDenonBits = 15;
const uint16_t kDenonLegacyBits = 14;
const uint16_t kDishBits = 16;
@@ -455,12 +527,16 @@ const uint16_t kGicableBits = 16;
const uint16_t kGicableMinRepeat = kSingleRepeat;
const uint16_t kGreeStateLength = 8;
const uint16_t kGreeBits = kGreeStateLength * 8;
+const uint16_t kGreeDefaultRepeat = kNoRepeat;
const uint16_t kHaierACStateLength = 9;
const uint16_t kHaierACBits = kHaierACStateLength * 8;
+const uint16_t kHaierAcDefaultRepeat = kNoRepeat;
const uint16_t kHaierACYRW02StateLength = 14;
const uint16_t kHaierACYRW02Bits = kHaierACYRW02StateLength * 8;
+const uint16_t kHaierAcYrw02DefaultRepeat = kNoRepeat;
const uint16_t kHitachiAcStateLength = 28;
const uint16_t kHitachiAcBits = kHitachiAcStateLength * 8;
+const uint16_t kHitachiAcDefaultRepeat = kNoRepeat;
const uint16_t kHitachiAc1StateLength = 13;
const uint16_t kHitachiAc1Bits = kHitachiAc1StateLength * 8;
const uint16_t kHitachiAc2StateLength = 53;
@@ -468,8 +544,11 @@ const uint16_t kHitachiAc2Bits = kHitachiAc2StateLength * 8;
const uint16_t kJvcBits = 16;
const uint16_t kKelvinatorStateLength = 16;
const uint16_t kKelvinatorBits = kKelvinatorStateLength * 8;
+const uint16_t kKelvinatorDefaultRepeat = kNoRepeat;
const uint16_t kLasertagBits = 13;
const uint16_t kLasertagMinRepeat = kNoRepeat;
+const uint16_t kLegoPfBits = 16;
+const uint16_t kLegoPfMinRepeat = kNoRepeat;
const uint16_t kLgBits = 28;
const uint16_t kLg32Bits = 32;
const uint16_t kLutronBits = 35;
@@ -483,6 +562,12 @@ const uint16_t kMitsubishiMinRepeat = kSingleRepeat;
const uint16_t kMitsubishiACStateLength = 18;
const uint16_t kMitsubishiACBits = kMitsubishiACStateLength * 8;
const uint16_t kMitsubishiACMinRepeat = kSingleRepeat;
+const uint16_t kMitsubishiHeavy88StateLength = 11;
+const uint16_t kMitsubishiHeavy88Bits = kMitsubishiHeavy88StateLength * 8;
+const uint16_t kMitsubishiHeavy88MinRepeat = kNoRepeat;
+const uint16_t kMitsubishiHeavy152StateLength = 19;
+const uint16_t kMitsubishiHeavy152Bits = kMitsubishiHeavy152StateLength * 8;
+const uint16_t kMitsubishiHeavy152MinRepeat = kNoRepeat;
const uint16_t kNikaiBits = 24;
const uint16_t kNECBits = 32;
const uint16_t kPanasonicBits = 48;
@@ -491,6 +576,7 @@ const uint16_t kPanasonicAcStateLength = 27;
const uint16_t kPanasonicAcStateShortLength = 16;
const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8;
const uint16_t kPanasonicAcShortBits = kPanasonicAcStateShortLength * 8;
+const uint16_t kPanasonicAcDefaultRepeat = kNoRepeat;
const uint16_t kPioneerBits = 64;
const uint16_t kProntoMinLength = 6;
const uint16_t kRC5RawBits = 14;
@@ -500,10 +586,12 @@ const uint16_t kRC6Mode0Bits = 20; // Excludes the 'start' bit.
const uint16_t kRC6_36Bits = 36; // Excludes the 'start' bit.
const uint16_t kRCMMBits = 24;
const uint16_t kSamsungBits = 32;
+const uint16_t kSamsung36Bits = 36;
const uint16_t kSamsungAcStateLength = 14;
const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8;
const uint16_t kSamsungAcExtendedStateLength = 21;
const uint16_t kSamsungAcExtendedBits = kSamsungAcExtendedStateLength * 8;
+const uint16_t kSamsungAcDefaultRepeat = kNoRepeat;
const uint16_t kSanyoSA8650BBits = 12;
const uint16_t kSanyoLC7461AddressBits = 13;
const uint16_t kSanyoLC7461CommandBits = 8;
@@ -519,13 +607,22 @@ const uint16_t kSony15Bits = 15;
const uint16_t kSony20Bits = 20;
const uint16_t kSonyMinBits = 12;
const uint16_t kSonyMinRepeat = 2;
+const uint16_t kTcl112AcStateLength = 14;
+const uint16_t kTcl112AcBits = kTcl112AcStateLength * 8;
+const uint16_t kTcl112AcDefaultRepeat = kNoRepeat;
+const uint16_t kTecoBits = 35;
+const uint16_t kTecoDefaultRepeat = kNoRepeat;
const uint16_t kToshibaACStateLength = 9;
const uint16_t kToshibaACBits = kToshibaACStateLength * 8;
const uint16_t kToshibaACMinRepeat = kSingleRepeat;
const uint16_t kTrotecStateLength = 9;
+const uint16_t kTrotecDefaultRepeat = kNoRepeat;
const uint16_t kWhirlpoolAcStateLength = 21;
const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8;
+const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat;
const uint16_t kWhynterBits = 32;
+const uint8_t kVestelAcBits = 56;
+
// Legacy defines. (Deprecated)
#define AIWA_RC_T501_BITS kAiwaRcT501Bits
@@ -598,4 +695,14 @@ const uint16_t kWhynterBits = 32;
#define DPRINTLN(x)
#endif // DEBUG
+#ifdef UNIT_TEST
+#ifndef F
+// Create a no-op F() macro so the code base still compiles outside of the
+// Arduino framework. Thus we can safely use the Arduino 'F()' macro through-out
+// the code base. That macro stores constants in Flash (PROGMEM) memory.
+// See: https://github.com/markszabo/IRremoteESP8266/issues/667
+#define F(x) x
+#endif // F
+#endif // UNIT_TEST
+
#endif // IRREMOTEESP8266_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.cpp b/lib/IRremoteESP8266-2.6.0/src/IRsend.cpp
similarity index 92%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRsend.cpp
rename to lib/IRremoteESP8266-2.6.0/src/IRsend.cpp
index 96f95172da0f..22c0c874b474 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/IRsend.cpp
@@ -1,6 +1,6 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
-// Copyright 2017 David Conran
+// Copyright 2017,2019 David Conran
#include "IRsend.h"
#ifndef UNIT_TEST
@@ -110,6 +110,9 @@ void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
}
if (freq < 1000) // Were we given kHz? Supports the old call usage.
freq *= 1000;
+#ifdef UNIT_TEST
+ _freq_unittest = freq;
+#endif // UNIT_TEST
uint32_t period = calcUSecPeriod(freq);
// Nr. of uSeconds the LED will be on per pulse.
onTimePeriod = (period * _dutycycle) / kDutyMax;
@@ -488,27 +491,34 @@ void IRsend::sendRaw(uint16_t buf[], uint16_t len, uint16_t hz) {
}
#endif // SEND_RAW
-#ifndef UNIT_TEST
-void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
+// Send a simple (up to 64 bits) IR message of a given type.
+// An unknown/unsupported type will do nothing.
+// Args:
+// type: Protocol number/type of the message you want to send.
+// data: The data you want to send (up to 64 bits).
+// nbits: How many bits long the message is to be.
+// Returns:
+// bool: True if it is a type we can attempt to send, false if not.
+bool IRsend::send(decode_type_t type, uint64_t data, uint16_t nbits) {
switch (type) {
-#if SEND_NEC
- case NEC:
- sendNEC(data, nbits);
+#if SEND_AIWA_RC_T501
+ case AIWA_RC_T501:
+ sendAiwaRCT501(data, nbits);
break;
#endif
-#if SEND_SONY
- case SONY:
- sendSony(data, nbits);
+#if SEND_CARRIER_AC
+ case CARRIER_AC:
+ sendCarrierAC(data, nbits);
break;
#endif
-#if SEND_RC5
- case RC5:
- sendRC5(data, nbits);
+#if SEND_COOLIX
+ case COOLIX:
+ sendCOOLIX(data, nbits);
break;
#endif
-#if SEND_RC6
- case RC6:
- sendRC6(data, nbits);
+#if SEND_DENON
+ case DENON:
+ sendDenon(data, nbits);
break;
#endif
#if SEND_DISH
@@ -516,44 +526,93 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendDISH(data, nbits);
break;
#endif
+#if SEND_GICABLE
+ case GICABLE:
+ sendGICable(data, nbits);
+ break;
+#endif
+#if SEND_GREE
+ case GREE:
+ sendGree(data, nbits);
+ break;
+#endif
#if SEND_JVC
case JVC:
sendJVC(data, nbits);
break;
#endif
-#if SEND_SAMSUNG
- case SAMSUNG:
- sendSAMSUNG(data, nbits);
+#if SEND_LASERTAG
+ case LASERTAG:
+ sendLasertag(data, nbits);
+ break;
+#endif
+#if SEND_LEGOPF
+ case LEGOPF:
+ sendLegoPf(data, nbits);
break;
#endif
#if SEND_LG
case LG:
sendLG(data, nbits);
break;
-#endif
-#if SEND_LG
case LG2:
sendLG2(data, nbits);
break;
#endif
-#if SEND_WHYNTER
- case WHYNTER:
- sendWhynter(data, nbits);
+#if SEND_LUTRON
+ case LUTRON:
+ sendLutron(data, nbits);
break;
#endif
-#if SEND_COOLIX
- case COOLIX:
- sendCOOLIX(data, nbits);
+#if SEND_MAGIQUEST
+ case MAGIQUEST:
+ sendMagiQuest(data, nbits);
break;
#endif
-#if SEND_DENON
- case DENON:
- sendDenon(data, nbits);
+#if SEND_MIDEA
+ case MIDEA:
+ sendMidea(data, nbits);
break;
#endif
-#if SEND_SHERWOOD
- case SHERWOOD:
- sendSherwood(data, nbits);
+#if SEND_MITSUBISHI
+ case MITSUBISHI:
+ sendMitsubishi(data, nbits);
+ break;
+#endif
+#if SEND_MITSUBISHI2
+ case MITSUBISHI2:
+ sendMitsubishi2(data, nbits);
+ break;
+#endif
+#if SEND_NIKAI
+ case NIKAI:
+ sendNikai(data, nbits);
+ break;
+#endif
+#if SEND_NEC
+ case NEC:
+ case NEC_LIKE:
+ sendNEC(data, nbits);
+ break;
+#endif
+#if SEND_PANASONIC
+ case PANASONIC:
+ sendPanasonic64(data, nbits);
+ break;
+#endif
+#if SEND_PIONEER
+ case PIONEER:
+ sendPioneer(data, nbits);
+ break;
+#endif
+#if SEND_RC5
+ case RC5:
+ sendRC5(data, nbits);
+ break;
+#endif
+#if SEND_RC6
+ case RC6:
+ sendRC6(data, nbits);
break;
#endif
#if SEND_RCMM
@@ -561,14 +620,19 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendRCMM(data, nbits);
break;
#endif
-#if SEND_MITSUBISHI
- case MITSUBISHI:
- sendMitsubishi(data, nbits);
+#if SEND_SAMSUNG
+ case SAMSUNG:
+ sendSAMSUNG(data, nbits);
break;
#endif
-#if SEND_MITSUBISHI2
- case MITSUBISHI2:
- sendMitsubishi2(data, nbits);
+#if SEND_SAMSUNG36
+ case SAMSUNG36:
+ sendSamsung36(data, nbits);
+ break;
+#endif
+#if SEND_SANYO
+ case SANYO_LC7461:
+ sendSanyoLC7461(data, nbits);
break;
#endif
#if SEND_SHARP
@@ -576,26 +640,33 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendSharpRaw(data, nbits);
break;
#endif
-#if SEND_AIWA_RC_T501
- case AIWA_RC_T501:
- sendAiwaRCT501(data, nbits);
+#if SEND_SHERWOOD
+ case SHERWOOD:
+ sendSherwood(data, nbits);
break;
#endif
-#if SEND_MIDEA
- case MIDEA:
- sendMidea(data, nbits);
+#if SEND_SONY
+ case SONY:
+ sendSony(data, nbits);
break;
#endif
-#if SEND_GICABLE
- case GICABLE:
- sendGICable(data, nbits);
+#if SEND_TECO
+ case TECO:
+ sendTeco(data, nbits);
break;
#endif
-#if SEND_PIONEER
- case PIONEER:
- sendPioneer(data, nbits);
+#if SEND_VESTEL_AC
+ case VESTEL_AC:
+ sendVestelAc(data, nbits);
break;
#endif
+#if SEND_WHYNTER
+ case WHYNTER:
+ sendWhynter(data, nbits);
+ break;
+#endif
+ default:
+ return false;
}
+ return true;
}
-#endif
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.h b/lib/IRremoteESP8266-2.6.0/src/IRsend.h
similarity index 77%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRsend.h
rename to lib/IRremoteESP8266-2.6.0/src/IRsend.h
index 8e2dc248e178..b065f6582302 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRsend.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRsend.h
@@ -28,6 +28,49 @@ const uint8_t kDutyMax = 100; // Percentage
// delayMicroseconds() is only accurate to 16383us.
// Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
const uint16_t kMaxAccurateUsecDelay = 16383;
+// Usecs to wait between messages we don't know the proper gap time.
+const uint32_t kDefaultMessageGap = 100000;
+
+
+namespace stdAc {
+ enum class opmode_t {
+ kOff = -1,
+ kAuto = 0,
+ kCool = 1,
+ kHeat = 2,
+ kDry = 3,
+ kFan = 4,
+ };
+
+ enum class fanspeed_t {
+ kAuto = 0,
+ kMin = 1,
+ kLow = 2,
+ kMedium = 3,
+ kHigh = 4,
+ kMax = 5,
+ };
+
+ enum class swingv_t {
+ kOff = -1,
+ kAuto = 0,
+ kHighest = 1,
+ kHigh = 2,
+ kMiddle = 3,
+ kLow = 4,
+ kLowest = 5,
+ };
+
+ enum class swingh_t {
+ kOff = -1,
+ kAuto = 0, // a.k.a. On.
+ kLeftMax = 1,
+ kLeft = 2,
+ kMiddle = 3,
+ kRight = 4,
+ kRightMax = 5,
+ };
+}; // namespace stdAc
// Classes
class IRsend {
@@ -66,7 +109,7 @@ class IRsend {
const uint8_t *dataptr, const uint16_t nbytes,
const uint16_t frequency, const bool MSBfirst,
const uint16_t repeat, const uint8_t dutycycle);
- void send(uint16_t type, uint64_t data, uint16_t nbits);
+ bool send(decode_type_t type, uint64_t data, uint16_t nbits);
#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO)
void sendNEC(uint64_t data, uint16_t nbits = kNECBits,
uint16_t repeat = kNoRepeat);
@@ -92,10 +135,14 @@ class IRsend {
uint16_t repeat = kNoRepeat);
uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command);
#endif
+#if SEND_SAMSUNG36
+ void sendSamsung36(const uint64_t data, const uint16_t nbits = kSamsung36Bits,
+ const uint16_t repeat = kNoRepeat);
+#endif
#if SEND_SAMSUNG_AC
- void sendSamsungAC(unsigned char data[],
- uint16_t nbytes = kSamsungAcStateLength,
- uint16_t repeat = kNoRepeat);
+ void sendSamsungAC(const unsigned char data[],
+ const uint16_t nbytes = kSamsungAcStateLength,
+ const uint16_t repeat = kSamsungAcDefaultRepeat);
#endif
#if SEND_LG
void sendLG(uint64_t data, uint16_t nbits = kLgBits,
@@ -166,7 +213,7 @@ class IRsend {
#endif
#if SEND_COOLIX
void sendCOOLIX(uint64_t data, uint16_t nbits = kCoolixBits,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kCoolixDefaultRepeat);
#endif
#if SEND_WHYNTER
void sendWhynter(uint64_t data, uint16_t nbits = kWhynterBits,
@@ -185,6 +232,16 @@ class IRsend {
uint16_t nbytes = kMitsubishiACStateLength,
uint16_t repeat = kMitsubishiACMinRepeat);
#endif
+#if SEND_MITSUBISHIHEAVY
+ void sendMitsubishiHeavy88(
+ const unsigned char data[],
+ const uint16_t nbytes = kMitsubishiHeavy88StateLength,
+ const uint16_t repeat = kMitsubishiHeavy88MinRepeat);
+ void sendMitsubishiHeavy152(
+ const unsigned char data[],
+ const uint16_t nbytes = kMitsubishiHeavy152StateLength,
+ const uint16_t repeat = kMitsubishiHeavy152MinRepeat);
+#endif
#if SEND_FUJITSU_AC
void sendFujitsuAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat = kFujitsuAcMinRepeat);
@@ -195,12 +252,21 @@ class IRsend {
#if SEND_KELVINATOR
void sendKelvinator(unsigned char data[],
uint16_t nbytes = kKelvinatorStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kKelvinatorDefaultRepeat);
#endif
#if SEND_DAIKIN
- void sendDaikin(unsigned char data[], uint16_t nbytes = kDaikinStateLength,
- uint16_t repeat = kNoRepeat);
- void sendDaikinGapHeader();
+ void sendDaikin(const unsigned char data[],
+ const uint16_t nbytes = kDaikinStateLength,
+ const uint16_t repeat = kDaikinDefaultRepeat);
+#endif
+#if SEND_DAIKIN2
+ void sendDaikin2(unsigned char data[], uint16_t nbytes = kDaikin2StateLength,
+ uint16_t repeat = kDaikin2DefaultRepeat);
+#endif
+#if SEND_DAIKIN216
+ void sendDaikin216(const unsigned char data[],
+ const uint16_t nbytes = kDaikin216StateLength,
+ const uint16_t repeat = kDaikin216DefaultRepeat);
#endif
#if SEND_AIWA_RC_T501
void sendAiwaRCT501(uint64_t data, uint16_t nbits = kAiwaRcT501Bits,
@@ -208,20 +274,20 @@ class IRsend {
#endif
#if SEND_GREE
void sendGree(uint64_t data, uint16_t nbits = kGreeBits,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kGreeDefaultRepeat);
void sendGree(uint8_t data[], uint16_t nbytes = kGreeStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kGreeDefaultRepeat);
#endif
#if SEND_PRONTO
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
#endif
#if SEND_ARGO
void sendArgo(unsigned char data[], uint16_t nbytes = kArgoStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kArgoDefaultRepeat);
#endif
#if SEND_TROTEC
void sendTrotec(unsigned char data[], uint16_t nbytes = kTrotecStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kTrotecDefaultRepeat);
#endif
#if SEND_NIKAI
void sendNikai(uint64_t data, uint16_t nbits = kNikaiBits,
@@ -251,17 +317,17 @@ class IRsend {
#endif
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02)
void sendHaierAC(unsigned char data[], uint16_t nbytes = kHaierACStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kHaierAcDefaultRepeat);
#endif
#if SEND_HAIER_AC_YRW02
void sendHaierACYRW02(unsigned char data[],
uint16_t nbytes = kHaierACYRW02StateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kHaierAcYrw02DefaultRepeat);
#endif
#if SEND_HITACHI_AC
void sendHitachiAC(unsigned char data[],
uint16_t nbytes = kHitachiAcStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kHitachiAcDefaultRepeat);
#endif
#if SEND_HITACHI_AC1
void sendHitachiAC1(unsigned char data[],
@@ -280,7 +346,7 @@ class IRsend {
#if SEND_WHIRLPOOL_AC
void sendWhirlpoolAC(unsigned char data[],
uint16_t nbytes = kWhirlpoolAcStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kWhirlpoolAcDefaultRepeat);
#endif
#if SEND_LUTRON
void sendLutron(uint64_t data, uint16_t nbits = kLutronBits,
@@ -294,7 +360,7 @@ class IRsend {
#if SEND_PANASONIC_AC
void sendPanasonicAC(unsigned char data[],
uint16_t nbytes = kPanasonicAcStateLength,
- uint16_t repeat = kNoRepeat);
+ uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif
#if SEND_PIONEER
void sendPioneer(const uint64_t data, const uint16_t nbits = kPioneerBits,
@@ -305,6 +371,24 @@ class IRsend {
void sendMWM(unsigned char data[], uint16_t nbytes,
uint16_t repeat = kNoRepeat);
#endif
+#if SEND_VESTEL_AC
+ void sendVestelAc(const uint64_t data, const uint16_t nbits = kVestelAcBits,
+ const uint16_t repeat = kNoRepeat);
+#endif
+#if SEND_TCL112AC
+ void sendTcl112Ac(const unsigned char data[],
+ const uint16_t nbytes = kTcl112AcStateLength,
+ const uint16_t repeat = kTcl112AcDefaultRepeat);
+#endif
+#if SEND_TECO
+ void sendTeco(uint64_t data, uint16_t nbits = kTecoBits,
+ uint16_t repeat = kNoRepeat);
+#endif
+#if SEND_LEGOPF
+ void sendLegoPf(const uint64_t data, const uint16_t nbits = kLegoPfBits,
+ const uint16_t repeat = kLegoPfMinRepeat);
+#endif
+
protected:
#ifdef UNIT_TEST
@@ -319,8 +403,12 @@ class IRsend {
uint8_t outputOff;
VIRTUAL void ledOff();
VIRTUAL void ledOn();
+#ifndef UNIT_TEST
private:
+#else
+ uint32_t _freq_unittest;
+#endif // UNIT_TEST
uint16_t onTimePeriod;
uint16_t offTimePeriod;
uint16_t IRpin;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.cpp b/lib/IRremoteESP8266-2.6.0/src/IRtimer.cpp
similarity index 53%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRtimer.cpp
rename to lib/IRremoteESP8266-2.6.0/src/IRtimer.cpp
index 029637cbb94d..4173d763bae8 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/IRtimer.cpp
@@ -7,12 +7,12 @@
#ifdef UNIT_TEST
// Used to help simulate elapsed time in unit tests.
-extern uint32_t _IRtimer_unittest_now;
+uint32_t _IRtimer_unittest_now = 0;
+uint32_t _TimerMs_unittest_now = 0;
#endif // UNIT_TEST
// This class performs a simple time in useconds since instantiated.
// Handles when the system timer wraps around (once).
-
IRtimer::IRtimer() { reset(); }
void IRtimer::reset() {
@@ -39,3 +39,32 @@ uint32_t IRtimer::elapsed() {
#ifdef UNIT_TEST
void IRtimer::add(uint32_t usecs) { _IRtimer_unittest_now += usecs; }
#endif // UNIT_TEST
+
+// This class performs a simple time in milli-seoncds since instantiated.
+// Handles when the system timer wraps around (once).
+TimerMs::TimerMs() { reset(); }
+
+void TimerMs::reset() {
+#ifndef UNIT_TEST
+ start = millis();
+#else
+ start = _TimerMs_unittest_now;
+#endif
+}
+
+uint32_t TimerMs::elapsed() {
+#ifndef UNIT_TEST
+ uint32_t now = millis();
+#else
+ uint32_t now = _TimerMs_unittest_now;
+#endif
+ if (start <= now) // Check if the system timer has wrapped.
+ return now - start; // No wrap.
+ else
+ return UINT32_MAX - start + now; // Has wrapped.
+}
+
+// Only used in unit testing.
+#ifdef UNIT_TEST
+void TimerMs::add(uint32_t msecs) { _IRtimer_unittest_now += msecs; }
+#endif // UNIT_TEST
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.h b/lib/IRremoteESP8266-2.6.0/src/IRtimer.h
similarity index 64%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRtimer.h
rename to lib/IRremoteESP8266-2.6.0/src/IRtimer.h
index baca1cf74d3e..d00e1d0fad04 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRtimer.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRtimer.h
@@ -20,4 +20,16 @@ class IRtimer {
uint32_t start;
};
+class TimerMs {
+ public:
+ TimerMs();
+ void reset();
+ uint32_t elapsed();
+#ifdef UNIT_TEST
+ static void add(uint32_t msecs);
+#endif // UNIT_TEST
+
+ private:
+ uint32_t start;
+};
#endif // IRTIMER_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/IRutils.cpp b/lib/IRremoteESP8266-2.6.0/src/IRutils.cpp
new file mode 100644
index 000000000000..d909252413c5
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/IRutils.cpp
@@ -0,0 +1,768 @@
+// Copyright 2017 David Conran
+
+#include "IRutils.h"
+#ifndef UNIT_TEST
+#include
+#endif
+
+#define __STDC_LIMIT_MACROS
+#include
+#include
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+
+// Reverse the order of the requested least significant nr. of bits.
+// Args:
+// input: Bit pattern/integer to reverse.
+// nbits: Nr. of bits to reverse.
+// Returns:
+// The reversed bit pattern.
+uint64_t reverseBits(uint64_t input, uint16_t nbits) {
+ if (nbits <= 1) return input; // Reversing <= 1 bits makes no change at all.
+ // Cap the nr. of bits to rotate to the max nr. of bits in the input.
+ nbits = std::min(nbits, (uint16_t)(sizeof(input) * 8));
+ uint64_t output = 0;
+ for (uint16_t i = 0; i < nbits; i++) {
+ output <<= 1;
+ output |= (input & 1);
+ input >>= 1;
+ }
+ // Merge any remaining unreversed bits back to the top of the reversed bits.
+ return (input << nbits) | output;
+}
+
+// Convert a uint64_t (unsigned long long) to a string.
+// Arduino String/toInt/Serial.print() can't handle printing 64 bit values.
+//
+// Args:
+// input: The value to print
+// base: The output base.
+// Returns:
+// A string representation of the integer.
+// Note: Based on Arduino's Print::printNumber()
+#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
+String uint64ToString(uint64_t input, uint8_t base) {
+ String result = "";
+#else
+std::string uint64ToString(uint64_t input, uint8_t base) {
+ std::string result = "";
+#endif
+ // prevent issues if called with base <= 1
+ if (base < 2) base = 10;
+ // Check we have a base that we can actually print.
+ // i.e. [0-9A-Z] == 36
+ if (base > 36) base = 10;
+
+ do {
+ char c = input % base;
+ input /= base;
+
+ if (c < 10)
+ c += '0';
+ else
+ c += 'A' - 10;
+ result = c + result;
+ } while (input);
+ return result;
+}
+
+#ifdef ARDUINO
+// Print a uint64_t/unsigned long long to the Serial port
+// Serial.print() can't handle printing long longs. (uint64_t)
+//
+// Args:
+// input: The value to print
+// base: The output base.
+void serialPrintUint64(uint64_t input, uint8_t base) {
+ Serial.print(uint64ToString(input, base));
+}
+#endif
+
+// Convert a c-style str to a decode_type_t
+// Note: Assumes str is upper case.
+//
+// Args:
+// str: An upper-case C-style string.
+// Returns:
+// A decode_type_t enum.
+decode_type_t strToDecodeType(const char *str) {
+ if (!strcmp(str, "UNKNOWN"))
+ return decode_type_t::UNKNOWN;
+ else if (!strcmp(str, "UNUSED"))
+ return decode_type_t::UNUSED;
+ else if (!strcmp(str, "AIWA_RC_T501"))
+ return decode_type_t::AIWA_RC_T501;
+ else if (!strcmp(str, "ARGO"))
+ return decode_type_t::ARGO;
+ else if (!strcmp(str, "CARRIER_AC"))
+ return decode_type_t::CARRIER_AC;
+ else if (!strcmp(str, "COOLIX"))
+ return decode_type_t::COOLIX;
+ else if (!strcmp(str, "DAIKIN"))
+ return decode_type_t::DAIKIN;
+ else if (!strcmp(str, "DAIKIN2"))
+ return decode_type_t::DAIKIN2;
+ else if (!strcmp(str, "DAIKIN216"))
+ return decode_type_t::DAIKIN216;
+ else if (!strcmp(str, "DENON"))
+ return decode_type_t::DENON;
+ else if (!strcmp(str, "DISH"))
+ return decode_type_t::DISH;
+ else if (!strcmp(str, "ELECTRA_AC"))
+ return decode_type_t::ELECTRA_AC;
+ else if (!strcmp(str, "FUJITSU_AC"))
+ return decode_type_t::FUJITSU_AC;
+ else if (!strcmp(str, "GICABLE"))
+ return decode_type_t::GICABLE;
+ else if (!strcmp(str, "GLOBALCACHE"))
+ return decode_type_t::GLOBALCACHE;
+ else if (!strcmp(str, "GREE"))
+ return decode_type_t::GREE;
+ else if (!strcmp(str, "HAIER_AC"))
+ return decode_type_t::HAIER_AC;
+ else if (!strcmp(str, "HAIER_AC_YRW02"))
+ return decode_type_t::HAIER_AC_YRW02;
+ else if (!strcmp(str, "HITACHI_AC"))
+ return decode_type_t::HITACHI_AC;
+ else if (!strcmp(str, "HITACHI_AC1"))
+ return decode_type_t::HITACHI_AC1;
+ else if (!strcmp(str, "HITACHI_AC2"))
+ return decode_type_t::HITACHI_AC2;
+ else if (!strcmp(str, "JVC"))
+ return decode_type_t::JVC;
+ else if (!strcmp(str, "KELVINATOR"))
+ return decode_type_t::KELVINATOR;
+ else if (!strcmp(str, "LEGOPF"))
+ return decode_type_t::LEGOPF;
+ else if (!strcmp(str, "LG"))
+ return decode_type_t::LG;
+ else if (!strcmp(str, "LG2"))
+ return decode_type_t::LG2;
+ else if (!strcmp(str, "LASERTAG"))
+ return decode_type_t::LASERTAG;
+ else if (!strcmp(str, "LUTRON"))
+ return decode_type_t::LUTRON;
+ else if (!strcmp(str, "MAGIQUEST"))
+ return decode_type_t::MAGIQUEST;
+ else if (!strcmp(str, "MIDEA"))
+ return decode_type_t::MIDEA;
+ else if (!strcmp(str, "MITSUBISHI"))
+ return decode_type_t::MITSUBISHI;
+ else if (!strcmp(str, "MITSUBISHI2"))
+ return decode_type_t::MITSUBISHI2;
+ else if (!strcmp(str, "MITSUBISHI_AC"))
+ return decode_type_t::MITSUBISHI_AC;
+ else if (!strcmp(str, "MWM"))
+ return decode_type_t::MWM;
+ else if (!strcmp(str, "NEC") || !strcmp(str, "NEC (NON-STRICT"))
+ return decode_type_t::NEC;
+ else if (!strcmp(str, "NIKAI"))
+ return decode_type_t::NIKAI;
+ else if (!strcmp(str, "PANASONIC"))
+ return decode_type_t::PANASONIC;
+ else if (!strcmp(str, "PANASONIC_AC"))
+ return decode_type_t::PANASONIC_AC;
+ else if (!strcmp(str, "PIONEER"))
+ return decode_type_t::PIONEER;
+ else if (!strcmp(str, "PRONTO"))
+ return decode_type_t::PRONTO;
+ else if (!strcmp(str, "RAW"))
+ return decode_type_t::RAW;
+ else if (!strcmp(str, "RC5"))
+ return decode_type_t::RC5;
+ else if (!strcmp(str, "RC5X"))
+ return decode_type_t::RC5X;
+ else if (!strcmp(str, "RC6"))
+ return decode_type_t::RC6;
+ else if (!strcmp(str, "RCMM"))
+ return decode_type_t::RCMM;
+ else if (!strcmp(str, "SAMSUNG"))
+ return decode_type_t::SAMSUNG;
+ else if (!strcmp(str, "SAMSUNG36"))
+ return decode_type_t::SAMSUNG36;
+ else if (!strcmp(str, "SAMSUNG_AC"))
+ return decode_type_t::SAMSUNG_AC;
+ else if (!strcmp(str, "SANYO"))
+ return decode_type_t::SANYO;
+ else if (!strcmp(str, "SANYO_LC7461"))
+ return decode_type_t::SANYO_LC7461;
+ else if (!strcmp(str, "SHARP"))
+ return decode_type_t::SHARP;
+ else if (!strcmp(str, "SHERWOOD"))
+ return decode_type_t::SHERWOOD;
+ else if (!strcmp(str, "SONY"))
+ return decode_type_t::SONY;
+ else if (!strcmp(str, "TCL112AC"))
+ return decode_type_t::TCL112AC;
+ else if (!strcmp(str, "TECO"))
+ return decode_type_t::TECO;
+ else if (!strcmp(str, "TOSHIBA_AC"))
+ return decode_type_t::TOSHIBA_AC;
+ else if (!strcmp(str, "TROTEC"))
+ return decode_type_t::TROTEC;
+ else if (!strcmp(str, "VESTEL_AC"))
+ return decode_type_t::VESTEL_AC;
+ else if (!strcmp(str, "WHIRLPOOL_AC"))
+ return decode_type_t::WHIRLPOOL_AC;
+ else if (!strcmp(str, "WHYNTER"))
+ return decode_type_t::WHYNTER;
+ // 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());
+ if (result > 0)
+ return result;
+ else
+ return decode_type_t::UNKNOWN;
+}
+
+// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS.
+// Args:
+// unescaped: A string containing text to make HTML safe.
+// Returns:
+// A string that is HTML safe.
+#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
+String htmlEscape(const String unescaped) {
+ String result = "";
+#else
+std::string htmlEscape(const std::string unescaped) {
+ std::string result = "";
+#endif
+ uint16_t ulen = unescaped.length();
+ result.reserve(ulen); // The result will be at least the size of input.
+ for (size_t i = 0; i < ulen; i++) {
+ char c = unescaped[i];
+ switch (c) {
+ // ';!-"<>={}() are all unsafe.
+ case '\'':
+ result += F("'");
+ break;
+ case ';':
+ result += F(";");
+ break;
+ case '!':
+ result += F("!");
+ break;
+ case '-':
+ result += F("‐");
+ break;
+ case '\"':
+ result += F(""");
+ break;
+ case '<':
+ result += F("<");
+ break;
+ case '>':
+ result += F(">");
+ break;
+ case '=':
+ result += F("equals;");
+ break;
+ case '&':
+ result += F("&");
+ break;
+ case '#':
+ result += F("#");
+ break;
+ case '{':
+ result += F("{");
+ break;
+ case '}':
+ result += F("}");
+ break;
+ case '(':
+ result += F("(");
+ break;
+ case ')':
+ result += F(")");
+ break;
+ default:
+ result += c;
+ }
+ }
+ return result;
+}
+
+// Convert a protocol type (enum etc) to a human readable string.
+// Args:
+// protocol: Nr. (enum) of the protocol.
+// isRepeat: A flag indicating if it is a repeat message of the protocol.
+// Returns:
+// A string containing the protocol name.
+#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
+String typeToString(const decode_type_t protocol, const bool isRepeat) {
+ String result = "";
+#else
+std::string typeToString(const decode_type_t protocol, const bool isRepeat) {
+ std::string result = "";
+#endif
+ switch (protocol) {
+ case UNUSED:
+ result = F("UNUSED");
+ break;
+ case AIWA_RC_T501:
+ result = F("AIWA_RC_T501");
+ 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 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 FUJITSU_AC:
+ result = F("FUJITSU_AC");
+ break;
+ case GICABLE:
+ result = F("GICABLE");
+ break;
+ case GLOBALCACHE:
+ result = F("GLOBALCACHE");
+ 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 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 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 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 SHERWOOD:
+ result = F("SHERWOOD");
+ break;
+ case SONY:
+ result = F("SONY");
+ 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 = F("UNKNOWN");
+ break;
+ }
+ if (isRepeat) result += F(" (Repeat)");
+ return result;
+}
+
+// Does the given protocol use a complex state as part of the decode?
+bool hasACState(const decode_type_t protocol) {
+ switch (protocol) {
+ case DAIKIN:
+ case DAIKIN2:
+ case DAIKIN216:
+ case ELECTRA_AC:
+ case FUJITSU_AC:
+ case GREE:
+ case HAIER_AC:
+ case HAIER_AC_YRW02:
+ case HITACHI_AC:
+ case HITACHI_AC1:
+ case HITACHI_AC2:
+ case KELVINATOR:
+ case MITSUBISHI_AC:
+ case MITSUBISHI_HEAVY_88:
+ case MITSUBISHI_HEAVY_152:
+ case MWM:
+ case PANASONIC_AC:
+ case SAMSUNG_AC:
+ case TCL112AC:
+ case TOSHIBA_AC:
+ case WHIRLPOOL_AC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Return the corrected length of a 'raw' format array structure
+// after over-large values are converted into multiple entries.
+// Args:
+// results: A ptr to a decode result.
+// Returns:
+// A uint16_t containing the length.
+uint16_t getCorrectedRawLength(const decode_results *results) {
+ uint16_t extended_length = results->rawlen - 1;
+ for (uint16_t i = 0; i < results->rawlen - 1; i++) {
+ uint32_t usecs = results->rawbuf[i] * kRawTick;
+ // Add two extra entries for multiple larger than UINT16_MAX it is.
+ extended_length += (usecs / (UINT16_MAX + 1)) * 2;
+ }
+ return extended_length;
+}
+
+// Return a string containing the key values of a decode_results structure
+// in a C/C++ code style format.
+#ifdef ARDUINO
+String resultToSourceCode(const decode_results *results) {
+ String output = "";
+#else
+std::string resultToSourceCode(const decode_results *results) {
+ std::string output = "";
+#endif
+ // Start declaration
+ output += F("uint16_t "); // variable type
+ output += F("rawData["); // array name
+ output += uint64ToString(getCorrectedRawLength(results), 10);
+ // array size
+ output += F("] = {"); // Start declaration
+
+ // Dump data
+ for (uint16_t i = 1; i < results->rawlen; i++) {
+ uint32_t usecs;
+ for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX;
+ usecs -= UINT16_MAX) {
+ output += uint64ToString(UINT16_MAX);
+ if (i % 2)
+ output += F(", 0, ");
+ else
+ output += F(", 0, ");
+ }
+ output += uint64ToString(usecs, 10);
+ if (i < results->rawlen - 1)
+ output += F(", "); // ',' not needed on the last one
+ if (i % 2 == 0) output += ' '; // Extra if it was even.
+ }
+
+ // End declaration
+ output += F("};");
+
+ // Comment
+ output += F(" // ");
+ output += typeToString(results->decode_type, results->repeat);
+ // Only display the value if the decode type doesn't have an A/C state.
+ if (!hasACState(results->decode_type))
+ output += ' ' + uint64ToString(results->value, 16);
+ output += F("\n");
+
+ // Now dump "known" codes
+ if (results->decode_type != UNKNOWN) {
+ if (hasACState(results->decode_type)) {
+#if DECODE_AC
+ uint16_t nbytes = results->bits / 8;
+ output += F("uint8_t state[");
+ output += uint64ToString(nbytes);
+ output += F("] = {");
+ for (uint16_t i = 0; i < nbytes; i++) {
+ output += F("0x");
+ if (results->state[i] < 0x10) output += '0';
+ output += uint64ToString(results->state[i], 16);
+ if (i < nbytes - 1) output += F(", ");
+ }
+ output += F("};\n");
+#endif // DECODE_AC
+ } else {
+ // Simple protocols
+ // Some protocols have an address &/or command.
+ // NOTE: It will ignore the atypical case when a message has been
+ // decoded but the address & the command are both 0.
+ if (results->address > 0 || results->command > 0) {
+ output += F("uint32_t address = 0x");
+ output += uint64ToString(results->address, 16);
+ output += F(";\n");
+ output += F("uint32_t command = 0x");
+ output += uint64ToString(results->command, 16);
+ output += F(";\n");
+ }
+ // Most protocols have data
+ output += F("uint64_t data = 0x");
+ output += uint64ToString(results->value, 16);
+ output += F(";\n");
+ }
+ }
+ return output;
+}
+
+// Dump out the decode_results structure.
+//
+#ifdef ARDUINO
+String resultToTimingInfo(const decode_results *results) {
+ String output = "";
+ String value = "";
+#else
+std::string resultToTimingInfo(const decode_results *results) {
+ std::string output = "";
+ std::string value = "";
+#endif
+ output += F("Raw Timing[");
+ output += uint64ToString(results->rawlen - 1, 10);
+ output += F("]:\n");
+
+ for (uint16_t i = 1; i < results->rawlen; i++) {
+ if (i % 2 == 0)
+ output += '-'; // even
+ else
+ output += F(" +"); // odd
+ value = uint64ToString(results->rawbuf[i] * kRawTick);
+ // Space pad the value till it is at least 6 chars long.
+ while (value.length() < 6) value = ' ' + value;
+ output += value;
+ if (i < results->rawlen - 1)
+ output += F(", "); // ',' not needed for last one
+ if (!(i % 8)) output += '\n'; // Newline every 8 entries.
+ }
+ output += '\n';
+ return output;
+}
+
+// Convert the decode_results structure's value/state to simple hexadecimal.
+//
+#ifdef ARDUINO
+String resultToHexidecimal(const decode_results *result) {
+ String output = "";
+#else
+std::string resultToHexidecimal(const decode_results *result) {
+ std::string output = "";
+#endif
+ if (hasACState(result->decode_type)) {
+#if DECODE_AC
+ for (uint16_t i = 0; result->bits > i * 8; i++) {
+ if (result->state[i] < 0x10) output += '0'; // Zero pad
+ output += uint64ToString(result->state[i], 16);
+ }
+#endif // DECODE_AC
+ } else {
+ output += uint64ToString(result->value, 16);
+ }
+ return output;
+}
+
+// Dump out the decode_results structure.
+//
+#ifdef ARDUINO
+String resultToHumanReadableBasic(const decode_results *results) {
+ String output = "";
+#else
+std::string resultToHumanReadableBasic(const decode_results *results) {
+ std::string output = "";
+#endif
+ // Show Encoding standard
+ output += F("Encoding : ");
+ output += typeToString(results->decode_type, results->repeat);
+ output += '\n';
+
+ // Show Code & length
+ output += F("Code : ");
+ output += resultToHexidecimal(results);
+ output += F(" (");
+ output += uint64ToString(results->bits);
+ output += F(" bits)\n");
+ return output;
+}
+
+uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init) {
+ uint8_t checksum = init;
+ uint8_t *ptr;
+ for (ptr = start; ptr - start < length; ptr++) checksum += *ptr;
+ return checksum;
+}
+
+uint8_t xorBytes(uint8_t *start, const uint16_t length, const uint8_t init) {
+ uint8_t checksum = init;
+ uint8_t *ptr;
+ for (ptr = start; ptr - start < length; ptr++) checksum ^= *ptr;
+ return checksum;
+}
+
+// Count the number of bits of a certain type.
+// Args:
+// start: Ptr to the start of data to count bits in.
+// length: How many bytes to count.
+// ones: Count the binary 1 bits. False for counting the 0 bits.
+// init: Start the counting from this value.
+// Returns:
+// Nr. of bits found.
+uint16_t countBits(const uint8_t *start, const uint16_t length, const bool ones,
+ const uint16_t init) {
+ uint16_t count = init;
+ for (uint16_t offset = 0; offset < length; offset++)
+ for (uint8_t currentbyte = *(start + offset);
+ currentbyte;
+ currentbyte >>= 1)
+ if (currentbyte & 1) count++;
+ if (ones || length == 0)
+ return count;
+ else
+ return (length * 8) - count;
+}
+
+// Count the number of bits of a certain type.
+// Args:
+// data: The value you want bits counted for, starting from the LSB.
+// length: How many bits to count.
+// ones: Count the binary 1 bits. False for counting the 0 bits.
+// init: Start the counting from this value.
+// Returns:
+// Nr. of bits found.
+uint16_t countBits(const uint64_t data, const uint8_t length, const bool ones,
+ const uint16_t init) {
+ uint16_t count = init;
+ uint8_t bitsSoFar = length;
+ for (uint64_t remainder = data; remainder && bitsSoFar;
+ remainder >>= 1, bitsSoFar--)
+ if (remainder & 1) count++;
+ if (ones || length == 0)
+ return count;
+ else
+ return length - count;
+}
+
+uint64_t invertBits(const uint64_t data, const uint16_t nbits) {
+ // No change if we are asked to invert no bits.
+ if (nbits == 0) return data;
+ uint64_t result = ~data;
+ // If we are asked to invert all the bits or more than we have, it's simple.
+ if (nbits >= sizeof(data) * 8) return result;
+ // Mask off any unwanted bits and return the result.
+ return (result & ((1ULL << nbits) - 1));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/IRutils.h b/lib/IRremoteESP8266-2.6.0/src/IRutils.h
similarity index 74%
rename from lib/IRremoteESP8266-2.5.2.03/src/IRutils.h
rename to lib/IRremoteESP8266-2.6.0/src/IRutils.h
index c17375d98121..0d0b677b57b1 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/IRutils.h
+++ b/lib/IRremoteESP8266-2.6.0/src/IRutils.h
@@ -24,7 +24,8 @@ String resultToSourceCode(const decode_results *results);
String resultToTimingInfo(const decode_results *results);
String resultToHumanReadableBasic(const decode_results *results);
String resultToHexidecimal(const decode_results *result);
-#else
+String htmlEscape(const String unescaped);
+#else // ARDUINO
std::string uint64ToString(uint64_t input, uint8_t base = 10);
std::string typeToString(const decode_type_t protocol,
const bool isRepeat = false);
@@ -32,10 +33,16 @@ std::string resultToSourceCode(const decode_results *results);
std::string resultToTimingInfo(const decode_results *results);
std::string resultToHumanReadableBasic(const decode_results *results);
std::string resultToHexidecimal(const decode_results *result);
-#endif
+std::string htmlEscape(const std::string unescaped);
+#endif // ARDUINO
bool hasACState(const decode_type_t protocol);
uint16_t getCorrectedRawLength(const decode_results *results);
uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init = 0);
+uint8_t xorBytes(uint8_t *start, const uint16_t length, const uint8_t init = 0);
+uint16_t countBits(const uint8_t *start, const uint16_t length,
+ const bool ones = true, const uint16_t init = 0);
+uint16_t countBits(const uint64_t data, const uint8_t length,
+ const bool ones = true, const uint16_t init = 0);
uint64_t invertBits(const uint64_t data, const uint16_t nbits);
-
+decode_type_t strToDecodeType(const char *str);
#endif // IRUTILS_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Aiwa.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Aiwa.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Aiwa.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Aiwa.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.cpp
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Argo.cpp
index 8a3e69f72ef8..d6711acd3872 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.cpp
@@ -40,9 +40,9 @@ IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) { stateReset(); }
void IRArgoAC::begin() { _irsend.begin(); }
#if SEND_ARGO
-void IRArgoAC::send() {
+void IRArgoAC::send(const uint16_t repeat) {
checksum(); // Create valid checksum before sending
- _irsend.sendArgo(argo);
+ _irsend.sendArgo(argo, kArgoStateLength, repeat);
}
#endif // SEND_ARGO
@@ -228,3 +228,37 @@ void IRArgoAC::setRoomTemp(uint8_t temp) {
argo[3] += temp << 5; // Append to bit 5,6,7
argo[4] += temp >> 3; // Remove lowest 3 bits and append in 0,1
}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRArgoAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kArgoFan1;
+ case stdAc::fanspeed_t::kMedium:
+ return kArgoFan2;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kArgoFan3;
+ default:
+ return kArgoFanAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRArgoAC::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ return kArgoFlapFull;
+ case stdAc::swingv_t::kHigh:
+ return kArgoFlap5;
+ case stdAc::swingv_t::kMiddle:
+ return kArgoFlap4;
+ case stdAc::swingv_t::kLow:
+ return kArgoFlap3;
+ case stdAc::swingv_t::kLowest:
+ return kArgoFlap1;
+ default:
+ return kArgoFlapAuto;
+ }
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.h b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.h
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Argo.h
index b49fc35177cd..883c2ddfdb5d 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Argo.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Argo.h
@@ -6,6 +6,10 @@
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
// ARGO Ulisse DCI
@@ -55,7 +59,7 @@ const uint8_t kArgoFlapFull = 7; // 0b111
#define ARGO_COOL_ON kArgoCoolOn
#define ARGO_COOL_OFF kArgoCoolOff
#define ARGO_COOL_AUTO kArgoCoolAuto
-#define ARGO_COOl_HUM kArgoCoolHum
+#define ARGO_COOL_HUM kArgoCoolHum
#define ARGO_HEAT_ON kArgoHeatOn
#define ARGO_HEAT_AUTO kArgoHeatAuto
#define ARGO_HEAT_BLINK kArgoHeatBlink
@@ -80,7 +84,7 @@ class IRArgoAC {
explicit IRArgoAC(uint16_t pin);
#if SEND_ARGO
- void send();
+ void send(const uint16_t repeat = kArgoDefaultRepeat);
#endif // SEND_ARGO
void begin();
void on();
@@ -118,13 +122,19 @@ class IRArgoAC {
void setRoomTemp(uint8_t temp);
uint8_t* getRaw();
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+#ifndef UNIT_TEST
private:
+ IRsend _irsend; // instance of the IR send class
+#else
+ IRsendTest _irsend; // instance of the testing IR send class
+#endif
// # of bytes per command
uint8_t argo[kArgoStateLength]; // Defined in IRremoteESP8266.h
void stateReset();
void checksum();
- IRsend _irsend; // instance of the IR send class
// Attributes
uint8_t set_temp;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Carrier.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Carrier.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Carrier.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Carrier.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.cpp
similarity index 72%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Coolix.cpp
index ee539af25660..2659a1d88176 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.cpp
@@ -93,25 +93,62 @@ void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) {
// https://github.com/markszabo/IRremoteESP8266/issues/484
IRCoolixAC::IRCoolixAC(uint16_t pin) : _irsend(pin) { stateReset(); }
-void IRCoolixAC::stateReset() { remote_state = kCoolixDefaultState; }
+void IRCoolixAC::stateReset() { setRaw(kCoolixDefaultState); }
void IRCoolixAC::begin() { _irsend.begin(); }
#if SEND_COOLIX
-void IRCoolixAC::send() { _irsend.sendCOOLIX(remote_state); }
+void IRCoolixAC::send(const uint16_t repeat) {
+ _irsend.sendCOOLIX(remote_state, kCoolixBits, repeat);
+}
#endif // SEND_COOLIX
uint32_t IRCoolixAC::getRaw() { return remote_state; }
-void IRCoolixAC::setRaw(const uint32_t new_code) { remote_state = new_code; }
+void IRCoolixAC::setRaw(const uint32_t new_code) {
+ remote_state = new_code;
+ saved_state = new_code;
+}
+
+// Return true if the current state is a special state.
+bool IRCoolixAC::isSpecialState(void) {
+ switch (remote_state) {
+ case kCoolixClean:
+ case kCoolixLed:
+ case kCoolixOff:
+ case kCoolixSwing:
+ case kCoolixSleep:
+ case kCoolixTurbo:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void IRCoolixAC::updateSavedState(void) {
+ if (!isSpecialState()) saved_state = remote_state;
+}
+
+void IRCoolixAC::recoverSavedState(void) {
+ // If the current state is a special one, last known normal one.
+ if (isSpecialState()) remote_state = saved_state;
+ // If the saved_state was also a special state, reset as we expect a normal
+ // state out of all this.
+ if (isSpecialState()) stateReset();
+}
+
+uint32_t IRCoolixAC::getNormalState(void) {
+ return isSpecialState() ? saved_state : remote_state;
+}
void IRCoolixAC::setTempRaw(const uint8_t code) {
+ recoverSavedState();
remote_state &= ~kCoolixTempMask; // Clear the old temp.
remote_state |= (code << 4);
}
uint8_t IRCoolixAC::getTempRaw() {
- return (remote_state & kCoolixTempMask) >> 4;
+ return (getNormalState() & kCoolixTempMask) >> 4;
}
void IRCoolixAC::setTemp(const uint8_t desired) {
@@ -130,6 +167,7 @@ uint8_t IRCoolixAC::getTemp() {
}
void IRCoolixAC::setSensorTempRaw(const uint8_t code) {
+ recoverSavedState();
remote_state &= ~kCoolixSensorTempMask; // Clear previous sensor temp.
remote_state |= ((code & 0xF) << 8);
}
@@ -143,7 +181,8 @@ void IRCoolixAC::setSensorTemp(const uint8_t desired) {
}
uint8_t IRCoolixAC::getSensorTemp() {
- return ((remote_state & kCoolixSensorTempMask) >> 8) + kCoolixSensorTempMin;
+ return ((getNormalState() & kCoolixSensorTempMask) >> 8) +
+ kCoolixSensorTempMin;
}
bool IRCoolixAC::getPower() {
@@ -152,25 +191,35 @@ bool IRCoolixAC::getPower() {
}
void IRCoolixAC::setPower(const bool power) {
- if (!power) remote_state = kCoolixOff;
- // There really is no distinct "on" setting, so do nothing.
+ if (power) {
+ // There really is no distinct "on" setting, just ensure it a normal state.
+ recoverSavedState();
+ } else {
+ updateSavedState();
+ remote_state = kCoolixOff;
+ }
}
bool IRCoolixAC::getSwing() { return remote_state == kCoolixSwing; }
void IRCoolixAC::setSwing() {
// Assumes that repeated sending "swing" toggles the action on the device.
+ updateSavedState();
remote_state = kCoolixSwing;
}
bool IRCoolixAC::getSleep() { return remote_state == kCoolixSleep; }
-void IRCoolixAC::setSleep() { remote_state = kCoolixSleep; }
+void IRCoolixAC::setSleep() {
+ updateSavedState();
+ remote_state = kCoolixSleep;
+}
bool IRCoolixAC::getTurbo() { return remote_state == kCoolixTurbo; }
void IRCoolixAC::setTurbo() {
// Assumes that repeated sending "turbo" toggles the action on the device.
+ updateSavedState();
remote_state = kCoolixTurbo;
}
@@ -178,19 +227,24 @@ bool IRCoolixAC::getLed() { return remote_state == kCoolixLed; }
void IRCoolixAC::setLed() {
// Assumes that repeated sending "Led" toggles the action on the device.
+ updateSavedState();
remote_state = kCoolixLed;
}
bool IRCoolixAC::getClean() { return remote_state == kCoolixClean; }
-void IRCoolixAC::setClean() { remote_state = kCoolixClean; }
+void IRCoolixAC::setClean() {
+ updateSavedState();
+ remote_state = kCoolixClean;
+}
bool IRCoolixAC::getZoneFollow() {
- return remote_state & kCoolixZoneFollowMask;
+ return getNormalState() & kCoolixZoneFollowMask;
}
// Internal use only.
void IRCoolixAC::setZoneFollow(bool state) {
+ recoverSavedState();
if (state) {
remote_state |= kCoolixZoneFollowMask;
} else {
@@ -199,6 +253,7 @@ void IRCoolixAC::setZoneFollow(bool state) {
}
void IRCoolixAC::clearSensorTemp() {
+ recoverSavedState();
setZoneFollow(false);
setSensorTempRaw(kCoolixSensorTempIgnoreCode);
}
@@ -212,6 +267,7 @@ void IRCoolixAC::setMode(const uint8_t mode) {
case kCoolixAuto:
case kCoolixHeat:
case kCoolixDry:
+ recoverSavedState();
remote_state = (remote_state & ~kCoolixModeMask) | (actualmode << 2);
// Force the temp into a known-good state.
setTemp(getTemp());
@@ -220,21 +276,25 @@ void IRCoolixAC::setMode(const uint8_t mode) {
}
uint8_t IRCoolixAC::getMode() {
- uint8_t mode = (remote_state & kCoolixModeMask) >> 2;
+ uint8_t mode = (getNormalState() & kCoolixModeMask) >> 2;
if (mode == kCoolixDry)
if (getTempRaw() == kCoolixFanTempCode) return kCoolixFan;
return mode;
}
-uint8_t IRCoolixAC::getFan() { return (remote_state & kCoolixFanMask) >> 13; }
+uint8_t IRCoolixAC::getFan() {
+ return (getNormalState() & kCoolixFanMask) >> 13;
+}
void IRCoolixAC::setFan(const uint8_t speed) {
+ recoverSavedState();
uint8_t newspeed = speed;
switch (speed) {
case kCoolixFanMin:
case kCoolixFanMed:
case kCoolixFanMax:
case kCoolixFanAuto:
+ case kCoolixFanAuto0:
case kCoolixFanZoneFollow:
case kCoolixFanFixed:
break;
@@ -245,6 +305,38 @@ void IRCoolixAC::setFan(const uint8_t speed) {
remote_state |= ((newspeed << 13) & kCoolixFanMask);
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRCoolixAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kCoolixCool;
+ case stdAc::opmode_t::kHeat:
+ return kCoolixHeat;
+ case stdAc::opmode_t::kDry:
+ return kCoolixDry;
+ case stdAc::opmode_t::kFan:
+ return kCoolixFan;
+ default:
+ return kCoolixAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRCoolixAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kCoolixFanMin;
+ case stdAc::fanspeed_t::kMedium:
+ return kCoolixFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kCoolixFanMax;
+ default:
+ return kCoolixFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRCoolixAC::toString() {
@@ -253,89 +345,97 @@ String IRCoolixAC::toString() {
std::string IRCoolixAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower()) {
- result += "On";
+ result += F("On");
} else {
- result += "Off";
+ result += F("Off");
return result; // If it's off, there is no other info.
}
- result += ", Fan: " + uint64ToString(getFan());
- switch (getFan()) {
- case kCoolixFanAuto:
- result += " (AUTO)";
- break;
- case kCoolixFanMax:
- result += " (MAX)";
- break;
- case kCoolixFanMin:
- result += " (MIN)";
- break;
- case kCoolixFanMed:
- result += " (MED)";
- break;
- case kCoolixFanZoneFollow:
- result += " (ZONEFOLLOW)";
- break;
- case kCoolixFanFixed:
- result += " (FIXED)";
- break;
- default:
- result += " (UNKNOWN)";
- }
// Special modes.
if (getSwing()) {
- result += ", Swing: Toggle";
+ result += F(", Swing: Toggle");
return result;
}
if (getSleep()) {
- result += ", Sleep: Toggle";
+ result += F(", Sleep: Toggle");
return result;
}
if (getTurbo()) {
- result += ", Turbo: Toggle";
+ result += F(", Turbo: Toggle");
return result;
}
if (getLed()) {
- result += ", Led: Toggle";
+ result += F(", Led: Toggle");
return result;
}
if (getClean()) {
- result += ", Mode: Self clean";
+ result += F(", Clean: Toggle");
return result;
}
- result += ", Mode: " + uint64ToString(getMode());
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kCoolixAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kCoolixCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kCoolixHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kCoolixDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kCoolixFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kCoolixFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kCoolixFanAuto0:
+ result += F(" (AUTO0)");
+ break;
+ case kCoolixFanMax:
+ result += F(" (MAX)");
+ break;
+ case kCoolixFanMin:
+ result += F(" (MIN)");
+ break;
+ case kCoolixFanMed:
+ result += F(" (MED)");
+ break;
+ case kCoolixFanZoneFollow:
+ result += F(" (ZONEFOLLOW)");
+ break;
+ case kCoolixFanFixed:
+ result += F(" (FIXED)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ if (getMode() != kCoolixFan) { // Fan mode doesn't have a temperature.
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += 'C';
}
- if (getMode() != kCoolixFan) // Fan mode doesn't have a temperature.
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Zone Follow: ";
+ result += F(", Zone Follow: ");
if (getZoneFollow())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Sensor Temp: ";
+ result += F("Off");
+ result += F(", Sensor Temp: ");
if (getSensorTemp() > kCoolixSensorTempMax)
- result += "Ignored";
+ result += F("Ignored");
else
- result += uint64ToString(getSensorTemp()) + "C";
+ result += uint64ToString(getSensorTemp()) + F("C");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.h b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.h
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Coolix.h
index ee455207485c..d85db98d7da0 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Coolix.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Coolix.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// CCCCC OOOOO OOOOO LL IIIII XX XX
// CC C OO OO OO OO LL III XX XX
@@ -30,11 +33,11 @@
// Constants
// Modes
-const uint8_t kCoolixCool = 0b00;
-const uint8_t kCoolixDry = 0b01;
-const uint8_t kCoolixAuto = 0b10;
-const uint8_t kCoolixHeat = 0b11;
-const uint8_t kCoolixFan = 4; // Synthetic.
+const uint8_t kCoolixCool = 0b000;
+const uint8_t kCoolixDry = 0b001;
+const uint8_t kCoolixAuto = 0b010;
+const uint8_t kCoolixHeat = 0b011;
+const uint8_t kCoolixFan = 0b100; // Synthetic.
const uint32_t kCoolixModeMask = 0b000000000000000000001100; // 0xC
const uint32_t kCoolixZoneFollowMask = 0b000010000000000000000000; // 0x80000
// Fan Control
@@ -42,6 +45,7 @@ const uint8_t kCoolixFanMin = 0b100;
const uint8_t kCoolixFanMed = 0b010;
const uint8_t kCoolixFanMax = 0b001;
const uint8_t kCoolixFanAuto = 0b101;
+const uint8_t kCoolixFanAuto0 = 0b000;
const uint8_t kCoolixFanZoneFollow = 0b110;
const uint8_t kCoolixFanFixed = 0b111;
const uint32_t kCoolixFanMask = 0b000000001110000000000000; // 0x00E000
@@ -90,7 +94,7 @@ class IRCoolixAC {
void stateReset();
#if SEND_COOLIX
- void send();
+ void send(const uint16_t repeat = kCoolixDefaultRepeat);
#endif // SEND_COOLIX
void begin();
void on();
@@ -119,21 +123,30 @@ class IRCoolixAC {
bool getZoneFollow();
uint32_t getRaw();
void setRaw(const uint32_t new_code);
-
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
- // The state of the IR remote in IR code form.
- uint32_t remote_state;
IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint32_t remote_state; // The state of the IR remote in IR code form.
+ uint32_t saved_state; // Copy of the state if we required a special mode.
void setTempRaw(const uint8_t code);
uint8_t getTempRaw();
void setSensorTempRaw(const uint8_t code);
void setZoneFollow(const bool state);
+ bool isSpecialState(void);
+ void updateSavedState(void);
+ void recoverSavedState(void);
+ uint32_t getNormalState(void);
};
#endif // IR_COOLIX_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.cpp
new file mode 100644
index 000000000000..358dbd603c39
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.cpp
@@ -0,0 +1,1712 @@
+/*
+An Arduino sketch to emulate IR Daikin ARC433** & ARC477A1 remote control unit
+Read more at:
+http://harizanov.com/2012/02/control-daikin-air-conditioner-over-the-internet/
+
+Copyright 2016 sillyfrog
+Copyright 2017 sillyfrog, crankyoldgit
+Copyright 2018-2019 crankyoldgit
+*/
+
+#include "ir_Daikin.h"
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+#include "IRutils.h"
+
+// DDDDD AAA IIIII KK KK IIIII NN NN
+// DD DD AAAAA III KK KK III NNN NN
+// DD DD AA AA III KKKK III NN N NN
+// DD DD AAAAAAA III KK KK III NN NNN
+// DDDDDD AA AA IIIII KK KK IIIII NN NN
+
+// Constants
+// Ref:
+// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
+// http://rdlab.cdmt.vn/project-2013/daikin-ir-protocol
+// https://github.com/markszabo/IRremoteESP8266/issues/582
+
+#if SEND_DAIKIN
+// Send a Daikin A/C message.
+//
+// Args:
+// data: An array of kDaikinStateLength bytes containing the IR command.
+//
+// Status: STABLE
+//
+// Ref:
+// IRDaikinESP.cpp
+// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
+// https://github.com/blafois/Daikin-IR-Reverse
+void IRsend::sendDaikin(const unsigned char data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kDaikinStateLengthShort)
+ return; // Not enough bytes to send a proper message.
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ uint16_t offset = 0;
+ // Send the header, 0b00000
+ sendGeneric(0, 0, // No header for the header
+ kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark,
+ kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ (uint64_t)0b00000, kDaikinHeaderLength, 38, false, 0, 50);
+ // Data #1
+ if (nbytes < kDaikinStateLength) { // Are we using the legacy size?
+ // Do this as a constant to save RAM and keep in flash memory
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ kDaikinFirstHeader64, 64, 38, false, 0, 50);
+ } else { // We are using the newer/more correct size.
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ data, kDaikinSection1Length, 38, false, 0, 50);
+ offset += kDaikinSection1Length;
+ }
+ // Data #2
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ data + offset, kDaikinSection2Length, 38, false, 0, 50);
+ offset += kDaikinSection2Length;
+ // Data #3
+ sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
+ kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
+ data + offset, nbytes - offset, 38, false, 0, 50);
+ }
+}
+#endif // SEND_DAIKIN
+
+IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRDaikinESP::begin(void) { _irsend.begin(); }
+
+#if SEND_DAIKIN
+void IRDaikinESP::send(const uint16_t repeat) {
+ this->checksum();
+ _irsend.sendDaikin(remote, kDaikinStateLength, repeat);
+}
+#endif // SEND_DAIKIN
+
+// Verify the checksums are valid for a given state.
+// Args:
+// state: The array to verify the checksums of.
+// length: The size of the state.
+// Returns:
+// A boolean.
+bool IRDaikinESP::validChecksum(uint8_t state[], const uint16_t length) {
+ // Data #1
+ if (length < kDaikinSection1Length ||
+ state[kDaikinByteChecksum1] != sumBytes(state, kDaikinSection1Length - 1))
+ return false;
+ // Data #2
+ if (length < kDaikinSection1Length + kDaikinSection2Length ||
+ state[kDaikinByteChecksum2] != sumBytes(state + kDaikinSection1Length,
+ kDaikinSection2Length - 1))
+ return false;
+ // Data #3
+ if (length < kDaikinSection1Length + kDaikinSection2Length + 2 ||
+ state[length - 1] != sumBytes(state + kDaikinSection1Length +
+ kDaikinSection2Length,
+ length - (kDaikinSection1Length +
+ kDaikinSection2Length) - 1))
+ return false;
+ return true;
+}
+
+// Calculate and set the checksum values for the internal state.
+void IRDaikinESP::checksum(void) {
+ remote[kDaikinByteChecksum1] = sumBytes(remote, kDaikinSection1Length - 1);
+ remote[kDaikinByteChecksum2] = sumBytes(remote + kDaikinSection1Length,
+ kDaikinSection2Length - 1);
+ remote[kDaikinByteChecksum3] = sumBytes(remote + kDaikinSection1Length +
+ kDaikinSection2Length,
+ kDaikinSection3Length - 1);
+}
+
+void IRDaikinESP::stateReset(void) {
+ for (uint8_t i = 0; i < kDaikinStateLength; i++) remote[i] = 0x0;
+
+ remote[0] = 0x11;
+ remote[1] = 0xDA;
+ remote[2] = 0x27;
+ remote[4] = 0xC5;
+ // remote[7] is a checksum byte, it will be set by checksum().
+
+ remote[8] = 0x11;
+ remote[9] = 0xDA;
+ remote[10] = 0x27;
+ remote[12] = 0x42;
+ // remote[15] is a checksum byte, it will be set by checksum().
+ remote[16] = 0x11;
+ remote[17] = 0xDA;
+ remote[18] = 0x27;
+ remote[21] = 0x49;
+ remote[22] = 0x1E;
+ remote[24] = 0xB0;
+ remote[27] = 0x06;
+ remote[28] = 0x60;
+ remote[31] = 0xC0;
+ // remote[34] is a checksum byte, it will be set by checksum().
+ this->checksum();
+}
+
+uint8_t *IRDaikinESP::getRaw(void) {
+ this->checksum(); // Ensure correct settings before sending.
+ return remote;
+}
+
+void IRDaikinESP::setRaw(const uint8_t new_code[], const uint16_t length) {
+ uint8_t offset = 0;
+ if (length == kDaikinStateLengthShort) { // Handle the "short" length case.
+ offset = kDaikinStateLength - kDaikinStateLengthShort;
+ this->stateReset();
+ }
+ for (uint8_t i = 0; i < length && i < kDaikinStateLength; i++)
+ remote[i + offset] = new_code[i];
+}
+
+void IRDaikinESP::on(void) { remote[kDaikinBytePower] |= kDaikinBitPower; }
+
+void IRDaikinESP::off(void) { remote[kDaikinBytePower] &= ~kDaikinBitPower; }
+
+void IRDaikinESP::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRDaikinESP::getPower(void) {
+ return remote[kDaikinBytePower] & kDaikinBitPower;
+}
+
+// Set the temp in deg C
+void IRDaikinESP::setTemp(const uint8_t temp) {
+ uint8_t degrees = std::max(temp, kDaikinMinTemp);
+ degrees = std::min(degrees, kDaikinMaxTemp);
+ remote[kDaikinByteTemp] = degrees << 1;
+}
+
+uint8_t IRDaikinESP::getTemp(void) { return remote[kDaikinByteTemp] >> 1; }
+
+// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
+void IRDaikinESP::setFan(const uint8_t fan) {
+ // Set the fan speed bits, leave low 4 bits alone
+ uint8_t fanset;
+ if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto)
+ fanset = fan;
+ else if (fan < kDaikinFanMin || fan > kDaikinFanMax)
+ fanset = kDaikinFanAuto;
+ else
+ fanset = 2 + fan;
+ remote[kDaikinByteFan] &= 0x0F;
+ remote[kDaikinByteFan] |= (fanset << 4);
+}
+
+uint8_t IRDaikinESP::getFan(void) {
+ uint8_t fan = remote[kDaikinByteFan] >> 4;
+ if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
+ return fan;
+}
+
+uint8_t IRDaikinESP::getMode(void) { return remote[kDaikinBytePower] >> 4; }
+
+void IRDaikinESP::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kDaikinAuto:
+ case kDaikinCool:
+ case kDaikinHeat:
+ case kDaikinFan:
+ case kDaikinDry:
+ remote[kDaikinBytePower] &= 0b10001111;
+ remote[kDaikinBytePower] |= (mode << 4);
+ break;
+ default:
+ this->setMode(kDaikinAuto);
+ }
+}
+
+void IRDaikinESP::setSwingVertical(const bool on) {
+ if (on)
+ remote[kDaikinByteFan] |= 0x0F;
+ else
+ remote[kDaikinByteFan] &= 0xF0;
+}
+
+bool IRDaikinESP::getSwingVertical(void) {
+ return remote[kDaikinByteFan] & 0x0F;
+}
+
+void IRDaikinESP::setSwingHorizontal(const bool on) {
+ if (on)
+ remote[kDaikinByteSwingH] |= 0x0F;
+ else
+ remote[kDaikinByteSwingH] &= 0xF0;
+}
+
+bool IRDaikinESP::getSwingHorizontal(void) {
+ return remote[kDaikinByteSwingH] & 0x0F;
+}
+
+void IRDaikinESP::setQuiet(const bool on) {
+ if (on) {
+ remote[kDaikinByteSilent] |= kDaikinBitSilent;
+ // Powerful & Quiet mode being on are mutually exclusive.
+ this->setPowerful(false);
+ } else {
+ remote[kDaikinByteSilent] &= ~kDaikinBitSilent;
+ }
+}
+
+bool IRDaikinESP::getQuiet(void) {
+ return remote[kDaikinByteSilent] & kDaikinBitSilent;
+}
+
+void IRDaikinESP::setPowerful(const bool on) {
+ if (on) {
+ remote[kDaikinBytePowerful] |= kDaikinBitPowerful;
+ // Powerful, Quiet, & Econo mode being on are mutually exclusive.
+ this->setQuiet(false);
+ this->setEcono(false);
+ } else {
+ remote[kDaikinBytePowerful] &= ~kDaikinBitPowerful;
+ }
+}
+
+bool IRDaikinESP::getPowerful(void) {
+ return remote[kDaikinBytePowerful] & kDaikinBitPowerful;
+}
+
+void IRDaikinESP::setSensor(const bool on) {
+ if (on)
+ remote[kDaikinByteSensor] |= kDaikinBitSensor;
+ else
+ remote[kDaikinByteSensor] &= ~kDaikinBitSensor;
+}
+
+bool IRDaikinESP::getSensor(void) {
+ return remote[kDaikinByteSensor] & kDaikinBitSensor;
+}
+
+void IRDaikinESP::setEcono(const bool on) {
+ if (on) {
+ remote[kDaikinByteEcono] |= kDaikinBitEcono;
+ // Powerful & Econo mode being on are mutually exclusive.
+ this->setPowerful(false);
+ } else {
+ remote[kDaikinByteEcono] &= ~kDaikinBitEcono;
+ }
+}
+
+bool IRDaikinESP::getEcono(void) {
+ return remote[kDaikinByteEcono] & kDaikinBitEcono;
+}
+
+void IRDaikinESP::setEye(const bool on) {
+ if (on)
+ remote[kDaikinByteEye] |= kDaikinBitEye;
+ else
+ remote[kDaikinByteEye] &= ~kDaikinBitEye;
+}
+
+bool IRDaikinESP::getEye(void) {
+ return remote[kDaikinByteEye] & kDaikinBitEye;
+}
+
+void IRDaikinESP::setMold(const bool on) {
+ if (on)
+ remote[kDaikinByteMold] |= kDaikinBitMold;
+ else
+ remote[kDaikinByteMold] &= ~kDaikinBitMold;
+}
+
+bool IRDaikinESP::getMold(void) {
+ return remote[kDaikinByteMold] & kDaikinBitMold;
+}
+
+void IRDaikinESP::setComfort(const bool on) {
+ if (on)
+ remote[kDaikinByteComfort] |= kDaikinBitComfort;
+ else
+ remote[kDaikinByteComfort] &= ~kDaikinBitComfort;
+}
+
+bool IRDaikinESP::getComfort(void) {
+ return remote[kDaikinByteComfort] & kDaikinBitComfort;
+}
+
+// starttime: Number of minutes after midnight.
+void IRDaikinESP::enableOnTimer(const uint16_t starttime) {
+ remote[kDaikinByteOnTimer] |= kDaikinBitOnTimer;
+ remote[kDaikinByteOnTimerMinsLow] = starttime;
+ // only keep 4 bits
+ remote[kDaikinByteOnTimerMinsHigh] &= 0xF0;
+ remote[kDaikinByteOnTimerMinsHigh] |= ((starttime >> 8) & 0x0F);
+}
+
+void IRDaikinESP::disableOnTimer(void) {
+ this->enableOnTimer(kDaikinUnusedTime);
+ remote[kDaikinByteOnTimer] &= ~kDaikinBitOnTimer;
+}
+
+uint16_t IRDaikinESP::getOnTime(void) {
+ return ((remote[kDaikinByteOnTimerMinsHigh] & 0x0F) << 8) +
+ remote[kDaikinByteOnTimerMinsLow];
+}
+
+bool IRDaikinESP::getOnTimerEnabled(void) {
+ return remote[kDaikinByteOnTimer] & kDaikinBitOnTimer;
+}
+
+// endtime: Number of minutes after midnight.
+void IRDaikinESP::enableOffTimer(const uint16_t endtime) {
+ remote[kDaikinByteOffTimer] |= kDaikinBitOffTimer;
+ remote[kDaikinByteOffTimerMinsHigh] = endtime >> 4;
+ remote[kDaikinByteOffTimerMinsLow] &= 0x0F;
+ remote[kDaikinByteOffTimerMinsLow] |= ((endtime & 0x0F) << 4);
+}
+
+void IRDaikinESP::disableOffTimer(void) {
+ this->enableOffTimer(kDaikinUnusedTime);
+ remote[kDaikinByteOffTimer] &= ~kDaikinBitOffTimer;
+}
+
+uint16_t IRDaikinESP::getOffTime(void) {
+ return (remote[kDaikinByteOffTimerMinsHigh] << 4) +
+ ((remote[kDaikinByteOffTimerMinsLow] & 0xF0) >> 4);
+}
+
+bool IRDaikinESP::getOffTimerEnabled(void) {
+ return remote[kDaikinByteOffTimer] & kDaikinBitOffTimer;
+}
+
+void IRDaikinESP::setCurrentTime(const uint16_t mins_since_midnight) {
+ uint16_t mins = mins_since_midnight;
+ if (mins > 24 * 60) mins = 0; // If > 23:59, set to 00:00
+ remote[kDaikinByteClockMinsLow] = mins;
+ // only keep 4 bits
+ remote[kDaikinByteClockMinsHigh] &= 0xF0;
+ remote[kDaikinByteClockMinsHigh] |= ((mins >> 8) & 0x0F);
+}
+
+uint16_t IRDaikinESP::getCurrentTime(void) {
+ return ((remote[kDaikinByteClockMinsHigh] & 0x0F) << 8) +
+ remote[kDaikinByteClockMinsLow];
+}
+
+#ifdef ARDUINO
+String IRDaikinESP::renderTime(const uint16_t timemins) {
+ String ret;
+#else // ARDUINO
+std::string IRDaikinESP::renderTime(const uint16_t timemins) {
+ std::string ret;
+#endif // ARDUINO
+ ret = uint64ToString(timemins / 60) + ':';
+ uint8_t mins = timemins % 60;
+ if (mins < 10) ret += '0';
+ ret += uint64ToString(mins);
+ return ret;
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRDaikinESP::toString(void) {
+ String result = "";
+#else // ARDUINO
+std::string IRDaikinESP::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += this->getPower() ? F("On") : F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kDaikinAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinCool:
+ result += F(" (COOL)");
+ break;
+ case kDaikinHeat:
+ result += F(" (HEAT)");
+ break;
+ case kDaikinDry:
+ result += F(" (DRY)");
+ break;
+ case kDaikinFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kDaikinFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinFanQuiet:
+ result += F(" (QUIET)");
+ break;
+ case kDaikinFanMin:
+ result += F(" (MIN)");
+ break;
+ case kDaikinFanMax:
+ result += F(" (MAX)");
+ break;
+ }
+ result += F(", Powerful: ");
+ result += this->getPowerful() ? F("On") : F("Off");
+ result += F(", Quiet: ");
+ result += this->getQuiet() ? F("On") : F("Off");
+ result += F(", Sensor: ");
+ result += this->getSensor() ? F("On") : F("Off");
+ result += F(", Eye: ");
+ result += this->getEye() ? F("On") : F("Off");
+ result += F(", Mold: ");
+ result += this->getMold() ? F("On") : F("Off");
+ result += F(", Comfort: ");
+ result += this->getComfort() ? F("On") : F("Off");
+ result += F(", Swing (Horizontal): ");
+ result += this->getSwingHorizontal() ? F("On") : F("Off");
+ result += F(", Swing (Vertical): ");
+ result += this->getSwingVertical() ? F("On") : F("Off");
+ result += F(", Current Time: ");
+ result += this->renderTime(this->getCurrentTime());
+ result += F(", On Time: ");
+ if (this->getOnTimerEnabled())
+ result += this->renderTime(this->getOnTime());
+ else
+ result += F("Off");
+ result += F(", Off Time: ");
+ if (this->getOffTimerEnabled())
+ result += this->renderTime(this->getOffTime());
+ else
+ result += F("Off");
+ return result;
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRDaikinESP::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kDaikinCool;
+ case stdAc::opmode_t::kHeat:
+ return kDaikinHeat;
+ case stdAc::opmode_t::kDry:
+ return kDaikinDry;
+ case stdAc::opmode_t::kFan:
+ return kDaikinFan;
+ default:
+ return kDaikinAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikinESP::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kDaikinFanQuiet;
+ case stdAc::fanspeed_t::kLow:
+ return kDaikinFanMin;
+ case stdAc::fanspeed_t::kMedium:
+ return kDaikinFanMin + 1;
+ case stdAc::fanspeed_t::kHigh:
+ return kDaikinFanMax - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kDaikinFanMax;
+ default:
+ return kDaikinFanAuto;
+ }
+}
+
+#if DECODE_DAIKIN
+// Decode the supplied Daikin A/C message.
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: Nr. of bits to expect in the data portion. (kDaikinBits)
+// 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: BETA / Should be working.
+//
+// Ref:
+// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
+bool IRrecv::decodeDaikin(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ // Is there enough data to match successfully?
+ if (results->rawlen < (2 * (nbits + kDaikinHeaderLength) +
+ kDaikinSections * (kHeader + kFooter) + kFooter - 1))
+ return false;
+
+ // Compliance
+ if (strict && nbits != kDaikinBits) return false;
+
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+ uint16_t dataBitsSoFar = 0;
+ uint16_t i = 0;
+
+ // Header #1 - Doesn't count as data.
+ data_result = matchData(&(results->rawbuf[offset]), kDaikinHeaderLength,
+ kDaikinBitMark, kDaikinOneSpace,
+ kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinTolerance, kDaikinMarkExcess, false);
+ offset += data_result.used;
+ if (data_result.success == false) return false; // Fail
+ if (data_result.data) return false; // The header bits should be zero.
+
+ // Read the Data sections.
+ // Keep reading bytes until we either run out of section or state to fill.
+ const uint8_t kSectionSize[kDaikinSections] = {
+ kDaikinSection1Length, kDaikinSection2Length, kDaikinSection3Length};
+ for (uint8_t section = 0, pos = 0; section < kDaikinSections;
+ section++) {
+ pos += kSectionSize[section];
+ // Section Footer
+ if (!matchMark(results->rawbuf[offset++], kDaikinBitMark,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikinZeroSpace + kDaikinGap,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+ // Section Header
+ if (!matchMark(results->rawbuf[offset++], kDaikinHdrMark,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikinHdrSpace,
+ kDaikinTolerance, kDaikinMarkExcess)) return false;
+
+ // Section Data
+ for (; offset <= results->rawlen - 16 && i < pos;
+ i++, dataBitsSoFar += 8, offset += data_result.used) {
+ // Read in a byte at a time.
+ data_result =
+ matchData(&(results->rawbuf[offset]), 8,
+ kDaikinBitMark, kDaikinOneSpace,
+ kDaikinBitMark, kDaikinZeroSpace,
+ kDaikinTolerance, kDaikinMarkExcess, false);
+ if (data_result.success == false) break; // Fail
+ results->state[i] = (uint8_t)data_result.data;
+ }
+ }
+
+ // Footer
+ if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kDaikinGap))
+ return false;
+
+ // Compliance
+ if (strict) {
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != kDaikinBits) return false;
+ // Validate the checksum.
+ if (!IRDaikinESP::validChecksum(results->state)) return false;
+ }
+
+ // Success
+ results->decode_type = DAIKIN;
+ results->bits = dataBitsSoFar;
+ // No need to record the state as we stored it as we decoded it.
+ // As we use result->state, we don't record value, address, or command as it
+ // is a union data type.
+ return true;
+}
+#endif // DECODE_DAIKIN
+
+#if SEND_DAIKIN2
+// Send a Daikin2 A/C message.
+//
+// Args:
+// data: An array of kDaikin2StateLength bytes containing the IR command.
+//
+// Status: BETA/Appears to work.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/582
+void IRsend::sendDaikin2(unsigned char data[], uint16_t nbytes,
+ uint16_t repeat) {
+ if (nbytes < kDaikin2Section1Length)
+ return; // Not enough bytes to send a partial message.
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Leader
+ sendGeneric(kDaikin2LeaderMark, kDaikin2LeaderSpace,
+ 0, 0, 0, 0, 0, 0, (uint64_t) 0, // No data payload.
+ 0, kDaikin2Freq, false, 0, 50);
+ // Section #1
+ sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark,
+ kDaikin2OneSpace, kDaikin2BitMark, kDaikin2ZeroSpace,
+ kDaikin2BitMark, kDaikin2Gap, data, kDaikin2Section1Length,
+ kDaikin2Freq, false, 0, 50);
+ // Section #2
+ sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark,
+ kDaikin2OneSpace, kDaikin2BitMark, kDaikin2ZeroSpace,
+ kDaikin2BitMark, kDaikin2Gap, data + kDaikin2Section1Length,
+ nbytes - kDaikin2Section1Length,
+ kDaikin2Freq, false, 0, 50);
+ }
+}
+#endif // SEND_DAIKIN2
+
+// Class for handling Daikin2 A/C messages.
+//
+// Code by crankyoldgit, Reverse engineering analysis by sheppy99
+//
+// Supported Remotes: Daikin ARC477A1 remote
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/582
+// https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit?usp=sharing
+// https://www.daikin.co.nz/sites/default/files/daikin-split-system-US7-FTXZ25-50NV1B.pdf
+IRDaikin2::IRDaikin2(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRDaikin2::begin() { _irsend.begin(); }
+
+#if SEND_DAIKIN2
+void IRDaikin2::send(const uint16_t repeat) {
+ checksum();
+ _irsend.sendDaikin2(remote_state, kDaikin2StateLength, repeat);
+}
+#endif // SEND_DAIKIN2
+
+// 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 IRDaikin2::validChecksum(uint8_t state[], const uint16_t length) {
+ // Validate the checksum of section #1.
+ if (length <= kDaikin2Section1Length - 1 ||
+ state[kDaikin2Section1Length - 1] != sumBytes(state,
+ kDaikin2Section1Length - 1))
+ return false;
+ // Validate the checksum of section #2 (a.k.a. the rest)
+ if (length <= kDaikin2Section1Length + 1 ||
+ state[length - 1] != sumBytes(state + kDaikin2Section1Length,
+ length - kDaikin2Section1Length - 1))
+ return false;
+ return true;
+}
+
+// Calculate and set the checksum values for the internal state.
+void IRDaikin2::checksum() {
+ remote_state[kDaikin2Section1Length - 1] = sumBytes(
+ remote_state, kDaikin2Section1Length - 1);
+ remote_state[kDaikin2StateLength -1 ] = sumBytes(
+ remote_state + kDaikin2Section1Length, kDaikin2Section2Length - 1);
+}
+
+void IRDaikin2::stateReset() {
+ for (uint8_t i = 0; i < kDaikin2StateLength; i++) remote_state[i] = 0x0;
+
+ remote_state[0] = 0x11;
+ remote_state[1] = 0xDA;
+ remote_state[2] = 0x27;
+ remote_state[4] = 0x01;
+ remote_state[6] = 0xC0;
+ remote_state[7] = 0x70;
+ remote_state[8] = 0x08;
+ remote_state[9] = 0x0C;
+ remote_state[10] = 0x80;
+ remote_state[11] = 0x04;
+ remote_state[12] = 0xB0;
+ remote_state[13] = 0x16;
+ remote_state[14] = 0x24;
+ remote_state[17] = 0xBE;
+ remote_state[18] = 0xD0;
+ // remote_state[19] is a checksum byte, it will be set by checksum().
+ remote_state[20] = 0x11;
+ remote_state[21] = 0xDA;
+ remote_state[22] = 0x27;
+ remote_state[25] = 0x08;
+ remote_state[28] = 0xA0;
+ remote_state[35] = 0xC1;
+ remote_state[36] = 0x80;
+ remote_state[37] = 0x60;
+ // remote_state[38] is a checksum byte, it will be set by checksum().
+ disableOnTimer();
+ disableOffTimer();
+ disableSleepTimer();
+ checksum();
+}
+
+uint8_t *IRDaikin2::getRaw() {
+ checksum(); // Ensure correct settings before sending.
+ return remote_state;
+}
+
+void IRDaikin2::setRaw(const uint8_t new_code[]) {
+ for (uint8_t i = 0; i < kDaikin2StateLength; i++)
+ remote_state[i] = new_code[i];
+}
+
+void IRDaikin2::on() {
+ remote_state[25] |= kDaikinBitPower;
+ remote_state[6] &= ~kDaikin2BitPower;
+}
+
+void IRDaikin2::off() {
+ remote_state[25] &= ~kDaikinBitPower;
+ remote_state[6] |= kDaikin2BitPower;
+}
+
+void IRDaikin2::setPower(const bool state) {
+ if (state)
+ on();
+ else
+ off();
+}
+
+bool IRDaikin2::getPower() {
+ return (remote_state[25] & kDaikinBitPower) &&
+ !(remote_state[6] & kDaikin2BitPower);
+}
+
+uint8_t IRDaikin2::getMode() { return remote_state[25] >> 4; }
+
+void IRDaikin2::setMode(const uint8_t desired_mode) {
+ uint8_t mode = desired_mode;
+ switch (mode) {
+ case kDaikinCool:
+ case kDaikinHeat:
+ case kDaikinFan:
+ case kDaikinDry:
+ break;
+ default:
+ mode = kDaikinAuto;
+ }
+ remote_state[25] &= 0b10001111;
+ remote_state[25] |= (mode << 4);
+ // Redo the temp setting as Cool mode has a different min temp.
+ if (mode == kDaikinCool) this->setTemp(this->getTemp());
+}
+
+// Set the temp in deg C
+void IRDaikin2::setTemp(const uint8_t desired) {
+ // The A/C has a different min temp if in cool mode.
+ uint8_t temp = std::max(
+ (this->getMode() == kDaikinCool) ? kDaikin2MinCoolTemp : kDaikinMinTemp,
+ desired);
+ temp = std::min(kDaikinMaxTemp, temp);
+ remote_state[26] = temp * 2;
+}
+
+// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
+void IRDaikin2::setFan(const uint8_t fan) {
+ // Set the fan speed bits, leave low 4 bits alone
+ uint8_t fanset;
+ if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto)
+ fanset = fan;
+ else if (fan < kDaikinFanMin || fan > kDaikinFanMax)
+ fanset = kDaikinFanAuto;
+ else
+ fanset = 2 + fan;
+ remote_state[28] &= 0x0F;
+ remote_state[28] |= (fanset << 4);
+}
+
+uint8_t IRDaikin2::getFan() {
+ uint8_t fan = remote_state[28] >> 4;
+ if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
+ return fan;
+}
+
+uint8_t IRDaikin2::getTemp() { return remote_state[26] / 2; }
+
+void IRDaikin2::setSwingVertical(const uint8_t position) {
+ switch (position) {
+ case kDaikin2SwingVHigh:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case kDaikin2SwingVLow:
+ case kDaikin2SwingVBreeze:
+ case kDaikin2SwingVCirculate:
+ case kDaikin2SwingVAuto:
+ remote_state[18] &= 0xF0;
+ remote_state[18] |= (position & 0x0F);
+ }
+}
+
+uint8_t IRDaikin2::getSwingVertical() { return remote_state[18] & 0x0F; }
+
+void IRDaikin2::setSwingHorizontal(const uint8_t position) {
+ remote_state[17] = position;
+}
+
+uint8_t IRDaikin2::getSwingHorizontal() { return remote_state[17]; }
+
+void IRDaikin2::setCurrentTime(const uint16_t numMins) {
+ uint16_t mins = numMins;
+ if (numMins > 24 * 60) mins = 0; // If > 23:59, set to 00:00
+ remote_state[5] = (uint8_t)(mins & 0xFF);
+ // only keep 4 bits
+ remote_state[6] &= 0xF0;
+ remote_state[6] |= (uint8_t)((mins >> 8) & 0x0F);
+}
+
+uint16_t IRDaikin2::getCurrentTime() {
+ return ((remote_state[6] & 0x0F) << 8) + remote_state[5];
+}
+
+// starttime: Number of minutes after midnight.
+// Note: Timer location is shared with sleep timer.
+void IRDaikin2::enableOnTimer(const uint16_t starttime) {
+ clearSleepTimerFlag();
+ remote_state[25] |= kDaikinBitOnTimer; // Set the On Timer flag.
+ remote_state[30] = (uint8_t)(starttime & 0xFF);
+ // only keep 4 bits
+ remote_state[31] &= 0xF0;
+ remote_state[31] |= (uint8_t)((starttime >> 8) & 0x0F);
+}
+
+void IRDaikin2::clearOnTimerFlag() {
+ remote_state[25] &= ~kDaikinBitOnTimer;
+}
+
+void IRDaikin2::disableOnTimer() {
+ enableOnTimer(kDaikinUnusedTime);
+ clearOnTimerFlag();
+ clearSleepTimerFlag();
+}
+
+uint16_t IRDaikin2::getOnTime() {
+ return ((remote_state[31] & 0x0F) << 8) + remote_state[30];
+}
+
+bool IRDaikin2::getOnTimerEnabled() {
+ return remote_state[25] & kDaikinBitOnTimer;
+}
+
+// endtime: Number of minutes after midnight.
+void IRDaikin2::enableOffTimer(const uint16_t endtime) {
+ remote_state[25] |= kDaikinBitOffTimer; // Set the Off Timer flag.
+ remote_state[32] = (uint8_t)((endtime >> 4) & 0xFF);
+ remote_state[31] &= 0x0F;
+ remote_state[31] |= (uint8_t)((endtime & 0xF) << 4);
+}
+
+void IRDaikin2::disableOffTimer() {
+ enableOffTimer(kDaikinUnusedTime);
+ remote_state[25] &= ~kDaikinBitOffTimer; // Clear the Off Timer flag.
+}
+
+uint16_t IRDaikin2::getOffTime() {
+ return (remote_state[32] << 4) + (remote_state[31] >> 4);
+}
+
+bool IRDaikin2::getOffTimerEnabled() {
+ return remote_state[25] & kDaikinBitOffTimer;
+}
+
+uint8_t IRDaikin2::getBeep() {
+ return remote_state[7] >> 6;
+}
+
+void IRDaikin2::setBeep(const uint8_t beep) {
+ remote_state[7] &= ~kDaikin2BeepMask;
+ remote_state[7] |= ((beep << 6) & kDaikin2BeepMask);
+}
+
+uint8_t IRDaikin2::getLight() {
+ return (remote_state[7] & kDaikin2LightMask) >> 4;
+}
+
+void IRDaikin2::setLight(const uint8_t light) {
+ remote_state[7] &= ~kDaikin2LightMask;
+ remote_state[7] |= ((light << 4) & kDaikin2LightMask);
+}
+
+void IRDaikin2::setMold(const bool on) {
+ if (on)
+ remote_state[8] |= kDaikin2BitMold;
+ else
+ remote_state[8] &= ~kDaikin2BitMold;
+}
+
+bool IRDaikin2::getMold() {
+ return remote_state[8] & kDaikin2BitMold;
+}
+
+// Auto clean setting.
+void IRDaikin2::setClean(const bool on) {
+ if (on)
+ remote_state[8] |= kDaikin2BitClean;
+ else
+ remote_state[8] &= ~kDaikin2BitClean;
+}
+
+bool IRDaikin2::getClean() {
+ return remote_state[8] & kDaikin2BitClean;
+}
+
+// Fresh Air settings.
+void IRDaikin2::setFreshAir(const bool on) {
+ if (on)
+ remote_state[8] |= kDaikin2BitFreshAir;
+ else
+ remote_state[8] &= ~kDaikin2BitFreshAir;
+}
+
+bool IRDaikin2::getFreshAir() {
+ return remote_state[8] & kDaikin2BitFreshAir;
+}
+
+void IRDaikin2::setFreshAirHigh(const bool on) {
+ if (on)
+ remote_state[8] |= kDaikin2BitFreshAirHigh;
+ else
+ remote_state[8] &= ~kDaikin2BitFreshAirHigh;
+}
+
+bool IRDaikin2::getFreshAirHigh() {
+ return remote_state[8] & kDaikin2BitFreshAirHigh;
+}
+
+void IRDaikin2::setEyeAuto(bool on) {
+ if (on)
+ remote_state[13] |= kDaikin2BitEyeAuto;
+ else
+ remote_state[13] &= ~kDaikin2BitEyeAuto;
+}
+
+bool IRDaikin2::getEyeAuto() {
+ return remote_state[13] & kDaikin2BitEyeAuto;
+}
+
+void IRDaikin2::setEye(bool on) {
+ if (on)
+ remote_state[36] |= kDaikin2BitEye;
+ else
+ remote_state[36] &= ~kDaikin2BitEye;
+}
+
+bool IRDaikin2::getEye() {
+ return remote_state[36] & kDaikin2BitEye;
+}
+
+void IRDaikin2::setEcono(bool on) {
+ if (on)
+ remote_state[36] |= kDaikinBitEcono;
+ else
+ remote_state[36] &= ~kDaikinBitEcono;
+}
+
+bool IRDaikin2::getEcono() {
+ return remote_state[36] & kDaikinBitEcono;
+}
+
+// sleeptime: Number of minutes.
+// Note: Timer location is shared with On Timer.
+void IRDaikin2::enableSleepTimer(const uint16_t sleeptime) {
+ enableOnTimer(sleeptime);
+ clearOnTimerFlag();
+ remote_state[36] |= kDaikin2BitSleepTimer; // Set the Sleep Timer flag.
+}
+
+void IRDaikin2::clearSleepTimerFlag() {
+ remote_state[36] &= ~kDaikin2BitSleepTimer;
+}
+
+void IRDaikin2::disableSleepTimer() {
+ disableOnTimer();
+}
+
+uint16_t IRDaikin2::getSleepTime() {
+ return getOnTime();
+}
+
+bool IRDaikin2::getSleepTimerEnabled() {
+ return remote_state[36] & kDaikin2BitSleepTimer;
+}
+
+void IRDaikin2::setQuiet(const bool on) {
+ if (on) {
+ remote_state[33] |= kDaikinBitSilent;
+ // Powerful & Quiet mode being on are mutually exclusive.
+ setPowerful(false);
+ } else {
+ remote_state[33] &= ~kDaikinBitSilent;
+ }
+}
+
+bool IRDaikin2::getQuiet() { return remote_state[33] & kDaikinBitSilent; }
+
+void IRDaikin2::setPowerful(const bool on) {
+ if (on) {
+ remote_state[33] |= kDaikinBitPowerful;
+ // Powerful & Quiet mode being on are mutually exclusive.
+ setQuiet(false);
+ } else {
+ remote_state[33] &= ~kDaikinBitPowerful;
+ }
+}
+
+bool IRDaikin2::getPowerful() { return remote_state[33] & kDaikinBitPowerful; }
+
+void IRDaikin2::setPurify(const bool on) {
+ if (on)
+ remote_state[36] |= kDaikin2BitPurify;
+ else
+ remote_state[36] &= ~kDaikin2BitPurify;
+}
+
+bool IRDaikin2::getPurify() { return remote_state[36] & kDaikin2BitPurify; }
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRDaikin2::convertMode(const stdAc::opmode_t mode) {
+ return IRDaikinESP::convertMode(mode);
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikin2::convertFan(const stdAc::fanspeed_t speed) {
+ return IRDaikinESP::convertFan(speed);
+}
+
+// Convert a standard A/C vertical swing into its native version.
+uint8_t IRDaikin2::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return (uint8_t)position + kDaikin2SwingVHigh;
+ default:
+ return kDaikin2SwingVAuto;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRDaikin2::toString() {
+ String result = "";
+#else // ARDUINO
+std::string IRDaikin2::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ if (getPower())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (getMode()) {
+ case kDaikinAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinCool:
+ result += F(" (COOL)");
+ break;
+ case kDaikinHeat:
+ result += F(" (HEAT)");
+ break;
+ case kDaikinDry:
+ result += F(" (DRY)");
+ break;
+ case kDaikinFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kDaikinFanAuto:
+ result += F(" (Auto)");
+ break;
+ case kDaikinFanQuiet:
+ result += F(" (Quiet)");
+ break;
+ case kDaikinFanMin:
+ result += F(" (Min)");
+ break;
+ case kDaikinFanMax:
+ result += F(" (Max)");
+ break;
+ }
+ result += F(", Swing (V): ");
+ result += uint64ToString(getSwingVertical());
+ switch (getSwingVertical()) {
+ case kDaikin2SwingVHigh:
+ result += F(" (Highest)");
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ case kDaikin2SwingVLow:
+ result += F(" (Lowest)");
+ break;
+ case kDaikin2SwingVBreeze:
+ result += F(" (Breeze)");
+ break;
+ case kDaikin2SwingVCirculate:
+ result += F(" (Circulate)");
+ break;
+ case kDaikin2SwingVAuto:
+ result += F(" (Auto)");
+ break;
+ default:
+ result += F(" (Unknown)");
+ }
+ result += F(", Swing (H): ");
+ result += uint64ToString(getSwingHorizontal());
+ switch (getSwingHorizontal()) {
+ case kDaikin2SwingHAuto:
+ result += F(" (Auto)");
+ break;
+ case kDaikin2SwingHSwing:
+ result += F(" (Swing)");
+ break;
+ }
+ result += F(", Clock: ");
+ result += IRDaikinESP::renderTime(getCurrentTime());
+ result += F(", On Time: ");
+ if (getOnTimerEnabled())
+ result += IRDaikinESP::renderTime(getOnTime());
+ else
+ result += F("Off");
+ result += F(", Off Time: ");
+ if (getOffTimerEnabled())
+ result += IRDaikinESP::renderTime(getOffTime());
+ else
+ result += F("Off");
+ result += F(", Sleep Time: ");
+ if (getSleepTimerEnabled())
+ result += IRDaikinESP::renderTime(getSleepTime());
+ else
+ result += F("Off");
+ result += F(", Beep: ");
+ result += uint64ToString(getBeep());
+ switch (getBeep()) {
+ case kDaikinBeepLoud:
+ result += F(" (Loud)");
+ break;
+ case kDaikinBeepQuiet:
+ result += F(" (Quiet)");
+ break;
+ case kDaikinBeepOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Light: ");
+ result += uint64ToString(getLight());
+ switch (getLight()) {
+ case kDaikinLightBright:
+ result += F(" (Bright)");
+ break;
+ case kDaikinLightDim:
+ result += F(" (Dim)");
+ break;
+ case kDaikinLightOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Mold: ");
+ result += (getMold() ? F("On") : F("Off"));
+ result += F(", Clean: ");
+ result += (getClean() ? F("On") : F("Off"));
+ result += F(", Fresh Air: ");
+ if (getFreshAir())
+ result += (getFreshAirHigh() ? "High" : "On");
+ else
+ result += F("Off");
+ result += F(", Eye: ");
+ result += (getEye() ? F("On") : F("Off"));
+ result += F(", Eye Auto: ");
+ result += (getEyeAuto() ? F("On") : F("Off"));
+ result += F(", Quiet: ");
+ result += (getQuiet() ? F("On") : F("Off"));
+ result += F(", Powerful: ");
+ result += (getPowerful() ? F("On") : F("Off"));
+ result += ", Purify: ";
+ result += (getPurify() ? F("On") : F("Off"));
+ result += F(", Econo: ");
+ result += (getEcono() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_DAIKIN2
+// Decode the supplied Daikin2 A/C message.
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: Nr. of bits to expect in the data portion. (kDaikin2Bits)
+// 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 FTXZ25NV1B, FTXZ35NV1B, FTXZ50NV1B Aircon
+// - Daikin ARC477A1 remote
+//
+// Status: BETA / Work as expected.
+//
+// Ref:
+// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
+bool IRrecv::decodeDaikin2(decode_results *results, uint16_t nbits,
+ bool strict) {
+ if (results->rawlen < 2 * (nbits + kHeader + kFooter) + kHeader - 1)
+ return false;
+
+ // Compliance
+ if (strict && nbits != kDaikin2Bits) return false;
+
+ uint16_t offset = kStartOffset;
+ uint16_t dataBitsSoFar = 0;
+ uint16_t i = 0;
+ match_result_t data_result;
+ uint8_t sectionSize[kDaikin2Sections] = {kDaikin2Section1Length,
+ kDaikin2Section2Length};
+
+ // Leader
+ if (!matchMark(results->rawbuf[offset++], kDaikin2LeaderMark,
+ kDaikin2Tolerance)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2LeaderSpace,
+ kDaikin2Tolerance)) return false;
+
+ // Sections
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint8_t section = 0, pos = 0; section < kDaikin2Sections;
+ section++) {
+ pos += sectionSize[section];
+
+ // Section Header
+ if (!matchMark(results->rawbuf[offset++], kDaikin2HdrMark,
+ kDaikin2Tolerance)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2HdrSpace,
+ kDaikin2Tolerance)) return false;
+
+ // Section Data
+ for (; offset <= results->rawlen - 16 && i < pos;
+ i++, dataBitsSoFar += 8, offset += data_result.used) {
+ // Read in a byte at a time.
+ data_result =
+ matchData(&(results->rawbuf[offset]), 8, kDaikin2BitMark,
+ kDaikin2OneSpace, kDaikin2BitMark,
+ kDaikin2ZeroSpace, kDaikin2Tolerance, kMarkExcess, false);
+ if (data_result.success == false) break; // Fail
+ results->state[i] = (uint8_t)data_result.data;
+ }
+
+ // Section Footer
+ if (!matchMark(results->rawbuf[offset++], kDaikin2BitMark,
+ kDaikin2Tolerance)) return false;
+ if (section < kDaikin2Sections - 1) { // Inter-section gaps.
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2Gap,
+ kDaikin2Tolerance)) return false;
+ } else { // Last section / End of message gap.
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kDaikin2Gap,
+ kDaikin2Tolerance)) return false;
+ }
+ }
+
+ // Compliance
+ if (strict) {
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != kDaikin2Bits) return false;
+ // Validate the checksum.
+ if (!IRDaikin2::validChecksum(results->state)) return false;
+ }
+
+ // Success
+ results->decode_type = DAIKIN2;
+ results->bits = dataBitsSoFar;
+ // No need to record the state as we stored it as we decoded it.
+ // As we use result->state, we don't record value, address, or command as it
+ // is a union data type.
+ return true;
+}
+#endif // DECODE_DAIKIN2
+
+#if SEND_DAIKIN216
+// Send a Daikin 216 bit A/C message.
+//
+// Args:
+// data: An array of kDaikin216StateLength bytes containing the IR command.
+//
+// Status: Alpha/Untested on a real device.
+//
+// Supported devices:
+// - Daikin ARC433B69 remote.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+// https://github.com/danny-source/Arduino_DY_IRDaikin
+void IRsend::sendDaikin216(const unsigned char data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kDaikin216Section1Length)
+ return; // Not enough bytes to send a partial message.
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Section #1
+ sendGeneric(kDaikin216HdrMark, kDaikin216HdrSpace, kDaikin216BitMark,
+ kDaikin216OneSpace, kDaikin216BitMark, kDaikin216ZeroSpace,
+ kDaikin216BitMark, kDaikin216Gap, data,
+ kDaikin216Section1Length,
+ kDaikin216Freq, false, 0, kDutyDefault);
+ // Section #2
+ sendGeneric(kDaikin216HdrMark, kDaikin216HdrSpace, kDaikin216BitMark,
+ kDaikin216OneSpace, kDaikin216BitMark, kDaikin216ZeroSpace,
+ kDaikin216BitMark, kDaikin216Gap,
+ data + kDaikin216Section1Length,
+ nbytes - kDaikin216Section1Length,
+ kDaikin216Freq, false, 0, kDutyDefault);
+ }
+}
+#endif // SEND_DAIKIN216
+
+// Class for handling Daikin 216 bit / 27 byte A/C messages.
+//
+// Code by crankyoldgit.
+//
+// Supported Remotes: Daikin ARC433B69 remote
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+// https://github.com/danny-source/Arduino_DY_IRDaikin
+IRDaikin216::IRDaikin216(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRDaikin216::begin() { _irsend.begin(); }
+
+#if SEND_DAIKIN216
+void IRDaikin216::send(const uint16_t repeat) {
+ checksum();
+ _irsend.sendDaikin216(remote_state, kDaikin216StateLength, repeat);
+}
+#endif // SEND_DAIKIN216
+
+// 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 IRDaikin216::validChecksum(uint8_t state[], const uint16_t length) {
+ // Validate the checksum of section #1.
+ if (length <= kDaikin216Section1Length - 1 ||
+ state[kDaikin216Section1Length - 1] != sumBytes(
+ state, kDaikin216Section1Length - 1))
+ return false;
+ // Validate the checksum of section #2 (a.k.a. the rest)
+ if (length <= kDaikin216Section1Length + 1 ||
+ state[length - 1] != sumBytes(state + kDaikin216Section1Length,
+ length - kDaikin216Section1Length - 1))
+ return false;
+ return true;
+}
+
+// Calculate and set the checksum values for the internal state.
+void IRDaikin216::checksum() {
+ remote_state[kDaikin216Section1Length - 1] = sumBytes(
+ remote_state, kDaikin216Section1Length - 1);
+ remote_state[kDaikin216StateLength - 1] = sumBytes(
+ remote_state + kDaikin216Section1Length, kDaikin216Section2Length - 1);
+}
+
+void IRDaikin216::stateReset() {
+ for (uint8_t i = 0; i < kDaikin216StateLength; i++) remote_state[i] = 0x00;
+ remote_state[0] = 0x11;
+ remote_state[1] = 0xDA;
+ remote_state[2] = 0x27;
+ remote_state[3] = 0xF0;
+ // remote_state[7] is a checksum byte, it will be set by checksum().
+ remote_state[8] = 0x11;
+ remote_state[9] = 0xDA;
+ remote_state[10] = 0x27;
+ remote_state[23] = 0xC0;
+ // remote_state[26] is a checksum byte, it will be set by checksum().
+}
+
+uint8_t *IRDaikin216::getRaw() {
+ checksum(); // Ensure correct settings before sending.
+ return remote_state;
+}
+
+void IRDaikin216::setRaw(const uint8_t new_code[]) {
+ for (uint8_t i = 0; i < kDaikin216StateLength; i++)
+ remote_state[i] = new_code[i];
+}
+
+
+void IRDaikin216::on() {
+ remote_state[kDaikin216BytePower] |= kDaikinBitPower;
+}
+
+void IRDaikin216::off() {
+ remote_state[kDaikin216BytePower] &= ~kDaikinBitPower;
+}
+
+void IRDaikin216::setPower(const bool state) {
+ if (state)
+ on();
+ else
+ off();
+}
+
+bool IRDaikin216::getPower() {
+ return remote_state[kDaikin216BytePower] & kDaikinBitPower;
+}
+
+uint8_t IRDaikin216::getMode() {
+ return (remote_state[kDaikin216ByteMode] & kDaikin216MaskMode) >> 4;
+}
+
+void IRDaikin216::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kDaikinAuto:
+ case kDaikinCool:
+ case kDaikinHeat:
+ case kDaikinFan:
+ case kDaikinDry:
+ remote_state[kDaikin216ByteMode] &= ~kDaikin216MaskMode;
+ remote_state[kDaikin216ByteMode] |= (mode << 4);
+ break;
+ default:
+ this->setMode(kDaikinAuto);
+ }
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRDaikin216::convertMode(const stdAc::opmode_t mode) {
+ return IRDaikinESP::convertMode(mode);
+}
+
+// Set the temp in deg C
+void IRDaikin216::setTemp(const uint8_t temp) {
+ uint8_t degrees = std::max(temp, kDaikinMinTemp);
+ degrees = std::min(degrees, kDaikinMaxTemp);
+ remote_state[kDaikin216ByteTemp] &= ~kDaikin216MaskTemp;
+ remote_state[kDaikin216ByteTemp] |= (degrees << 1);
+}
+
+uint8_t IRDaikin216::getTemp(void) {
+ return (remote_state[kDaikin216ByteTemp] & kDaikin216MaskTemp) >> 1;
+}
+
+// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
+void IRDaikin216::setFan(const uint8_t fan) {
+ // Set the fan speed bits, leave low 4 bits alone
+ uint8_t fanset;
+ if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto)
+ fanset = fan;
+ else if (fan < kDaikinFanMin || fan > kDaikinFanMax)
+ fanset = kDaikinFanAuto;
+ else
+ fanset = 2 + fan;
+ remote_state[kDaikin216ByteFan] &= ~kDaikin216MaskFan;
+ remote_state[kDaikin216ByteFan] |= (fanset << 4);
+}
+
+uint8_t IRDaikin216::getFan() {
+ uint8_t fan = remote_state[kDaikin216ByteFan] >> 4;
+ if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
+ return fan;
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRDaikin216::convertFan(const stdAc::fanspeed_t speed) {
+ return IRDaikinESP::convertFan(speed);
+}
+
+void IRDaikin216::setSwingVertical(const bool on) {
+ if (on)
+ remote_state[kDaikin216ByteSwingV] |= kDaikin216MaskSwingV;
+ else
+ remote_state[kDaikin216ByteSwingV] &= ~kDaikin216MaskSwingV;
+}
+
+bool IRDaikin216::getSwingVertical(void) {
+ return remote_state[kDaikin216ByteSwingV] & kDaikin216MaskSwingV;
+}
+
+void IRDaikin216::setSwingHorizontal(const bool on) {
+ if (on)
+ remote_state[kDaikin216ByteSwingH] |= kDaikin216MaskSwingH;
+ else
+ remote_state[kDaikin216ByteSwingH] &= ~kDaikin216MaskSwingH;
+}
+
+bool IRDaikin216::getSwingHorizontal(void) {
+ return remote_state[kDaikin216ByteSwingH] & kDaikin216MaskSwingH;
+}
+
+// This is a horrible hack till someone works out the quiet mode bit.
+void IRDaikin216::setQuiet(const bool on) {
+ if (on)
+ this->setFan(kDaikinFanQuiet);
+ else if (this->getFan() == kDaikinFanQuiet)
+ this->setFan(kDaikinFanAuto);
+}
+
+// This is a horrible hack till someone works out the quiet mode bit.
+bool IRDaikin216::getQuiet(void) {
+ return this->getFan() == kDaikinFanQuiet;
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRDaikin216::toString() {
+ String result = "";
+#else // ARDUINO
+std::string IRDaikin216::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ if (this->getPower())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (getMode()) {
+ case kDaikinAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinCool:
+ result += F(" (COOL)");
+ break;
+ case kDaikinHeat:
+ result += F(" (HEAT)");
+ break;
+ case kDaikinDry:
+ result += F(" (DRY)");
+ break;
+ case kDaikinFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kDaikinFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kDaikinFanQuiet:
+ result += F(" (QUIET)");
+ break;
+ case kDaikinFanMin:
+ result += F(" (MIN)");
+ break;
+ case kDaikinFanMax:
+ result += F(" (MAX)");
+ break;
+ }
+ result += F(", Swing (Horizontal): ");
+ result += this->getSwingHorizontal() ? F("On") : F("Off");
+ result += F(", Swing (Vertical): ");
+ result += this->getSwingVertical() ? F("On") : F("Off");
+ result += F(", Quiet: ");
+ result += (getQuiet() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_DAIKIN216
+// Decode the supplied Daikin 216 bit A/C message.
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: Nr. of bits to expect in the data portion. (kDaikin216Bits)
+// 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 ARC433B69 remote.
+//
+// Status: BETA / Should be working.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+// https://github.com/danny-source/Arduino_DY_IRDaikin
+bool IRrecv::decodeDaikin216(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1)
+ return false;
+
+ // Compliance
+ if (strict && nbits != kDaikin216Bits) return false;
+
+ uint16_t offset = kStartOffset;
+ uint16_t dataBitsSoFar = 0;
+ uint16_t i = 0;
+ match_result_t data_result;
+ uint8_t sectionSize[kDaikin216Sections] = {kDaikin216Section1Length,
+ kDaikin216Section2Length};
+
+ // Sections
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint8_t section = 0, pos = 0; section < kDaikin216Sections;
+ section++) {
+ pos += sectionSize[section];
+
+ // Section Header
+ if (!matchMark(results->rawbuf[offset++], kDaikin216HdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kDaikin2HdrSpace)) return false;
+
+ // Section Data
+ for (; offset <= results->rawlen - 16 && i < pos;
+ i++, dataBitsSoFar += 8, offset += data_result.used) {
+ // Read in a byte at a time.
+ data_result =
+ matchData(&(results->rawbuf[offset]), 8, kDaikin216BitMark,
+ kDaikin216OneSpace, kDaikin216BitMark,
+ kDaikin216ZeroSpace, kTolerance, kMarkExcess, false);
+ if (data_result.success == false) break; // Fail
+ results->state[i] = (uint8_t)data_result.data;
+ }
+
+ // Section Footer
+ if (!matchMark(results->rawbuf[offset++], kDaikin216BitMark)) return false;
+ if (section < kDaikin216Sections - 1) { // Inter-section gaps.
+ if (!matchSpace(results->rawbuf[offset++], kDaikin216Gap)) return false;
+ } else { // Last section / End of message gap.
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kDaikin216Gap)) return false;
+ }
+ }
+
+ // Compliance
+ if (strict) {
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != kDaikin216Bits) return false;
+ // Validate the checksum.
+ if (!IRDaikin216::validChecksum(results->state)) return false;
+ }
+
+ // Success
+ results->decode_type = decode_type_t::DAIKIN216;
+ results->bits = dataBitsSoFar;
+ // No need to record the state as we stored it as we decoded it.
+ // As we use result->state, we don't record value, address, or command as it
+ // is a union data type.
+ return true;
+}
+#endif // DECODE_DAIKIN216
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.h b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.h
new file mode 100644
index 000000000000..038e8edd97f3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Daikin.h
@@ -0,0 +1,444 @@
+// Copyright 2016 sillyfrog
+// Copyright 2017 sillyfrog, crankyoldgit
+// Copyright 2018-2019 crankyoldgit
+#ifndef IR_DAIKIN_H_
+#define IR_DAIKIN_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// DDDDD AAA IIIII KK KK IIIII NN NN
+// DD DD AAAAA III KK KK III NNN NN
+// DD DD AA AA III KKKK III NN N NN
+// DD DD AAAAAAA III KK KK III NN NNN
+// DDDDDD AA AA IIIII KK KK IIIII NN NN
+
+/*
+ Daikin AC map
+ byte 6=
+ b4:Comfort
+ byte 7= checksum of the first part (and last byte before a 29ms pause)
+ byte 13=Current time, mins past midnight, low bits
+ byte 14
+ b0-b3=Current time, mins past midnight, high bits
+ byte 15= checksum of the second part (and last byte before a 29ms pause)
+ byte 21=mode
+ b7 = 0
+ b6+b5+b4 = Mode
+ Modes: b6+b5+b4
+ 011 = Cool
+ 100 = Heat (temp 23)
+ 110 = FAN (temp not shown, but 25)
+ 000 = Fully Automatic (temp 25)
+ 010 = DRY (temp 0xc0 = 96 degrees c)
+ b3 = 1
+ b2 = OFF timer set
+ b1 = ON timer set
+ b0 = Air Conditioner ON
+ byte 22=temp*2 (Temp should be between 10 - 32)
+ byte 24=Fan
+ FAN control
+ b7+b6+b5+b4 = Fan speed
+ Fan: b7+b6+b5+b4
+ 0Ă—3 = 1 bar
+ 0Ă—4 = 2 bar
+ 0Ă—5 = 3 bar
+ 0Ă—6 = 4 bar
+ 0Ă—7 = 5 bar
+ 0xa = Auto
+ 0xb = Quite
+ b3+b2+b1+b0 = Swing control up/down
+ Swing control up/down:
+ 0000 = Swing up/down off
+ 1111 = Swing up/down on
+ byte 25
+ Swing control left/right:
+ 0000 = Swing left/right off
+ 1111 = Swing left/right on
+ byte 26=On timer mins past midnight, low bits
+ byte 27
+ b0-b3=On timer mins past midnight, high bits
+ b4-b7=Off timer mins past midnight, low bits
+ byte 28=Off timer mins past midnight, high bits
+ byte 29=Aux -> Powerful (bit 1), Silent (bit 5)
+ byte 32=Aux2
+ b1: Sensor
+ b2: Econo mode
+ b7: Intelligent eye on
+ byte 33=Aux3
+ b1: Mold Proof
+ byte 34= checksum of the third part
+*/
+
+// Constants
+const uint8_t kDaikinAuto = 0b000;
+const uint8_t kDaikinDry = 0b010;
+const uint8_t kDaikinCool = 0b011;
+const uint8_t kDaikinHeat = 0b100;
+const uint8_t kDaikinFan = 0b110;
+const uint8_t kDaikinMinTemp = 10; // Celsius
+const uint8_t kDaikinMaxTemp = 32; // Celsius
+const uint8_t kDaikinFanMin = 1;
+const uint8_t kDaikinFanMax = 5;
+const uint8_t kDaikinFanAuto = 0b1010;
+const uint8_t kDaikinFanQuiet = 0b1011;
+const uint16_t kDaikinHeaderLength = 5;
+const uint8_t kDaikinSections = 3;
+const uint8_t kDaikinSection1Length = 8;
+const uint8_t kDaikinSection2Length = 8;
+const uint8_t kDaikinSection3Length =
+ kDaikinStateLength - kDaikinSection1Length - kDaikinSection2Length;
+const uint8_t kDaikinByteComfort = 6;
+const uint8_t kDaikinByteChecksum1 = 7;
+const uint8_t kDaikinBitComfort = 0b00010000;
+const uint8_t kDaikinByteClockMinsLow = 13;
+const uint8_t kDaikinByteClockMinsHigh = 14;
+const uint8_t kDaikinByteChecksum2 = 15;
+const uint8_t kDaikinBytePower = 21;
+const uint8_t kDaikinBitPower = 0b00000001;
+const uint8_t kDaikinByteTemp = 22;
+const uint8_t kDaikinByteFan = 24;
+const uint8_t kDaikinByteSwingH = 25;
+const uint8_t kDaikinByteOnTimerMinsLow = 26;
+const uint8_t kDaikinByteOnTimerMinsHigh = 27;
+const uint8_t kDaikinByteOffTimerMinsLow = kDaikinByteOnTimerMinsHigh;
+const uint8_t kDaikinByteOffTimerMinsHigh = 28;
+const uint8_t kDaikinBytePowerful = 29;
+const uint8_t kDaikinBitPowerful = 0b00000001;
+const uint8_t kDaikinByteSilent = kDaikinBytePowerful;
+const uint8_t kDaikinBitSilent = 0b00100000;
+const uint8_t kDaikinByteSensor = 32;
+const uint8_t kDaikinBitSensor = 0b00000010;
+const uint8_t kDaikinByteEcono = kDaikinByteSensor;
+const uint8_t kDaikinBitEcono = 0b00000100;
+const uint8_t kDaikinByteEye = kDaikinByteSensor;
+const uint8_t kDaikinBitEye = 0b10000000;
+const uint8_t kDaikinByteMold = 33;
+const uint8_t kDaikinBitMold = 0b00000010;
+const uint8_t kDaikinByteOffTimer = kDaikinBytePower;
+const uint8_t kDaikinBitOffTimer = 0b00000100;
+const uint8_t kDaikinByteOnTimer = kDaikinByteOffTimer;
+const uint8_t kDaikinBitOnTimer = 0b00000010;
+const uint8_t kDaikinByteChecksum3 = kDaikinStateLength - 1;
+const uint16_t kDaikinUnusedTime = 0x600;
+const uint8_t kDaikinBeepQuiet = 1;
+const uint8_t kDaikinBeepLoud = 2;
+const uint8_t kDaikinBeepOff = 3;
+const uint8_t kDaikinLightBright = 1;
+const uint8_t kDaikinLightDim = 2;
+const uint8_t kDaikinLightOff = 3;
+const uint8_t kDaikinCurBit = kDaikinStateLength;
+const uint8_t kDaikinCurIndex = kDaikinStateLength + 1;
+const uint8_t kDaikinTolerance = 35;
+const uint16_t kDaikinMarkExcess = kMarkExcess;
+const uint16_t kDaikinHdrMark = 3650; // kDaikinBitMark * 8
+const uint16_t kDaikinHdrSpace = 1623; // kDaikinBitMark * 4
+const uint16_t kDaikinBitMark = 428;
+const uint16_t kDaikinZeroSpace = 428;
+const uint16_t kDaikinOneSpace = 1280;
+const uint16_t kDaikinGap = 29000;
+// Note bits in each octet swapped so can be sent as a single value
+const uint64_t kDaikinFirstHeader64 =
+ 0b1101011100000000000000001100010100000000001001111101101000010001;
+
+// Another variant of the protocol for the Daikin ARC477A1 remote.
+const uint16_t kDaikin2Freq = 36700; // Modulation Frequency in Hz.
+const uint16_t kDaikin2LeaderMark = 10024;
+const uint16_t kDaikin2LeaderSpace = 25180;
+const uint16_t kDaikin2Gap = kDaikin2LeaderMark + kDaikin2LeaderSpace;
+const uint16_t kDaikin2HdrMark = 3500;
+const uint16_t kDaikin2HdrSpace = 1728;
+const uint16_t kDaikin2BitMark = 460;
+const uint16_t kDaikin2OneSpace = 1270;
+const uint16_t kDaikin2ZeroSpace = 420;
+const uint16_t kDaikin2Sections = 2;
+const uint16_t kDaikin2Section1Length = 20;
+const uint16_t kDaikin2Section2Length = 19;
+const uint8_t kDaikin2Tolerance = kTolerance + 5;
+
+const uint8_t kDaikin2BitSleepTimer = 0b00100000;
+const uint8_t kDaikin2BitPurify = 0b00010000;
+const uint8_t kDaikin2BitEye = 0b00000010;
+const uint8_t kDaikin2BitEyeAuto = 0b10000000;
+const uint8_t kDaikin2BitMold = 0b00001000;
+const uint8_t kDaikin2BitClean = 0b00100000;
+const uint8_t kDaikin2BitFreshAir = 0b00000001;
+const uint8_t kDaikin2BitFreshAirHigh = 0b10000000;
+const uint8_t kDaikin2BitPower = 0b10000000;
+const uint8_t kDaikin2LightMask = 0b00110000;
+const uint8_t kDaikin2BeepMask = 0b11000000;
+const uint8_t kDaikin2SwingVHigh = 0x1;
+const uint8_t kDaikin2SwingVLow = 0x6;
+const uint8_t kDaikin2SwingVBreeze = 0xC;
+const uint8_t kDaikin2SwingVCirculate = 0xD;
+const uint8_t kDaikin2SwingVAuto = 0xE;
+const uint8_t kDaikin2SwingHAuto = 0xBE;
+const uint8_t kDaikin2SwingHSwing = 0xBF;
+const uint8_t kDaikin2MinCoolTemp = 18; // Min temp (in C) when in Cool mode.
+
+// Another variant of the protocol for the Daikin ARC433B69 remote.
+const uint16_t kDaikin216Freq = 38000; // Modulation Frequency in Hz.
+const uint16_t kDaikin216HdrMark = 3400;
+const uint16_t kDaikin216HdrSpace = 1800;
+const uint16_t kDaikin216BitMark = 380;
+const uint16_t kDaikin216OneSpace = 1350;
+const uint16_t kDaikin216ZeroSpace = 480;
+const uint16_t kDaikin216Gap = 29650;
+const uint16_t kDaikin216Sections = 2;
+const uint16_t kDaikin216Section1Length = 8;
+const uint16_t kDaikin216Section2Length = kDaikin216StateLength -
+ kDaikin216Section1Length;
+const uint8_t kDaikin216BytePower = 13;
+const uint8_t kDaikin216ByteMode = kDaikin216BytePower;
+const uint8_t kDaikin216MaskMode = 0b01110000;
+const uint8_t kDaikin216ByteTemp = 14;
+const uint8_t kDaikin216MaskTemp = 0b01111110;
+const uint8_t kDaikin216ByteFan = 16;
+const uint8_t kDaikin216MaskFan = 0b11110000;
+const uint8_t kDaikin216ByteSwingV = 16;
+const uint8_t kDaikin216MaskSwingV = 0b00001111;
+const uint8_t kDaikin216ByteSwingH = 17;
+const uint8_t kDaikin216MaskSwingH = kDaikin216MaskSwingV;
+
+
+// Legacy defines.
+#define DAIKIN_COOL kDaikinCool
+#define DAIKIN_HEAT kDaikinHeat
+#define DAIKIN_FAN kDaikinFan
+#define DAIKIN_AUTO kDaikinAuto
+#define DAIKIN_DRY kDaikinDry
+#define DAIKIN_MIN_TEMP kDaikinMinTemp
+#define DAIKIN_MAX_TEMP kDaikinMaxTemp
+#define DAIKIN_FAN_MIN kDaikinFanMin
+#define DAIKIN_FAN_MAX kDaikinFanMax
+#define DAIKIN_FAN_AUTO kDaikinFanAuto
+#define DAIKIN_FAN_QUIET kDaikinFanQuiet
+
+class IRDaikinESP {
+ public:
+ explicit IRDaikinESP(uint16_t pin);
+
+#if SEND_DAIKIN
+ void send(const uint16_t repeat = kDaikinDefaultRepeat);
+#endif
+ 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 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 setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ bool getQuiet(void);
+ void setQuiet(const bool on);
+ bool getPowerful(void);
+ void setPowerful(const bool on);
+ void setSensor(const bool on);
+ bool getSensor(void);
+ void setEcono(const bool on);
+ bool getEcono(void);
+ void setEye(const bool on);
+ bool getEye(void);
+ void setMold(const bool on);
+ bool getMold(void);
+ void setComfort(const bool on);
+ bool getComfort(void);
+ void enableOnTimer(const uint16_t starttime);
+ void disableOnTimer(void);
+ uint16_t getOnTime(void);
+ bool getOnTimerEnabled();
+ void enableOffTimer(const uint16_t endtime);
+ void disableOffTimer(void);
+ uint16_t getOffTime(void);
+ bool getOffTimerEnabled(void);
+ void setCurrentTime(const uint16_t mins_since_midnight);
+ uint16_t getCurrentTime(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kDaikinStateLength);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kDaikinStateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString(void);
+ static String renderTime(const uint16_t timemins);
+#else
+ std::string toString(void);
+ static std::string renderTime(const uint16_t timemins);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // # of bytes per command
+ uint8_t remote[kDaikinStateLength];
+ void stateReset(void);
+ void checksum(void);
+};
+
+// Class to emulate a Daikin ARC477A1 remote.
+class IRDaikin2 {
+ public:
+ explicit IRDaikin2(uint16_t pin);
+
+#if SEND_DAIKIN2
+ void send(const uint16_t repeat = kDaikin2DefaultRepeat);
+#endif
+ void begin();
+ void on();
+ void off();
+ void setPower(const bool state);
+ bool getPower();
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp();
+ void setFan(const uint8_t fan);
+ uint8_t getFan();
+ uint8_t getMode();
+ void setMode(const uint8_t mode);
+ void setSwingVertical(const uint8_t position);
+ uint8_t getSwingVertical();
+ void setSwingHorizontal(const uint8_t position);
+ uint8_t getSwingHorizontal();
+ bool getQuiet();
+ void setQuiet(const bool on);
+ bool getPowerful();
+ void setPowerful(const bool on);
+ void setSensor(const bool on);
+ bool getSensor();
+ void setEcono(const bool on);
+ bool getEcono();
+ void setEye(const bool on);
+ bool getEye();
+ void setEyeAuto(const bool on);
+ bool getEyeAuto();
+ void setPurify(const bool on);
+ bool getPurify();
+ void setMold(const bool on);
+ bool getMold();
+ void enableOnTimer(const uint16_t starttime);
+ void disableOnTimer();
+ uint16_t getOnTime();
+ bool getOnTimerEnabled();
+ void enableSleepTimer(const uint16_t sleeptime);
+ void disableSleepTimer();
+ uint16_t getSleepTime();
+ bool getSleepTimerEnabled();
+ void enableOffTimer(const uint16_t endtime);
+ void disableOffTimer();
+ uint16_t getOffTime();
+ bool getOffTimerEnabled();
+ void setCurrentTime(const uint16_t time);
+ uint16_t getCurrentTime();
+ void setBeep(const uint8_t beep);
+ uint8_t getBeep();
+ void setLight(const uint8_t light);
+ uint8_t getLight();
+ void setClean(const bool on);
+ bool getClean();
+ void setFreshAir(const bool on);
+ bool getFreshAir();
+ void setFreshAirHigh(const bool on);
+ bool getFreshAirHigh();
+ uint8_t* getRaw();
+ void setRaw(const uint8_t new_code[]);
+ uint32_t getCommand();
+ void setCommand(uint32_t value);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kDaikin2StateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+#ifdef ARDUINO
+ String toString();
+ static String renderTime(uint16_t timemins);
+#else
+ std::string toString();
+ static std::string renderTime(uint16_t timemins);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // # of bytes per command
+ uint8_t remote_state[kDaikin2StateLength];
+ void stateReset();
+ void checksum();
+ void clearOnTimerFlag();
+ void clearSleepTimerFlag();
+};
+
+// Class to emulate a Daikin ARC433B69 remote.
+class IRDaikin216 {
+ public:
+ explicit IRDaikin216(uint16_t pin);
+
+#if SEND_DAIKIN216
+ void send(const uint16_t repeat = kDaikin216DefaultRepeat);
+#endif
+ void begin();
+ uint8_t* getRaw();
+ void setRaw(const uint8_t new_code[]);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kDaikin216StateLength);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp();
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ void setFan(const uint8_t fan);
+ uint8_t getFan(void);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ void setQuiet(const bool on);
+ bool getQuiet(void);
+#ifdef ARDUINO
+ String toString(void);
+ static String renderTime(const uint16_t timemins);
+#else
+ std::string toString(void);
+ static std::string renderTime(const uint16_t timemins);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // # of bytes per command
+ uint8_t remote_state[kDaikin216StateLength];
+ void stateReset();
+ void checksum();
+};
+
+#endif // IR_DAIKIN_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Denon.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Denon.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Denon.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Denon.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Dish.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Dish.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Dish.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Dish.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Electra.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Electra.cpp
similarity index 87%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Electra.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Electra.cpp
index df69be748dab..0700ab69856a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Electra.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Electra.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 David Conran
+// Copyright 2018, 2019 David Conran
#include "IRrecv.h"
#include "IRsend.h"
@@ -17,6 +17,7 @@
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/527
+// https://github.com/markszabo/IRremoteESP8266/issues/642
// Constants
const uint16_t kElectraAcHdrMark = 9166;
@@ -24,7 +25,7 @@ const uint16_t kElectraAcBitMark = 646;
const uint16_t kElectraAcHdrSpace = 4470;
const uint16_t kElectraAcOneSpace = 1647;
const uint16_t kElectraAcZeroSpace = 547;
-const uint32_t kElectraAcMessageGap = 100000; // Completely made-up guess.
+const uint32_t kElectraAcMessageGap = kDefaultMessageGap; // Just a guess.
#if SEND_ELECTRA_AC
// Send a Electra message
@@ -42,7 +43,8 @@ void IRsend::sendElectraAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
kElectraAcOneSpace, kElectraAcBitMark, kElectraAcZeroSpace,
kElectraAcBitMark, kElectraAcMessageGap, data, nbytes,
38000, // Complete guess of the modulation frequency.
- true, 0, 50);
+ false, // Send data in LSB order per byte
+ 0, 50);
}
#endif
@@ -56,7 +58,7 @@ void IRsend::sendElectraAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: Alpha / Needs testing against a real device.
+// Status: Beta / Probably works.
//
bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
bool strict) {
@@ -68,8 +70,6 @@ bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
return false; // Not strictly a ELECTRA_AC message.
}
- // The protocol sends the data normal + inverted, alternating on
- // each byte. Hence twice the number of expected data bits.
if (results->rawlen < 2 * nbits + kHeader + kFooter - 1)
return false; // Can't possibly be a valid ELECTRA_AC message.
@@ -87,7 +87,7 @@ bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
i++, dataBitsSoFar += 8, offset += data_result.used) {
data_result = matchData(&(results->rawbuf[offset]), 8, kElectraAcBitMark,
kElectraAcOneSpace, kElectraAcBitMark,
- kElectraAcZeroSpace, kTolerance, 0, true);
+ kElectraAcZeroSpace, kTolerance, 0, false);
if (data_result.success == false) return false; // Fail
results->state[i] = data_result.data;
}
@@ -99,7 +99,12 @@ bool IRrecv::decodeElectraAC(decode_results *results, uint16_t nbits,
return false;
// Compliance
- if (strict && dataBitsSoFar != nbits) return false;
+ if (strict) {
+ if (dataBitsSoFar != nbits) return false;
+ // Verify the checksum.
+ if (sumBytes(results->state, (dataBitsSoFar / 8) - 1) !=
+ results->state[(dataBitsSoFar / 8) - 1]) return false;
+ }
// Success
results->decode_type = ELECTRA_AC;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.cpp
similarity index 88%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.cpp
index 7c1b998348b4..de1b97e87f69 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.cpp
@@ -84,9 +84,9 @@ void IRFujitsuAC::begin() { _irsend.begin(); }
#if SEND_FUJITSU_AC
// Send the current desired state to the IR LED.
-void IRFujitsuAC::send() {
+void IRFujitsuAC::send(const uint16_t repeat) {
getRaw();
- _irsend.sendFujitsuAC(remote_state, getStateLength());
+ _irsend.sendFujitsuAC(remote_state, getStateLength(), repeat);
}
#endif // SEND_FUJITSU_AC
@@ -281,6 +281,7 @@ void IRFujitsuAC::setMode(uint8_t mode) {
}
uint8_t IRFujitsuAC::getMode() { return _mode; }
+
// Set the requested swing operation mode of the a/c unit.
void IRFujitsuAC::setSwing(uint8_t swingMode) {
switch (_model) {
@@ -319,6 +320,39 @@ bool IRFujitsuAC::validChecksum(uint8_t state[], uint16_t length) {
return checksum == (uint8_t)(sum_complement - sum); // Does it match?
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRFujitsuAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kFujitsuAcModeCool;
+ case stdAc::opmode_t::kHeat:
+ return kFujitsuAcModeHeat;
+ case stdAc::opmode_t::kDry:
+ return kFujitsuAcModeDry;
+ case stdAc::opmode_t::kFan:
+ return kFujitsuAcModeFan;
+ default:
+ return kFujitsuAcModeAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRFujitsuAC::convertFan(stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kFujitsuAcFanQuiet;
+ case stdAc::fanspeed_t::kLow:
+ return kFujitsuAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kFujitsuAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kFujitsuAcFanHigh;
+ default:
+ return kFujitsuAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRFujitsuAC::toString() {
@@ -327,77 +361,80 @@ String IRFujitsuAC::toString() {
std::string IRFujitsuAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kFujitsuAcModeAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kFujitsuAcModeCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kFujitsuAcModeHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kFujitsuAcModeDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kFujitsuAcModeFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFanSpeed());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFanSpeed());
switch (getFanSpeed()) {
case kFujitsuAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kFujitsuAcFanHigh:
- result += " (HIGH)";
+ result += F(" (HIGH)");
break;
case kFujitsuAcFanMed:
- result += " (MED)";
+ result += F(" (MED)");
break;
case kFujitsuAcFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kFujitsuAcFanQuiet:
- result += " (QUIET)";
+ result += F(" (QUIET)");
break;
}
- result += ", Swing: ";
+ result += F(", Swing: ");
switch (getSwing()) {
case kFujitsuAcSwingOff:
- result += "Off";
+ result += F("Off");
break;
case kFujitsuAcSwingVert:
- result += "Vert";
+ result += F("Vert");
break;
case kFujitsuAcSwingHoriz:
- result += "Horiz";
+ result += F("Horiz");
break;
case kFujitsuAcSwingBoth:
- result += "Vert + Horiz";
+ result += F("Vert + Horiz");
break;
default:
- result += "UNKNOWN";
+ result += F("UNKNOWN");
}
- result += ", Command: ";
+ result += F(", Command: ");
switch (getCmd()) {
case kFujitsuAcCmdStepHoriz:
- result += "Step vane horizontally";
+ result += F("Step vane horizontally");
break;
case kFujitsuAcCmdStepVert:
- result += "Step vane vertically";
+ result += F("Step vane vertically");
break;
default:
- result += "N/A";
+ result += F("N/A");
}
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.h b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.h
similarity index 93%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.h
index bba634be622b..78a4f8951710 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Fujitsu.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Fujitsu.h
@@ -13,6 +13,9 @@
#include "IRrecv.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// FUJITSU A/C support added by Jonny Graham
@@ -78,7 +81,7 @@ class IRFujitsuAC {
void setModel(fujitsu_ac_remote_model_t model);
void stateReset();
#if SEND_FUJITSU_AC
- void send();
+ void send(const uint16_t repeat = kFujitsuAcMinRepeat);
#endif // SEND_FUJITSU_AC
void begin();
void off();
@@ -99,15 +102,21 @@ class IRFujitsuAC {
uint8_t getStateLength();
static bool validChecksum(uint8_t* state, uint16_t length);
bool getPower();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
- uint8_t remote_state[kFujitsuAcStateLength];
IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint8_t remote_state[kFujitsuAcStateLength];
uint8_t _temp;
uint8_t _fanSpeed;
uint8_t _mode;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_GICable.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_GICable.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_GICable.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_GICable.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_GlobalCache.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_GlobalCache.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_GlobalCache.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.cpp
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Gree.cpp
index df8afada6fa9..756f008d42b2 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.cpp
@@ -27,7 +27,7 @@
// Constants
// Ref: https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h
const uint16_t kGreeHdrMark = 9000;
-const uint16_t kGreeHdrSpace = 4000;
+const uint16_t kGreeHdrSpace = 4500; // See #684 and real example in unit tests
const uint16_t kGreeBitMark = 620;
const uint16_t kGreeOneSpace = 1600;
const uint16_t kGreeZeroSpace = 540;
@@ -59,7 +59,7 @@ void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
// Footer #1
sendGeneric(0, 0, // No Header
kGreeBitMark, kGreeOneSpace, kGreeBitMark, kGreeZeroSpace,
- kGreeBitMark, kGreeMsgSpace, 0b010, 3, 38, true, 0, false);
+ kGreeBitMark, kGreeMsgSpace, 0b010, 3, 38, false, 0, 50);
// Block #2
sendGeneric(0, 0, // No Header for Block #2
@@ -129,9 +129,9 @@ void IRGreeAC::fixup() {
void IRGreeAC::begin() { _irsend.begin(); }
#if SEND_GREE
-void IRGreeAC::send() {
+void IRGreeAC::send(const uint16_t repeat) {
fixup(); // Ensure correct settings before sending.
- _irsend.sendGree(remote_state);
+ _irsend.sendGree(remote_state, kGreeStateLength, repeat);
}
#endif // SEND_GREE
@@ -305,6 +305,57 @@ uint8_t IRGreeAC::getSwingVerticalPosition() {
return remote_state[4] & kGreeSwingPosMask;
}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRGreeAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kGreeCool;
+ case stdAc::opmode_t::kHeat:
+ return kGreeHeat;
+ case stdAc::opmode_t::kDry:
+ return kGreeDry;
+ case stdAc::opmode_t::kFan:
+ return kGreeFan;
+ default:
+ return kGreeAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRGreeAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kGreeFanMin;
+ case stdAc::fanspeed_t::kLow:
+ case stdAc::fanspeed_t::kMedium:
+ return kGreeFanMax - 1;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kGreeFanMax;
+ default:
+ return kGreeFanAuto;
+ }
+}
+
+// Convert a standard A/C Vertical Swing into its native version.
+uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) {
+ switch (swingv) {
+ case stdAc::swingv_t::kHighest:
+ return kGreeSwingUp;
+ case stdAc::swingv_t::kHigh:
+ return kGreeSwingMiddleUp;
+ case stdAc::swingv_t::kMiddle:
+ return kGreeSwingMiddle;
+ case stdAc::swingv_t::kLow:
+ return kGreeSwingMiddleDown;
+ case stdAc::swingv_t::kLowest:
+ return kGreeSwingDown;
+ default:
+ return kGreeSwingAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRGreeAC::toString() {
@@ -313,74 +364,77 @@ String IRGreeAC::toString() {
std::string IRGreeAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kGreeAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kGreeCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kGreeHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kGreeDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kGreeFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case 0:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kGreeFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
- result += ", Turbo: ";
+ result += F(", Turbo: ");
if (getTurbo())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", XFan: ";
+ result += F("Off");
+ result += F(", XFan: ");
if (getXFan())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Light: ";
+ result += F("Off");
+ result += F(", Light: ");
if (getLight())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Sleep: ";
+ result += F("Off");
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing Vertical Mode: ";
+ result += F("Off");
+ result += F(", Swing Vertical Mode: ");
if (getSwingVerticalAuto())
- result += "Auto";
+ result += F("Auto");
else
- result += "Manual";
- result +=
- ", Swing Vertical Pos: " + uint64ToString(getSwingVerticalPosition());
+ result += F("Manual");
+ result += F(", Swing Vertical Pos: ");
+ result += uint64ToString(getSwingVerticalPosition());
switch (getSwingVerticalPosition()) {
case kGreeSwingLastPos:
- result += " (Last Pos)";
+ result += F(" (Last Pos)");
break;
case kGreeSwingAuto:
- result += " (Auto)";
+ result += F(" (Auto)");
break;
}
return result;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.h b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.h
similarity index 89%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Gree.h
index 73f69eb31b47..c3c5916dc4f2 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Gree.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Gree.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// GGGG RRRRRR EEEEEEE EEEEEEE
// GG GG RR RR EE EE
@@ -44,6 +47,8 @@ const uint8_t kGreeSwingPosMask = 0b00001111;
const uint8_t kGreeMinTemp = 16; // Celsius
const uint8_t kGreeMaxTemp = 30; // Celsius
+const uint8_t kGreeFanAuto = 0;
+const uint8_t kGreeFanMin = 1;
const uint8_t kGreeFanMax = 3;
const uint8_t kGreeSwingLastPos = 0b00000000;
@@ -84,7 +89,7 @@ class IRGreeAC {
void stateReset();
#if SEND_GREE
- void send();
+ void send(const uint16_t repeat = kGreeDefaultRepeat);
#endif // SEND_GREE
void begin();
void on();
@@ -108,7 +113,9 @@ class IRGreeAC {
void setSwingVertical(const bool automatic, const uint8_t position);
bool getSwingVerticalAuto();
uint8_t getSwingVerticalPosition();
-
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t swingv);
uint8_t* getRaw();
void setRaw(uint8_t new_code[]);
static bool validChecksum(const uint8_t state[],
@@ -118,13 +125,17 @@ class IRGreeAC {
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else // UNIT_TEST
+ IRsendTest _irsend;
+#endif // UNIT_TEST
// The state of the IR remote in IR code form.
uint8_t remote_state[kGreeStateLength];
void checksum(const uint16_t length = kGreeStateLength);
void fixup();
- IRsend _irsend;
};
#endif // IR_GREE_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.cpp
similarity index 75%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Haier.cpp
index 2c47e4eac2a5..f76bb3447a58 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.cpp
@@ -45,7 +45,7 @@ const uint32_t kHaierAcMinGap = 150000; // Completely made up value.
// nbytes: Nr. of bytes of data in the array. (>=kHaierACStateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
-// Status: Beta / Probably working.
+// Status: STABLE / Known to be working.
//
void IRsend::sendHaierAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
@@ -86,9 +86,9 @@ IRHaierAC::IRHaierAC(uint16_t pin) : _irsend(pin) { stateReset(); }
void IRHaierAC::begin() { _irsend.begin(); }
#if SEND_HAIER_AC
-void IRHaierAC::send() {
+void IRHaierAC::send(const uint16_t repeat) {
checksum();
- _irsend.sendHaierAC(remote_state);
+ _irsend.sendHaierAC(remote_state, kHaierACStateLength, repeat);
}
#endif // SEND_HAIER_AC
@@ -104,7 +104,10 @@ bool IRHaierAC::validChecksum(uint8_t state[], const uint16_t length) {
void IRHaierAC::stateReset() {
for (uint8_t i = 1; i < kHaierACStateLength; i++) remote_state[i] = 0x0;
remote_state[0] = kHaierAcPrefix;
- remote_state[2] = 0b00100000;
+ remote_state[2] = 0x20;
+ remote_state[4] = 0x0C;
+ remote_state[5] = 0xC0;
+ remote_state[6] = 0x20;
setTemp(kHaierAcDefTemp);
setFan(kHaierAcFanAuto);
@@ -304,14 +307,63 @@ std::string IRHaierAC::timeToString(const uint16_t nr_mins) {
std::string result = "";
#endif // ARDUINO
- if (nr_mins / 24 < 10) result += "0"; // Zero pad.
+ if (nr_mins / 24 < 10) result += '0'; // Zero pad.
result += uint64ToString(nr_mins / 60);
- result += ":";
- if (nr_mins % 60 < 10) result += "0"; // Zero pad.
+ result += ':';
+ if (nr_mins % 60 < 10) result += '0'; // Zero pad.
result += uint64ToString(nr_mins % 60);
return result;
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHaierAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kHaierAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kHaierAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kHaierAcDry;
+ case stdAc::opmode_t::kFan:
+ return kHaierAcFan;
+ default:
+ return kHaierAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHaierAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kHaierAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kHaierAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kHaierAcFanHigh;
+ default:
+ return kHaierAcFanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRHaierAC::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ return kHaierAcSwingUp;
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return kHaierAcSwingDown;
+ case stdAc::swingv_t::kOff:
+ return kHaierAcSwingOff;
+ default:
+ return kHaierAcSwingChg;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRHaierAC::toString() {
@@ -321,114 +373,122 @@ std::string IRHaierAC::toString() {
std::string result = "";
#endif // ARDUINO
uint8_t cmd = getCommand();
- result += "Command: " + uint64ToString(cmd) + " (";
+ result += F("Command: ");
+ result += uint64ToString(cmd);
+ result += F(" (");
switch (cmd) {
case kHaierAcCmdOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcCmdOn:
- result += "On";
+ result += F("On");
break;
case kHaierAcCmdMode:
- result += "Mode";
+ result += F("Mode");
break;
case kHaierAcCmdFan:
- result += "Fan";
+ result += F("Fan");
break;
case kHaierAcCmdTempUp:
- result += "Temp Up";
+ result += F("Temp Up");
break;
case kHaierAcCmdTempDown:
- result += "Temp Down";
+ result += F("Temp Down");
break;
case kHaierAcCmdSleep:
- result += "Sleep";
+ result += F("Sleep");
break;
case kHaierAcCmdTimerSet:
- result += "Timer Set";
+ result += F("Timer Set");
break;
case kHaierAcCmdTimerCancel:
- result += "Timer Cancel";
+ result += F("Timer Cancel");
break;
case kHaierAcCmdHealth:
- result += "Health";
+ result += F("Health");
break;
case kHaierAcCmdSwing:
- result += "Swing";
+ result += F("Swing");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Mode: " + uint64ToString(getMode());
+ result += ')';
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kHaierAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHaierAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kHaierAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kHaierAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kHaierAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kHaierAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHaierAcFanHigh:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
- result += ", Swing: " + uint64ToString(getSwing()) + " (";
+ result += F(", Swing: ");
+ result += uint64ToString(getSwing());
+ result += F(" (");
switch (getSwing()) {
case kHaierAcSwingOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcSwingUp:
- result += "Up";
+ result += F("Up");
break;
case kHaierAcSwingDown:
- result += "Down";
+ result += F("Down");
break;
case kHaierAcSwingChg:
- result += "Chg";
+ result += F("Chg");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Sleep: ";
+ result += ')';
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Health: ";
+ result += F("Off");
+ result += F(", Health: ");
if (getHealth())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Current Time: " + timeToString(getCurrTime());
- result += ", On Timer: ";
+ result += F("Off");
+ result += F(", Current Time: ");
+ result += timeToString(getCurrTime());
+ result += F(", On Timer: ");
if (getOnTimer() >= 0)
result += timeToString(getOnTimer());
else
- result += "Off";
- result += ", Off Timer: ";
+ result += F("Off");
+ result += F(", Off Timer: ");
if (getOffTimer() >= 0)
result += timeToString(getOffTimer());
else
- result += "Off";
+ result += F("Off");
return result;
}
@@ -440,9 +500,9 @@ IRHaierACYRW02::IRHaierACYRW02(uint16_t pin) : _irsend(pin) { stateReset(); }
void IRHaierACYRW02::begin() { _irsend.begin(); }
#if SEND_HAIER_AC_YRW02
-void IRHaierACYRW02::send() {
+void IRHaierACYRW02::send(const uint16_t repeat) {
checksum();
- _irsend.sendHaierACYRW02(remote_state);
+ _irsend.sendHaierACYRW02(remote_state, kHaierACYRW02StateLength, repeat);
}
#endif // SEND_HAIER_AC_YRW02
@@ -628,6 +688,57 @@ void IRHaierACYRW02::setSwing(uint8_t state) {
remote_state[1] |= newstate;
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHaierACYRW02::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kHaierAcYrw02Cool;
+ case stdAc::opmode_t::kHeat:
+ return kHaierAcYrw02Heat;
+ case stdAc::opmode_t::kDry:
+ return kHaierAcYrw02Dry;
+ case stdAc::opmode_t::kFan:
+ return kHaierAcYrw02Fan;
+ default:
+ return kHaierAcYrw02Auto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHaierACYRW02::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kHaierAcYrw02FanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kHaierAcYrw02FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kHaierAcYrw02FanHigh;
+ default:
+ return kHaierAcYrw02FanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRHaierACYRW02::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ return kHaierAcYrw02SwingTop;
+ case stdAc::swingv_t::kMiddle:
+ return kHaierAcYrw02SwingMiddle;
+ case stdAc::swingv_t::kLow:
+ return kHaierAcYrw02SwingDown;
+ case stdAc::swingv_t::kLowest:
+ return kHaierAcYrw02SwingBottom;
+ case stdAc::swingv_t::kOff:
+ return kHaierAcYrw02SwingOff;
+ default:
+ return kHaierAcYrw02SwingAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRHaierACYRW02::toString() {
@@ -636,132 +747,141 @@ String IRHaierACYRW02::toString() {
std::string IRHaierACYRW02::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
uint8_t cmd = getButton();
- result += ", Button: " + uint64ToString(cmd) + " (";
+ result += F(", Button: ");
+ result += uint64ToString(cmd);
+ result += F(" (");
switch (cmd) {
case kHaierAcYrw02ButtonPower:
- result += "Power";
+ result += F("Power");
break;
case kHaierAcYrw02ButtonMode:
- result += "Mode";
+ result += F("Mode");
break;
case kHaierAcYrw02ButtonFan:
- result += "Fan";
+ result += F("Fan");
break;
case kHaierAcYrw02ButtonTempUp:
- result += "Temp Up";
+ result += F("Temp Up");
break;
case kHaierAcYrw02ButtonTempDown:
- result += "Temp Down";
+ result += F("Temp Down");
break;
case kHaierAcYrw02ButtonSleep:
- result += "Sleep";
+ result += F("Sleep");
break;
case kHaierAcYrw02ButtonHealth:
result += "Health";
break;
case kHaierAcYrw02ButtonSwing:
- result += "Swing";
+ result += F("Swing");
break;
case kHaierAcYrw02ButtonTurbo:
- result += "Turbo";
+ result += F("Turbo");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Mode: " + uint64ToString(getMode());
+ result += ')';
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kHaierAcYrw02Auto:
- result += " (Auto)";
+ result += F(" (Auto)");
break;
case kHaierAcYrw02Cool:
- result += " (Cool)";
+ result += F(" (Cool)");
break;
case kHaierAcYrw02Heat:
- result += " (Heat)";
+ result += F(" (Heat)");
break;
case kHaierAcYrw02Dry:
- result += " (Dry)";
+ result += F(" (Dry)");
break;
case kHaierAcYrw02Fan:
- result += " (Fan)";
+ result += F(" (Fan)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kHaierAcYrw02FanAuto:
- result += " (Auto)";
+ result += F(" (Auto)");
break;
case kHaierAcYrw02FanHigh:
- result += " (High)";
+ result += F(" (High)");
break;
case kHaierAcYrw02FanLow:
- result += " (Low)";
+ result += F(" (Low)");
break;
case kHaierAcYrw02FanMed:
- result += " (Med)";
+ result += F(" (Med)");
break;
default:
- result += " (Unknown)";
+ result += F(" (Unknown)");
}
- result += ", Turbo: " + uint64ToString(getTurbo()) + " (";
+ result += F(", Turbo: ");
+ result += uint64ToString(getTurbo());
+ result += F(" (");
switch (getTurbo()) {
case kHaierAcYrw02TurboOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcYrw02TurboLow:
- result += "Low";
+ result += F("Low");
break;
case kHaierAcYrw02TurboHigh:
- result += "High";
+ result += F("High");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Swing: " + uint64ToString(getSwing()) + " (";
+ result += ')';
+ result += F(", Swing: ");
+ result += uint64ToString(getSwing());
+ result += F(" (");
switch (getSwing()) {
case kHaierAcYrw02SwingOff:
- result += "Off";
+ result += F("Off");
break;
case kHaierAcYrw02SwingAuto:
- result += "Auto";
+ result += F("Auto");
break;
case kHaierAcYrw02SwingBottom:
- result += "Bottom";
+ result += F("Bottom");
break;
case kHaierAcYrw02SwingDown:
- result += "Down";
+ result += F("Down");
break;
case kHaierAcYrw02SwingTop:
- result += "Top";
+ result += F("Top");
break;
case kHaierAcYrw02SwingMiddle:
- result += "Middle";
+ result += F("Middle");
break;
default:
- result += "Unknown";
+ result += F("Unknown");
}
- result += ")";
- result += ", Sleep: ";
+ result += ')';
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Health: ";
+ result += F("Off");
+ result += F(", Health: ");
if (getHealth())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
@@ -777,7 +897,7 @@ std::string IRHaierACYRW02::toString() {
// Returns:
// boolean: True if it can decode it, false if it can't.
//
-// Status: BETA / Appears to be working.
+// Status: STABLE / Known to be working.
//
bool IRrecv::decodeHaierAC(decode_results* results, uint16_t nbits,
bool strict) {
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.h b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.h
similarity index 93%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Haier.h
index fdc15a3a8ebe..8f7b351965c6 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Haier.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Haier.h
@@ -11,6 +11,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// HH HH AAA IIIII EEEEEEE RRRRRR
// HH HH AAAAA III EE RR RR
@@ -186,7 +189,7 @@ class IRHaierAC {
explicit IRHaierAC(uint16_t pin);
#if SEND_HAIER_AC
- void send();
+ void send(const uint16_t repeat = kHaierAcDefaultRepeat);
#endif // SEND_HAIER_AC
void begin();
@@ -223,6 +226,10 @@ class IRHaierAC {
void setRaw(uint8_t new_code[]);
static bool validChecksum(uint8_t state[],
const uint16_t length = kHaierACStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+
#ifdef ARDUINO
String toString();
static String timeToString(const uint16_t nr_mins);
@@ -230,14 +237,18 @@ class IRHaierAC {
std::string toString();
static std::string timeToString(const uint16_t nr_mins);
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
uint8_t remote_state[kHaierACStateLength];
void stateReset();
void checksum();
static uint16_t getTime(const uint8_t ptr[]);
static void setTime(uint8_t ptr[], const uint16_t nr_mins);
- IRsend _irsend;
};
class IRHaierACYRW02 {
@@ -245,7 +256,7 @@ class IRHaierACYRW02 {
explicit IRHaierACYRW02(uint16_t pin);
#if SEND_HAIER_AC_YRW02
- void send();
+ void send(const uint16_t repeat = kHaierAcYrw02DefaultRepeat);
#endif // SEND_HAIER_AC_YRW02
void begin();
@@ -281,17 +292,24 @@ class IRHaierACYRW02 {
void setRaw(uint8_t new_code[]);
static bool validChecksum(uint8_t state[],
const uint16_t length = kHaierACYRW02StateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
uint8_t remote_state[kHaierACYRW02StateLength];
void stateReset();
void checksum();
- IRsend _irsend;
};
#endif // IR_HAIER_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.cpp
similarity index 86%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.cpp
index 111051974c84..b88189f4a03b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.cpp
@@ -30,7 +30,7 @@ const uint16_t kHitachiAc1HdrSpace = 3400;
const uint16_t kHitachiAcBitMark = 400;
const uint16_t kHitachiAcOneSpace = 1250;
const uint16_t kHitachiAcZeroSpace = 500;
-const uint32_t kHitachiAcMinGap = 100000; // Completely made up value.
+const uint32_t kHitachiAcMinGap = kDefaultMessageGap; // Just a guess.
#if (SEND_HITACHI_AC || SEND_HITACHI_AC2)
// Send a Hitachi A/C message.
@@ -106,7 +106,7 @@ void IRsend::sendHitachiAC2(unsigned char data[], uint16_t nbytes,
}
#endif // SEND_HITACHI_AC2
-// Class for handling the remote control oh a Hitachi 28 byte A/C message.
+// Class for handling the remote control on a Hitachi 28 byte A/C message.
// Inspired by:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/HitachiHeatpumpIR.cpp
@@ -159,9 +159,9 @@ void IRHitachiAc::setRaw(const uint8_t new_code[], const uint16_t length) {
}
#if SEND_HITACHI_AC
-void IRHitachiAc::send() {
+void IRHitachiAc::send(const uint16_t repeat) {
checksum();
- _irsend.sendHitachiAC(remote_state);
+ _irsend.sendHitachiAC(remote_state, kHitachiAcStateLength, repeat);
}
#endif // SEND_HITACHI_AC
@@ -257,6 +257,40 @@ void IRHitachiAc::setSwingHorizontal(const bool on) {
remote_state[15] &= 0x7F;
}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRHitachiAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kHitachiAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kHitachiAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kHitachiAcDry;
+ case stdAc::opmode_t::kFan:
+ return kHitachiAcFan;
+ default:
+ return kHitachiAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRHitachiAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kHitachiAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kHitachiAcFanLow + 1;
+ case stdAc::fanspeed_t::kHigh:
+ return kHitachiAcFanHigh - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kHitachiAcFanHigh;
+ default:
+ return kHitachiAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRHitachiAc::toString() {
@@ -265,57 +299,60 @@ String IRHitachiAc::toString() {
std::string IRHitachiAc::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kHitachiAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHitachiAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kHitachiAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kHitachiAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kHitachiAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kHitachiAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kHitachiAcFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kHitachiAcFanHigh:
- result += " (HIGH)";
+ result += F(" (HIGH)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
- result += ", Swing (Vertical): ";
+ result += F(", Swing (Vertical): ");
if (getSwingVertical())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing (Horizontal): ";
+ result += F("Off");
+ result += F(", Swing (Horizontal): ");
if (getSwingHorizontal())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.h b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.h
similarity index 87%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.h
index eddab59e43c6..532717447df9 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Hitachi.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Hitachi.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// Constants
const uint8_t kHitachiAcAuto = 2;
@@ -35,7 +38,7 @@ class IRHitachiAc {
void stateReset();
#if SEND_HITACHI_AC
- void send();
+ void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC
void begin();
void on();
@@ -59,17 +62,23 @@ class IRHitachiAc {
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);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#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);
- IRsend _irsend;
uint8_t _previoustemp;
};
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_JVC.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_JVC.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_JVC.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_JVC.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.cpp
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.cpp
index ddf61b097aba..c69f4cb8ad13 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.cpp
@@ -19,6 +19,7 @@
#ifndef ARDUINO
#include
#endif
+#include "IRac.h"
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
@@ -141,9 +142,9 @@ void IRKelvinatorAC::fixup() {
}
#if SEND_KELVINATOR
-void IRKelvinatorAC::send() {
+void IRKelvinatorAC::send(const uint16_t repeat) {
fixup(); // Ensure correct settings before sending.
- _irsend.sendKelvinator(remote_state);
+ _irsend.sendKelvinator(remote_state, kKelvinatorStateLength, repeat);
}
#endif // SEND_KELVINATOR
@@ -347,6 +348,22 @@ bool IRKelvinatorAC::getTurbo() {
return ((remote_state[2] & kKelvinatorTurbo) != 0);
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRKelvinatorAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kKelvinatorCool;
+ case stdAc::opmode_t::kHeat:
+ return kKelvinatorHeat;
+ case stdAc::opmode_t::kDry:
+ return kKelvinatorDry;
+ case stdAc::opmode_t::kFan:
+ return kKelvinatorFan;
+ default:
+ return kKelvinatorAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRKelvinatorAC::toString() {
@@ -355,76 +372,79 @@ String IRKelvinatorAC::toString() {
std::string IRKelvinatorAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kKelvinatorAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kKelvinatorCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kKelvinatorHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kKelvinatorDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kKelvinatorFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kKelvinatorFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kKelvinatorFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
- result += ", Turbo: ";
+ result += F(", Turbo: ");
if (getTurbo())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Quiet: ";
+ result += F("Off");
+ result += F(", Quiet: ");
if (getQuiet())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", XFan: ";
+ result += F("Off");
+ result += F(", XFan: ");
if (getXFan())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", IonFilter: ";
+ result += F("Off");
+ result += F(", IonFilter: ");
if (getIonFilter())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Light: ";
+ result += F("Off");
+ result += F(", Light: ");
if (getLight())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing (Horizontal): ";
+ result += F("Off");
+ result += F(", Swing (Horizontal): ");
if (getSwingHorizontal())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Swing (Vertical): ";
+ result += F("Off");
+ result += F(", Swing (Vertical): ");
if (getSwingVertical())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.h b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.h
similarity index 96%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.h
index 1508d6cdc8f2..ce830c70af69 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Kelvinator.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Kelvinator.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// KK KK EEEEEEE LL VV VV IIIII NN NN AAA TTTTTTT OOOOO RRRRRR
// KK KK EE LL VV VV III NNN NN AAAAA TTT OO OO RR RR
@@ -130,7 +133,7 @@ class IRKelvinatorAC {
void stateReset();
#if SEND_KELVINATOR
- void send();
+ void send(const uint16_t repeat = kKelvinatorDefaultRepeat);
#endif // SEND_KELVINATOR
void begin();
void on();
@@ -163,18 +166,23 @@ class IRKelvinatorAC {
const uint8_t* block, const uint16_t length = kKelvinatorStateLength / 2);
static bool validChecksum(const uint8_t state[],
const uint16_t length = kKelvinatorStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
// The state of the IR remote in IR code form.
uint8_t remote_state[kKelvinatorStateLength];
void checksum(const uint16_t length = kKelvinatorStateLength);
void fixup();
- IRsend _irsend;
};
#endif // IR_KELVINATOR_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_LG.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_LG.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_LG.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_LG.cpp
index f9d922fc740e..36c85ff1518e 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_LG.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_LG.cpp
@@ -85,11 +85,13 @@ uint8_t calcLGChecksum(uint16_t data) {
// IR Remote models: 6711A20083V
void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
uint16_t repeatHeaderMark = 0;
+ uint8_t duty = kDutyDefault;
if (nbits >= kLg32Bits) {
// LG 32bit protocol is near identical to Samsung except for repeats.
sendSAMSUNG(data, nbits, 0); // Send it as a single Samsung message.
repeatHeaderMark = kLg32RptHdrMark;
+ duty = 33;
repeat++;
} else {
// LG (28-bit) protocol.
@@ -97,7 +99,7 @@ void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
sendGeneric(kLgHdrMark, kLgHdrSpace, kLgBitMark, kLgOneSpace, kLgBitMark,
kLgZeroSpace, kLgBitMark, kLgMinGap, kLgMinMessageLength, data,
nbits, 38, true, 0, // Repeats are handled later.
- 50);
+ duty);
}
// Repeat
@@ -105,7 +107,7 @@ void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (repeat)
sendGeneric(repeatHeaderMark, kLgRptSpace, 0, 0, 0, 0, // No data is sent.
kLgBitMark, kLgMinGap, kLgMinMessageLength, 0, 0, // No data.
- 38, true, repeat - 1, 50);
+ 38, true, repeat - 1, duty);
}
// Send an LG Variant-2 formatted message.
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_LG.h b/lib/IRremoteESP8266-2.6.0/src/ir_LG.h
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_LG.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_LG.h
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Lasertag.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Lasertag.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Lasertag.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Lasertag.cpp
index 7f0b89ae9110..b1cbdc9b1d83 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Lasertag.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Lasertag.cpp
@@ -14,7 +14,7 @@
// Constants
const uint16_t kLasertagMinSamples = 13;
const uint16_t kLasertagTick = 333;
-const uint32_t kLasertagMinGap = 100000; // Completely made up amount.
+const uint32_t kLasertagMinGap = kDefaultMessageGap; // Just a guess.
const uint8_t kLasertagTolerance = 0; // Percentage error margin.
const uint16_t kLasertagExcess = 0; // See kMarkExcess.
const uint16_t kLasertagDelta = 150; // Use instead of Excess and Tolerance.
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Lego.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Lego.cpp
new file mode 100644
index 000000000000..b051aba512e7
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Lego.cpp
@@ -0,0 +1,128 @@
+// Copyright 2019 David Conran
+
+#include
+#include "IRrecv.h"
+#include "IRsend.h"
+#include "IRutils.h"
+
+// LEGO
+// (LEGO is a Registrated Trademark of the Lego Group.)
+//
+// Supported Devices:
+// - LEGO Power Functions IR Receiver
+//
+// Ref:
+// - https://github.com/markszabo/IRremoteESP8266/issues/641
+// - https://github.com/markszabo/IRremoteESP8266/files/2974525/LEGO_Power_Functions_RC_v120.pdf
+
+// Constants
+const uint16_t kLegoPfBitMark = 158;
+const uint16_t kLegoPfHdrSpace = 1026;
+const uint16_t kLegoPfZeroSpace = 263;
+const uint16_t kLegoPfOneSpace = 553;
+const uint32_t kLegoPfMinCommandLength = 16000; // 16ms
+
+
+#if SEND_LEGOPF
+// Send a LEGO Power Functions message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kLegoPfBits.
+// repeat: Nr. of additional times the message is to be sent.
+// Note: Non-zero repeats results in at least 5 messages per spec.
+//
+// Status: Beta / Should work.
+void IRsend::sendLegoPf(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ uint8_t channelid = ((data >> (nbits - 4)) & 0b11) + 1;
+ if (repeat) {
+ // We are in repeat mode.
+ // Spec says a pause before transmittion.
+ if (channelid < 4) space((4 - channelid) * kLegoPfMinCommandLength);
+ // Spec says there are a minimum of 5 message repeats.
+ for (uint16_t r = 0; r < std::max(repeat, (uint16_t)5); r++) {
+ // Lego has a special repeat mode which repeats a message with varying
+ // start to start times.
+ sendGeneric(kLegoPfBitMark, kLegoPfHdrSpace,
+ kLegoPfBitMark, kLegoPfOneSpace,
+ kLegoPfBitMark, kLegoPfZeroSpace,
+ kLegoPfBitMark, kLegoPfHdrSpace,
+ ((r < 2) ? 5 : (6 + 2 * channelid)) * kLegoPfMinCommandLength,
+ data, nbits, 38000, true, 0, kDutyDefault);
+ }
+ } else { // No repeat, just a simple message.
+ sendGeneric(kLegoPfBitMark, kLegoPfHdrSpace,
+ kLegoPfBitMark, kLegoPfOneSpace,
+ kLegoPfBitMark, kLegoPfZeroSpace,
+ kLegoPfBitMark, kLegoPfHdrSpace,
+ kLegoPfMinCommandLength * 5,
+ data, nbits, 38000, true, 0, kDutyDefault);
+ }
+}
+#endif // SEND_LEGO
+
+#if DECODE_LEGOPF
+// Decode the supplied LEGO Power Functions message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: The number of data bits to expect. Typically kLegoPfBits.
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: Alpha / Untested.
+bool IRrecv::decodeLegoPf(decode_results* results,
+ const uint16_t nbits, const bool strict) {
+ // Check if can possibly be a valid LEGO message.
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
+ if (strict && nbits != kLegoPfBits) return false; // Not what is expected
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kLegoPfBitMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kLegoPfHdrSpace)) return false;
+ // Data (Typically 16 bits)
+ data_result =
+ matchData(&(results->rawbuf[offset]), nbits,
+ kLegoPfBitMark, kLegoPfOneSpace,
+ kLegoPfBitMark, kLegoPfZeroSpace,
+ kTolerance, kMarkExcess, true);
+ if (data_result.success == false) return false;
+ data = data_result.data;
+ offset += data_result.used;
+ uint16_t actualBits = data_result.used / 2;
+
+ // Footer.
+ if (!matchMark(results->rawbuf[offset++], kLegoPfBitMark)) return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kLegoPfMinCommandLength))
+ return false;
+
+ // Compliance
+ if (actualBits < nbits) return false;
+ if (strict) {
+ if (actualBits != nbits) return false; // Not as we expected.
+ // Verify the Longitudinal Redundancy Check (LRC)
+ uint16_t lrc_data = data;
+ uint8_t lrc = 0xF;
+ for (uint8_t i = 0; i < 4; i++) {
+ lrc ^= (lrc_data & 0xF);
+ lrc_data >>= 4;
+ }
+ if (lrc) return false;
+ }
+
+ // Success
+ results->decode_type = LEGOPF;
+ results->bits = actualBits;
+ results->value = data;
+ results->address = ((data >> (nbits - 4)) & 0b11) + 1; // Channel Id
+ results->command = (data >> 4) & 0xFF; // Stuff between Channel Id and LRC.
+ return true;
+}
+#endif // DECODE_LEGOPF
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Lutron.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Lutron.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Lutron.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Lutron.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_MWM.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_MWM.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_MWM.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_MWM.cpp
index a75e99e3a51d..61eac49e2744 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_MWM.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_MWM.cpp
@@ -105,7 +105,7 @@ bool IRrecv::decodeMWM(decode_results *results, uint16_t nbits, bool strict) {
for (; offset < results->rawlen && results->bits < 8 * kStateSizeMax;
frame_bits++) {
DPRINT("DEBUG: decodeMWM: offset = ");
- DPRINTLN(uint64ToString(offset));
+ DPRINTLN(offset);
int16_t level = getRClevel(results, &offset, &used, kMWMTick, kMWMTolerance,
kMWMExcess, kMWMDelta, kMWMMaxWidth);
if (level < 0) {
@@ -129,7 +129,7 @@ bool IRrecv::decodeMWM(decode_results *results, uint16_t nbits, bool strict) {
DPRINT("DEBUG: decodeMWM: data_bits = ");
DPRINTLN(data_bits);
DPRINT("DEBUG: decodeMWM: Finished byte: ");
- DPRINTLN(data);
+ DPRINTLN(uint64ToString(data));
results->state[data_bits / 8 - 1] = data & 0xFF;
results->bits = data_bits;
data = 0;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.h b/lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.h
similarity index 86%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.h
index d2d82d152767..81fff53adf13 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Magiquest.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Magiquest.h
@@ -31,5 +31,5 @@ const uint16_t kMagiQuestMarkZero = 280;
const uint16_t kMagiQuestSpaceZero = 850;
const uint16_t kMagiQuestMarkOne = 580;
const uint16_t kMagiQuestSpaceOne = 600;
-const uint32_t kMagiQuestGap = 100000; // A guess of the gap between messages
-#endif // IR_MAGIQUEST_H_
+const uint32_t kMagiQuestGap = kDefaultMessageGap; // Just a guess.
+#endif // IR_MAGIQUEST_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.cpp
similarity index 87%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Midea.cpp
index 8e55c7d227be..8d5d9494fd84 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.cpp
@@ -104,9 +104,9 @@ void IRMideaAC::begin() { _irsend.begin(); }
#if SEND_MIDEA
// Send the current desired state to the IR LED.
-void IRMideaAC::send() {
+void IRMideaAC::send(const uint16_t repeat) {
checksum(); // Ensure correct checksum before sending.
- _irsend.sendMidea(remote_state);
+ _irsend.sendMidea(remote_state, kMideaBits, repeat);
}
#endif // SEND_MIDEA
@@ -257,6 +257,39 @@ void IRMideaAC::checksum() {
remote_state |= calcChecksum(remote_state);
}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMideaAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kMideaACCool;
+ case stdAc::opmode_t::kHeat:
+ return kMideaACHeat;
+ case stdAc::opmode_t::kDry:
+ return kMideaACDry;
+ case stdAc::opmode_t::kFan:
+ return kMideaACFan;
+ default:
+ return kMideaACAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMideaAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kMideaACFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kMideaACFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kMideaACFanHigh;
+ default:
+ return kMideaACFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRMideaAC::toString() {
@@ -265,53 +298,57 @@ String IRMideaAC::toString() {
std::string IRMideaAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kMideaACAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kMideaACCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kMideaACHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kMideaACDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kMideaACFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp(true)) + "C/" +
- uint64ToString(getTemp(false)) + "F";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp(true));
+ result += F("C/");
+ result += uint64ToString(getTemp(false));
+ result += F("F, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kMideaACFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kMideaACFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kMideaACFanMed:
- result += " (MED)";
+ result += F(" (MED)");
break;
case kMideaACFanHigh:
- result += " (HI)";
+ result += F(" (HI)");
break;
}
- result += ", Sleep: ";
+ result += F(", Sleep: ");
if (getSleep())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.h b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.h
similarity index 93%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Midea.h
index aa9f94a928a2..ab14eb252e2c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Midea.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Midea.h
@@ -11,6 +11,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// MM MM IIIII DDDDD EEEEEEE AAA
// MMM MMM III DD DD EE AAAAA
@@ -67,7 +70,7 @@ class IRMideaAC {
void stateReset();
#if SEND_MIDEA
- void send();
+ void send(const uint16_t repeat = kMideaMinRepeat);
#endif // SEND_MIDEA
void begin();
void on();
@@ -85,6 +88,8 @@ class IRMideaAC {
static bool validChecksum(const uint64_t state);
void setSleep(const bool state);
bool getSleep();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
@@ -93,11 +98,13 @@ class IRMideaAC {
#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
#endif
uint64_t remote_state;
void checksum();
static uint8_t calcChecksum(const uint64_t state);
- IRsend _irsend;
};
#endif // IR_MIDEA_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.cpp
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.cpp
index b092c27b9573..ca9bef5d98c9 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.cpp
@@ -165,7 +165,7 @@ bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits,
// This protocol appears to have a manditory in-protocol repeat.
// That is in *addition* to the entire message needing to be sent twice
// for the device to accept the command. That is separate from the repeat.
-// i.e. Allegedly, the real remote requires the "OFF" button pressed twice.
+// i.e. Allegedly, the real remote requires the "Off" button pressed twice.
// You will need to add a suitable gap yourself.
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/441
@@ -453,9 +453,9 @@ void IRMitsubishiAC::begin() { _irsend.begin(); }
#if SEND_MITSUBISHI_AC
// Send the current desired state to the IR LED.
-void IRMitsubishiAC::send() {
+void IRMitsubishiAC::send(const uint16_t repeat) {
checksum(); // Ensure correct checksum before sending.
- _irsend.sendMitsubishiAC(remote_state);
+ _irsend.sendMitsubishiAC(remote_state, kMitsubishiACStateLength, repeat);
}
#endif // SEND_MITSUBISHI_AC
@@ -615,6 +615,52 @@ void IRMitsubishiAC::setTimer(uint8_t timer) {
remote_state[13] = timer & 0b111;
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMitsubishiAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kMitsubishiAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kMitsubishiAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kMitsubishiAcDry;
+ default:
+ return kMitsubishiAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMitsubishiAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kMitsubishiAcFanSilent;
+ case stdAc::fanspeed_t::kLow:
+ return kMitsubishiAcFanRealMax - 3;
+ case stdAc::fanspeed_t::kMedium:
+ return kMitsubishiAcFanRealMax - 2;
+ case stdAc::fanspeed_t::kHigh:
+ return kMitsubishiAcFanRealMax - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kMitsubishiAcFanRealMax;
+ default:
+ return kMitsubishiAcFanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRMitsubishiAC::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return kMitsubishiAcVaneAutoMove;
+ default:
+ return kMitsubishiAcVaneAuto;
+ }
+}
+
#ifdef ARDUINO
String IRMitsubishiAC::timeToString(uint64_t time) {
String result = "";
@@ -622,10 +668,10 @@ String IRMitsubishiAC::timeToString(uint64_t time) {
std::string IRMitsubishiAC::timeToString(uint64_t time) {
std::string result = "";
#endif // ARDUINO
- if (time / 6 < 10) result += "0";
+ if (time / 6 < 10) result += '0';
result += uint64ToString(time / 6);
- result += ":";
- if (time * 10 % 60 < 10) result += "0";
+ result += ':';
+ if (time * 10 % 60 < 10) result += '0';
result += uint64ToString(time * 10 % 60);
return result;
}
@@ -638,77 +684,78 @@ String IRMitsubishiAC::toString() {
std::string IRMitsubishiAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
switch (getMode()) {
case MITSUBISHI_AC_AUTO:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case MITSUBISHI_AC_COOL:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case MITSUBISHI_AC_DRY:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case MITSUBISHI_AC_HEAT:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", FAN: ";
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, FAN: ");
switch (getFan()) {
case MITSUBISHI_AC_FAN_AUTO:
- result += "AUTO";
+ result += F("AUTO");
break;
case MITSUBISHI_AC_FAN_MAX:
- result += "MAX";
+ result += F("MAX");
break;
case MITSUBISHI_AC_FAN_SILENT:
- result += "SILENT";
+ result += F("SILENT");
break;
default:
result += uint64ToString(getFan());
}
- result += ", VANE: ";
+ result += F(", VANE: ");
switch (getVane()) {
case MITSUBISHI_AC_VANE_AUTO:
- result += "AUTO";
+ result += F("AUTO");
break;
case MITSUBISHI_AC_VANE_AUTO_MOVE:
- result += "AUTO MOVE";
+ result += F("AUTO MOVE");
break;
default:
result += uint64ToString(getVane());
}
- result += ", Time: ";
+ result += F(", Time: ");
result += timeToString(getClock());
- result += ", On timer: ";
+ result += F(", On timer: ");
result += timeToString(getStartClock());
- result += ", Off timer: ";
+ result += F(", Off timer: ");
result += timeToString(getStopClock());
- result += ", Timer: ";
+ result += F(", Timer: ");
switch (getTimer()) {
case kMitsubishiAcNoTimer:
- result += "-";
+ result += '-';
break;
case kMitsubishiAcStartTimer:
- result += "Start";
+ result += F("Start");
break;
case kMitsubishiAcStopTimer:
- result += "Stop";
+ result += F("Stop");
break;
case kMitsubishiAcStartStopTimer:
- result += "Start+Stop";
+ result += F("Start+Stop");
break;
default:
- result += "? (";
+ result += F("? (");
result += getTimer();
- result += ")\n";
+ result += F(")\n");
}
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.h
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.h
index 7b03efce6463..c8dca5dbcd47 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Mitsubishi.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Mitsubishi.h
@@ -12,6 +12,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII
// M M M I T S U U B B I S H H I
@@ -64,7 +67,7 @@ class IRMitsubishiAC {
void stateReset();
#if SEND_MITSUBISHI_AC
- void send();
+ void send(const uint16_t repeat = kMitsubishiACMinRepeat);
#endif // SEND_MITSUBISHI_AC
void begin();
void on();
@@ -89,13 +92,21 @@ class IRMitsubishiAC {
void setStopClock(uint8_t clock);
uint8_t getTimer();
void setTimer(uint8_t timer);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
#ifdef ARDUINO
String timeToString(uint64_t time);
#else
@@ -103,7 +114,6 @@ class IRMitsubishiAC {
#endif
uint8_t remote_state[kMitsubishiACStateLength];
void checksum();
- IRsend _irsend;
};
#endif // IR_MITSUBISHI_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.cpp
new file mode 100644
index 000000000000..9048124d4bda
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.cpp
@@ -0,0 +1,1014 @@
+// Copyright 2019 David Conran
+// Mitsubishi Heavy Industries A/C remote emulation.
+
+// Code to emulate Mitsubishi Heavy Industries A/C IR remote control units,
+// which should control at least the following A/C units:
+// Remote Control RLA502A700B:
+// Model SRKxxZM-S
+// Model SRKxxZMXA-S
+// Remote Control RKX502A001C:
+// Model SRKxxZJ-S
+
+// Note: This code was *heavily* influenced by @ToniA's great work & code,
+// but it has been written from scratch.
+// Nothing was copied other than constants and message analysis.
+
+#include "ir_MitsubishiHeavy.h"
+#include
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+#ifndef ARDUINO
+#include
+#endif
+
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/660
+// https://github.com/ToniA/Raw-IR-decoder-for-Arduino/blob/master/MitsubishiHeavy.cpp
+// https://github.com/ToniA/arduino-heatpumpir/blob/master/MitsubishiHeavyHeatpumpIR.cpp
+
+// Constants
+const uint16_t kMitsubishiHeavyHdrMark = 3140;
+const uint16_t kMitsubishiHeavyHdrSpace = 1630;
+const uint16_t kMitsubishiHeavyBitMark = 370;
+const uint16_t kMitsubishiHeavyOneSpace = 420;
+const uint16_t kMitsubishiHeavyZeroSpace = 1220;
+const uint32_t kMitsubishiHeavyGap = kDefaultMessageGap; // Just a guess.
+
+#if SEND_MITSUBISHIHEAVY
+// Send a MitsubishiHeavy 88 bit A/C message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kMitsubishiHeavy88Bits.
+// repeat: Nr. of additional times the message is to be sent.
+//
+// Status: BETA / Appears to be working. Needs testing against a real device.
+void IRsend::sendMitsubishiHeavy88(const unsigned char data[],
+ const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kMitsubishiHeavy88StateLength)
+ return; // Not enough bytes to send a proper message.
+ sendGeneric(kMitsubishiHeavyHdrMark, kMitsubishiHeavyHdrSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyOneSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyZeroSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyGap,
+ data, nbytes, 38000, false, repeat, kDutyDefault);
+}
+
+// Send a MitsubishiHeavy 152 bit A/C message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kMitsubishiHeavy152Bits.
+// repeat: Nr. of additional times the message is to be sent.
+//
+// Status: BETA / Appears to be working. Needs testing against a real device.
+void IRsend::sendMitsubishiHeavy152(const unsigned char data[],
+ const uint16_t nbytes,
+ const uint16_t repeat) {
+ if (nbytes < kMitsubishiHeavy152StateLength)
+ return; // Not enough bytes to send a proper message.
+ sendMitsubishiHeavy88(data, nbytes, repeat);
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+// Class for decoding and constructing MitsubishiHeavy152 AC messages.
+IRMitsubishiHeavy152Ac::IRMitsubishiHeavy152Ac(
+ const uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRMitsubishiHeavy152Ac::begin() { _irsend.begin(); }
+
+#if SEND_MITSUBISHIHEAVY
+void IRMitsubishiHeavy152Ac::send(const uint16_t repeat) {
+ _irsend.sendMitsubishiHeavy152(this->getRaw(), kMitsubishiHeavy152StateLength,
+ repeat);
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+void IRMitsubishiHeavy152Ac::stateReset(void) {
+ uint8_t i = 0;
+ for (; i < kMitsubishiHeavySigLength; i++)
+ remote_state[i] = kMitsubishiHeavyZmsSig[i];
+ for (; i < kMitsubishiHeavy152StateLength - 3; i += 2) remote_state[i] = 0;
+ remote_state[17] = 0x80;
+}
+
+uint8_t *IRMitsubishiHeavy152Ac::getRaw(void) {
+ checksum();
+ return remote_state;
+}
+
+void IRMitsubishiHeavy152Ac::setRaw(const uint8_t *data) {
+ for (uint8_t i = 0; i < kMitsubishiHeavy152StateLength; i++)
+ remote_state[i] = data[i];
+}
+
+void IRMitsubishiHeavy152Ac::on(void) {
+ remote_state[5] |= kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy152Ac::off(void) {
+ remote_state[5] &= ~kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy152Ac::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRMitsubishiHeavy152Ac::getPower(void) {
+ return remote_state[5] & kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy152Ac::setTemp(const uint8_t temp) {
+ uint8_t newtemp = temp;
+ newtemp = std::min(newtemp, kMitsubishiHeavyMaxTemp);
+ newtemp = std::max(newtemp, kMitsubishiHeavyMinTemp);
+
+ remote_state[7] &= ~kMitsubishiHeavyTempMask;
+ remote_state[7] |= newtemp - kMitsubishiHeavyMinTemp;
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getTemp(void) {
+ return (remote_state[7] & kMitsubishiHeavyTempMask) + kMitsubishiHeavyMinTemp;
+}
+
+// Set the speed of the fan
+void IRMitsubishiHeavy152Ac::setFan(const uint8_t speed) {
+ uint8_t newspeed = speed;
+ switch (speed) {
+ case kMitsubishiHeavy152FanLow:
+ case kMitsubishiHeavy152FanMed:
+ case kMitsubishiHeavy152FanHigh:
+ case kMitsubishiHeavy152FanMax:
+ case kMitsubishiHeavy152FanEcono:
+ case kMitsubishiHeavy152FanTurbo:
+ break;
+ default:
+ newspeed = kMitsubishiHeavy152FanAuto;
+ }
+ remote_state[9] &= ~kMitsubishiHeavyFanMask;
+ remote_state[9] |= newspeed;
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getFan(void) {
+ return remote_state[9] & kMitsubishiHeavyFanMask;
+}
+
+void IRMitsubishiHeavy152Ac::setMode(const uint8_t mode) {
+ uint8_t newmode = mode;
+ switch (mode) {
+ case kMitsubishiHeavyCool:
+ case kMitsubishiHeavyDry:
+ case kMitsubishiHeavyFan:
+ case kMitsubishiHeavyHeat:
+ break;
+ default:
+ newmode = kMitsubishiHeavyAuto;
+ }
+ remote_state[5] &= ~kMitsubishiHeavyModeMask;
+ remote_state[5] |= newmode;
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getMode(void) {
+ return remote_state[5] & kMitsubishiHeavyModeMask;
+}
+
+void IRMitsubishiHeavy152Ac::setSwingVertical(const uint8_t pos) {
+ uint8_t newpos = std::min(pos, kMitsubishiHeavy152SwingVOff);
+ remote_state[11] &= ~kMitsubishiHeavy152SwingVMask;
+ remote_state[11] |= (newpos << 5);
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getSwingVertical(void) {
+ return remote_state[11] >> 5;
+}
+
+void IRMitsubishiHeavy152Ac::setSwingHorizontal(const uint8_t pos) {
+ uint8_t newpos = std::min(pos, kMitsubishiHeavy152SwingHOff);
+ remote_state[13] &= ~kMitsubishiHeavy152SwingHMask;
+ remote_state[13] |= (newpos & kMitsubishiHeavy152SwingHMask);
+}
+
+uint8_t IRMitsubishiHeavy152Ac::getSwingHorizontal(void) {
+ return remote_state[13] & kMitsubishiHeavy152SwingHMask;
+}
+
+void IRMitsubishiHeavy152Ac::setNight(const bool on) {
+ if (on)
+ remote_state[15] |= kMitsubishiHeavyNightBit;
+ else
+ remote_state[15] &= ~kMitsubishiHeavyNightBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getNight(void) {
+ return remote_state[15] & kMitsubishiHeavyNightBit;
+}
+
+void IRMitsubishiHeavy152Ac::set3D(const bool on) {
+ if (on)
+ remote_state[11] |= kMitsubishiHeavy3DMask;
+ else
+ remote_state[11] &= ~kMitsubishiHeavy3DMask;
+}
+
+bool IRMitsubishiHeavy152Ac::get3D(void) {
+ return (remote_state[11] & kMitsubishiHeavy3DMask) == kMitsubishiHeavy3DMask;
+}
+
+void IRMitsubishiHeavy152Ac::setSilent(const bool on) {
+ if (on)
+ remote_state[15] |= kMitsubishiHeavySilentBit;
+ else
+ remote_state[15] &= ~kMitsubishiHeavySilentBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getSilent(void) {
+ return remote_state[15] & kMitsubishiHeavySilentBit;
+}
+
+void IRMitsubishiHeavy152Ac::setFilter(const bool on) {
+ if (on)
+ remote_state[5] |= kMitsubishiHeavyFilterBit;
+ else
+ remote_state[5] &= ~kMitsubishiHeavyFilterBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getFilter(void) {
+ return remote_state[5] & kMitsubishiHeavyFilterBit;
+}
+
+void IRMitsubishiHeavy152Ac::setClean(const bool on) {
+ this->setFilter(on);
+ if (on)
+ remote_state[5] |= kMitsubishiHeavyCleanBit;
+ else
+ remote_state[5] &= ~kMitsubishiHeavyCleanBit;
+}
+
+bool IRMitsubishiHeavy152Ac::getClean(void) {
+ return remote_state[5] & kMitsubishiHeavyCleanBit && this->getFilter();
+}
+
+void IRMitsubishiHeavy152Ac::setTurbo(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy152FanTurbo);
+ else if (this->getTurbo()) this->setFan(kMitsubishiHeavy152FanAuto);
+}
+
+bool IRMitsubishiHeavy152Ac::getTurbo(void) {
+ return this->getFan() == kMitsubishiHeavy152FanTurbo;
+}
+
+void IRMitsubishiHeavy152Ac::setEcono(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy152FanEcono);
+ else if (this->getEcono()) this->setFan(kMitsubishiHeavy152FanAuto);
+}
+
+bool IRMitsubishiHeavy152Ac::getEcono(void) {
+ return this->getFan() == kMitsubishiHeavy152FanEcono;
+}
+
+// Verify the given state has a ZM-S signature.
+bool IRMitsubishiHeavy152Ac::checkZmsSig(const uint8_t *state) {
+ for (uint8_t i = 0; i < kMitsubishiHeavySigLength; i++)
+ if (state[i] != kMitsubishiHeavyZmsSig[i]) return false;
+ return true;
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+void IRMitsubishiHeavy152Ac::checksum(void) {
+ for (uint8_t i = kMitsubishiHeavySigLength - 2;
+ i < kMitsubishiHeavy152StateLength;
+ i += 2) {
+ remote_state[i + 1] = ~remote_state[i];
+ }
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+bool IRMitsubishiHeavy152Ac::validChecksum(const uint8_t *state,
+ const uint16_t length) {
+ // Assume anything too short is fine.
+ if (length < kMitsubishiHeavySigLength) return true;
+ // Check all the byte pairs.
+ for (uint16_t i = kMitsubishiHeavySigLength - 2;
+ i < length;
+ i += 2) {
+ // XOR of a byte and it's self inverted should be 0xFF;
+ if ((state[i] ^ state[i + 1]) != 0xFF) return false;
+ }
+ return true;
+}
+
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMitsubishiHeavy152Ac::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kMitsubishiHeavyCool;
+ case stdAc::opmode_t::kHeat:
+ return kMitsubishiHeavyHeat;
+ case stdAc::opmode_t::kDry:
+ return kMitsubishiHeavyDry;
+ case stdAc::opmode_t::kFan:
+ return kMitsubishiHeavyFan;
+ default:
+ return kMitsubishiHeavyAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMitsubishiHeavy152Ac::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kMitsubishiHeavy152FanEcono; // Assumes Econo is slower than Low.
+ case stdAc::fanspeed_t::kLow:
+ return kMitsubishiHeavy152FanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kMitsubishiHeavy152FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ return kMitsubishiHeavy152FanHigh;
+ case stdAc::fanspeed_t::kMax:
+ return kMitsubishiHeavy152FanMax;
+ default:
+ return kMitsubishiHeavy152FanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRMitsubishiHeavy152Ac::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kAuto:
+ return kMitsubishiHeavy152SwingVAuto;
+ case stdAc::swingv_t::kHighest:
+ return kMitsubishiHeavy152SwingVHighest;
+ case stdAc::swingv_t::kHigh:
+ return kMitsubishiHeavy152SwingVHigh;
+ case stdAc::swingv_t::kMiddle:
+ return kMitsubishiHeavy152SwingVMiddle;
+ case stdAc::swingv_t::kLow:
+ return kMitsubishiHeavy152SwingVLow;
+ case stdAc::swingv_t::kLowest:
+ return kMitsubishiHeavy152SwingVLowest;
+ default:
+ return kMitsubishiHeavy152SwingVOff;
+ }
+}
+
+// Convert a standard A/C horizontal swing into its native setting.
+uint8_t IRMitsubishiHeavy152Ac::convertSwingH(const stdAc::swingh_t position) {
+ switch (position) {
+ case stdAc::swingh_t::kAuto:
+ return kMitsubishiHeavy152SwingHAuto;
+ case stdAc::swingh_t::kLeftMax:
+ return kMitsubishiHeavy152SwingHLeftMax;
+ case stdAc::swingh_t::kLeft:
+ return kMitsubishiHeavy152SwingHLeft;
+ case stdAc::swingh_t::kMiddle:
+ return kMitsubishiHeavy152SwingHMiddle;
+ case stdAc::swingh_t::kRight:
+ return kMitsubishiHeavy152SwingHRight;
+ case stdAc::swingh_t::kRightMax:
+ return kMitsubishiHeavy152SwingHRightMax;
+ default:
+ return kMitsubishiHeavy152SwingHOff;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRMitsubishiHeavy152Ac::toString(void) {
+ String result = "";
+#else
+std::string IRMitsubishiHeavy152Ac::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kMitsubishiHeavyAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavyCool:
+ result += F(" (Cool)");
+ break;
+ case kMitsubishiHeavyHeat:
+ result += F(" (Heat)");
+ break;
+ case kMitsubishiHeavyDry:
+ result += F(" (Dry)");
+ break;
+ case kMitsubishiHeavyFan:
+ result += F(" (Fan)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp()) + 'C';
+ result += F(", Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kMitsubishiHeavy152FanAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy152FanHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy152FanLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy152FanMed:
+ result += F(" (Med)");
+ break;
+ case kMitsubishiHeavy152FanMax:
+ result += F(" (Max)");
+ break;
+ case kMitsubishiHeavy152FanEcono:
+ result += F(" (Econo)");
+ break;
+ case kMitsubishiHeavy152FanTurbo:
+ result += F(" (Turbo)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (V): ");
+ result += uint64ToString(this->getSwingVertical());
+ switch (this->getSwingVertical()) {
+ case kMitsubishiHeavy152SwingVAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy152SwingVHighest:
+ result += F(" (Highest)");
+ break;
+ case kMitsubishiHeavy152SwingVHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy152SwingVMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy152SwingVLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy152SwingVLowest:
+ result += F(" (Lowest)");
+ break;
+ case kMitsubishiHeavy152SwingVOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (H): ");
+ result += uint64ToString(this->getSwingHorizontal());
+ switch (this->getSwingHorizontal()) {
+ case kMitsubishiHeavy152SwingHAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy152SwingHLeftMax:
+ result += F(" (Max Left)");
+ break;
+ case kMitsubishiHeavy152SwingHLeft:
+ result += F(" (Left)");
+ break;
+ case kMitsubishiHeavy152SwingHMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy152SwingHRight:
+ result += F(" (Right)");
+ break;
+ case kMitsubishiHeavy152SwingHRightMax:
+ result += F(" (Max Right)");
+ break;
+ case kMitsubishiHeavy152SwingHLeftRight:
+ result += F(" (Left Right)");
+ break;
+ case kMitsubishiHeavy152SwingHRightLeft:
+ result += F(" (Right Left)");
+ break;
+ case kMitsubishiHeavy152SwingHOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Silent: ");
+ result += (this->getSilent() ? F("On") : F("Off"));
+ result += F(", Turbo: ");
+ result += (this->getTurbo() ? F("On") : F("Off"));
+ result += F(", Econo: ");
+ result += (this->getEcono() ? F("On") : F("Off"));
+ result += F(", Night: ");
+ result += (this->getNight() ? F("On") : F("Off"));
+ result += F(", Filter: ");
+ result += (this->getFilter() ? F("On") : F("Off"));
+ result += F(", 3D: ");
+ result += (this->get3D() ? F("On") : F("Off"));
+ result += F(", Clean: ");
+ result += (this->getClean() ? F("On") : F("Off"));
+ return result;
+}
+
+
+// Class for decoding and constructing MitsubishiHeavy88 AC messages.
+IRMitsubishiHeavy88Ac::IRMitsubishiHeavy88Ac(
+ const uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRMitsubishiHeavy88Ac::begin() { _irsend.begin(); }
+
+#if SEND_MITSUBISHIHEAVY
+void IRMitsubishiHeavy88Ac::send(const uint16_t repeat) {
+ _irsend.sendMitsubishiHeavy88(this->getRaw(), kMitsubishiHeavy88StateLength,
+ repeat);
+}
+#endif // SEND_MITSUBISHIHEAVY
+
+void IRMitsubishiHeavy88Ac::stateReset(void) {
+ uint8_t i = 0;
+ for (; i < kMitsubishiHeavySigLength; i++)
+ remote_state[i] = kMitsubishiHeavyZjsSig[i];
+ for (; i < kMitsubishiHeavy88StateLength; i++) remote_state[i] = 0;
+}
+
+uint8_t *IRMitsubishiHeavy88Ac::getRaw(void) {
+ checksum();
+ return remote_state;
+}
+
+void IRMitsubishiHeavy88Ac::setRaw(const uint8_t *data) {
+ for (uint8_t i = 0; i < kMitsubishiHeavy88StateLength; i++)
+ remote_state[i] = data[i];
+}
+
+void IRMitsubishiHeavy88Ac::on(void) {
+ remote_state[9] |= kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy88Ac::off(void) {
+ remote_state[9] &= ~kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy88Ac::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRMitsubishiHeavy88Ac::getPower(void) {
+ return remote_state[9] & kMitsubishiHeavyPowerBit;
+}
+
+void IRMitsubishiHeavy88Ac::setTemp(const uint8_t temp) {
+ uint8_t newtemp = temp;
+ newtemp = std::min(newtemp, kMitsubishiHeavyMaxTemp);
+ newtemp = std::max(newtemp, kMitsubishiHeavyMinTemp);
+
+ remote_state[9] &= kMitsubishiHeavyTempMask;
+ remote_state[9] |= ((newtemp - kMitsubishiHeavyMinTemp) << 4);
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getTemp(void) {
+ return (remote_state[9] >> 4) + kMitsubishiHeavyMinTemp;
+}
+
+// Set the speed of the fan
+void IRMitsubishiHeavy88Ac::setFan(const uint8_t speed) {
+ uint8_t newspeed = speed;
+ switch (speed) {
+ case kMitsubishiHeavy88FanLow:
+ case kMitsubishiHeavy88FanMed:
+ case kMitsubishiHeavy88FanHigh:
+ case kMitsubishiHeavy88FanTurbo:
+ case kMitsubishiHeavy88FanEcono:
+ break;
+ default:
+ newspeed = kMitsubishiHeavy88FanAuto;
+ }
+ remote_state[7] &= ~kMitsubishiHeavy88FanMask;
+ remote_state[7] |= (newspeed << 5);
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getFan(void) {
+ return remote_state[7] >> 5;
+}
+
+void IRMitsubishiHeavy88Ac::setMode(const uint8_t mode) {
+ uint8_t newmode = mode;
+ switch (mode) {
+ case kMitsubishiHeavyCool:
+ case kMitsubishiHeavyDry:
+ case kMitsubishiHeavyFan:
+ case kMitsubishiHeavyHeat:
+ break;
+ default:
+ newmode = kMitsubishiHeavyAuto;
+ }
+ remote_state[9] &= ~kMitsubishiHeavyModeMask;
+ remote_state[9] |= newmode;
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getMode(void) {
+ return remote_state[9] & kMitsubishiHeavyModeMask;
+}
+
+void IRMitsubishiHeavy88Ac::setSwingVertical(const uint8_t pos) {
+ uint8_t newpos;
+ switch (pos) {
+ case kMitsubishiHeavy88SwingVAuto:
+ case kMitsubishiHeavy88SwingVHighest:
+ case kMitsubishiHeavy88SwingVHigh:
+ case kMitsubishiHeavy88SwingVMiddle:
+ case kMitsubishiHeavy88SwingVLow:
+ case kMitsubishiHeavy88SwingVLowest:
+ newpos = pos;
+ break;
+ default:
+ newpos = kMitsubishiHeavy88SwingVOff;
+ }
+ remote_state[5] &= ~kMitsubishiHeavy88SwingVMaskByte5;
+ remote_state[5] |= (newpos & kMitsubishiHeavy88SwingVMaskByte5);
+ remote_state[7] &= ~kMitsubishiHeavy88SwingVMaskByte7;
+ remote_state[7] |= (newpos & kMitsubishiHeavy88SwingVMaskByte7);
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getSwingVertical(void) {
+ return (remote_state[5] & kMitsubishiHeavy88SwingVMaskByte5) |
+ (remote_state[7] & kMitsubishiHeavy88SwingVMaskByte7);
+}
+
+void IRMitsubishiHeavy88Ac::setSwingHorizontal(const uint8_t pos) {
+ uint8_t newpos;
+ switch (pos) {
+ case kMitsubishiHeavy88SwingHAuto:
+ case kMitsubishiHeavy88SwingHLeftMax:
+ case kMitsubishiHeavy88SwingHLeft:
+ case kMitsubishiHeavy88SwingHMiddle:
+ case kMitsubishiHeavy88SwingHRight:
+ case kMitsubishiHeavy88SwingHRightMax:
+ case kMitsubishiHeavy88SwingHLeftRight:
+ case kMitsubishiHeavy88SwingHRightLeft:
+ case kMitsubishiHeavy88SwingH3D:
+ newpos = pos;
+ break;
+ default:
+ newpos = kMitsubishiHeavy88SwingHOff;
+ }
+ remote_state[5] &= ~kMitsubishiHeavy88SwingHMask;
+ remote_state[5] |= newpos;
+}
+
+uint8_t IRMitsubishiHeavy88Ac::getSwingHorizontal(void) {
+ return remote_state[5] & kMitsubishiHeavy88SwingHMask;
+}
+
+void IRMitsubishiHeavy88Ac::setTurbo(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy88FanTurbo);
+ else if (this->getTurbo()) this->setFan(kMitsubishiHeavy88FanAuto);
+}
+
+bool IRMitsubishiHeavy88Ac::getTurbo(void) {
+ return this->getFan() == kMitsubishiHeavy88FanTurbo;
+}
+
+void IRMitsubishiHeavy88Ac::setEcono(const bool on) {
+ if (on)
+ this->setFan(kMitsubishiHeavy88FanEcono);
+ else if (this->getEcono()) this->setFan(kMitsubishiHeavy88FanAuto);
+}
+
+bool IRMitsubishiHeavy88Ac::getEcono(void) {
+ return this->getFan() == kMitsubishiHeavy88FanEcono;
+}
+
+void IRMitsubishiHeavy88Ac::set3D(const bool on) {
+ if (on)
+ this->setSwingHorizontal(kMitsubishiHeavy88SwingH3D);
+ else if (this->get3D())
+ this->setSwingHorizontal(kMitsubishiHeavy88SwingHOff);
+}
+
+bool IRMitsubishiHeavy88Ac::get3D(void) {
+ return this->getSwingHorizontal() == kMitsubishiHeavy88SwingH3D;
+}
+
+void IRMitsubishiHeavy88Ac::setClean(const bool on) {
+ if (on)
+ remote_state[5] |= kMitsubishiHeavy88CleanBit;
+ else
+ remote_state[5] &= ~kMitsubishiHeavy88CleanBit;
+}
+
+bool IRMitsubishiHeavy88Ac::getClean(void) {
+ return remote_state[5] & kMitsubishiHeavy88CleanBit;
+}
+
+// Verify the given state has a ZJ-S signature.
+bool IRMitsubishiHeavy88Ac::checkZjsSig(const uint8_t *state) {
+ for (uint8_t i = 0; i < kMitsubishiHeavySigLength; i++)
+ if (state[i] != kMitsubishiHeavyZjsSig[i]) return false;
+ return true;
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+void IRMitsubishiHeavy88Ac::checksum(void) {
+ for (uint8_t i = kMitsubishiHeavySigLength - 2;
+ i < kMitsubishiHeavy88StateLength;
+ i += 2) {
+ remote_state[i + 1] = ~remote_state[i];
+ }
+}
+
+// Protocol technically has no checksum, but does has inverted byte pairs.
+bool IRMitsubishiHeavy88Ac::validChecksum(const uint8_t *state,
+ const uint16_t length) {
+ return IRMitsubishiHeavy152Ac::validChecksum(state, length);
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRMitsubishiHeavy88Ac::convertMode(const stdAc::opmode_t mode) {
+ return IRMitsubishiHeavy152Ac::convertMode(mode);
+}
+
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRMitsubishiHeavy88Ac::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kMitsubishiHeavy88FanEcono; // Assumes Econo is slower than Low.
+ case stdAc::fanspeed_t::kLow:
+ return kMitsubishiHeavy88FanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kMitsubishiHeavy88FanMed;
+ case stdAc::fanspeed_t::kHigh:
+ return kMitsubishiHeavy88FanHigh;
+ case stdAc::fanspeed_t::kMax:
+ return kMitsubishiHeavy88FanTurbo;
+ default:
+ return kMitsubishiHeavy88FanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRMitsubishiHeavy88Ac::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kAuto:
+ return kMitsubishiHeavy88SwingVAuto;
+ case stdAc::swingv_t::kHighest:
+ return kMitsubishiHeavy88SwingVHighest;
+ case stdAc::swingv_t::kHigh:
+ return kMitsubishiHeavy88SwingVHigh;
+ case stdAc::swingv_t::kMiddle:
+ return kMitsubishiHeavy88SwingVMiddle;
+ case stdAc::swingv_t::kLow:
+ return kMitsubishiHeavy88SwingVLow;
+ case stdAc::swingv_t::kLowest:
+ return kMitsubishiHeavy88SwingVLowest;
+ default:
+ return kMitsubishiHeavy88SwingVOff;
+ }
+}
+
+// Convert a standard A/C horizontal swing into its native setting.
+uint8_t IRMitsubishiHeavy88Ac::convertSwingH(const stdAc::swingh_t position) {
+ switch (position) {
+ case stdAc::swingh_t::kAuto:
+ return kMitsubishiHeavy88SwingHAuto;
+ case stdAc::swingh_t::kLeftMax:
+ return kMitsubishiHeavy88SwingHLeftMax;
+ case stdAc::swingh_t::kLeft:
+ return kMitsubishiHeavy88SwingHLeft;
+ case stdAc::swingh_t::kMiddle:
+ return kMitsubishiHeavy88SwingHMiddle;
+ case stdAc::swingh_t::kRight:
+ return kMitsubishiHeavy88SwingHRight;
+ case stdAc::swingh_t::kRightMax:
+ return kMitsubishiHeavy88SwingHRightMax;
+ default:
+ return kMitsubishiHeavy88SwingHOff;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRMitsubishiHeavy88Ac::toString(void) {
+ String result = "";
+#else
+std::string IRMitsubishiHeavy88Ac::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kMitsubishiHeavyAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavyCool:
+ result += F(" (Cool)");
+ break;
+ case kMitsubishiHeavyHeat:
+ result += F(" (Heat)");
+ break;
+ case kMitsubishiHeavyDry:
+ result += F(" (Dry)");
+ break;
+ case kMitsubishiHeavyFan:
+ result += F(" (Fan)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(this->getTemp()) + 'C';
+ result += F(", Fan: ");
+ result += uint64ToString(this->getFan());
+ switch (this->getFan()) {
+ case kMitsubishiHeavy88FanAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy88FanHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy88FanLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy88FanMed:
+ result += F(" (Med)");
+ break;
+ case kMitsubishiHeavy88FanEcono:
+ result += F(" (Econo)");
+ break;
+ case kMitsubishiHeavy88FanTurbo:
+ result += F(" (Turbo)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (V): ");
+ result += uint64ToString(this->getSwingVertical());
+ switch (this->getSwingVertical()) {
+ case kMitsubishiHeavy88SwingVAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy88SwingVHighest:
+ result += F(" (Highest)");
+ break;
+ case kMitsubishiHeavy88SwingVHigh:
+ result += F(" (High)");
+ break;
+ case kMitsubishiHeavy88SwingVMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy88SwingVLow:
+ result += F(" (Low)");
+ break;
+ case kMitsubishiHeavy88SwingVLowest:
+ result += F(" (Lowest)");
+ break;
+ case kMitsubishiHeavy88SwingVOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Swing (H): ");
+ result += uint64ToString(this->getSwingHorizontal());
+ switch (this->getSwingHorizontal()) {
+ case kMitsubishiHeavy88SwingHAuto:
+ result += F(" (Auto)");
+ break;
+ case kMitsubishiHeavy88SwingHLeftMax:
+ result += F(" (Max Left)");
+ break;
+ case kMitsubishiHeavy88SwingHLeft:
+ result += F(" (Left)");
+ break;
+ case kMitsubishiHeavy88SwingHMiddle:
+ result += F(" (Middle)");
+ break;
+ case kMitsubishiHeavy88SwingHRight:
+ result += F(" (Right)");
+ break;
+ case kMitsubishiHeavy88SwingHRightMax:
+ result += F(" (Max Right)");
+ break;
+ case kMitsubishiHeavy88SwingHLeftRight:
+ result += F(" (Left Right)");
+ break;
+ case kMitsubishiHeavy88SwingHRightLeft:
+ result += F(" (Right Left)");
+ break;
+ case kMitsubishiHeavy88SwingH3D:
+ result += F(" (3D)");
+ break;
+ case kMitsubishiHeavy88SwingHOff:
+ result += F(" (Off)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Turbo: ");
+ result += (this->getTurbo() ? F("On") : F("Off"));
+ result += F(", Econo: ");
+ result += (this->getEcono() ? F("On") : F("Off"));
+ result += F(", 3D: ");
+ result += (this->get3D() ? F("On") : F("Off"));
+ result += F(", Clean: ");
+ result += (this->getClean() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_MITSUBISHIHEAVY
+// Decode the supplied MitsubishiHeavy message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: The number of data bits to expect.
+// Typically kMitsubishiHeavy88Bits or kMitsubishiHeavy152Bits.
+// 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. Needs testing against a real device.
+bool IRrecv::decodeMitsubishiHeavy(decode_results* results,
+ const uint16_t nbits, const bool strict) {
+ // Check if can possibly be a valid MitsubishiHeavy message.
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
+ if (strict) {
+ switch (nbits) {
+ case kMitsubishiHeavy88Bits:
+ case kMitsubishiHeavy152Bits:
+ break;
+ default:
+ return false; // Not what is expected
+ }
+ }
+
+ uint16_t actualBits = 0;
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kMitsubishiHeavyHdrMark))
+ return false;
+ if (!matchSpace(results->rawbuf[offset++], kMitsubishiHeavyHdrSpace))
+ return false;
+ // Data
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint16_t i = 0;
+ offset <= results->rawlen - 16 && actualBits < nbits;
+ i++, actualBits += 8, offset += data_result.used) {
+ data_result = matchData(&(results->rawbuf[offset]), 8,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyOneSpace,
+ kMitsubishiHeavyBitMark, kMitsubishiHeavyZeroSpace,
+ kTolerance, 0, false);
+ if (data_result.success == false) {
+ DPRINT("DEBUG: offset = ");
+ DPRINTLN(offset + data_result.used);
+ return false; // Fail
+ }
+ results->state[i] = data_result.data;
+ }
+ // Footer.
+ if (!matchMark(results->rawbuf[offset++], kMitsubishiHeavyBitMark))
+ return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kMitsubishiHeavyGap)) return false;
+
+ // Compliance
+ if (actualBits < nbits) return false;
+ if (strict && actualBits != nbits) return false; // Not as we expected.
+ switch (actualBits) {
+ case kMitsubishiHeavy88Bits:
+ if (strict && !(IRMitsubishiHeavy88Ac::checkZjsSig(results->state) &&
+ IRMitsubishiHeavy88Ac::validChecksum(results->state)))
+ return false;
+ results->decode_type = MITSUBISHI_HEAVY_88;
+ break;
+ case kMitsubishiHeavy152Bits:
+ if (strict && !(IRMitsubishiHeavy152Ac::checkZmsSig(results->state) &&
+ IRMitsubishiHeavy152Ac::validChecksum(results->state)))
+ return false;
+ results->decode_type = MITSUBISHI_HEAVY_152;
+ break;
+ default:
+ return false;
+ }
+
+ // Success
+ results->bits = actualBits;
+ // No need to record the state as we stored it as we decoded it.
+ // As we use result->state, we don't record value, address, or command as it
+ // is a union data type.
+ return true;
+}
+#endif // DECODE_MITSUBISHIHEAVY
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.h b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.h
new file mode 100644
index 000000000000..bcd85c6e015d
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_MitsubishiHeavy.h
@@ -0,0 +1,264 @@
+// Copyright 2019 David Conran
+
+#ifndef IR_MITSUBISHIHEAVY_H_
+#define IR_MITSUBISHIHEAVY_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/660
+// https://github.com/ToniA/Raw-IR-decoder-for-Arduino/blob/master/MitsubishiHeavy.cpp
+// https://github.com/ToniA/arduino-heatpumpir/blob/master/MitsubishiHeavyHeatpumpIR.cpp
+
+// Constants.
+const uint8_t kMitsubishiHeavySigLength = 5;
+
+
+// ZMS (152 bit)
+const uint8_t kMitsubishiHeavyZmsSig[kMitsubishiHeavySigLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A};
+// Byte[5]
+const uint8_t kMitsubishiHeavyFilterBit = 0b01000000;
+const uint8_t kMitsubishiHeavyCleanBit = 0b00100000;
+const uint8_t kMitsubishiHeavyPowerBit = 0b00001000; // Byte 9 on ZJS
+const uint8_t kMitsubishiHeavyModeMask = 0b00000111; // Byte 9 on ZJS
+const uint8_t kMitsubishiHeavyAuto = 0; // 0b000
+const uint8_t kMitsubishiHeavyCool = 1; // 0b001
+const uint8_t kMitsubishiHeavyDry = 2; // 0b010
+const uint8_t kMitsubishiHeavyFan = 3; // 0b011
+const uint8_t kMitsubishiHeavyHeat = 4; // 0b100
+// Byte[7]
+const uint8_t kMitsubishiHeavyTempMask = 0b00001111;
+const uint8_t kMitsubishiHeavyMinTemp = 17; // 17C
+const uint8_t kMitsubishiHeavyMaxTemp = 31; // 31C
+// Byte[9]
+const uint8_t kMitsubishiHeavyFanMask = 0b00001111; // ~Byte 7 on ZJS.
+const uint8_t kMitsubishiHeavy152FanAuto = 0x0; // 0b0000
+const uint8_t kMitsubishiHeavy152FanLow = 0x1; // 0b0001
+const uint8_t kMitsubishiHeavy152FanMed = 0x2; // 0b0010
+const uint8_t kMitsubishiHeavy152FanHigh = 0x3; // 0b0011
+const uint8_t kMitsubishiHeavy152FanMax = 0x4; // 0b0100
+const uint8_t kMitsubishiHeavy152FanEcono = 0x6; // 0b0110
+const uint8_t kMitsubishiHeavy152FanTurbo = 0x8; // 0b1000
+// Byte[11]
+const uint8_t kMitsubishiHeavy3DMask = 0b00010010;
+const uint8_t kMitsubishiHeavy152SwingVMask = 0b11100000;
+const uint8_t kMitsubishiHeavy152SwingVAuto = 0; // 0b000
+const uint8_t kMitsubishiHeavy152SwingVHighest = 1; // 0b001
+const uint8_t kMitsubishiHeavy152SwingVHigh = 2; // 0b010
+const uint8_t kMitsubishiHeavy152SwingVMiddle = 3; // 0b011
+const uint8_t kMitsubishiHeavy152SwingVLow = 4; // 0b100
+const uint8_t kMitsubishiHeavy152SwingVLowest = 5; // 0b101
+const uint8_t kMitsubishiHeavy152SwingVOff = 6; // 0b110
+// Byte[13]
+const uint8_t kMitsubishiHeavy152SwingHMask = 0b00001111;
+const uint8_t kMitsubishiHeavy152SwingHAuto = 0; // 0b0000
+const uint8_t kMitsubishiHeavy152SwingHLeftMax = 1; // 0b0001
+const uint8_t kMitsubishiHeavy152SwingHLeft = 2; // 0b0010
+const uint8_t kMitsubishiHeavy152SwingHMiddle = 3; // 0b0011
+const uint8_t kMitsubishiHeavy152SwingHRight = 4; // 0b0100
+const uint8_t kMitsubishiHeavy152SwingHRightMax = 5; // 0b0101
+const uint8_t kMitsubishiHeavy152SwingHRightLeft = 6; // 0b0110
+const uint8_t kMitsubishiHeavy152SwingHLeftRight = 7; // 0b0111
+const uint8_t kMitsubishiHeavy152SwingHOff = 8; // 0b1000
+// Byte[15]
+const uint8_t kMitsubishiHeavyNightBit = 0b01000000;
+const uint8_t kMitsubishiHeavySilentBit = 0b10000000;
+
+
+// ZJS (88 bit)
+const uint8_t kMitsubishiHeavyZjsSig[kMitsubishiHeavySigLength] = {
+ 0xAD, 0x51, 0x3C, 0xD9, 0x26};
+// Byte [5]
+const uint8_t kMitsubishiHeavy88CleanBit = 0b00100000;
+const uint8_t kMitsubishiHeavy88SwingHMask = 0b11001100;
+const uint8_t kMitsubishiHeavy88SwingHAuto = 0x80; // 0b10000000
+const uint8_t kMitsubishiHeavy88SwingHLeftMax = 0x04; // 0b00000100
+const uint8_t kMitsubishiHeavy88SwingHLeft = 0x44; // 0b01000100
+const uint8_t kMitsubishiHeavy88SwingHMiddle = 0x84; // 0b10000100
+const uint8_t kMitsubishiHeavy88SwingHRight = 0xC4; // 0b11000100
+const uint8_t kMitsubishiHeavy88SwingHRightMax = 0x08; // 0b00001000
+const uint8_t kMitsubishiHeavy88SwingHRightLeft = 0x88; // 0b10001000
+const uint8_t kMitsubishiHeavy88SwingHLeftRight = 0x48; // 0b01001000
+const uint8_t kMitsubishiHeavy88SwingHOff = 0x00; // 0b00000000
+const uint8_t kMitsubishiHeavy88SwingH3D = 0xC8; // 0b11001000
+// Byte[7]
+const uint8_t kMitsubishiHeavy88FanMask = 0b11100000;
+const uint8_t kMitsubishiHeavy88FanAuto = 0; // 0b000
+const uint8_t kMitsubishiHeavy88FanLow = 2; // 0b010
+const uint8_t kMitsubishiHeavy88FanMed = 3; // 0b011
+const uint8_t kMitsubishiHeavy88FanHigh = 4; // 0b100
+const uint8_t kMitsubishiHeavy88FanTurbo = 6; // 0b110
+const uint8_t kMitsubishiHeavy88FanEcono = 7; // 0b111
+const uint8_t kMitsubishiHeavy88SwingVMaskByte5 = 0b00000010;
+const uint8_t kMitsubishiHeavy88SwingVMaskByte7 = 0b00011000;
+const uint8_t kMitsubishiHeavy88SwingVMask =
+ kMitsubishiHeavy88SwingVMaskByte5 | kMitsubishiHeavy88SwingVMaskByte7;
+ // i.e. 0b00011010
+const uint8_t kMitsubishiHeavy88SwingVAuto = 0b00010000; // 0x10
+const uint8_t kMitsubishiHeavy88SwingVHighest = 0b00011000; // 0x18
+const uint8_t kMitsubishiHeavy88SwingVHigh = 0b00000010; // 0x02
+const uint8_t kMitsubishiHeavy88SwingVMiddle = 0b00001010; // 0x0A
+const uint8_t kMitsubishiHeavy88SwingVLow = 0b00010010; // 0x12
+const uint8_t kMitsubishiHeavy88SwingVLowest = 0b00011010; // 0x1A
+const uint8_t kMitsubishiHeavy88SwingVOff = 0b00000000; // 0x00
+// Byte[9] is Power & Mode & Temp.
+
+
+// Classes
+class IRMitsubishiHeavy152Ac {
+ public:
+ explicit IRMitsubishiHeavy152Ac(const uint16_t pin);
+
+ void stateReset(void);
+#if SEND_MITSUBISHIHEAVY
+ void send(const uint16_t repeat = kMitsubishiHeavy152MinRepeat);
+#endif // SEND_MITSUBISHIHEAVY
+ 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 fan);
+ uint8_t getFan(void);
+
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+
+ void setSwingVertical(const uint8_t pos);
+ uint8_t getSwingVertical(void);
+ void setSwingHorizontal(const uint8_t pos);
+ uint8_t getSwingHorizontal(void);
+
+ void setNight(const bool on);
+ bool getNight(void);
+
+ void set3D(const bool on);
+ bool get3D(void);
+
+ void setSilent(const bool on);
+ bool getSilent(void);
+
+ void setFilter(const bool on);
+ bool getFilter(void);
+
+ void setClean(const bool on);
+ bool getClean(void);
+
+ void setTurbo(const bool on);
+ bool getTurbo(void);
+
+ void setEcono(const bool on);
+ bool getEcono(void);
+
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t* data);
+
+ static bool checkZmsSig(const uint8_t *state);
+ static bool validChecksum(
+ const uint8_t *state,
+ const uint16_t length = kMitsubishiHeavy152StateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static uint8_t convertSwingV(const stdAc::swingv_t position);
+ static uint8_t convertSwingH(const stdAc::swingh_t position);
+#ifdef ARDUINO
+ String toString(void);
+#else // ARDUINO
+ std::string toString(void);
+#endif // ARDUINO
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else // UNIT_TEST
+ IRsendTest _irsend;
+#endif // UNIT_TEST
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kMitsubishiHeavy152StateLength];
+ void checksum();
+};
+
+class IRMitsubishiHeavy88Ac {
+ public:
+ explicit IRMitsubishiHeavy88Ac(const uint16_t pin);
+
+ void stateReset(void);
+#if SEND_MITSUBISHIHEAVY
+ void send(const uint16_t repeat = kMitsubishiHeavy88MinRepeat);
+#endif // SEND_MITSUBISHIHEAVY
+ 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 fan);
+ uint8_t getFan(void);
+
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+
+ void setSwingVertical(const uint8_t pos);
+ uint8_t getSwingVertical(void);
+ void setSwingHorizontal(const uint8_t pos);
+ uint8_t getSwingHorizontal(void);
+
+ void setTurbo(const bool on);
+ bool getTurbo(void);
+
+ void setEcono(const bool on);
+ bool getEcono(void);
+
+ void set3D(const bool on);
+ bool get3D(void);
+
+ void setClean(const bool on);
+ bool getClean(void);
+
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t* data);
+
+ static bool checkZjsSig(const uint8_t *state);
+ static bool validChecksum(
+ const uint8_t *state,
+ const uint16_t length = kMitsubishiHeavy88StateLength);
+ static uint8_t convertMode(const stdAc::opmode_t mode);
+ static uint8_t convertFan(const stdAc::fanspeed_t speed);
+ static uint8_t convertSwingV(const stdAc::swingv_t position);
+ static uint8_t convertSwingH(const stdAc::swingh_t position);
+#ifdef ARDUINO
+ String toString(void);
+#else // ARDUINO
+ std::string toString(void);
+#endif // ARDUINO
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else // UNIT_TEST
+ IRsendTest _irsend;
+#endif // UNIT_TEST
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kMitsubishiHeavy152StateLength];
+ void checksum();
+};
+#endif // IR_MITSUBISHIHEAVY_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_NEC.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_NEC.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.h b/lib/IRremoteESP8266-2.6.0/src/ir_NEC.h
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_NEC.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_NEC.h
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Nikai.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Nikai.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Nikai.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Nikai.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.cpp
similarity index 83%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.cpp
index e79b136a5430..47aa51c96dbb 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.cpp
@@ -27,8 +27,8 @@
// Code by crankyoldgit
// Panasonic A/C models supported:
// A/C Series/models:
-// JKE, LKE, DKE, CKP, & NKE series. (In theory)
-// CS-YW9MKD (confirmed)
+// JKE, LKE, DKE, CKP, RKR, & NKE series. (In theory)
+// CS-YW9MKD, CS-Z9RKR (confirmed)
// CS-ME14CKPG / CS-ME12CKPG / CS-ME10CKPG
// A/C Remotes:
// A75C3747 (confirmed)
@@ -63,7 +63,7 @@ const uint32_t kPanasonicMinGap = kPanasonicMinGapTicks * kPanasonicTick;
const uint16_t kPanasonicAcSectionGap = 10000;
const uint16_t kPanasonicAcSection1Length = 8;
-const uint32_t kPanasonicAcMessageGap = 100000; // A complete guess.
+const uint32_t kPanasonicAcMessageGap = kDefaultMessageGap; // Just a guess.
#if (SEND_PANASONIC || SEND_DENON)
// Send a Panasonic formatted message.
@@ -211,7 +211,7 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits,
//:
// Panasonic A/C models supported:
// A/C Series/models:
-// JKE, LKE, DKE, & NKE series.
+// JKE, LKE, DKE, CKP, RKR, & NKE series.
// CS-YW9MKD
// A/C Remotes:
// A75C3747
@@ -268,9 +268,9 @@ void IRPanasonicAc::fixChecksum(const uint16_t length) {
}
#if SEND_PANASONIC_AC
-void IRPanasonicAc::send() {
+void IRPanasonicAc::send(const uint16_t repeat) {
fixChecksum();
- _irsend.sendPanasonicAC(remote_state);
+ _irsend.sendPanasonicAC(remote_state, kPanasonicAcStateLength, repeat);
}
#endif // SEND_PANASONIC_AC
@@ -281,6 +281,7 @@ void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) {
case kPanasonicLke:
case kPanasonicNke:
case kPanasonicCkp:
+ case kPanasonicRkr:
break;
default: // Only proceed if we know what to do.
return;
@@ -311,12 +312,17 @@ void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) {
case kPanasonicCkp:
remote_state[21] |= 0x10;
remote_state[23] = 0x01;
+ break;
+ case kPanasonicRkr:
+ remote_state[13] |= 0x08;
+ remote_state[23] = 0x89;
default:
break;
}
}
panasonic_ac_remote_model_t IRPanasonicAc::getModel() {
+ if (remote_state[23] == 0x89) return kPanasonicRkr;
if (remote_state[17] == 0x00) {
if ((remote_state[21] & 0x10) && (remote_state[23] & 0x01))
return kPanasonicCkp;
@@ -438,6 +444,7 @@ void IRPanasonicAc::setSwingHorizontal(const uint8_t desired_direction) {
uint8_t direction = desired_direction;
switch (getModel()) {
case kPanasonicDke:
+ case kPanasonicRkr:
break;
case kPanasonicNke:
case kPanasonicLke:
@@ -460,18 +467,25 @@ uint8_t IRPanasonicAc::getFan() {
}
bool IRPanasonicAc::getQuiet() {
- if (getModel() == kPanasonicCkp)
- return remote_state[21] & kPanasonicAcQuietCkp;
- else
- return remote_state[21] & kPanasonicAcQuiet;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ return remote_state[21] & kPanasonicAcQuietCkp;
+ default:
+ return remote_state[21] & kPanasonicAcQuiet;
+ }
}
void IRPanasonicAc::setQuiet(const bool state) {
uint8_t quiet;
- if (getModel() == kPanasonicCkp)
- quiet = kPanasonicAcQuietCkp;
- else
- quiet = kPanasonicAcQuiet;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ quiet = kPanasonicAcQuietCkp;
+ break;
+ default:
+ quiet = kPanasonicAcQuiet;
+ }
if (state) {
setPowerful(false); // Powerful is mutually exclusive.
@@ -482,18 +496,25 @@ void IRPanasonicAc::setQuiet(const bool state) {
}
bool IRPanasonicAc::getPowerful() {
- if (getModel() == kPanasonicCkp)
- return remote_state[21] & kPanasonicAcPowerfulCkp;
- else
- return remote_state[21] & kPanasonicAcPowerful;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ return remote_state[21] & kPanasonicAcPowerfulCkp;
+ default:
+ return remote_state[21] & kPanasonicAcPowerful;
+ }
}
void IRPanasonicAc::setPowerful(const bool state) {
uint8_t powerful;
- if (getModel() == kPanasonicCkp)
- powerful = kPanasonicAcPowerfulCkp;
- else
- powerful = kPanasonicAcPowerful;
+ switch (getModel()) {
+ case kPanasonicRkr:
+ case kPanasonicCkp:
+ powerful = kPanasonicAcPowerfulCkp;
+ break;
+ default:
+ powerful = kPanasonicAcPowerful;
+ }
if (state) {
setQuiet(false); // Quiet is mutually exclusive.
@@ -591,12 +612,79 @@ String IRPanasonicAc::timeToString(const uint16_t mins_since_midnight) {
std::string IRPanasonicAc::timeToString(const uint16_t mins_since_midnight) {
std::string result = "";
#endif // ARDUINO
- result += uint64ToString(mins_since_midnight / 60) + ":";
+ result += uint64ToString(mins_since_midnight / 60) + ':';
uint8_t mins = mins_since_midnight % 60;
- if (mins < 10) result += "0"; // Zero pad the minutes.
+ if (mins < 10) result += '0'; // Zero pad the minutes.
return result + uint64ToString(mins);
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRPanasonicAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kPanasonicAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kPanasonicAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kPanasonicAcDry;
+ case stdAc::opmode_t::kFan:
+ return kPanasonicAcFan;
+ default:
+ return kPanasonicAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRPanasonicAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kPanasonicAcFanMin;
+ case stdAc::fanspeed_t::kLow:
+ return kPanasonicAcFanMin + 1;
+ case stdAc::fanspeed_t::kMedium:
+ return kPanasonicAcFanMin + 2;
+ case stdAc::fanspeed_t::kHigh:
+ return kPanasonicAcFanMin + 3;
+ case stdAc::fanspeed_t::kMax:
+ return kPanasonicAcFanMax;
+ default:
+ return kPanasonicAcFanAuto;
+ }
+}
+
+// Convert a standard A/C vertical swing into its native setting.
+uint8_t IRPanasonicAc::convertSwingV(const stdAc::swingv_t position) {
+ switch (position) {
+ case stdAc::swingv_t::kHighest:
+ case stdAc::swingv_t::kHigh:
+ case stdAc::swingv_t::kMiddle:
+ return kPanasonicAcSwingVUp;
+ case stdAc::swingv_t::kLow:
+ case stdAc::swingv_t::kLowest:
+ return kPanasonicAcSwingVDown;
+ default:
+ return kPanasonicAcSwingVAuto;
+ }
+}
+
+// Convert a standard A/C horizontal swing into its native setting.
+uint8_t IRPanasonicAc::convertSwingH(const stdAc::swingh_t position) {
+ switch (position) {
+ case stdAc::swingh_t::kLeftMax:
+ return kPanasonicAcSwingHFullLeft;
+ case stdAc::swingh_t::kLeft:
+ return kPanasonicAcSwingHLeft;
+ case stdAc::swingh_t::kMiddle:
+ return kPanasonicAcSwingHMiddle;
+ case stdAc::swingh_t::kRight:
+ return kPanasonicAcSwingHRight;
+ case stdAc::swingh_t::kRightMax:
+ return kPanasonicAcSwingHFullRight;
+ default:
+ return kPanasonicAcSwingHAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRPanasonicAc::toString() {
@@ -605,84 +693,92 @@ String IRPanasonicAc::toString() {
std::string IRPanasonicAc::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Model: " + uint64ToString(getModel());
+ result += F("Model: ");
+ result += uint64ToString(getModel());
switch (getModel()) {
case kPanasonicDke:
- result += " (DKE)";
+ result += F(" (DKE)");
break;
case kPanasonicJke:
- result += " (JKE)";
+ result += F(" (JKE)");
break;
case kPanasonicNke:
- result += " (NKE)";
+ result += F(" (NKE)");
break;
case kPanasonicLke:
- result += " (LKE)";
+ result += F(" (LKE)");
break;
case kPanasonicCkp:
- result += " (CKP)";
+ result += F(" (CKP)");
+ break;
+ case kPanasonicRkr:
+ result += F(" (RKR)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Power: ";
+ result += F(", Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kPanasonicAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kPanasonicAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kPanasonicAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kPanasonicAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kPanasonicAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
case kPanasonicAcFanMin:
- result += " (MIN)";
+ result += F(" (MIN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
- result += ", Swing (Vertical): " + uint64ToString(getSwingVertical());
+ result += F(", Swing (Vertical): ");
+ result += uint64ToString(getSwingVertical());
switch (getSwingVertical()) {
case kPanasonicAcSwingVAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcSwingVUp:
- result += " (Full Up)";
+ result += F(" (Full Up)");
break;
case kPanasonicAcSwingVDown:
- result += " (Full Down)";
+ result += F(" (Full Down)");
break;
case 2:
case 3:
case 4:
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
switch (getModel()) {
@@ -690,52 +786,54 @@ std::string IRPanasonicAc::toString() {
case kPanasonicCkp:
break; // No Horizontal Swing support.
default:
- result += ", Swing (Horizontal): " + uint64ToString(getSwingHorizontal());
+ result += F(", Swing (Horizontal): ");
+ result += uint64ToString(getSwingHorizontal());
switch (getSwingHorizontal()) {
case kPanasonicAcSwingHAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kPanasonicAcSwingHFullLeft:
- result += " (Full Left)";
+ result += F(" (Full Left)");
break;
case kPanasonicAcSwingHLeft:
- result += " (Left)";
+ result += F(" (Left)");
break;
case kPanasonicAcSwingHMiddle:
- result += " (Middle)";
+ result += F(" (Middle)");
break;
case kPanasonicAcSwingHFullRight:
- result += " (Full Right)";
+ result += F(" (Full Right)");
break;
case kPanasonicAcSwingHRight:
- result += " (Right)";
+ result += F(" (Right)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
}
- result += ", Quiet: ";
+ result += F(", Quiet: ");
if (getQuiet())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Powerful: ";
+ result += F("Off");
+ result += F(", Powerful: ");
if (getPowerful())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Clock: " + timeToString(getClock());
- result += ", On Timer: ";
+ result += F("Off");
+ result += F(", Clock: ");
+ result += timeToString(getClock());
+ result += F(", On Timer: ");
if (isOnTimerEnabled())
result += timeToString(getOnTimer());
else
- result += "Off";
- result += ", Off Timer: ";
+ result += F("Off");
+ result += F(", Off Timer: ");
if (isOffTimerEnabled())
result += timeToString(getOffTimer());
else
- result += "Off";
+ result += F("Off");
return result;
}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.h b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.h
similarity index 91%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.h
index 762631fe79ea..1a7b4e11449f 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Panasonic.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Panasonic.h
@@ -12,6 +12,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// PPPP AAA N N AAA SSSS OOO N N IIIII CCCC
// P P A A NN N A A S O O NN N I C
@@ -43,7 +46,7 @@ const uint8_t kPanasonicAcMaxTemp = 30; // Celsius
const uint8_t kPanasonicAcFanModeTemp = 27; // Celsius
const uint8_t kPanasonicAcQuiet = 1; // 0b1
const uint8_t kPanasonicAcPowerful = 0x20; // 0b100000
-// CKP models have Powerful and Quiet bits swapped.
+// CKP & RKR models have Powerful and Quiet bits swapped.
const uint8_t kPanasonicAcQuietCkp = 0x20; // 0b100000
const uint8_t kPanasonicAcPowerfulCkp = 1; // 0b1
const uint8_t kPanasonicAcSwingVAuto = 0xF;
@@ -73,6 +76,7 @@ enum panasonic_ac_remote_model_t {
kPanasonicDke = 3,
kPanasonicJke = 4,
kPanasonicCkp = 5,
+ kPanasonicRkr = 6,
};
class IRPanasonicAc {
@@ -81,7 +85,7 @@ class IRPanasonicAc {
void stateReset();
#if SEND_PANASONIC
- void send();
+ void send(const uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif // SEND_PANASONIC
void begin();
void on();
@@ -122,6 +126,10 @@ class IRPanasonicAc {
const bool enable = true);
void cancelOffTimer();
bool isOffTimerEnabled();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+ uint8_t convertSwingV(const stdAc::swingv_t position);
+ uint8_t convertSwingH(const stdAc::swingh_t position);
#ifdef ARDUINO
String toString();
static String timeToString(const uint16_t mins_since_midnight);
@@ -132,6 +140,9 @@ class IRPanasonicAc {
#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
#endif
uint8_t remote_state[kPanasonicAcStateLength];
uint8_t _swingh;
@@ -139,7 +150,6 @@ class IRPanasonicAc {
void fixChecksum(const uint16_t length = kPanasonicAcStateLength);
static uint8_t calcChecksum(const uint8_t *state,
const uint16_t length = kPanasonicAcStateLength);
- IRsend _irsend;
};
#endif // IR_PANASONIC_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Pioneer.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Pioneer.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Pioneer.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Pronto.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Pronto.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Pronto.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Pronto.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_RC5_RC6.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_RC5_RC6.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_RC5_RC6.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_RCMM.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_RCMM.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_RCMM.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_RCMM.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.cpp
similarity index 66%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Samsung.cpp
index d943f8cf976e..7e54d17df60d 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.cpp
@@ -1,5 +1,5 @@
// Copyright 2009 Ken Shirriff
-// Copyright 2017 David Conran
+// Copyright 2017, 2018, 2019 David Conran
#include "ir_Samsung.h"
#include
@@ -168,6 +168,127 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits,
}
#endif
+#if SEND_SAMSUNG36
+// Send a Samsung 36-bit formatted message.
+//
+// Args:
+// data: The message to be sent.
+// nbits: The bit size of the message being sent. typically kSamsung36Bits.
+// repeat: The number of times the message is to be repeated.
+//
+// Status: Alpha / Experimental.
+//
+// Note:
+// Protocol is used by Samsung Bluray Remote: ak59-00167a
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/621
+void IRsend::sendSamsung36(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ if (nbits < 16) return; // To small to send.
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Block #1 (16 bits)
+ sendGeneric(kSamsungHdrMark, kSamsungHdrSpace,
+ kSamsungBitMark, kSamsungOneSpace,
+ kSamsungBitMark, kSamsungZeroSpace,
+ kSamsungBitMark, kSamsungHdrSpace,
+ data >> (nbits - 16), 16, 38, true, 0, kDutyDefault);
+ // Block #2 (The rest, typically 20 bits)
+ sendGeneric(0, 0, // No header
+ kSamsungBitMark, kSamsungOneSpace,
+ kSamsungBitMark, kSamsungZeroSpace,
+ kSamsungBitMark, kSamsungMinGap, // Gap is just a guess.
+ // Mask off the rest of the bits.
+ data & ((1ULL << (nbits - 16)) - 1),
+ nbits - 16, 38, true, 0, kDutyDefault);
+ }
+}
+#endif // SEND_SAMSUNG36
+
+#if DECODE_SAMSUNG36
+// Decode the supplied Samsung36 message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: Nr. of bits to expect in the data portion.
+// Typically kSamsung36Bits.
+// 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: Alpha / Experimental
+//
+// Note:
+// Protocol is used by Samsung Bluray Remote: ak59-00167a
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/621
+bool IRrecv::decodeSamsung36(decode_results *results, const uint16_t nbits,
+ const bool strict) {
+ if (results->rawlen < 2 * nbits + kHeader + kFooter * 2 - 1)
+ return false; // Can't possibly be a valid Samsung message.
+ // We need to be looking for > 16 bits to make sense.
+ if (nbits <= 16) return false;
+ if (strict && nbits != kSamsung36Bits)
+ return false; // We expect nbits to be 36 bits of message.
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset], kSamsungHdrMark)) return false;
+ // Calculate how long the common tick time is based on the header mark.
+ uint32_t m_tick = results->rawbuf[offset++] * kRawTick / kSamsungHdrMarkTicks;
+ if (!matchSpace(results->rawbuf[offset], kSamsungHdrSpace)) return false;
+ // Calculate how long the common tick time is based on the header space.
+ uint32_t s_tick =
+ results->rawbuf[offset++] * kRawTick / kSamsungHdrSpaceTicks;
+ // Data (Block #1)
+ match_result_t data_result =
+ matchData(&(results->rawbuf[offset]), 16,
+ kSamsungBitMarkTicks * m_tick, kSamsungOneSpaceTicks * s_tick,
+ kSamsungBitMarkTicks * m_tick, kSamsungZeroSpaceTicks * s_tick);
+ if (data_result.success == false) return false;
+ data = data_result.data;
+ offset += data_result.used;
+ uint16_t bitsSoFar = data_result.used / 2;
+ // Footer (Block #1)
+ if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick))
+ return false;
+ if (!matchSpace(results->rawbuf[offset++], kSamsungHdrSpaceTicks * s_tick))
+ return false;
+ // Data (Block #2)
+ data_result = matchData(&(results->rawbuf[offset]),
+ nbits - 16,
+ kSamsungBitMarkTicks * m_tick,
+ kSamsungOneSpaceTicks * s_tick,
+ kSamsungBitMarkTicks * m_tick,
+ kSamsungZeroSpaceTicks * s_tick);
+ if (data_result.success == false) return false;
+ data <<= (nbits - 16);
+ data += data_result.data;
+ offset += data_result.used;
+ bitsSoFar += data_result.used / 2;
+ // Footer (Block #2)
+ if (!matchMark(results->rawbuf[offset++], kSamsungBitMarkTicks * m_tick))
+ return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kSamsungMinGapTicks * s_tick))
+ return false;
+
+ // Compliance
+ if (nbits != bitsSoFar) return false;
+
+ // Success
+ results->bits = bitsSoFar;
+ results->value = data;
+ results->decode_type = SAMSUNG36;
+ results->command = data & ((1ULL << (nbits - 16)) - 1);
+ results->address = data >> (nbits - 16);
+ return true;
+}
+#endif // DECODE_SAMSUNG36
+
#if SEND_SAMSUNG_AC
// Send a Samsung A/C message.
//
@@ -180,7 +301,8 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits,
//
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/505
-void IRsend::sendSamsungAC(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
+void IRsend::sendSamsungAC(const uint8_t data[], const uint16_t nbytes,
+ const uint16_t repeat) {
if (nbytes < kSamsungAcStateLength && nbytes % kSamsungACSectionLength)
return; // Not an appropriate number of bytes to send a proper message.
@@ -226,53 +348,85 @@ void IRSamsungAc::begin() { _irsend.begin(); }
uint8_t IRSamsungAc::calcChecksum(const uint8_t state[],
const uint16_t length) {
uint8_t sum = 0;
- uint8_t currentbyte;
// Safety check so we don't go outside the array.
- if (length <= 5) return 255;
+ if (length < 7) return 255;
// Shamelessly inspired by:
// https://github.com/adafruit/Raw-IR-decoder-for-Arduino/pull/3/files
// Count most of the '1' bits after the checksum location.
- for (uint8_t i = length - 5; i < length - 1; i++) {
- currentbyte = state[i];
- if (i == length - 5) currentbyte = state[length - 5] & 0b11111110;
- for (; currentbyte; currentbyte >>= 1)
- if (currentbyte & 1) sum++;
- }
+ sum += countBits(state[length - 7], 8);
+ sum -= countBits(state[length - 6] & 0xF, 8);
+ sum += countBits(state[length - 5] & 0b11111110, 8);
+ sum += countBits(state + length - 4, 3);
return (28 - sum) & 0xF;
}
bool IRSamsungAc::validChecksum(const uint8_t state[], const uint16_t length) {
- if (length <= 5) return true; // No checksum to compare with. Assume okay.
- return (state[length - 6] >> 4) == calcChecksum(state, length);
+ if (length < kSamsungAcStateLength)
+ return true; // No checksum to compare with. Assume okay.
+ uint8_t offset = 0;
+ if (length >= kSamsungAcExtendedStateLength) offset = 7;
+ return ((state[length - 6] >> 4) == calcChecksum(state, length) &&
+ (state[length - (13 + offset)] >> 4) == calcChecksum(state, length -
+ (7 + offset)));
}
// Update the checksum for the internal state.
void IRSamsungAc::checksum(uint16_t length) {
- if (length < 9) return;
+ if (length < 13) return;
remote_state[length - 6] &= 0x0F;
remote_state[length - 6] |= (calcChecksum(remote_state, length) << 4);
+ remote_state[length - 13] &= 0x0F;
+ remote_state[length - 13] |= (calcChecksum(remote_state, length - 7) << 4);
}
#if SEND_SAMSUNG_AC
-void IRSamsungAc::send(const bool calcchecksum) {
+// Use for most function/mode/settings changes to the unit.
+// i.e. When the device is already running.
+void IRSamsungAc::send(const uint16_t repeat, const bool calcchecksum) {
if (calcchecksum) checksum();
- _irsend.sendSamsungAC(remote_state);
+ _irsend.sendSamsungAC(remote_state, kSamsungAcStateLength, repeat);
}
-#endif // SEND_SAMSUNG_AC
-#if SEND_SAMSUNG_AC
-void IRSamsungAc::sendExtended(const bool calcchecksum) {
+// Use this for when you need to power on/off the device.
+// Samsung A/C requires an extended length message when you want to
+// change the power operating mode of the A/C unit.
+void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) {
if (calcchecksum) checksum();
uint8_t extended_state[kSamsungAcExtendedStateLength] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xD2, 0x0F, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 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++)
extended_state[i] = 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.
- _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength);
+ _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat);
+}
+
+// Send the special extended "On" message as the library can't seem to reproduce
+// this message automatically.
+// See: https://github.com/markszabo/IRremoteESP8266/issues/604#issuecomment-475020036
+void IRSamsungAc::sendOn(const uint16_t repeat) {
+ const uint8_t extended_state[21] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0};
+ _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat);
+}
+
+// Send the special extended "Off" message as the library can't seem to
+// reproduce this message automatically.
+// See: https://github.com/markszabo/IRremoteESP8266/issues/604#issuecomment-475020036
+void IRSamsungAc::sendOff(const uint16_t repeat) {
+ const uint8_t extended_state[21] = {
+ 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0};
+ _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat);
}
#endif // SEND_SAMSUNG_AC
@@ -423,6 +577,39 @@ void IRSamsungAc::setQuiet(const bool state) {
}
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRSamsungAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kSamsungAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kSamsungAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kSamsungAcDry;
+ case stdAc::opmode_t::kFan:
+ return kSamsungAcFan;
+ default:
+ return kSamsungAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRSamsungAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kSamsungAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kSamsungAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ return kSamsungAcFanHigh;
+ case stdAc::fanspeed_t::kMax:
+ return kSamsungAcFanTurbo;
+ default:
+ return kSamsungAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRSamsungAc::toString() {
@@ -431,74 +618,77 @@ String IRSamsungAc::toString() {
std::string IRSamsungAc::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kSamsungAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kSamsungAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kSamsungAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kSamsungAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
case kSamsungAcFan:
- result += " (FAN)";
+ result += F(" (FAN)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kSamsungAcFanAuto:
case kSamsungAcFanAuto2:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kSamsungAcFanLow:
- result += " (LOW)";
+ result += F(" (LOW)");
break;
case kSamsungAcFanMed:
- result += " (MED)";
+ result += F(" (MED)");
break;
case kSamsungAcFanHigh:
- result += " (HIGH)";
+ result += F(" (HIGH)");
break;
case kSamsungAcFanTurbo:
- result += " (TURBO)";
+ result += F(" (TURBO)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
break;
}
- result += ", Swing: ";
+ result += F(", Swing: ");
if (getSwing())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Beep: ";
+ result += F("Off");
+ result += F(", Beep: ");
if (getBeep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Clean: ";
+ result += F("Off");
+ result += F(", Clean: ");
if (getBeep())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Quiet: ";
+ result += F("Off");
+ result += F(", Quiet: ");
if (getQuiet())
- result += "On";
+ result += F("On");
else
- result += "Off";
+ result += F("Off");
return result;
}
@@ -571,7 +761,6 @@ bool IRrecv::decodeSamsungAC(decode_results *results, uint16_t nbits,
// Is the signature correct?
DPRINTLN("DEBUG: Checking signature.");
if (results->state[0] != 0x02 || results->state[2] != 0x0F) return false;
- if (results->state[1] != 0x92 && results->state[1] != 0xB2) return false;
if (strict) {
// Is the checksum valid?
if (!IRSamsungAc::validChecksum(results->state, nbits / 8)) {
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.h b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.h
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Samsung.h
index f80b47d20baf..9df427c6ff9e 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Samsung.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Samsung.h
@@ -14,6 +14,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// SSSS AAA MMM SSSS U U N N GGGG
// S A A M M M S U U NN N G
@@ -62,8 +65,12 @@ class IRSamsungAc {
void stateReset();
#if SEND_SAMSUNG_AC
- void send(const bool calcchecksum = true);
- void sendExtended(const bool calcchecksum = true);
+ void send(const uint16_t repeat = kSamsungAcDefaultRepeat,
+ const bool calcchecksum = true);
+ void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat,
+ const bool calcchecksum = true);
+ void sendOn(const uint16_t repeat = kSamsungAcDefaultRepeat);
+ void sendOff(const uint16_t repeat = kSamsungAcDefaultRepeat);
#endif // SEND_SAMSUNG_AC
void begin();
void on();
@@ -91,17 +98,23 @@ class IRSamsungAc {
const uint16_t length = kSamsungAcStateLength);
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kSamsungAcStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
std::string toString();
#endif
+#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
// The state of the IR remote in IR code form.
uint8_t remote_state[kSamsungAcExtendedStateLength];
void checksum(const uint16_t length = kSamsungAcStateLength);
- IRsend _irsend;
};
#endif // IR_SAMSUNG_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sanyo.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sanyo.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sanyo.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sharp.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sharp.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sharp.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sharp.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sherwood.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sherwood.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sherwood.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sherwood.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Sony.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Sony.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Sony.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Sony.cpp
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.cpp
new file mode 100644
index 000000000000..79fb23cf1af2
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.cpp
@@ -0,0 +1,420 @@
+// Copyright 2019 David Conran
+
+#include "ir_Tcl.h"
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+
+// Constants
+
+
+#if SEND_TCL112AC
+void IRsend::sendTcl112Ac(const unsigned char data[], const uint16_t nbytes,
+ const uint16_t repeat) {
+ sendGeneric(kTcl112AcHdrMark, kTcl112AcHdrSpace,
+ kTcl112AcBitMark, kTcl112AcOneSpace,
+ kTcl112AcBitMark, kTcl112AcZeroSpace,
+ kTcl112AcBitMark, kTcl112AcGap,
+ data, nbytes, 38000, false, repeat, 50);
+}
+#endif // SEND_TCL112AC
+
+IRTcl112Ac::IRTcl112Ac(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRTcl112Ac::begin() { this->_irsend.begin(); }
+
+#if SEND_TCL112AC
+void IRTcl112Ac::send(const uint16_t repeat) {
+ this->checksum();
+ this->_irsend.sendTcl112Ac(remote_state, kTcl112AcStateLength, repeat);
+}
+#endif // SEND_TCL112AC
+
+// Calculate the checksum for a given array.
+// Args:
+// state: The array to calculate the checksum over.
+// length: The size of the array.
+// Returns:
+// The 8 bit checksum value.
+uint8_t IRTcl112Ac::calcChecksum(uint8_t state[],
+ const uint16_t length) {
+ if (length)
+ return sumBytes(state, length - 1);
+ else
+ return 0;
+}
+
+// Calculate & set the checksum for the current internal state of the remote.
+void IRTcl112Ac::checksum(const uint16_t length) {
+ // Stored the checksum value in the last byte.
+ if (length > 1)
+ remote_state[length - 1] = calcChecksum(remote_state, length);
+}
+
+// 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 IRTcl112Ac::validChecksum(uint8_t state[], const uint16_t length) {
+ return (length > 1 && state[length - 1] == calcChecksum(state, length));
+}
+
+void IRTcl112Ac::stateReset() {
+ for (uint8_t i = 0; i < kTcl112AcStateLength; i++)
+ remote_state[i] = 0x0;
+ // A known good state. (On, Cool, 24C)
+ remote_state[0] = 0x23;
+ remote_state[1] = 0xCB;
+ remote_state[2] = 0x26;
+ remote_state[3] = 0x01;
+ remote_state[5] = 0x24;
+ remote_state[6] = 0x03;
+ remote_state[7] = 0x07;
+ remote_state[8] = 0x40;
+ remote_state[13] = 0x03;
+}
+
+uint8_t* IRTcl112Ac::getRaw() {
+ this->checksum();
+ return remote_state;
+}
+
+void IRTcl112Ac::setRaw(const uint8_t new_code[], const uint16_t length) {
+ for (uint8_t i = 0; i < length && i < kTcl112AcStateLength; i++) {
+ remote_state[i] = new_code[i];
+ }
+}
+
+// Set the requested power state of the A/C to on.
+void IRTcl112Ac::on(void) { this->setPower(true); }
+
+// Set the requested power state of the A/C to off.
+void IRTcl112Ac::off(void) { this->setPower(false); }
+
+// Set the requested power state of the A/C.
+void IRTcl112Ac::setPower(const bool on) {
+ if (on)
+ remote_state[5] |= kTcl112AcPowerMask;
+ else
+ remote_state[5] &= ~kTcl112AcPowerMask;
+}
+
+// Return the requested power state of the A/C.
+bool IRTcl112Ac::getPower(void) {
+ return remote_state[5] & kTcl112AcPowerMask;
+}
+
+// Get the requested climate operation mode of the a/c unit.
+// Returns:
+// A uint8_t containing the A/C mode.
+uint8_t IRTcl112Ac::getMode() {
+ return remote_state[6] & 0xF;
+}
+
+// Set the requested climate operation mode of the a/c unit.
+// Note: Fan/Ventilation mode sets the fan speed to high.
+// Unknown values default to Auto.
+void IRTcl112Ac::setMode(const uint8_t mode) {
+ // If we get an unexpected mode, default to AUTO.
+ switch (mode) {
+ case kTcl112AcFan:
+ this->setFan(kTcl112AcFanHigh);
+ // FALLTHRU
+ case kTcl112AcAuto:
+ case kTcl112AcCool:
+ case kTcl112AcHeat:
+ case kTcl112AcDry:
+ remote_state[6] &= 0xF0;
+ remote_state[6] |= mode;
+ break;
+ default:
+ setMode(kTcl112AcAuto);
+ }
+}
+
+void IRTcl112Ac::setTemp(const float celsius) {
+ // Make sure we have desired temp in the correct range.
+ float safecelsius = std::max(celsius, kTcl112AcTempMin);
+ safecelsius = std::min(safecelsius, kTcl112AcTempMax);
+ // Convert to integer nr. of half degrees.
+ uint8_t nrHalfDegrees = safecelsius * 2;
+ if (nrHalfDegrees & 1) // Do we have a half degree celsius?
+ remote_state[12] |= kTcl112AcHalfDegree; // Add 0.5 degrees
+ else
+ remote_state[12] &= ~kTcl112AcHalfDegree; // Clear the half degree.
+ remote_state[7] &= 0xF0; // Clear temp bits.
+ remote_state[7] |= ((uint8_t)kTcl112AcTempMax - nrHalfDegrees / 2);
+}
+
+float IRTcl112Ac::getTemp() {
+ float result = kTcl112AcTempMax - (remote_state[7] & 0xF);
+ if (remote_state[12] & kTcl112AcHalfDegree) result += 0.5;
+ return result;
+}
+
+// Set the speed of the fan.
+// Unknown speeds will default to Auto.
+void IRTcl112Ac::setFan(const uint8_t speed) {
+ switch (speed) {
+ case kTcl112AcFanAuto:
+ case kTcl112AcFanLow:
+ case kTcl112AcFanMed:
+ case kTcl112AcFanHigh:
+ remote_state[8] &= ~kTcl112AcFanMask;
+ remote_state[8] |= speed;
+ break;
+ default:
+ this->setFan(kTcl112AcFanAuto);
+ }
+}
+
+// Return the currect fan speed.
+uint8_t IRTcl112Ac::getFan() {
+ return remote_state[8] & kTcl112AcFanMask;
+}
+
+// Control economy mode.
+void IRTcl112Ac::setEcono(const bool on) {
+ if (on)
+ remote_state[5] |= kTcl112AcBitEcono;
+ else
+ remote_state[5] &= ~kTcl112AcBitEcono;
+}
+
+// Return the economy state of the A/C.
+bool IRTcl112Ac::getEcono(void) {
+ return remote_state[5] & kTcl112AcBitEcono;
+}
+
+// Control Health mode.
+void IRTcl112Ac::setHealth(const bool on) {
+ if (on)
+ remote_state[6] |= kTcl112AcBitHealth;
+ else
+ remote_state[6] &= ~kTcl112AcBitHealth;
+}
+
+// Return the Health mode state of the A/C.
+bool IRTcl112Ac::getHealth(void) {
+ return remote_state[6] & kTcl112AcBitHealth;
+}
+
+// Control Light/Display mode.
+void IRTcl112Ac::setLight(const bool on) {
+ if (on)
+ remote_state[5] &= ~kTcl112AcBitLight;
+ else
+ remote_state[5] |= kTcl112AcBitLight;
+}
+
+// Return the Light/Display mode state of the A/C.
+bool IRTcl112Ac::getLight(void) {
+ return !(remote_state[5] & kTcl112AcBitLight);
+}
+
+// Control Horizontal Swing.
+void IRTcl112Ac::setSwingHorizontal(const bool on) {
+ if (on)
+ remote_state[12] |= kTcl112AcBitSwingH;
+ else
+ remote_state[12] &= ~kTcl112AcBitSwingH;
+}
+
+// Return the Horizontal Swing state of the A/C.
+bool IRTcl112Ac::getSwingHorizontal(void) {
+ return remote_state[12] & kTcl112AcBitSwingH;
+}
+
+// Control Vertical Swing.
+void IRTcl112Ac::setSwingVertical(const bool on) {
+ if (on)
+ remote_state[8] |= kTcl112AcBitSwingV;
+ else
+ remote_state[8] &= ~kTcl112AcBitSwingV;
+}
+
+// Return the Vertical Swing state of the A/C.
+bool IRTcl112Ac::getSwingVertical(void) {
+ return remote_state[8] & kTcl112AcBitSwingV;
+}
+
+// Control the Turbo setting.
+void IRTcl112Ac::setTurbo(const bool on) {
+ if (on) {
+ remote_state[6] |= kTcl112AcBitTurbo;
+ this->setFan(kTcl112AcFanHigh);
+ this->setSwingVertical(true);
+ } else {
+ remote_state[6] &= ~kTcl112AcBitTurbo;
+ }
+}
+
+// Return the Turbo setting state of the A/C.
+bool IRTcl112Ac::getTurbo(void) {
+ return remote_state[6] & kTcl112AcBitTurbo;
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRTcl112Ac::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kTcl112AcCool;
+ case stdAc::opmode_t::kHeat:
+ return kTcl112AcHeat;
+ case stdAc::opmode_t::kDry:
+ return kTcl112AcDry;
+ case stdAc::opmode_t::kFan:
+ return kTcl112AcFan;
+ default:
+ return kTcl112AcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRTcl112Ac::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kTcl112AcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kTcl112AcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kTcl112AcFanHigh;
+ default:
+ return kTcl112AcFanAuto;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRTcl112Ac::toString() {
+ String result = "";
+#else
+std::string IRTcl112Ac::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (this->getMode()) {
+ case kTcl112AcAuto:
+ result += F(" (AUTO)");
+ break;
+ case kTcl112AcCool:
+ result += F(" (COOL)");
+ break;
+ case kTcl112AcHeat:
+ result += F(" (HEAT)");
+ break;
+ case kTcl112AcDry:
+ result += F(" (DRY)");
+ break;
+ case kTcl112AcFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ uint16_t nrHalfDegrees = this->getTemp() * 2;
+ result += F(", Temp: ");
+ result += uint64ToString(nrHalfDegrees / 2);
+ if (nrHalfDegrees & 1) result += F(".5");
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kTcl112AcFanAuto:
+ result += F(" (Auto)");
+ break;
+ case kTcl112AcFanLow:
+ result += F(" (Low)");
+ break;
+ case kTcl112AcFanMed:
+ result += F(" (Med)");
+ break;
+ case kTcl112AcFanHigh:
+ result += F(" (High)");
+ break;
+ }
+ result += F(", Econo: ");
+ result += (this->getEcono() ? F("On") : F("Off"));
+ result += ", Health: ";
+ result += (this->getHealth() ? F("On") : F("Off"));
+ result += F(", Light: ");
+ result += (this->getLight() ? F("On") : F("Off"));
+ result += F(", Turbo: ");
+ result += (this->getTurbo() ? F("On") : F("Off"));
+ result += ", Swing (H): ";
+ result += (this->getSwingHorizontal() ? F("On") : F("Off"));
+ result += F(", Swing (V): ");
+ result += (this->getSwingVertical() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_TCL112AC
+// Decode the supplied TCL112AC message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: The number of data bits to expect. Typically kTcl112AcBits.
+// 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 mostly work.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/619
+bool IRrecv::decodeTcl112Ac(decode_results *results, uint16_t nbits,
+ bool strict) {
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1)
+ return false; // Can't possibly be a valid Samsung A/C message.
+ if (strict && nbits != kTcl112AcBits) return false;
+
+ uint16_t offset = kStartOffset;
+ uint16_t dataBitsSoFar = 0;
+ match_result_t data_result;
+
+ // Message Header
+ if (!matchMark(results->rawbuf[offset++], kTcl112AcHdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kTcl112AcHdrSpace)) return false;
+
+ // Data
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint16_t i = 0; offset <= results->rawlen - 16 && i < nbits / 8;
+ i++, dataBitsSoFar += 8, offset += data_result.used) {
+ data_result = matchData(&(results->rawbuf[offset]), 8, kTcl112AcBitMark,
+ kTcl112AcOneSpace, kTcl112AcBitMark,
+ kTcl112AcZeroSpace, kTolerance, 0, false);
+ if (data_result.success == false) {
+ DPRINT("DEBUG: offset = ");
+ DPRINTLN(offset + data_result.used);
+ return false; // Fail
+ }
+ results->state[i] = data_result.data;
+ }
+
+ // Footer
+ if (!matchMark(results->rawbuf[offset++], kTcl112AcBitMark)) return false;
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kTcl112AcGap)) return false;
+ // Compliance
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != nbits) return false;
+ // Verify we got a valid checksum.
+ if (strict && !IRTcl112Ac::validChecksum(results->state)) return false;
+ // Success
+ results->decode_type = TCL112AC;
+ results->bits = dataBitsSoFar;
+ // No need to record the state as we stored it as we decoded it.
+ // As we use result->state, we don't record value, address, or command as it
+ // is a union data type.
+ return true;
+}
+#endif // DECODE_TCL112AC
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.h b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.h
new file mode 100644
index 000000000000..a1595451d1d2
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Tcl.h
@@ -0,0 +1,105 @@
+// Copyright 2019 David Conran
+
+#ifndef IR_TCL_H_
+#define IR_TCL_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Constants
+const uint16_t kTcl112AcHdrMark = 3000;
+const uint16_t kTcl112AcHdrSpace = 1650;
+const uint16_t kTcl112AcBitMark = 500;
+const uint16_t kTcl112AcOneSpace = 1050;
+const uint16_t kTcl112AcZeroSpace = 325;
+const uint32_t kTcl112AcGap = kDefaultMessageGap; // Just a guess.
+
+const uint8_t kTcl112AcHeat = 1;
+const uint8_t kTcl112AcDry = 2;
+const uint8_t kTcl112AcCool = 3;
+const uint8_t kTcl112AcFan = 7;
+const uint8_t kTcl112AcAuto = 8;
+const uint8_t kTcl112AcFanMask = 0b00000111;
+const uint8_t kTcl112AcFanAuto = 0b00000000;
+const uint8_t kTcl112AcFanLow = 0b00000010;
+const uint8_t kTcl112AcFanMed = 0b00000011;
+const uint8_t kTcl112AcFanHigh = 0b00000101;
+
+const uint8_t kTcl112AcHalfDegree = 0b00100000;
+const float kTcl112AcTempMax = 31.0;
+const float kTcl112AcTempMin = 16.0;
+
+const uint8_t kTcl112AcPowerMask = 0b00000100;
+const uint8_t kTcl112AcBitEcono = 0b10000000;
+const uint8_t kTcl112AcBitLight = 0b01000000;
+const uint8_t kTcl112AcBitHealth = 0b00010000;
+const uint8_t kTcl112AcBitSwingH = 0b00001000;
+const uint8_t kTcl112AcBitSwingV = 0b00111000;
+const uint8_t kTcl112AcBitTurbo = 0b01000000;
+
+
+class IRTcl112Ac {
+ public:
+ explicit IRTcl112Ac(uint16_t pin);
+
+#if SEND_TCL112AC
+ void send(const uint16_t repeat = kTcl112AcDefaultRepeat);
+#endif // SEND_TCL
+ void begin(void);
+ uint8_t* getRaw(void);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kTcl112AcStateLength);
+ void on(void);
+ void off(void);
+ void setPower(const bool on);
+ bool getPower(void);
+ void setTemp(const float celsius); // Celsius in 0.5 increments
+ float getTemp(void);
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+ static uint8_t calcChecksum(uint8_t state[],
+ const uint16_t length = kTcl112AcStateLength);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kTcl112AcStateLength);
+ void setFan(const uint8_t speed);
+ uint8_t getFan(void);
+ void setEcono(const bool on);
+ bool getEcono(void);
+ void setHealth(const bool on);
+ bool getHealth(void);
+ void setLight(const bool on);
+ bool getLight(void);
+ void setSwingHorizontal(const bool on);
+ bool getSwingHorizontal(void);
+ void setSwingVertical(const bool on);
+ bool getSwingVertical(void);
+ void setTurbo(const bool on);
+ bool getTurbo(void);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString();
+#else
+ std::string toString();
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint8_t remote_state[kTcl112AcStateLength];
+ void stateReset();
+ void checksum(const uint16_t length = kTcl112AcStateLength);
+};
+
+#endif // IR_TCL_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Teco.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.cpp
new file mode 100644
index 000000000000..779bf8f8ff79
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.cpp
@@ -0,0 +1,278 @@
+// Copyright 2019 Fabien Valthier
+/*
+Node MCU/ESP8266 Sketch to emulate Teco
+*/
+
+#include "ir_Teco.h"
+#include
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+#ifndef ARDUINO
+#include
+#endif
+
+// Constants
+// using SPACE modulation.
+const uint16_t kTecoHdrMark = 9000;
+const uint16_t kTecoHdrSpace = 4440;
+const uint16_t kTecoBitMark = 620;
+const uint16_t kTecoOneSpace = 1650;
+const uint16_t kTecoZeroSpace = 580;
+const uint32_t kTecoGap = kDefaultMessageGap; // Made-up value. Just a guess.
+
+#if SEND_TECO
+// Send a Teco A/C message.
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kTecoBits.
+// repeat: Nr. of additional times the message is to be sent.
+void IRsend::sendTeco(uint64_t data, uint16_t nbits, uint16_t repeat) {
+ sendGeneric(kTecoHdrMark, kTecoHdrSpace, kTecoBitMark, kTecoOneSpace,
+ kTecoBitMark, kTecoZeroSpace, kTecoBitMark, kTecoGap,
+ data, nbits, 38000, false, repeat, kDutyDefault);
+}
+#endif // SEND_TECO
+
+// Class for decoding and constructing Teco AC messages.
+IRTecoAc::IRTecoAc(const uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRTecoAc::begin() { _irsend.begin(); }
+
+#if SEND_TECO
+void IRTecoAc::send(const uint16_t repeat) {
+ _irsend.sendTeco(remote_state, kTecoBits, repeat);
+}
+#endif // SEND_TECO
+
+void IRTecoAc::stateReset(void) {
+ // Mode:auto, Power:Off, fan:auto, temp:16, swing:off, sleep:off
+ remote_state = kTecoReset;
+}
+
+uint64_t IRTecoAc::getRaw(void) { return remote_state; }
+
+void IRTecoAc::setRaw(const uint64_t new_code) { remote_state = new_code; }
+
+void IRTecoAc::on(void) { remote_state |= kTecoPower; }
+
+void IRTecoAc::off(void) { remote_state &= ~kTecoPower; }
+
+void IRTecoAc::setPower(const bool on) {
+ if (on)
+ this->on();
+ else
+ this->off();
+}
+
+bool IRTecoAc::getPower(void) {
+ return (remote_state & kTecoPower) == kTecoPower; }
+
+void IRTecoAc::setTemp(const uint8_t temp) {
+ uint8_t newtemp = temp;
+ newtemp = std::min(newtemp, kTecoMaxTemp);
+ newtemp = std::max(newtemp, kTecoMinTemp);
+ newtemp -= kTecoMinTemp; // 16=0b000
+
+ remote_state &= ~kTecoTempMask; // reinit temp
+ remote_state |= (newtemp << 8);
+}
+
+uint8_t IRTecoAc::getTemp(void) {
+ return ((remote_state & kTecoTempMask) >> 8) + kTecoMinTemp;
+}
+
+// Set the speed of the fan
+void IRTecoAc::setFan(const uint8_t speed) {
+ uint8_t newspeed = speed;
+ switch (speed) {
+ case kTecoFanAuto:
+ case kTecoFanHigh:
+ case kTecoFanMed:
+ case kTecoFanLow:
+ break;
+ default:
+ newspeed = kTecoFanAuto;
+ }
+ remote_state &= ~kTecoFanMask; // reinit fan
+ remote_state |= (newspeed << 4);
+}
+
+uint8_t IRTecoAc::getFan(void) { return (remote_state & kTecoFanMask) >> 4; }
+
+void IRTecoAc::setMode(const uint8_t mode) {
+ uint8_t newmode = mode;
+ switch (mode) {
+ case kTecoAuto:
+ case kTecoCool:
+ case kTecoDry:
+ case kTecoFan:
+ case kTecoHeat:
+ break;
+ default:
+ newmode = kTecoAuto;
+ }
+ remote_state &= ~kTecoModeMask; // reinit mode
+ remote_state |= newmode;
+}
+
+uint8_t IRTecoAc::getMode(void) { return remote_state & kTecoModeMask; }
+
+void IRTecoAc::setSwing(const bool on) {
+ if (on)
+ remote_state |= kTecoSwing;
+ else
+ remote_state &= ~kTecoSwing;
+}
+
+bool IRTecoAc::getSwing(void) { return remote_state & kTecoSwing; }
+
+void IRTecoAc::setSleep(const bool on) {
+ if (on)
+ remote_state |= kTecoSleep;
+ else
+ remote_state &= ~kTecoSleep;
+}
+
+bool IRTecoAc::getSleep(void) { return remote_state & kTecoSleep; }
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRTecoAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kTecoCool;
+ case stdAc::opmode_t::kHeat:
+ return kTecoHeat;
+ case stdAc::opmode_t::kDry:
+ return kTecoDry;
+ case stdAc::opmode_t::kFan:
+ return kTecoFan;
+ default:
+ return kTecoAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRTecoAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kTecoFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kTecoFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kTecoFanHigh;
+ default:
+ return kTecoFanAuto;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRTecoAc::toString(void) {
+ String result = "";
+#else
+std::string IRTecoAc::toString(void) {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Power: ");
+ result += (this->getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(this->getMode());
+ switch (this->getMode()) {
+ case kTecoAuto:
+ result += F(" (AUTO)");
+ break;
+ case kTecoCool:
+ result += F(" (COOL)");
+ break;
+ case kTecoHeat:
+ result += F(" (HEAT)");
+ break;
+ case kTecoDry:
+ result += F(" (DRY)");
+ break;
+ case kTecoFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (this->getFan()) {
+ case kTecoFanAuto:
+ result += F(" (Auto)");
+ break;
+ case kTecoFanHigh:
+ result += F(" (High)");
+ break;
+ case kTecoFanLow:
+ result += F(" (Low)");
+ break;
+ case kTecoFanMed:
+ result += F(" (Med)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Sleep: ");
+ result += (this->getSleep() ? F("On") : F("Off"));
+ result += F(", Swing: ");
+ result += (this->getSwing() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_TECO
+// Decode the supplied Teco message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: The number of data bits to expect. Typically kTecoBits.
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: STABLE / Tested.
+bool IRrecv::decodeTeco(decode_results* results, uint16_t nbits, bool strict) {
+ // Check if can possibly be a valid Teco message.
+ if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) return false;
+ if (strict && nbits != kTecoBits) return false; // Not what is expected
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+ match_result_t data_result;
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kTecoHdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kTecoHdrSpace)) return false;
+ // Data (35 bits)
+ data_result =
+ matchData(&(results->rawbuf[offset]), 35, kTecoBitMark, kTecoOneSpace,
+ kTecoBitMark, kTecoZeroSpace, kTolerance, kMarkExcess, false);
+ if (data_result.success == false) return false;
+ data = data_result.data;
+ offset += data_result.used;
+ uint16_t actualBits = data_result.used / 2;
+
+ // Footer.
+ if (!matchMark(results->rawbuf[offset++], kTecoBitMark)) return false;
+ if (offset < results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset], kTecoGap)) return false;
+
+ // Compliance
+ if (actualBits < nbits) return false;
+ if (strict && actualBits != nbits) return false; // Not as we expected.
+
+ // Success
+ results->decode_type = TECO;
+ results->bits = actualBits;
+ results->value = data;
+ results->address = 0;
+ results->command = 0;
+ return true;
+}
+#endif // DECODE_TECO
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Teco.h b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.h
new file mode 100644
index 000000000000..65a0050ae251
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Teco.h
@@ -0,0 +1,144 @@
+// Copyright 2019 Fabien Valthier
+
+#ifndef IR_TECO_H_
+#define IR_TECO_H_
+
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// Constants. Using LSB to be able to send only 35bits.
+const uint8_t kTecoAuto = 0; // 0b000
+const uint8_t kTecoCool = 1; // 0b001
+const uint8_t kTecoDry = 2; // 0b010
+const uint8_t kTecoFan = 3; // 0b110
+const uint8_t kTecoHeat = 4; // 0b001
+const uint8_t kTecoFanAuto = 0; // 0b00
+const uint8_t kTecoFanHigh = 3; // 0b11
+const uint8_t kTecoFanMed = 2; // 0b10
+const uint8_t kTecoFanLow = 1; // 0b01
+const uint8_t kTecoMinTemp = 16; // 16C
+const uint8_t kTecoMaxTemp = 30; // 30C
+
+const uint64_t kTecoModeMask = 0b00000000000000000000000000000000111;
+const uint64_t kTecoPower = 0b00000000000000000000000000000001000;
+const uint64_t kTecoFanMask = 0b00000000000000000000000000000110000;
+const uint64_t kTecoSwing = 0b00000000000000000000000000001000000;
+const uint64_t kTecoSleep = 0b00000000000000000000000000010000000;
+const uint64_t kTecoTempMask = 0b00000000000000000000000111100000000;
+const uint64_t kTecoTimerHalfH = 0b00000000000000000000001000000000000;
+const uint64_t kTecoTimerTenHr = 0b00000000000000000000110000000000000;
+const uint64_t kTecoTimerOn = 0b00000000000000000001000000000000000;
+const uint64_t kTecoTimerUniHr = 0b00000000000000011110000000000000000;
+const uint64_t kTecoReset = 0b01001010000000000000010000000000000;
+/*
+ (header mark and space)
+ Teco AC map read and to be sent in LSB with number of bits
+
+ byte 0 = Cst 0x02
+ byte 1 = Cst 0x50
+ byte 2:
+ b0-3 = 0b0000
+ b4-7 = Timer hours (unit, not thenth)
+ hours:
+ 0000 (0) = +0 hour
+ 0001 (1) = +1 hour
+ ...
+ 1001 (9) = +9 hours
+ byte 3: = timer and Temperature
+ b0 = Timer (1 = On, 0 = Off)
+ b1-2 = Timer - number of 10hours
+ 10Hours:
+ 00 = 0 * 10hours of timer
+ 01 = 1 * 10 hours of timer
+ 10 = 2 * 10hours of timer
+ b3 = Timer - half hour (1=half hour on, 0 = round hour)
+ b4-7: Degrees C.
+ 0000 (0) = 16C
+ 0001 (1) = 17C
+ 0010 (2) = 18C
+ ...
+ 1101 (13) = 29C
+ 1110 (14) = 30C
+ byte 4: Basics
+ b0 = Sleep Mode (1 = On, 0 = Off)
+ b1 = Vent swing (1 = On, 0 = Off)
+ b2-3 = Fan
+ Fan:
+ 00 = Auto
+ 01 = Fan 1
+ 10 = Fan 2
+ 11 = Fan 3 or higher
+ b4 = Power Status (1 = On, 0 = Off)
+ b5-7 = Modes LSB first
+ Modes:
+ 000 = Auto (temp = 25C)
+ 001 = Cool
+ 010 = Dry (temp = 25C, but not shown)
+ 011 = Fan
+ 100 = Heat
+*/
+
+// Classes
+class IRTecoAc {
+ public:
+ explicit IRTecoAc(const uint16_t pin);
+
+ void stateReset(void);
+#if SEND_TECO
+ void send(const uint16_t repeat = kTecoDefaultRepeat);
+#endif // SEND_TECO
+ 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 fan);
+ uint8_t getFan(void);
+
+ void setMode(const uint8_t mode);
+ uint8_t getMode(void);
+
+ void setSwing(const bool state);
+ bool getSwing(void);
+
+ void setSleep(const bool state);
+ bool getSleep(void);
+
+ // void setTimer(uint8_t time); // To check unit
+ // uint8_t getTimer(uint8_t);
+
+ uint64_t getRaw(void);
+ void setRaw(const uint64_t new_code);
+
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString(void);
+#else
+ std::string toString(void);
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint64_t remote_state;
+};
+
+#endif // IR_TECO_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.cpp
similarity index 86%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.cpp
index 817b5fbaa598..a82a2fb24d93 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.cpp
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.cpp
@@ -89,9 +89,9 @@ void IRToshibaAC::begin() { _irsend.begin(); }
#if SEND_TOSHIBA_AC
// Send the current desired state to the IR LED.
-void IRToshibaAC::send() {
+void IRToshibaAC::send(const uint16_t repeat) {
checksum(); // Ensure correct checksum before sending.
- _irsend.sendToshibaAC(remote_state);
+ _irsend.sendToshibaAC(remote_state, kToshibaACStateLength, repeat);
}
#endif // SEND_TOSHIBA_AC
@@ -233,6 +233,39 @@ void IRToshibaAC::setMode(uint8_t mode) {
}
}
+// Convert a standard A/C mode into its native mode.
+uint8_t IRToshibaAC::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kToshibaAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kToshibaAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kToshibaAcDry;
+ // No Fan mode.
+ default:
+ return kToshibaAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRToshibaAC::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ return kToshibaAcFanMax - 4;
+ case stdAc::fanspeed_t::kLow:
+ return kToshibaAcFanMax - 3;
+ case stdAc::fanspeed_t::kMedium:
+ return kToshibaAcFanMax - 2;
+ case stdAc::fanspeed_t::kHigh:
+ return kToshibaAcFanMax - 1;
+ case stdAc::fanspeed_t::kMax:
+ return kToshibaAcFanMax;
+ default:
+ return kToshibaAcFanAuto;
+ }
+}
+
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRToshibaAC::toString() {
@@ -241,36 +274,39 @@ String IRToshibaAC::toString() {
std::string IRToshibaAC::toString() {
std::string result = "";
#endif // ARDUINO
- result += "Power: ";
+ result += F("Power: ");
if (getPower())
- result += "On";
+ result += F("On");
else
- result += "Off";
- result += ", Mode: " + uint64ToString(getMode());
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
switch (getMode()) {
case kToshibaAcAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kToshibaAcCool:
- result += " (COOL)";
+ result += F(" (COOL)");
break;
case kToshibaAcHeat:
- result += " (HEAT)";
+ result += F(" (HEAT)");
break;
case kToshibaAcDry:
- result += " (DRY)";
+ result += F(" (DRY)");
break;
default:
- result += " (UNKNOWN)";
+ result += F(" (UNKNOWN)");
}
- result += ", Temp: " + uint64ToString(getTemp()) + "C";
- result += ", Fan: " + uint64ToString(getFan());
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
switch (getFan()) {
case kToshibaAcFanAuto:
- result += " (AUTO)";
+ result += F(" (AUTO)");
break;
case kToshibaAcFanMax:
- result += " (MAX)";
+ result += F(" (MAX)");
break;
}
return result;
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.h
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.h
index 1a1e6cdc81a1..03b461add8ec 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Toshiba.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Toshiba.h
@@ -11,6 +11,9 @@
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// TTTTTTT OOOOO SSSSS HH HH IIIII BBBBB AAA
// TTT OO OO SS HH HH III BB B AAAAA
@@ -48,7 +51,7 @@ class IRToshibaAC {
void stateReset();
#if SEND_TOSHIBA_AC
- void send();
+ void send(const uint16_t repeat = kToshibaACMinRepeat);
#endif // SEND_TOSHIBA_AC
void begin();
void on();
@@ -65,6 +68,8 @@ class IRToshibaAC {
uint8_t* getRaw();
static bool validChecksum(const uint8_t state[],
const uint16_t length = kToshibaACStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
#ifdef ARDUINO
String toString();
#else
@@ -73,13 +78,15 @@ class IRToshibaAC {
#ifndef UNIT_TEST
private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
#endif
uint8_t remote_state[kToshibaACStateLength];
void checksum(const uint16_t length = kToshibaACStateLength);
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kToshibaACStateLength);
uint8_t mode_state;
- IRsend _irsend;
};
#endif // IR_TOSHIBA_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.cpp
new file mode 100644
index 000000000000..b5c15e7fdbd1
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.cpp
@@ -0,0 +1,162 @@
+// Copyright 2017 stufisher
+
+#include "ir_Trotec.h"
+#include
+#include "IRremoteESP8266.h"
+#include "IRutils.h"
+
+// Constants
+const uint16_t kTrotecHdrMark = 5952;
+const uint16_t kTrotecHdrSpace = 7364;
+const uint16_t kTrotecOneMark = 592;
+const uint16_t kTrotecOneSpace = 1560;
+const uint16_t kTrotecZeroMark = 592;
+const uint16_t kTrotecZeroSpace = 592;
+const uint16_t kTrotecGap = 6184;
+const uint16_t kTrotecGapEnd = 1500; // made up value
+
+#if SEND_TROTEC
+
+void IRsend::sendTrotec(unsigned char data[], uint16_t nbytes,
+ uint16_t repeat) {
+ if (nbytes < kTrotecStateLength) return;
+
+ for (uint16_t r = 0; r <= repeat; r++) {
+ sendGeneric(kTrotecHdrMark, kTrotecHdrSpace, kTrotecOneMark,
+ kTrotecOneSpace, kTrotecZeroMark, kTrotecZeroSpace,
+ kTrotecOneMark, kTrotecGap, data, nbytes, 36, false,
+ 0, // Repeats handled elsewhere
+ 50);
+ // More footer
+ enableIROut(36);
+ mark(kTrotecOneMark);
+ space(kTrotecGapEnd);
+ }
+}
+#endif // SEND_TROTEC
+
+IRTrotecESP::IRTrotecESP(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRTrotecESP::begin() { _irsend.begin(); }
+
+#if SEND_TROTEC
+void IRTrotecESP::send(const uint16_t repeat) {
+ checksum();
+ _irsend.sendTrotec(remote_state, kTrotecStateLength, repeat);
+}
+#endif // SEND_TROTEC
+
+void IRTrotecESP::checksum() {
+ uint8_t sum = 0;
+
+ for (uint8_t i = 2; i < 8; i++) sum += remote_state[i];
+ remote_state[8] = sum & 0xFF;
+}
+
+void IRTrotecESP::stateReset() {
+ for (uint8_t i = 2; i < kTrotecStateLength; i++) remote_state[i] = 0x0;
+
+ remote_state[0] = kTrotecIntro1;
+ remote_state[1] = kTrotecIntro2;
+
+ setPower(false);
+ setTemp(kTrotecDefTemp);
+ setSpeed(kTrotecFanMed);
+ setMode(kTrotecAuto);
+}
+
+uint8_t* IRTrotecESP::getRaw() {
+ checksum();
+ return remote_state;
+}
+
+void IRTrotecESP::setPower(const bool on) {
+ if (on)
+ remote_state[2] |= kTrotecPowerBit;
+ else
+ remote_state[2] &= ~kTrotecPowerBit;
+}
+
+bool IRTrotecESP::getPower() { return remote_state[2] & kTrotecPowerBit; }
+
+void IRTrotecESP::setSpeed(const uint8_t fan) {
+ uint8_t speed = std::min(fan, kTrotecFanHigh);
+ remote_state[2] = (remote_state[2] & 0b11001111) | (speed << 4);
+}
+
+uint8_t IRTrotecESP::getSpeed() { return (remote_state[2] & 0b00110000) >> 4; }
+
+void IRTrotecESP::setMode(const uint8_t mode) {
+ switch (mode) {
+ case kTrotecAuto:
+ case kTrotecCool:
+ case kTrotecDry:
+ case kTrotecFan:
+ remote_state[2] = (remote_state[2] & 0b11111100) | mode;
+ return;
+ default:
+ this->setMode(kTrotecAuto);
+ }
+}
+
+uint8_t IRTrotecESP::getMode() { return remote_state[2] & 0b00000011; }
+
+void IRTrotecESP::setTemp(const uint8_t celsius) {
+ uint8_t temp = std::max(celsius, kTrotecMinTemp);
+ temp = std::min(temp, kTrotecMaxTemp);
+ remote_state[3] = (remote_state[3] & 0x80) | (temp - kTrotecMinTemp);
+}
+
+uint8_t IRTrotecESP::getTemp() {
+ return (remote_state[3] & 0b01111111) + kTrotecMinTemp;
+}
+
+void IRTrotecESP::setSleep(bool sleep) {
+ if (sleep)
+ remote_state[3] |= kTrotecSleepBit;
+ else
+ remote_state[3] &= ~kTrotecSleepBit;
+}
+
+bool IRTrotecESP::getSleep(void) { return remote_state[3] & kTrotecSleepBit; }
+
+void IRTrotecESP::setTimer(const uint8_t timer) {
+ if (timer)
+ remote_state[5] |= kTrotecTimerBit;
+ else
+ remote_state[5] &= ~kTrotecTimerBit;
+ remote_state[6] = (timer > kTrotecMaxTimer) ? kTrotecMaxTimer : timer;
+}
+
+uint8_t IRTrotecESP::getTimer() { return remote_state[6]; }
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRTrotecESP::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kTrotecCool;
+ case stdAc::opmode_t::kDry:
+ return kTrotecDry;
+ case stdAc::opmode_t::kFan:
+ return kTrotecFan;
+ // Note: No Heat mode.
+ default:
+ return kTrotecAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRTrotecESP::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kTrotecFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kTrotecFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kTrotecFanHigh;
+ default:
+ return kTrotecFanMed;
+ }
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Trotec.h b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.h
similarity index 68%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Trotec.h
rename to lib/IRremoteESP8266-2.6.0/src/ir_Trotec.h
index 040d9a722d5d..dfbc26c074ca 100644
--- a/lib/IRremoteESP8266-2.5.2.03/src/ir_Trotec.h
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Trotec.h
@@ -5,6 +5,9 @@
#include "IRremoteESP8266.h"
#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
// Constants
// Byte 0
@@ -19,8 +22,7 @@ const uint8_t kTrotecCool = 1;
const uint8_t kTrotecDry = 2;
const uint8_t kTrotecFan = 3;
-const uint8_t kTrotecOn = 1;
-const uint8_t kTrotecOff = 0;
+const uint8_t kTrotecPowerBit = 0b00001000;
const uint8_t kTrotecFanLow = 1;
const uint8_t kTrotecFanMed = 2;
@@ -31,13 +33,12 @@ const uint8_t kTrotecMinTemp = 18;
const uint8_t kTrotecDefTemp = 25;
const uint8_t kTrotecMaxTemp = 32;
-const uint8_t kTrotecSleepOn = 1;
+const uint8_t kTrotecSleepBit = 0b10000000;
// Byte 5
-const uint8_t kTrotecTimerOn = 1;
+const uint8_t kTrotecTimerBit = 0b01000000;
// Byte 6
-const uint8_t kTrotecMinTimer = 0;
const uint8_t kTrotecMaxTimer = 23;
// Legacy defines. (Deperecated)
@@ -50,7 +51,6 @@ const uint8_t kTrotecMaxTimer = 23;
#define TROTEC_FAN_HIGH kTrotecFanHigh
#define TROTEC_MIN_TEMP kTrotecMinTemp
#define TROTEC_MAX_TEMP kTrotecMaxTemp
-#define TROTEC_MIN_TIMER kTrotecMinTimer
#define TROTEC_MAX_TIMER kTrotecMaxTimer
class IRTrotecESP {
@@ -58,35 +58,42 @@ class IRTrotecESP {
explicit IRTrotecESP(uint16_t pin);
#if SEND_TROTEC
- void send();
+ void send(const uint16_t repeat = kTrotecDefaultRepeat);
#endif // SEND_TROTEC
void begin();
- void setPower(bool state);
- uint8_t getPower();
+ void setPower(const bool state);
+ bool getPower();
- void setTemp(uint8_t temp);
+ void setTemp(const uint8_t celsius);
uint8_t getTemp();
- void setSpeed(uint8_t fan);
+ void setSpeed(const uint8_t fan);
uint8_t getSpeed();
uint8_t getMode();
- void setMode(uint8_t mode);
+ void setMode(const uint8_t mode);
bool getSleep();
void setSleep(bool sleep);
uint8_t getTimer();
- void setTimer(uint8_t timer);
+ void setTimer(const uint8_t timer);
uint8_t* getRaw();
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifndef UNIT_TEST
+
private:
- uint8_t trotec[kTrotecStateLength];
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint8_t remote_state[kTrotecStateLength];
void stateReset();
void checksum();
- IRsend _irsend;
};
#endif // IR_TROTEC_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.cpp
new file mode 100644
index 000000000000..1fbb822cf65d
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.cpp
@@ -0,0 +1,583 @@
+// Copyright 2018 Erdem U. Altinyurt
+// Copyright 2019 David Conran
+
+#include "ir_Vestel.h"
+#include
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#include "IRutils.h"
+#include "ir_Haier.h"
+
+// VV VV EEEEEEE SSSSS TTTTTTTT EEEEEEE LL
+// VV VV EE S TT EE LL
+// VV VV EEEEE SSSS TT EEEEE LL
+// VV VV EE S TT EE LL
+// VVV EEEEEEE SSSSS TT EEEEEEE LLLLLLL
+
+// Vestel added by Erdem U. Altinyurt
+
+// Equipment it seems compatible with:
+// * Vestel AC Model BIOX CXP-9 (9K BTU)
+// *
+
+// Ref:
+// None. Totally reverse engineered.
+
+#if SEND_VESTEL_AC
+// Send a Vestel message
+//
+// Args:
+// data: Contents of the message to be sent.
+// nbits: Nr. of bits of data to be sent. Typically kVestelBits.
+//
+// Status: STABLE / Working.
+//
+void IRsend::sendVestelAc(const uint64_t data, const uint16_t nbits,
+ const uint16_t repeat) {
+ if (nbits % 8 != 0) return; // nbits is required to be a multiple of 8.
+
+ sendGeneric(kVestelAcHdrMark, kVestelAcHdrSpace, // Header
+ kVestelAcBitMark, kVestelAcOneSpace, // Data
+ kVestelAcBitMark, kVestelAcZeroSpace, // Data
+ kVestelAcBitMark, 100000, // Footer + repeat gap
+ data, nbits, 38, false, repeat, 50);
+}
+#endif
+
+// Code to emulate Vestel A/C IR remote control unit.
+
+// Initialise the object.
+IRVestelAc::IRVestelAc(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+// Reset the state of the remote to a known good state/sequence.
+void IRVestelAc::stateReset() {
+ // Power On, Mode Auto, Fan Auto, Temp = 25C/77F
+ remote_state = kVestelAcStateDefault;
+ remote_time_state = kVestelAcTimeStateDefault;
+ use_time_state = false;
+}
+
+// Configure the pin for output.
+void IRVestelAc::begin() {
+ _irsend.begin();
+}
+
+#if SEND_VESTEL_AC
+// Send the current desired state to the IR LED.
+void IRVestelAc::send() {
+ checksum(); // Ensure correct checksum before sending.
+ uint64_t code_to_send;
+ if (use_time_state)
+ code_to_send = remote_time_state;
+ else
+ code_to_send = remote_state;
+ _irsend.sendVestelAc(code_to_send);
+}
+#endif // SEND_VESTEL_AC
+
+// Return the internal state date of the remote.
+uint64_t IRVestelAc::getRaw() {
+ checksum();
+ if (use_time_state) return remote_time_state;
+ return remote_state;
+}
+
+// Override the internal state with the new state.
+void IRVestelAc::setRaw(uint8_t* newState) {
+ uint64_t upState = 0;
+ for (int i = 0; i < 7; i++)
+ upState |= static_cast(newState[i]) << (i * 8);
+ this->setRaw(upState);
+}
+
+void IRVestelAc::setRaw(const uint64_t newState) {
+ use_time_state = false;
+ remote_state = newState;
+ remote_time_state = newState;
+ if (this->isTimeCommand()) {
+ use_time_state = true;
+ remote_state = kVestelAcStateDefault;
+ } else {
+ remote_time_state = kVestelAcTimeStateDefault;
+ }
+}
+
+// Set the requested power state of the A/C to on.
+void IRVestelAc::on() { setPower(true); }
+
+// Set the requested power state of the A/C to off.
+void IRVestelAc::off() { setPower(false); }
+
+// Set the requested power state of the A/C.
+void IRVestelAc::setPower(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcPowerOffset);
+ if (state)
+ remote_state |= ((uint64_t)0xF << kVestelAcPowerOffset);
+ else
+ remote_state |= ((uint64_t)0xC << kVestelAcPowerOffset);
+ use_time_state = false;
+}
+
+// Return the requested power state of the A/C.
+bool IRVestelAc::getPower() {
+ return (remote_state >> kVestelAcPowerOffset == 0xF);
+}
+
+// Set the temperature in Celsius degrees.
+void IRVestelAc::setTemp(const uint8_t temp) {
+ uint8_t new_temp = temp;
+ new_temp = std::max(kVestelAcMinTempC, new_temp);
+ // new_temp = std::max(kVestelAcMinTempH, new_temp); Check MODE
+ new_temp = std::min(kVestelAcMaxTemp, new_temp);
+ remote_state &= ~((uint64_t)0xF << kVestelAcTempOffset);
+ remote_state |= (uint64_t)(new_temp - 16) << kVestelAcTempOffset;
+ use_time_state = false;
+}
+
+// Return the set temperature.
+uint8_t IRVestelAc::getTemp(void) {
+ return ((remote_state >> kVestelAcTempOffset) & 0xF) + 16;
+}
+
+// Set the speed of the fan,
+// 1-3 set the fan speed, 0 or anything else set it to auto.
+void IRVestelAc::setFan(const uint8_t fan) {
+ switch (fan) {
+ case kVestelAcFanLow:
+ case kVestelAcFanMed:
+ case kVestelAcFanHigh:
+ case kVestelAcFanAutoCool:
+ case kVestelAcFanAutoHot:
+ case kVestelAcFanAuto:
+ remote_state &= ~((uint64_t)0xF << kVestelAcFanOffset);
+ remote_state |= (uint64_t)fan << kVestelAcFanOffset;
+ break;
+ default:
+ setFan(kVestelAcFanAuto);
+ }
+ use_time_state = false;
+}
+
+// Return the requested state of the unit's fan.
+uint8_t IRVestelAc::getFan() {
+ return (remote_state >> kVestelAcFanOffset) & 0xF;
+}
+
+// Get the requested climate operation mode of the a/c unit.
+// Returns:
+// A uint8_t containing the A/C mode.
+uint8_t IRVestelAc::getMode() {
+ return (remote_state >> kVestelAcModeOffset) & 0xF;
+}
+
+// Set the requested climate operation mode of the a/c unit.
+void IRVestelAc::setMode(const uint8_t mode) {
+ // If we get an unexpected mode, default to AUTO.
+ switch (mode) {
+ case kVestelAcAuto:
+ case kVestelAcCool:
+ case kVestelAcHeat:
+ case kVestelAcDry:
+ case kVestelAcFan:
+ remote_state &= ~((uint64_t)0xF << kVestelAcModeOffset);
+ remote_state |= (uint64_t)mode << kVestelAcModeOffset;
+ break;
+ default:
+ setMode(kVestelAcAuto);
+ }
+ use_time_state = false;
+}
+
+// Set Auto mode of AC.
+void IRVestelAc::setAuto(const int8_t autoLevel) {
+ if (autoLevel < -2 || autoLevel > 2) return;
+ setMode(kVestelAcAuto);
+ setFan((autoLevel < 0 ? kVestelAcFanAutoCool : kVestelAcFanAutoHot));
+ if (autoLevel == 2)
+ setTemp(30);
+ else if (autoLevel == 1)
+ setTemp(31);
+ else if (autoLevel == 0)
+ setTemp(25);
+ else if (autoLevel == -1)
+ setTemp(16);
+ else if (autoLevel == -2)
+ setTemp(17);
+}
+
+void IRVestelAc::setTimerActive(const bool on) {
+ if (on) // activation
+ remote_time_state |= ((uint64_t)1 << kVestelAcTimerFlagOffset);
+ else // deactivate
+ remote_time_state &= ~((uint64_t)1 << kVestelAcTimerFlagOffset);
+ use_time_state = true;
+}
+
+bool IRVestelAc::isTimerActive(void) {
+ return (remote_time_state >> kVestelAcTimerFlagOffset) & 1;
+}
+
+// Set Timer option of AC.
+// Valid time arguments are 0, 0.5, 1, 2, 3 and 5 hours (in min). 0 disables the
+// timer.
+void IRVestelAc::setTimer(const uint16_t minutes) {
+ // Clear both On & Off timers.
+ remote_time_state &= ~((uint64_t)0xFFFF << kVestelAcOffTimeOffset);
+ // Set the "Off" time with the nr of minutes before we turn off.
+ remote_time_state |= (uint64_t)(((minutes / 60) << 3) + (minutes % 60) / 10)
+ << kVestelAcOffTimeOffset;
+ setOffTimerActive(false);
+ // Yes. On Timer instead of Off timer active.
+ setOnTimerActive(minutes != 0);
+ setTimerActive(minutes != 0);
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getTimer(void) { return getOffTimer(); }
+
+// Set the AC's internal clock
+void IRVestelAc::setTime(const uint16_t minutes) {
+ remote_time_state &= ~((uint64_t)0x1F << kVestelAcHourOffset);
+ remote_time_state |= (uint64_t)((minutes / 60) & 0x1F)
+ << kVestelAcHourOffset;
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcMinuteOffset);
+ remote_time_state |= (uint64_t)((minutes % 60) & 0xFF)
+ << kVestelAcMinuteOffset;
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getTime(void) {
+ return ((remote_time_state >> kVestelAcHourOffset) & 0x1F) * 60 +
+ ((remote_time_state >> kVestelAcMinuteOffset) & 0xFF);
+}
+
+void IRVestelAc::setOnTimerActive(const bool on) {
+ if (on) // activation
+ remote_time_state |= ((uint64_t)1 << kVestelAcOnTimerFlagOffset);
+ else // deactivate
+ remote_time_state &= ~((uint64_t)1 << kVestelAcOnTimerFlagOffset);
+ use_time_state = true;
+}
+
+bool IRVestelAc::isOnTimerActive(void) {
+ return (remote_time_state >> kVestelAcOnTimerFlagOffset) & 1;
+}
+
+// Set AC's wake up time. Takes time in minute.
+void IRVestelAc::setOnTimer(const uint16_t minutes) {
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcOnTimeOffset);
+ remote_time_state |= (uint64_t)(((minutes / 60) << 3) + (minutes % 60) / 10)
+ << kVestelAcOnTimeOffset;
+ setOnTimerActive(minutes != 0);
+ setTimerActive(false);
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getOnTimer(void) {
+ uint8_t ontime = (remote_time_state >> kVestelAcOnTimeOffset) & 0xFF;
+ return (ontime >> 3) * 60 + (ontime & 0x7) * 10;
+}
+
+void IRVestelAc::setOffTimerActive(const bool on) {
+ if (on) // activation
+ remote_time_state |= ((uint64_t)1 << kVestelAcOffTimerFlagOffset);
+ else // deactivate
+ remote_time_state &= ~((uint64_t)1 << kVestelAcOffTimerFlagOffset);
+ use_time_state = true;
+}
+
+bool IRVestelAc::isOffTimerActive(void) {
+ return (remote_time_state >> kVestelAcOffTimerFlagOffset) & 1;
+}
+
+// Set AC's turn off time. Takes time in minute.
+void IRVestelAc::setOffTimer(const uint16_t minutes) {
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcOffTimeOffset);
+ remote_time_state |=
+ (uint64_t)((((minutes / 60) << 3) + (minutes % 60) / 10) & 0xFF)
+ << kVestelAcOffTimeOffset;
+ setOffTimerActive(minutes != 0);
+ setTimerActive(false);
+ use_time_state = true;
+}
+
+uint16_t IRVestelAc::getOffTimer(void) {
+ uint8_t offtime = (remote_time_state >> kVestelAcOffTimeOffset) & 0xFF;
+ return (offtime >> 3) * 60 + (offtime & 0x7) * 10;
+}
+
+// Set the Sleep state of the A/C.
+void IRVestelAc::setSleep(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcTurboSleepOffset);
+ remote_state |= (uint64_t)(state ? kVestelAcSleep : kVestelAcNormal)
+ << kVestelAcTurboSleepOffset;
+ use_time_state = false;
+}
+
+// Return the Sleep state of the A/C.
+bool IRVestelAc::getSleep() {
+ return ((remote_state >> kVestelAcTurboSleepOffset) & 0xF) == kVestelAcSleep;
+}
+
+// Set the Turbo state of the A/C.
+void IRVestelAc::setTurbo(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcTurboSleepOffset);
+ remote_state |= (uint64_t)(state ? kVestelAcTurbo : kVestelAcNormal)
+ << kVestelAcTurboSleepOffset;
+ use_time_state = false;
+}
+
+// Return the Turbo state of the A/C.
+bool IRVestelAc::getTurbo() {
+ return ((remote_state >> kVestelAcTurboSleepOffset) & 0xF) == kVestelAcTurbo;
+}
+
+// Set the Ion state of the A/C.
+void IRVestelAc::setIon(const bool state) {
+ remote_state &= ~((uint64_t)0x1 << kVestelAcIonOffset);
+
+ remote_state |= (uint64_t)(state ? 1 : 0) << kVestelAcIonOffset;
+ use_time_state = false;
+}
+
+// Return the Ion state of the A/C.
+bool IRVestelAc::getIon() { return (remote_state >> kVestelAcIonOffset) & 1; }
+
+// Set the Swing Roaming state of the A/C.
+void IRVestelAc::setSwing(const bool state) {
+ remote_state &= ~((uint64_t)0xF << kVestelAcSwingOffset);
+
+ remote_state |= (uint64_t)(state ? kVestelAcSwing : 0xF)
+ << kVestelAcSwingOffset;
+ use_time_state = false;
+}
+
+// Return the Swing Roaming state of the A/C.
+bool IRVestelAc::getSwing() {
+ return ((remote_state >> kVestelAcSwingOffset) & 0xF) == kVestelAcSwing;
+}
+
+// Calculate the checksum for a given array.
+// Args:
+// state: The state to calculate the checksum over.
+// Returns:
+// The 8 bit checksum value.
+uint8_t IRVestelAc::calcChecksum(const uint64_t state) {
+ // Just counts the set bits +1 on stream and take inverse after mask
+ uint8_t sum = 0;
+ uint64_t temp_state = state & kVestelAcCRCMask;
+ for (; temp_state; temp_state >>= 1)
+ if (temp_state & 1) sum++;
+ sum += 2;
+ sum = 0xff - sum;
+ return sum;
+}
+
+// Verify the checksum is valid for a given state.
+// Args:
+// state: The state to verify the checksum of.
+// Returns:
+// A boolean.
+bool IRVestelAc::validChecksum(const uint64_t state) {
+ return (((state >> kVestelAcChecksumOffset) & 0xFF) == calcChecksum(state));
+}
+
+// Calculate & set the checksum for the current internal state of the remote.
+void IRVestelAc::checksum() {
+ // Stored the checksum value in the last byte.
+ remote_state &= ~((uint64_t)0xFF << kVestelAcChecksumOffset);
+ remote_state |= (uint64_t)calcChecksum(remote_state)
+ << kVestelAcChecksumOffset;
+
+ remote_time_state &= ~((uint64_t)0xFF << kVestelAcChecksumOffset);
+ remote_time_state |= (uint64_t)calcChecksum(remote_time_state)
+ << kVestelAcChecksumOffset;
+}
+
+bool IRVestelAc::isTimeCommand() {
+ return (remote_state >> kVestelAcPowerOffset == 0x00 || use_time_state);
+}
+
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRVestelAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kVestelAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kVestelAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kVestelAcDry;
+ case stdAc::opmode_t::kFan:
+ return kVestelAcFan;
+ default:
+ return kVestelAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRVestelAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kVestelAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kVestelAcFanMed;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kVestelAcFanHigh;
+ default:
+ return kVestelAcFanAuto;
+ }
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRVestelAc::toString() {
+ String result = "";
+#else
+std::string IRVestelAc::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ if (isTimeCommand()) {
+ result += F("Time: ");
+ result += IRHaierAC::timeToString(getTime());
+
+ result += F(", Timer: ");
+ result += isTimerActive() ? IRHaierAC::timeToString(getTimer()) : F("Off");
+
+ result += F(", On Timer: ");
+ result += (isOnTimerActive() && !isTimerActive())
+ ? IRHaierAC::timeToString(getOnTimer())
+ : F("Off");
+
+ result += F(", Off Timer: ");
+ result +=
+ isOffTimerActive() ? IRHaierAC::timeToString(getOffTimer()) : F("Off");
+ return result;
+ }
+ // Not a time command, it's a normal command.
+ result += F("Power: ");
+ result += (getPower() ? F("On") : F("Off"));
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (getMode()) {
+ case kVestelAcAuto:
+ result += F(" (AUTO)");
+ break;
+ case kVestelAcCool:
+ result += F(" (COOL)");
+ break;
+ case kVestelAcHeat:
+ result += F(" (HEAT)");
+ break;
+ case kVestelAcDry:
+ result += F(" (DRY)");
+ break;
+ case kVestelAcFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kVestelAcFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kVestelAcFanLow:
+ result += F(" (LOW)");
+ break;
+ case kVestelAcFanMed:
+ result += F(" (MEDIUM)");
+ break;
+ case kVestelAcFanHigh:
+ result += F(" (HIGH)");
+ break;
+ case kVestelAcFanAutoCool:
+ result += F(" (AUTO COOL)");
+ break;
+ case kVestelAcFanAutoHot:
+ result += F(" (AUTO HOT)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Sleep: ");
+ result += (getSleep() ? F("On") : F("Off"));
+ result += F(", Turbo: ");
+ result += (getTurbo() ? F("On") : F("Off"));
+ result += F(", Ion: ");
+ result += (getIon() ? F("On") : F("Off"));
+ result += F(", Swing: ");
+ result += (getSwing() ? F("On") : F("Off"));
+ return result;
+}
+
+#if DECODE_VESTEL_AC
+// Decode the supplied Vestel message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: The number of data bits to expect. Typically kVestelBits.
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: Alpha / Needs testing against a real device.
+//
+bool IRrecv::decodeVestelAc(decode_results* results, uint16_t nbits,
+ bool strict) {
+ if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte.
+ return false;
+
+ if (strict)
+ if (nbits != kVestelAcBits)
+ return false; // Not strictly a Vestel AC message.
+
+ uint64_t data = 0;
+ uint16_t offset = kStartOffset;
+
+ if (nbits > sizeof(data) * 8)
+ return false; // We can't possibly capture a Vestel packet that big.
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kVestelAcHdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kVestelAcHdrSpace)) return false;
+
+ // Data (Normal)
+ match_result_t data_result =
+ matchData(&(results->rawbuf[offset]), nbits, kVestelAcBitMark,
+ kVestelAcOneSpace, kVestelAcBitMark, kVestelAcZeroSpace,
+ kVestelAcTolerance, kMarkExcess, false);
+
+ if (data_result.success == false) return false;
+ offset += data_result.used;
+ data = data_result.data;
+
+ // Footer
+ if (!matchMark(results->rawbuf[offset++], kVestelAcBitMark)) return false;
+
+ // Compliance
+ if (strict)
+ if (!IRVestelAc::validChecksum(data_result.data)) return false;
+
+ // Success
+ results->decode_type = VESTEL_AC;
+ results->bits = nbits;
+ results->value = data;
+ results->address = 0;
+ results->command = 0;
+
+ return true;
+}
+#endif // DECODE_VESTEL_AC
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.h b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.h
new file mode 100644
index 000000000000..ab04e8b35a83
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Vestel.h
@@ -0,0 +1,177 @@
+// Copyright 2018 Erdem U. Altinyurt
+// Copyright 2019 David Conran
+
+#ifndef IR_VESTEL_H_
+#define IR_VESTEL_H_
+
+#define __STDC_LIMIT_MACROS
+#include
+#ifdef ARDUINO
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// VV VV EEEEEEE SSSSS TTTTTTTT EEEEEEE LL
+// VV VV EE S TT EE LL
+// VV VV EEEEE SSSS TT EEEEE LL
+// VV VV EE S TT EE LL
+// VVV EEEEEEE SSSSS TT EEEEEEE LLLLLLL
+
+// Vestel added by Erdem U. Altinyurt
+
+// Structure of a Command message (56 bits)
+// Signature: 12 bits. e.g. 0x201
+// Checksum: 8 bits
+// Swing: 4 bits. (auto 0xA, stop 0xF)
+// turbo_sleep_normal: 4bits. (normal 0x1, sleep 0x3, turbo 0x7)
+// Unused: 8 bits. (0x00)
+// Temperature: 4 bits. (Celcius, but offset by -16 degrees. e.g. 0x0 = 16C)
+// Fan Speed: 4 bits (auto 0x1, low 0x5, mid 0x9, high 0xB, 0xD auto hot,
+// 0xC auto cool)
+// Mode: 3 bits. (auto 0x0, cold 0x1, dry 0x2, fan 0x3, hot 0x4)
+// unknown/unused: 6 bits.
+// Ion flag: 1 bit.
+// unknown/unused: 1 bit.
+// Power/message type: 4 bits. (on 0xF, off 0xC, 0x0 == Timer mesage)
+//
+// Structure of a Time(r) message (56 bits)
+// Signature: 12 bits. e.g. 0x201
+// Checksum: 8 bits
+// Off Minutes: 3 bits. (Stored in 10 min increments. eg. xx:20 is 0x2)
+// Off Hours: 5 bits. (0x17 == 11PM / 23:00)
+// On Minutes: 3 bits. (Stored in 10 min increments. eg. xx:20 is 0x2)
+// On Hours: 5 bits. (0x9 == 9AM / 09:00)
+// Clock Hours: 5 bits.
+// On Timer flag: 1 bit.
+// Off Timer flag: 1 bit.
+// Timer mode flag: 1 bit. (Off after X many hours/mins, not at clock time.)
+// Clock Minutes: 8 bits. (0-59)
+// Power/message type: 4 bits. (0x0 == Timer mesage, else see Comman message)
+
+// Constants
+const uint16_t kVestelAcHdrMark = 3110;
+const uint16_t kVestelAcHdrSpace = 9066;
+const uint16_t kVestelAcBitMark = 520;
+const uint16_t kVestelAcOneSpace = 1535;
+const uint16_t kVestelAcZeroSpace = 480;
+const uint16_t kVestelAcTolerance = 30;
+
+const uint8_t kVestelAcMinTempH = 16;
+const uint8_t kVestelAcMinTempC = 18;
+const uint8_t kVestelAcMaxTemp = 30;
+
+const uint64_t kVestelAcCRCMask = 0xFFFFFFFFFFF00000;
+
+const uint8_t kVestelAcAuto = 0;
+const uint8_t kVestelAcCool = 1;
+const uint8_t kVestelAcDry = 2;
+const uint8_t kVestelAcFan = 3;
+const uint8_t kVestelAcHeat = 4;
+
+const uint8_t kVestelAcFanAuto = 1;
+const uint8_t kVestelAcFanLow = 5;
+const uint8_t kVestelAcFanMed = 9;
+const uint8_t kVestelAcFanHigh = 0xB;
+const uint8_t kVestelAcFanAutoCool = 0xC;
+const uint8_t kVestelAcFanAutoHot = 0xD;
+
+const uint8_t kVestelAcNormal = 1;
+const uint8_t kVestelAcSleep = 3;
+const uint8_t kVestelAcTurbo = 7;
+const uint8_t kVestelAcIon = 4;
+const uint8_t kVestelAcSwing = 0xA;
+
+const uint8_t kVestelAcChecksumOffset = 12;
+const uint8_t kVestelAcSwingOffset = 20;
+const uint8_t kVestelAcTurboSleepOffset = 24;
+const uint8_t kVestelAcTempOffset = 36;
+const uint8_t kVestelAcFanOffset = 40;
+const uint8_t kVestelAcModeOffset = 44;
+const uint8_t kVestelAcIonOffset = 50;
+const uint8_t kVestelAcPowerOffset = 52;
+const uint8_t kVestelAcOffTimeOffset = 20;
+const uint8_t kVestelAcOnTimeOffset = 28;
+const uint8_t kVestelAcHourOffset = 36; // 5 bits
+const uint8_t kVestelAcOnTimerFlagOffset = kVestelAcHourOffset + 5;
+const uint8_t kVestelAcOffTimerFlagOffset = kVestelAcHourOffset + 6;
+const uint8_t kVestelAcTimerFlagOffset = kVestelAcHourOffset + 7;
+const uint8_t kVestelAcMinuteOffset = 44;
+
+const uint64_t kVestelAcStateDefault = 0x0F00D9001FEF201ULL;
+const uint64_t kVestelAcTimeStateDefault = 0x201ULL;
+
+class IRVestelAc {
+ public:
+ explicit IRVestelAc(uint16_t pin);
+
+ void stateReset();
+#if SEND_VESTEL_AC
+ void send();
+#endif // SEND_VESTEL_AC
+ void begin(void);
+ void on(void);
+ void off(void);
+ void setPower(const bool state);
+ bool getPower();
+ void setAuto(const int8_t autoLevel);
+ void setTimer(const uint16_t minutes);
+ uint16_t getTimer(void);
+ void setTime(const uint16_t minutes);
+ uint16_t getTime(void);
+ void setOnTimer(const uint16_t minutes);
+ uint16_t getOnTimer(void);
+ void setOffTimer(const uint16_t minutes);
+ uint16_t getOffTimer(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 setRaw(uint8_t* newState);
+ void setRaw(const uint64_t newState);
+ uint64_t getRaw(void);
+ static bool validChecksum(const uint64_t state);
+ void setSwing(const bool state);
+ bool getSwing(void);
+ void setSleep(const bool state);
+ bool getSleep(void);
+ void setTurbo(const bool state);
+ bool getTurbo(void);
+ void setIon(const bool state);
+ bool getIon(void);
+ bool isTimeCommand(void);
+ bool isOnTimerActive(void);
+ void setOnTimerActive(const bool on);
+ bool isOffTimerActive(void);
+ void setOffTimerActive(const bool on);
+ bool isTimerActive(void);
+ void setTimerActive(const bool on);
+ static uint8_t calcChecksum(const uint64_t state);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString();
+#else
+ std::string toString();
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ uint64_t remote_state;
+ uint64_t remote_time_state;
+ bool use_time_state;
+ void checksum();
+};
+
+#endif // IR_VESTEL_H_
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.cpp
new file mode 100644
index 000000000000..048c1a1eb9e4
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.cpp
@@ -0,0 +1,671 @@
+// Copyright 2018 David Conran
+//
+// Code to emulate Whirlpool protocol compatible devices.
+// Should be compatible with:
+// * SPIS409L, SPIS412L, SPIW409L, SPIW412L, SPIW418L
+// Remotes:
+// * DG11J1-3A / DG11J1-04
+// * DG11J1-91
+//
+// Note: Smart, iFeel, AroundU, PowerSave, & Silent modes are unsupported.
+// Advanced 6thSense, Dehumidify, & Sleep modes are not supported.
+// FYI:
+// Dim == !Light
+// Jet == Super == Turbo
+//
+
+#include "ir_Whirlpool.h"
+#include
+#ifndef ARDUINO
+#include
+#endif
+#include "IRrecv.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#include "IRutils.h"
+
+// WW WW HH HH IIIII RRRRRR LL PPPPPP OOOOO OOOOO LL
+// WW WW HH HH III RR RR LL PP PP OO OO OO OO LL
+// WW W WW HHHHHHH III RRRRRR LL PPPPPP OO OO OO OO LL
+// WW WWW WW HH HH III RR RR LL PP OO OO OO OO LL
+// WW WW HH HH IIIII RR RR LLLLLLL PP OOOO0 OOOO0 LLLLLLL
+
+// Constants
+// Ref: https://github.com/markszabo/IRremoteESP8266/issues/509
+const uint16_t kWhirlpoolAcHdrMark = 8950;
+const uint16_t kWhirlpoolAcHdrSpace = 4484;
+const uint16_t kWhirlpoolAcBitMark = 597;
+const uint16_t kWhirlpoolAcOneSpace = 1649;
+const uint16_t kWhirlpoolAcZeroSpace = 533;
+const uint16_t kWhirlpoolAcGap = 7920;
+const uint32_t kWhirlpoolAcMinGap = kDefaultMessageGap; // Just a guess.
+const uint8_t kWhirlpoolAcSections = 3;
+
+#if SEND_WHIRLPOOL_AC
+// Send a Whirlpool A/C message.
+//
+// Args:
+// data: An array of bytes containing the IR command.
+// 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.
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/509
+void IRsend::sendWhirlpoolAC(unsigned char data[], uint16_t nbytes,
+ uint16_t repeat) {
+ if (nbytes < kWhirlpoolAcStateLength)
+ return; // Not enough bytes to send a proper message.
+ for (uint16_t r = 0; r <= repeat; r++) {
+ // Section 1
+ sendGeneric(kWhirlpoolAcHdrMark, kWhirlpoolAcHdrSpace, kWhirlpoolAcBitMark,
+ kWhirlpoolAcOneSpace, kWhirlpoolAcBitMark,
+ kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark, kWhirlpoolAcGap,
+ data, 6, // 6 bytes == 48 bits
+ 38000, // Complete guess of the modulation frequency.
+ false, 0, 50);
+ // Section 2
+ sendGeneric(0, 0, kWhirlpoolAcBitMark, kWhirlpoolAcOneSpace,
+ kWhirlpoolAcBitMark, kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark,
+ kWhirlpoolAcGap, data + 6, 8, // 8 bytes == 64 bits
+ 38000, // Complete guess of the modulation frequency.
+ false, 0, 50);
+ // Section 3
+ sendGeneric(0, 0, kWhirlpoolAcBitMark, kWhirlpoolAcOneSpace,
+ kWhirlpoolAcBitMark, kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark,
+ kWhirlpoolAcMinGap, data + 14, 7, // 7 bytes == 56 bits
+ 38000, // Complete guess of the modulation frequency.
+ false, 0, 50);
+ }
+}
+#endif // SEND_WHIRLPOOL_AC
+
+// Class for emulating a Whirlpool A/C remote.
+// Decoding help from:
+// @redmusicxd, @josh929800, @raducostea
+
+IRWhirlpoolAc::IRWhirlpoolAc(uint16_t pin) : _irsend(pin) { stateReset(); }
+
+void IRWhirlpoolAc::stateReset() {
+ for (uint8_t i = 2; i < kWhirlpoolAcStateLength; i++) remote_state[i] = 0x0;
+ remote_state[0] = 0x83;
+ remote_state[1] = 0x06;
+ remote_state[6] = 0x80;
+ _setTemp(kWhirlpoolAcAutoTemp); // Default to a sane value.
+}
+
+void IRWhirlpoolAc::begin() { _irsend.begin(); }
+
+bool IRWhirlpoolAc::validChecksum(uint8_t state[], const uint16_t length) {
+ if (length > kWhirlpoolAcChecksumByte1 &&
+ state[kWhirlpoolAcChecksumByte1] !=
+ xorBytes(state + 2, kWhirlpoolAcChecksumByte1 - 1 - 2)) {
+ DPRINTLN("DEBUG: First Whirlpool AC checksum failed.");
+ return false;
+ }
+ if (length > kWhirlpoolAcChecksumByte2 &&
+ state[kWhirlpoolAcChecksumByte2] !=
+ xorBytes(state + kWhirlpoolAcChecksumByte1 + 1,
+ kWhirlpoolAcChecksumByte2 - kWhirlpoolAcChecksumByte1 - 1)) {
+ DPRINTLN("DEBUG: Second Whirlpool AC checksum failed.");
+ return false;
+ }
+ // State is too short to have a checksum or everything checked out.
+ return true;
+}
+
+// Update the checksum for the internal state.
+void IRWhirlpoolAc::checksum(uint16_t length) {
+ if (length >= kWhirlpoolAcChecksumByte1)
+ remote_state[kWhirlpoolAcChecksumByte1] =
+ xorBytes(remote_state + 2, kWhirlpoolAcChecksumByte1 - 1 - 2);
+ if (length >= kWhirlpoolAcChecksumByte2)
+ remote_state[kWhirlpoolAcChecksumByte2] =
+ xorBytes(remote_state + kWhirlpoolAcChecksumByte1 + 1,
+ kWhirlpoolAcChecksumByte2 - kWhirlpoolAcChecksumByte1 - 1);
+}
+
+#if SEND_WHIRLPOOL_AC
+void IRWhirlpoolAc::send(const uint16_t repeat, const bool calcchecksum) {
+ if (calcchecksum) checksum();
+ _irsend.sendWhirlpoolAC(remote_state, kWhirlpoolAcStateLength, repeat);
+}
+#endif // SEND_WHIRLPOOL_AC
+
+uint8_t *IRWhirlpoolAc::getRaw(const bool calcchecksum) {
+ if (calcchecksum) checksum();
+ return remote_state;
+}
+
+void IRWhirlpoolAc::setRaw(const uint8_t new_code[], const uint16_t length) {
+ for (uint8_t i = 0; i < length && i < kWhirlpoolAcStateLength; i++)
+ remote_state[i] = new_code[i];
+}
+
+whirlpool_ac_remote_model_t IRWhirlpoolAc::getModel() {
+ if (remote_state[kWhirlpoolAcAltTempPos] & kWhirlpoolAcAltTempMask)
+ return DG11J191;
+ else
+ return DG11J13A;
+}
+
+void IRWhirlpoolAc::setModel(const whirlpool_ac_remote_model_t model) {
+ switch (model) {
+ case DG11J191:
+ remote_state[kWhirlpoolAcAltTempPos] |= kWhirlpoolAcAltTempMask;
+ break;
+ case DG11J13A:
+ // FALL THRU
+ default:
+ remote_state[kWhirlpoolAcAltTempPos] &= ~kWhirlpoolAcAltTempMask;
+ }
+ _setTemp(_desiredtemp); // Different models have different temp values.
+}
+
+// Return the temp. offset in deg C for the current model.
+int8_t IRWhirlpoolAc::getTempOffset() {
+ switch (getModel()) {
+ case DG11J191:
+ return -2;
+ break;
+ default:
+ return 0;
+ }
+}
+
+// Set the temp. in deg C
+void IRWhirlpoolAc::_setTemp(const uint8_t temp, const bool remember) {
+ if (remember) _desiredtemp = temp;
+ int8_t offset = getTempOffset(); // Cache the min temp for the model.
+ uint8_t newtemp = std::max((uint8_t)(kWhirlpoolAcMinTemp + offset), temp);
+ newtemp = std::min((uint8_t)(kWhirlpoolAcMaxTemp + offset), newtemp);
+ remote_state[kWhirlpoolAcTempPos] =
+ (remote_state[kWhirlpoolAcTempPos] & ~kWhirlpoolAcTempMask) |
+ ((newtemp - (kWhirlpoolAcMinTemp + offset)) << 4);
+}
+
+// Set the temp. in deg C
+void IRWhirlpoolAc::setTemp(const uint8_t temp) {
+ _setTemp(temp);
+ setSuper(false); // Changing temp cancels Super/Jet mode.
+ setCommand(kWhirlpoolAcCommandTemp);
+}
+
+// Return the set temp. in deg C
+uint8_t IRWhirlpoolAc::getTemp() {
+ return ((remote_state[kWhirlpoolAcTempPos] & kWhirlpoolAcTempMask) >> 4) +
+ + kWhirlpoolAcMinTemp + getTempOffset();
+}
+
+void IRWhirlpoolAc::_setMode(const uint8_t mode) {
+ switch (mode) {
+ case kWhirlpoolAcAuto:
+ setFan(kWhirlpoolAcFanAuto);
+ _setTemp(kWhirlpoolAcAutoTemp, false);
+ setSleep(false); // Cancel sleep mode when in auto/6thsense mode.
+ // FALL THRU
+ case kWhirlpoolAcHeat:
+ case kWhirlpoolAcCool:
+ case kWhirlpoolAcDry:
+ case kWhirlpoolAcFan:
+ remote_state[kWhirlpoolAcModePos] &= ~kWhirlpoolAcModeMask;
+ remote_state[kWhirlpoolAcModePos] |= mode;
+ setCommand(kWhirlpoolAcCommandMode);
+ break;
+ default:
+ return;
+ }
+ if (mode == kWhirlpoolAcAuto) setCommand(kWhirlpoolAcCommand6thSense);
+}
+
+void IRWhirlpoolAc::setMode(const uint8_t mode) {
+ setSuper(false); // Changing mode cancels Super/Jet mode.
+ _setMode(mode);
+}
+
+uint8_t IRWhirlpoolAc::getMode() {
+ return remote_state[kWhirlpoolAcModePos] & kWhirlpoolAcModeMask;
+}
+
+void IRWhirlpoolAc::setFan(const uint8_t speed) {
+ switch (speed) {
+ case kWhirlpoolAcFanAuto:
+ case kWhirlpoolAcFanLow:
+ case kWhirlpoolAcFanMedium:
+ case kWhirlpoolAcFanHigh:
+ remote_state[kWhirlpoolAcFanPos] =
+ (remote_state[kWhirlpoolAcFanPos] & ~kWhirlpoolAcFanMask) | speed;
+ setSuper(false); // Changing fan speed cancels Super/Jet mode.
+ setCommand(kWhirlpoolAcCommandFanSpeed);
+ break;
+ }
+}
+
+uint8_t IRWhirlpoolAc::getFan() {
+ return remote_state[kWhirlpoolAcFanPos] & kWhirlpoolAcFanMask;
+}
+
+void IRWhirlpoolAc::setSwing(const bool on) {
+ if (on) {
+ remote_state[kWhirlpoolAcFanPos] |= kWhirlpoolAcSwing1Mask;
+ remote_state[kWhirlpoolAcOffTimerPos] |= kWhirlpoolAcSwing2Mask;
+ } else {
+ remote_state[kWhirlpoolAcFanPos] &= ~kWhirlpoolAcSwing1Mask;
+ remote_state[kWhirlpoolAcOffTimerPos] &= ~kWhirlpoolAcSwing2Mask;
+ }
+ setCommand(kWhirlpoolAcCommandSwing);
+}
+
+bool IRWhirlpoolAc::getSwing() {
+ return (remote_state[kWhirlpoolAcFanPos] & kWhirlpoolAcSwing1Mask) &&
+ (remote_state[kWhirlpoolAcOffTimerPos] & kWhirlpoolAcSwing2Mask);
+}
+
+void IRWhirlpoolAc::setLight(const bool on) {
+ if (on)
+ remote_state[kWhirlpoolAcClockPos] &= ~kWhirlpoolAcLightMask;
+ else
+ remote_state[kWhirlpoolAcClockPos] |= kWhirlpoolAcLightMask;
+}
+
+bool IRWhirlpoolAc::getLight() {
+ return !(remote_state[kWhirlpoolAcClockPos] & kWhirlpoolAcLightMask);
+}
+
+void IRWhirlpoolAc::setTime(const uint16_t pos,
+ const uint16_t minspastmidnight) {
+ // Hours
+ remote_state[pos] &= ~kWhirlpoolAcHourMask;
+ remote_state[pos] |= (minspastmidnight / 60) % 24;
+ // Minutes
+ remote_state[pos + 1] &= ~kWhirlpoolAcMinuteMask;
+ remote_state[pos + 1] |= minspastmidnight % 60;
+}
+
+uint16_t IRWhirlpoolAc::getTime(const uint16_t pos) {
+ return (remote_state[pos] & kWhirlpoolAcHourMask) * 60 +
+ (remote_state[pos + 1] & kWhirlpoolAcMinuteMask);
+}
+
+bool IRWhirlpoolAc::isTimerEnabled(const uint16_t pos) {
+ return remote_state[pos - 1] & kWhirlpoolAcTimerEnableMask;
+}
+
+void IRWhirlpoolAc::enableTimer(const uint16_t pos, const bool state) {
+ if (state)
+ remote_state[pos - 1] |= kWhirlpoolAcTimerEnableMask;
+ else
+ remote_state[pos - 1] &= ~kWhirlpoolAcTimerEnableMask;
+}
+
+void IRWhirlpoolAc::setClock(const uint16_t minspastmidnight) {
+ setTime(kWhirlpoolAcClockPos, minspastmidnight);
+}
+
+uint16_t IRWhirlpoolAc::getClock() { return getTime(kWhirlpoolAcClockPos); }
+
+void IRWhirlpoolAc::setOffTimer(const uint16_t minspastmidnight) {
+ setTime(kWhirlpoolAcOffTimerPos, minspastmidnight);
+}
+
+uint16_t IRWhirlpoolAc::getOffTimer() {
+ return getTime(kWhirlpoolAcOffTimerPos);
+}
+
+bool IRWhirlpoolAc::isOffTimerEnabled() {
+ return isTimerEnabled(kWhirlpoolAcOffTimerPos);
+}
+
+void IRWhirlpoolAc::enableOffTimer(const bool state) {
+ enableTimer(kWhirlpoolAcOffTimerPos, state);
+ setCommand(kWhirlpoolAcCommandOffTimer);
+}
+
+void IRWhirlpoolAc::setOnTimer(const uint16_t minspastmidnight) {
+ setTime(kWhirlpoolAcOnTimerPos, minspastmidnight);
+}
+
+uint16_t IRWhirlpoolAc::getOnTimer() { return getTime(kWhirlpoolAcOnTimerPos); }
+
+bool IRWhirlpoolAc::isOnTimerEnabled() {
+ return isTimerEnabled(kWhirlpoolAcOnTimerPos);
+}
+
+void IRWhirlpoolAc::enableOnTimer(const bool state) {
+ enableTimer(kWhirlpoolAcOnTimerPos, state);
+ setCommand(kWhirlpoolAcCommandOnTimer);
+}
+
+void IRWhirlpoolAc::setPowerToggle(const bool on) {
+ if (on)
+ remote_state[kWhirlpoolAcPowerTogglePos] |= kWhirlpoolAcPowerToggleMask;
+ else
+ remote_state[kWhirlpoolAcPowerTogglePos] &= ~kWhirlpoolAcPowerToggleMask;
+ setSuper(false); // Changing power cancels Super/Jet mode.
+ setCommand(kWhirlpoolAcCommandPower);
+}
+
+bool IRWhirlpoolAc::getPowerToggle() {
+ return remote_state[kWhirlpoolAcPowerTogglePos] & kWhirlpoolAcPowerToggleMask;
+}
+
+uint8_t IRWhirlpoolAc::getCommand() {
+ return remote_state[kWhirlpoolAcCommandPos];
+}
+
+void IRWhirlpoolAc::setSleep(const bool on) {
+ if (on) {
+ remote_state[kWhirlpoolAcSleepPos] |= kWhirlpoolAcSleepMask;
+ setFan(kWhirlpoolAcFanLow);
+ } else {
+ remote_state[kWhirlpoolAcSleepPos] &= ~kWhirlpoolAcSleepMask;
+ }
+ setCommand(kWhirlpoolAcCommandSleep);
+}
+
+bool IRWhirlpoolAc::getSleep() {
+ return remote_state[kWhirlpoolAcSleepPos] & kWhirlpoolAcSleepMask;
+}
+
+// AKA Jet/Turbo mode.
+void IRWhirlpoolAc::setSuper(const bool on) {
+ if (on) {
+ setFan(kWhirlpoolAcFanHigh);
+ switch (getMode()) {
+ case kWhirlpoolAcHeat:
+ setTemp(kWhirlpoolAcMaxTemp + getTempOffset());
+ break;
+ case kWhirlpoolAcCool:
+ default:
+ setTemp(kWhirlpoolAcMinTemp + getTempOffset());
+ setMode(kWhirlpoolAcCool);
+ break;
+ }
+ remote_state[kWhirlpoolAcSuperPos] |= kWhirlpoolAcSuperMask;
+ } else {
+ remote_state[kWhirlpoolAcSuperPos] &= ~kWhirlpoolAcSuperMask;
+ }
+ setCommand(kWhirlpoolAcCommandSuper);
+}
+
+bool IRWhirlpoolAc::getSuper() {
+ return remote_state[kWhirlpoolAcSuperPos] & kWhirlpoolAcSuperMask;
+}
+
+void IRWhirlpoolAc::setCommand(const uint8_t code) {
+ remote_state[kWhirlpoolAcCommandPos] = code;
+}
+
+// Convert a standard A/C mode into its native mode.
+uint8_t IRWhirlpoolAc::convertMode(const stdAc::opmode_t mode) {
+ switch (mode) {
+ case stdAc::opmode_t::kCool:
+ return kWhirlpoolAcCool;
+ case stdAc::opmode_t::kHeat:
+ return kWhirlpoolAcHeat;
+ case stdAc::opmode_t::kDry:
+ return kWhirlpoolAcDry;
+ case stdAc::opmode_t::kFan:
+ return kWhirlpoolAcFan;
+ default:
+ return kWhirlpoolAcAuto;
+ }
+}
+
+// Convert a standard A/C Fan speed into its native fan speed.
+uint8_t IRWhirlpoolAc::convertFan(const stdAc::fanspeed_t speed) {
+ switch (speed) {
+ case stdAc::fanspeed_t::kMin:
+ case stdAc::fanspeed_t::kLow:
+ return kWhirlpoolAcFanLow;
+ case stdAc::fanspeed_t::kMedium:
+ return kWhirlpoolAcFanMedium;
+ case stdAc::fanspeed_t::kHigh:
+ case stdAc::fanspeed_t::kMax:
+ return kWhirlpoolAcFanHigh;
+ default:
+ return kWhirlpoolAcFanAuto;
+ }
+}
+
+#ifdef ARDUINO
+String IRWhirlpoolAc::timeToString(const uint16_t minspastmidnight) {
+ String result = "";
+#else
+std::string IRWhirlpoolAc::timeToString(const uint16_t minspastmidnight) {
+ std::string result = "";
+#endif // ARDUINO
+ uint8_t hours = minspastmidnight / 60;
+ if (hours < 10) result += '0';
+ result += uint64ToString(hours);
+ result += ':';
+ uint8_t mins = minspastmidnight % 60;
+ if (mins < 10) result += '0';
+ result += uint64ToString(mins);
+ return result;
+}
+
+// Convert the internal state into a human readable string.
+#ifdef ARDUINO
+String IRWhirlpoolAc::toString() {
+ String result = "";
+#else
+std::string IRWhirlpoolAc::toString() {
+ std::string result = "";
+#endif // ARDUINO
+ result += F("Model: ");
+ result += uint64ToString(getModel());
+ switch (getModel()) {
+ case DG11J191:
+ result += F(" (DG11J191)");
+ break;
+ case DG11J13A:
+ result += F(" (DG11J13A)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Power toggle: ");
+ if (getPowerToggle())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Mode: ");
+ result += uint64ToString(getMode());
+ switch (getMode()) {
+ case kWhirlpoolAcHeat:
+ result += F(" (HEAT)");
+ break;
+ case kWhirlpoolAcAuto:
+ result += F(" (AUTO)");
+ break;
+ case kWhirlpoolAcCool:
+ result += F(" (COOL)");
+ break;
+ case kWhirlpoolAcDry:
+ result += F(" (DRY)");
+ break;
+ case kWhirlpoolAcFan:
+ result += F(" (FAN)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ }
+ result += F(", Temp: ");
+ result += uint64ToString(getTemp());
+ result += F("C, Fan: ");
+ result += uint64ToString(getFan());
+ switch (getFan()) {
+ case kWhirlpoolAcFanAuto:
+ result += F(" (AUTO)");
+ break;
+ case kWhirlpoolAcFanHigh:
+ result += F(" (HIGH)");
+ break;
+ case kWhirlpoolAcFanMedium:
+ result += F(" (MEDIUM)");
+ break;
+ case kWhirlpoolAcFanLow:
+ result += F(" (LOW)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ break;
+ }
+ result += F(", Swing: ");
+ if (getSwing())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Light: ");
+ if (getLight())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Clock: ");
+ result += timeToString(getClock());
+ result += F(", On Timer: ");
+ if (isOnTimerEnabled())
+ result += timeToString(getOnTimer());
+ else
+ result += F("Off");
+ result += F(", Off Timer: ");
+ if (isOffTimerEnabled())
+ result += timeToString(getOffTimer());
+ else
+ result += F("Off");
+ result += F(", Sleep: ");
+ if (getSleep())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Super: ");
+ if (getSuper())
+ result += F("On");
+ else
+ result += F("Off");
+ result += F(", Command: ");
+ result += uint64ToString(getCommand());
+ switch (getCommand()) {
+ case kWhirlpoolAcCommandLight:
+ result += F(" (LIGHT)");
+ break;
+ case kWhirlpoolAcCommandPower:
+ result += F(" (POWER)");
+ break;
+ case kWhirlpoolAcCommandTemp:
+ result += F(" (TEMP)");
+ break;
+ case kWhirlpoolAcCommandSleep:
+ result += F(" (SLEEP)");
+ break;
+ case kWhirlpoolAcCommandSuper:
+ result += F(" (SUPER)");
+ break;
+ case kWhirlpoolAcCommandOnTimer:
+ result += F(" (ONTIMER)");
+ break;
+ case kWhirlpoolAcCommandMode:
+ result += F(" (MODE)");
+ break;
+ case kWhirlpoolAcCommandSwing:
+ result += F(" (SWING)");
+ break;
+ case kWhirlpoolAcCommandIFeel:
+ result += F(" (IFEEL)");
+ break;
+ case kWhirlpoolAcCommandFanSpeed:
+ result += F(" (FANSPEED)");
+ break;
+ case kWhirlpoolAcCommand6thSense:
+ result += F(" (6THSENSE)");
+ break;
+ case kWhirlpoolAcCommandOffTimer:
+ result += F(" (OFFTIMER)");
+ break;
+ default:
+ result += F(" (UNKNOWN)");
+ break;
+ }
+ return result;
+}
+
+#if DECODE_WHIRLPOOL_AC
+// Decode the supplied Whirlpool A/C message.
+//
+// Args:
+// results: Ptr to the data to decode and where to store the decode result.
+// nbits: The number of data bits to expect. Typically kWhirlpoolAcBits
+// strict: Flag indicating if we should perform strict matching.
+// Returns:
+// boolean: True if it can decode it, false if it can't.
+//
+// Status: STABLE / Working as intended.
+//
+//
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/509
+bool IRrecv::decodeWhirlpoolAC(decode_results *results, uint16_t nbits,
+ bool strict) {
+ if (results->rawlen < 2 * nbits + 4 + kHeader + kFooter - 1)
+ return false; // Can't possibly be a valid Whirlpool A/C message.
+ if (strict) {
+ if (nbits != kWhirlpoolAcBits) return false;
+ }
+
+ uint16_t offset = kStartOffset;
+ uint16_t dataBitsSoFar = 0;
+ uint16_t i = 0;
+ match_result_t data_result;
+ uint8_t sectionSize[kWhirlpoolAcSections] = {6, 8, 7};
+
+ // Header
+ if (!matchMark(results->rawbuf[offset++], kWhirlpoolAcHdrMark)) return false;
+ if (!matchSpace(results->rawbuf[offset++], kWhirlpoolAcHdrSpace))
+ return false;
+
+ // Data Section
+ // Keep reading bytes until we either run out of section or state to fill.
+ for (uint8_t section = 0, pos = 0; section < kWhirlpoolAcSections;
+ section++) {
+ pos += sectionSize[section];
+ for (; offset <= results->rawlen - 16 && i < pos;
+ i++, dataBitsSoFar += 8, offset += data_result.used) {
+ data_result =
+ matchData(&(results->rawbuf[offset]), 8, kWhirlpoolAcBitMark,
+ kWhirlpoolAcOneSpace, kWhirlpoolAcBitMark,
+ kWhirlpoolAcZeroSpace, kTolerance, kMarkExcess, false);
+ if (data_result.success == false) break; // Fail
+ // Data is in LSB order. We need to reverse it.
+ results->state[i] = (uint8_t)data_result.data;
+ }
+ // Section Footer
+ if (!matchMark(results->rawbuf[offset++], kWhirlpoolAcBitMark))
+ return false;
+ if (section < kWhirlpoolAcSections - 1) { // Inter-section gaps.
+ if (!matchSpace(results->rawbuf[offset++], kWhirlpoolAcGap)) return false;
+ } else { // Last section / End of message gap.
+ if (offset <= results->rawlen &&
+ !matchAtLeast(results->rawbuf[offset++], kWhirlpoolAcGap))
+ return false;
+ }
+ }
+
+ // Compliance
+ if (strict) {
+ // Re-check we got the correct size/length due to the way we read the data.
+ if (dataBitsSoFar != kWhirlpoolAcBits) return false;
+ if (!IRWhirlpoolAc::validChecksum(results->state, dataBitsSoFar / 8))
+ return false;
+ }
+
+ // Success
+ results->decode_type = WHIRLPOOL_AC;
+ results->bits = dataBitsSoFar;
+ // No need to record the state as we stored it as we decoded it.
+ // As we use result->state, we don't record value, address, or command as it
+ // is a union data type.
+ return true;
+}
+#endif // WHIRLPOOL_AC
diff --git a/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.h b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.h
new file mode 100644
index 000000000000..9604d025c594
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/src/ir_Whirlpool.h
@@ -0,0 +1,167 @@
+// Whirlpool A/C
+//
+// Copyright 2018 David Conran
+
+#ifndef IR_WHIRLPOOL_H_
+#define IR_WHIRLPOOL_H_
+
+#define __STDC_LIMIT_MACROS
+#include
+#ifndef UNIT_TEST
+#include
+#else
+#include
+#endif
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#ifdef UNIT_TEST
+#include "IRsend_test.h"
+#endif
+
+// WW WW HH HH IIIII RRRRRR LL PPPPPP OOOOO OOOOO LL
+// WW WW HH HH III RR RR LL PP PP OO OO OO OO LL
+// WW W WW HHHHHHH III RRRRRR LL PPPPPP OO OO OO OO LL
+// WW WWW WW HH HH III RR RR LL PP OO OO OO OO LL
+// WW WW HH HH IIIII RR RR LLLLLLL PP OOOO0 OOOO0 LLLLLLL
+
+// Ref:
+// https://github.com/markszabo/IRremoteESP8266/issues/509
+
+// Constants
+const uint8_t kWhirlpoolAcChecksumByte1 = 13;
+const uint8_t kWhirlpoolAcChecksumByte2 = kWhirlpoolAcStateLength - 1;
+const uint8_t kWhirlpoolAcHeat = 0;
+const uint8_t kWhirlpoolAcAuto = 1;
+const uint8_t kWhirlpoolAcCool = 2;
+const uint8_t kWhirlpoolAcDry = 3;
+const uint8_t kWhirlpoolAcFan = 4;
+const uint8_t kWhirlpoolAcModeMask = 0b00000111;
+const uint8_t kWhirlpoolAcModePos = 3;
+const uint8_t kWhirlpoolAcFanAuto = 0;
+const uint8_t kWhirlpoolAcFanHigh = 1;
+const uint8_t kWhirlpoolAcFanMedium = 2;
+const uint8_t kWhirlpoolAcFanLow = 3;
+const uint8_t kWhirlpoolAcFanMask = 0b00000011;
+const uint8_t kWhirlpoolAcFanPos = 2;
+const uint8_t kWhirlpoolAcMinTemp = 18; // 18C (DG11J1-3A), 16C (DG11J1-91)
+const uint8_t kWhirlpoolAcMaxTemp = 32; // 32C (DG11J1-3A), 30C (DG11J1-91)
+const uint8_t kWhirlpoolAcAutoTemp = 23; // 23C
+const uint8_t kWhirlpoolAcTempMask = 0b11110000;
+const uint8_t kWhirlpoolAcTempPos = 3;
+const uint8_t kWhirlpoolAcSwing1Mask = 0b10000000;
+const uint8_t kWhirlpoolAcSwing2Mask = 0b01000000;
+const uint8_t kWhirlpoolAcLightMask = 0b00100000;
+const uint8_t kWhirlpoolAcPowerToggleMask = 0b00000100;
+const uint8_t kWhirlpoolAcPowerTogglePos = 2;
+const uint8_t kWhirlpoolAcSleepMask = 0b00001000;
+const uint8_t kWhirlpoolAcSleepPos = 2;
+const uint8_t kWhirlpoolAcSuperMask = 0b10010000;
+const uint8_t kWhirlpoolAcSuperPos = 5;
+const uint8_t kWhirlpoolAcHourMask = 0b00011111;
+const uint8_t kWhirlpoolAcMinuteMask = 0b00111111;
+const uint8_t kWhirlpoolAcTimerEnableMask = 0b10000000;
+const uint8_t kWhirlpoolAcClockPos = 6;
+const uint8_t kWhirlpoolAcOffTimerPos = 8;
+const uint8_t kWhirlpoolAcOnTimerPos = 10;
+const uint8_t kWhirlpoolAcCommandPos = 15;
+const uint8_t kWhirlpoolAcCommandLight = 0x00;
+const uint8_t kWhirlpoolAcCommandPower = 0x01;
+const uint8_t kWhirlpoolAcCommandTemp = 0x02;
+const uint8_t kWhirlpoolAcCommandSleep = 0x03;
+const uint8_t kWhirlpoolAcCommandSuper = 0x04;
+const uint8_t kWhirlpoolAcCommandOnTimer = 0x05;
+const uint8_t kWhirlpoolAcCommandMode = 0x06;
+const uint8_t kWhirlpoolAcCommandSwing = 0x07;
+const uint8_t kWhirlpoolAcCommandIFeel = 0x0D;
+const uint8_t kWhirlpoolAcCommandFanSpeed = 0x11;
+const uint8_t kWhirlpoolAcCommand6thSense = 0x17;
+const uint8_t kWhirlpoolAcCommandOffTimer = 0x1D;
+const uint8_t kWhirlpoolAcAltTempMask = 0b00001000;
+const uint8_t kWhirlpoolAcAltTempPos = 18;
+
+enum whirlpool_ac_remote_model_t {
+ DG11J13A = 1, // DG11J1-04 too
+ DG11J191,
+};
+
+// Classes
+class IRWhirlpoolAc {
+ public:
+ explicit IRWhirlpoolAc(uint16_t pin);
+
+ void stateReset();
+#if SEND_WHIRLPOOL_AC
+ void send(const uint16_t repeat = kWhirlpoolAcDefaultRepeat,
+ const bool calcchecksum = true);
+#endif // SEND_WHIRLPOOL_AC
+ void begin();
+ void on();
+ void off();
+ void setPowerToggle(const bool on);
+ bool getPowerToggle();
+ void setSleep(const bool on);
+ bool getSleep();
+ void setSuper(const bool on);
+ bool getSuper();
+ void setTemp(const uint8_t temp);
+ uint8_t getTemp();
+ void setFan(const uint8_t speed);
+ uint8_t getFan();
+ void setMode(const uint8_t mode);
+ uint8_t getMode();
+ void setSwing(const bool on);
+ bool getSwing();
+ void setLight(const bool on);
+ bool getLight();
+ uint16_t getClock();
+ void setClock(const uint16_t minspastmidnight);
+ uint16_t getOnTimer();
+ void setOnTimer(const uint16_t minspastmidnight);
+ void enableOnTimer(const bool state);
+ bool isOnTimerEnabled();
+ uint16_t getOffTimer();
+ void setOffTimer(const uint16_t minspastmidnight);
+ void enableOffTimer(const bool state);
+ bool isOffTimerEnabled();
+ void setCommand(const uint8_t code);
+ uint8_t getCommand();
+ whirlpool_ac_remote_model_t getModel();
+ void setModel(const whirlpool_ac_remote_model_t model);
+ uint8_t* getRaw(const bool calcchecksum = true);
+ void setRaw(const uint8_t new_code[],
+ const uint16_t length = kWhirlpoolAcStateLength);
+ static bool validChecksum(uint8_t state[],
+ const uint16_t length = kWhirlpoolAcStateLength);
+ uint8_t convertMode(const stdAc::opmode_t mode);
+ uint8_t convertFan(const stdAc::fanspeed_t speed);
+#ifdef ARDUINO
+ String toString();
+#else
+ std::string toString();
+#endif
+#ifndef UNIT_TEST
+
+ private:
+ IRsend _irsend;
+#else
+ IRsendTest _irsend;
+#endif
+ // The state of the IR remote in IR code form.
+ uint8_t remote_state[kWhirlpoolAcStateLength];
+ uint8_t _desiredtemp;
+ void checksum(const uint16_t length = kWhirlpoolAcStateLength);
+ uint16_t getTime(const uint16_t pos);
+ void setTime(const uint16_t pos, const uint16_t minspastmidnight);
+ bool isTimerEnabled(const uint16_t pos);
+ void enableTimer(const uint16_t pos, const bool state);
+ void _setTemp(const uint8_t temp, const bool remember = true);
+ void _setMode(const uint8_t mode);
+ int8_t getTempOffset();
+#ifdef ARDUINO
+ String timeToString(uint16_t minspastmidnight);
+#else
+ std::string timeToString(uint16_t minspastmidnight);
+#endif
+};
+
+#endif // IR_WHIRLPOOL_H_
diff --git a/lib/IRremoteESP8266-2.5.2.03/src/ir_Whynter.cpp b/lib/IRremoteESP8266-2.6.0/src/ir_Whynter.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/src/ir_Whynter.cpp
rename to lib/IRremoteESP8266-2.6.0/src/ir_Whynter.cpp
diff --git a/lib/IRremoteESP8266-2.6.0/test/IRac_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRac_test.cpp
new file mode 100644
index 000000000000..39c17a84b470
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/IRac_test.cpp
@@ -0,0 +1,865 @@
+// Copyright 2019 David Conran
+
+#include "ir_Argo.h"
+#include "ir_Daikin.h"
+#include "ir_Fujitsu.h"
+#include "ir_Gree.h"
+#include "ir_Haier.h"
+#include "ir_Hitachi.h"
+#include "ir_Kelvinator.h"
+#include "ir_Midea.h"
+#include "ir_Mitsubishi.h"
+#include "ir_MitsubishiHeavy.h"
+#include "ir_Panasonic.h"
+#include "ir_Samsung.h"
+#include "ir_Tcl.h"
+#include "ir_Teco.h"
+#include "ir_Toshiba.h"
+#include "ir_Trotec.h"
+#include "ir_Vestel.h"
+#include "ir_Whirlpool.h"
+#include "IRac.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for IRac class.
+
+TEST(TestIRac, Argo) {
+ IRArgoAC ac(0);
+ IRac irac(0);
+
+ ac.begin();
+ irac.argo(&ac,
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kHigh, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ false, // Turbo
+ -1); // Sleep
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_EQ(1, ac.getMode());
+ EXPECT_EQ(21, ac.getTemp());
+ EXPECT_EQ(kArgoFlapAuto, ac.getFlap());
+ EXPECT_FALSE(ac.getMax()); // Turbo
+ EXPECT_FALSE(ac.getNight()); // Sleep
+}
+
+TEST(TestIRac, Coolix) {
+ IRCoolixAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 3 (HEAT), Fan: 1 (MAX), Temp: 21C, Zone Follow: Off, "
+ "Sensor Temp: Ignored";
+
+ ac.begin();
+ irac.coolix(&ac,
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kHigh, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Turbo
+ false, // Light
+ false, // Clean
+ -1); // Sleep
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(COOLIX, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kCoolixBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.value);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Daikin) {
+ IRDaikinESP ac(0);
+ IRac irac(0);
+ char expected[] =
+ "Power: On, Mode: 3 (COOL), Temp: 19C, Fan: 2, Powerful: Off, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: On, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 0:00, On Time: Off, Off Time: Off";
+
+ ac.begin();
+ irac.daikin(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Quiet
+ false, // Turbo
+ true, // Filter
+ true); // Clean
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Daikin2) {
+ IRDaikin2 ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 3 (COOL), Temp: 19C, Fan: 2, Swing (V): 14 (Auto), "
+ "Swing (H): 0, Clock: 0:00, On Time: Off, Off Time: Off, "
+ "Sleep Time: Off, Beep: 1 (Quiet), Light: 1 (Bright), Mold: On, "
+ "Clean: Off, Fresh Air: Off, Eye: Off, Eye Auto: Off, Quiet: Off, "
+ "Powerful: Off, Purify: On, Econo: Off";
+
+ ac.begin();
+ irac.daikin2(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Quiet
+ false, // Turbo
+ true, // Light
+ false, // Econo
+ true, // Filter
+ true, // Clean (aka Mold)
+ -1, // Sleep time
+ -1); // Current time
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin2Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Daikin216) {
+ IRDaikin216 ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 4 (HEAT), Temp: 31C, Fan: 11 (QUIET), "
+ "Swing (Horizontal): On, Swing (Vertical): On, Quiet: On";
+
+ ac.begin();
+ irac.daikin216(&ac,
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 31, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ stdAc::swingh_t::kLeft, // Horizontal swing
+ true); // Quiet
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(DAIKIN216, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin216Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Fujitsu) {
+ IRFujitsuAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 2 (MED), "
+ "Swing: Off, Command: N/A";
+
+ ac.begin();
+ irac.fujitsu(&ac,
+ ARDB1, // Model
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false); // Quiet
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kFujitsuAcBits - 8, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state, ac._irsend.capture.bits / 8);
+ ASSERT_EQ(expected, ac.toString());
+
+ ac._irsend.reset();
+ irac.fujitsu(&ac,
+ ARRAH2E, // Model
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false); // Quiet
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state, ac._irsend.capture.bits / 8);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Gree) {
+ IRGreeAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (COOL), Temp: 22C, Fan: 2, Turbo: Off, XFan: On, "
+ "Light: On, Sleep: On, Swing Vertical Mode: Manual, "
+ "Swing Vertical Pos: 3";
+
+ ac.begin();
+ irac.gree(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Light
+ true, // Clean (aka Mold/XFan)
+ 8 * 60 + 0); // Sleep time
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(GREE, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kGreeBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Haier) {
+ IRHaierAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Command: 1 (On), Mode: 3 (HEAT), Temp: 24C, Fan: 2, Swing: 1 (Up), "
+ "Sleep: On, Health: On, Current Time: 13:45, On Timer: Off, "
+ "Off Timer: Off";
+
+ ac.begin();
+ irac.haier(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 24, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ true, // Filter
+ 8 * 60 + 0, // Sleep time
+ 13 * 60 + 45); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+
+TEST(TestIRac, HaierYrwo2) {
+ IRHaierACYRW02 ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Button: 5 (Power), Mode: 2 (Cool), Temp: 23C, Fan: 4 (Med), "
+ "Turbo: 1 (High), Swing: 1 (Top), Sleep: On, Health: On";
+
+ ac.begin();
+ irac.haierYrwo2(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 23, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ true, // Turbo
+ true, // Filter
+ 8 * 60 + 0); // Sleep time
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC_YRW02, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHaierACYRW02Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Hitachi) {
+ IRHitachiAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 2 (AUTO), Temp: 22C, Fan: 3 (UNKNOWN), "
+ "Swing (Vertical): Off, Swing (Horizontal): On";
+
+ ac.begin();
+ irac.hitachi(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kAuto); // Horizontal swing
+
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(HITACHI_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kHitachiAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Kelvinator) {
+ IRKelvinatorAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 3, Turbo: Off, Quiet: Off, "
+ "XFan: On, IonFilter: On, Light: On, Swing (Horizontal): Off, "
+ "Swing (Vertical): Off";
+
+ ac.begin();
+ irac.kelvinator(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 19, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Quiet
+ false, // Turbo
+ true, // Light
+ true, // Filter
+ true); // Clean
+
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(KELVINATOR, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kKelvinatorBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Midea) {
+ IRMideaAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (DRY), Temp: 27C/81F, Fan: 2 (MED), Sleep: On";
+
+ ac.begin();
+ irac.midea(&ac,
+ true, // Power
+ stdAc::opmode_t::kDry, // Mode
+ 27, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ 8 * 60 + 0); // Sleep time
+
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MIDEA, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMideaBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.value);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Mitsubishi) {
+ IRMitsubishiAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On (COOL), Temp: 20C, FAN: 2, VANE: AUTO, Time: 14:30, "
+ "On timer: 00:00, Off timer: 00:00, Timer: -";
+
+ ac.begin();
+ irac.mitsubishi(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 20, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ false, // Silent
+ 14 * 60 + 35); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MITSUBISHI_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiACBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, MitsubishiHeavy88) {
+ IRMitsubishiHeavy88Ac ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 3 (Med), "
+ "Swing (V): 16 (Auto), Swing (H): 0 (Off), Turbo: Off, Econo: Off, "
+ "3D: Off, Clean: On";
+
+ ac.begin();
+ irac.mitsubishiHeavy88(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ stdAc::swingh_t::kOff, // Horizontal swing
+ false, // Turbo
+ false, // Econo
+ true); // Clean
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_88, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy88Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, MitsubishiHeavy152) {
+ IRMitsubishiHeavy152Ac ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 6 (Econo), "
+ "Swing (V): 6 (Off), Swing (H): 0 (Auto), Silent: On, Turbo: Off, "
+ "Econo: On, Night: On, Filter: On, 3D: Off, Clean: Off";
+
+ ac.begin();
+ irac.mitsubishiHeavy152(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 20, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kAuto, // Horizontal swing
+ true, // Silent
+ false, // Turbo
+ true, // Econo
+ true, // Filter
+ false, // Clean
+ 8 * 60); // Sleep
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Panasonic) {
+ IRPanasonicAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected_nke[] =
+ "Model: 2 (NKE), Power: On, Mode: 4 (HEAT), Temp: 28C, Fan: 2 (UNKNOWN), "
+ "Swing (Vertical): 15 (AUTO), Swing (Horizontal): 6 (Middle), Quiet: On, "
+ "Powerful: Off, Clock: 19:17, On Timer: Off, Off Timer: Off";
+
+ ac.begin();
+ irac.panasonic(&ac,
+ kPanasonicNke, // Model
+ true, // Power
+ stdAc::opmode_t::kHeat, // Mode
+ 28, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ stdAc::swingh_t::kLeft, // Horizontal swing
+ true, // Quiet
+ false, // Turbo
+ 19 * 60 + 17); // Clock
+ ASSERT_EQ(expected_nke, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(PANASONIC_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected_nke, ac.toString());
+
+ char expected_dke[] =
+ "Model: 3 (DKE), Power: On, Mode: 3 (COOL), Temp: 18C, Fan: 4 (MAX), "
+ "Swing (Vertical): 1 (Full Up), Swing (Horizontal): 6 (Middle), "
+ "Quiet: Off, Powerful: On, Clock: 19:17, On Timer: Off, Off Timer: Off";
+ ac._irsend.reset();
+ irac.panasonic(&ac,
+ kPanasonicDke, // Model
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 18, // Celsius
+ stdAc::fanspeed_t::kMax, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ stdAc::swingh_t::kMiddle, // Horizontal swing
+ false, // Quiet
+ true, // Turbo
+ 19 * 60 + 17); // Clock
+ ASSERT_EQ(expected_dke, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(PANASONIC_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected_dke, ac.toString());
+}
+
+TEST(TestIRac, Samsung) {
+ IRSamsungAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 28C, Fan: 6 (AUTO), Swing: On, "
+ "Beep: On, Clean: On, Quiet: On";
+
+ ac.begin();
+ irac.samsung(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 28, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ true, // Quiet
+ false, // Turbo
+ true, // Clean
+ true, // Beep
+ false); // with the Hack Off
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kSamsungAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+
+ ac._irsend.reset();
+ irac.samsung(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 28, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ true, // Quiet
+ false, // Turbo
+ true, // Clean
+ true, // Beep
+ true); // with the Hack On
+ ASSERT_EQ(expected, ac.toString()); // Class should be in the desired mode.
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ // However, we expect a plain "on" state as it should be sent before the
+ // desired state.
+ char expected_on[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (AUTO), Swing: Off, "
+ "Beep: Off, Clean: Off, Quiet: Off";
+ ASSERT_EQ(expected_on, ac.toString());
+}
+
+TEST(TestIRac, Tcl112) {
+ IRTcl112Ac ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 3 (Med), Econo: On, "
+ "Health: On, Light: On, Turbo: Off, Swing (H): On, Swing (V): Off";
+
+ ac.begin();
+ irac.tcl112(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 20, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kOff, // Veritcal swing
+ stdAc::swingh_t::kAuto, // Horizontal swing
+ false, // Turbo
+ true, // Light
+ true, // Econo
+ true); // Filter (aka. Health)
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Teco) {
+ IRTecoAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 21C, Fan: 2 (Med), Sleep: On, "
+ "Swing: On";
+
+ ac.begin();
+ irac.teco(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ 8 * 60 + 30); // Sleep
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(TECO, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kTecoBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.value);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Toshiba) {
+ IRToshibaAC ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] = "Power: On, Mode: 2 (DRY), Temp: 29C, Fan: 2";
+
+ ac.begin();
+ irac.toshiba(&ac,
+ true, // Power
+ stdAc::opmode_t::kDry, // Mode
+ 29, // Celsius
+ stdAc::fanspeed_t::kLow); // Fan speed
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(TOSHIBA_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kToshibaACBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, Trotec) {
+ IRTrotecESP ac(0);
+ IRac irac(0);
+
+ ac.begin();
+ irac.trotec(&ac,
+ true, // Power
+ stdAc::opmode_t::kCool, // Mode
+ 18, // Celsius
+ stdAc::fanspeed_t::kHigh, // Fan speed
+ 8 * 60 + 17); // Sleep
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_EQ(kTrotecCool, ac.getMode());
+ EXPECT_EQ(18, ac.getTemp());
+ EXPECT_EQ(kTrotecFanHigh, ac.getSpeed());
+ EXPECT_TRUE(ac.getSleep());
+}
+
+TEST(TestIRac, Vestel) {
+ IRVestelAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Power: On, Mode: 0 (AUTO), Temp: 22C, Fan: 5 (LOW), Sleep: On, "
+ "Turbo: Off, Ion: On, Swing: On";
+
+ ac.begin();
+ irac.vestel(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Filter
+ 8 * 60 + 0); // Sleep time
+ // 13 * 60 + 45); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(VESTEL_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+
+ ac._irsend.reset();
+ char expected_clocks[] =
+ "Time: 13:45, Timer: Off, On Timer: Off, Off Timer: Off";
+
+ ac.begin();
+ irac.vestel(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Filter
+ 8 * 60 + 0, // Sleep time
+ 13 * 60 + 45, // Clock
+ false); // Don't send the normal message.
+ // Just for testing purposes.
+ ASSERT_EQ(expected_clocks, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(VESTEL_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected_clocks, ac.toString());
+
+ // Now check it sends both messages during normal operation when the
+ // clock is set.
+ ac._irsend.reset();
+ ac.begin();
+ irac.vestel(&ac,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 22, // Celsius
+ stdAc::fanspeed_t::kLow, // Fan speed
+ stdAc::swingv_t::kHigh, // Veritcal swing
+ false, // Turbo
+ true, // Filter
+ 8 * 60 + 0, // Sleep time
+ 13 * 60 + 45); // Clock
+
+ EXPECT_EQ(
+ "f38000d50"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s1535m520s1535m520s1535m520s1535m520s480m520s1535m520s480m520s1535"
+ "m520s1535m520s1535m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s480m520s1535m520s1535m520s480"
+ "m520s1535m520s480m520s1535m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s1535m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s100000"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s480m520s1535m520s1535m520s480"
+ "m520s1535m520s1535m520s1535m520s1535m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s1535m520s1535"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s1535m520s1535"
+ "m520s480m520s1535m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s100000", ac._irsend.outputStr());
+}
+
+
+TEST(TestIRac, Whirlpool) {
+ IRWhirlpoolAc ac(0);
+ IRac irac(0);
+ IRrecv capture(0);
+ char expected[] =
+ "Model: 1 (DG11J13A), Power toggle: On, Mode: 1 (AUTO), Temp: 21C, "
+ "Fan: 3 (LOW), Swing: On, Light: On, Clock: 23:58, On Timer: Off, "
+ "Off Timer: Off, Sleep: On, Super: Off, Command: 1 (POWER)";
+
+ ac.begin();
+ irac.whirlpool(&ac,
+ DG11J13A,
+ true, // Power
+ stdAc::opmode_t::kAuto, // Mode
+ 21, // Celsius
+ stdAc::fanspeed_t::kMedium, // Fan speed
+ stdAc::swingv_t::kAuto, // Veritcal swing
+ false, // Turbo
+ true, // Light
+ 8 * 60 + 30, // Sleep
+ 23 * 60 + 58); // Clock
+ ASSERT_EQ(expected, ac.toString());
+ ac._irsend.makeDecodeResult();
+ EXPECT_TRUE(capture.decode(&ac._irsend.capture));
+ ASSERT_EQ(WHIRLPOOL_AC, ac._irsend.capture.decode_type);
+ ASSERT_EQ(kWhirlpoolAcBits, ac._irsend.capture.bits);
+ ac.setRaw(ac._irsend.capture.state);
+ ASSERT_EQ(expected, ac.toString());
+}
+
+TEST(TestIRac, strToBool) {
+ EXPECT_TRUE(IRac::strToBool("ON"));
+ EXPECT_TRUE(IRac::strToBool("1"));
+ EXPECT_TRUE(IRac::strToBool("TRUE"));
+ EXPECT_TRUE(IRac::strToBool("YES"));
+ EXPECT_FALSE(IRac::strToBool("OFF"));
+ EXPECT_FALSE(IRac::strToBool("0"));
+ EXPECT_FALSE(IRac::strToBool("FALSE"));
+ EXPECT_FALSE(IRac::strToBool("NO"));
+ EXPECT_FALSE(IRac::strToBool("FOOBAR"));
+ EXPECT_TRUE(IRac::strToBool("FOOBAR", true));
+}
+
+TEST(TestIRac, strToOpmode) {
+ EXPECT_EQ(stdAc::opmode_t::kAuto, IRac::strToOpmode("AUTO"));
+ EXPECT_EQ(stdAc::opmode_t::kCool, IRac::strToOpmode("COOL"));
+ EXPECT_EQ(stdAc::opmode_t::kHeat, IRac::strToOpmode("HEAT"));
+ EXPECT_EQ(stdAc::opmode_t::kDry, IRac::strToOpmode("DRY"));
+ EXPECT_EQ(stdAc::opmode_t::kFan, IRac::strToOpmode("FAN"));
+ EXPECT_EQ(stdAc::opmode_t::kFan, IRac::strToOpmode("FAN_ONLY"));
+ EXPECT_EQ(stdAc::opmode_t::kAuto, IRac::strToOpmode("FOOBAR"));
+ EXPECT_EQ(stdAc::opmode_t::kOff, IRac::strToOpmode("OFF"));
+ EXPECT_EQ(stdAc::opmode_t::kOff, IRac::strToOpmode("FOOBAR",
+ stdAc::opmode_t::kOff));
+}
+
+TEST(TestIRac, strToFanspeed) {
+ EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("AUTO"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMin, IRac::strToFanspeed("MIN"));
+ EXPECT_EQ(stdAc::fanspeed_t::kLow, IRac::strToFanspeed("LOW"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMedium, IRac::strToFanspeed("MEDIUM"));
+ EXPECT_EQ(stdAc::fanspeed_t::kHigh, IRac::strToFanspeed("HIGH"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMax, IRac::strToFanspeed("MAX"));
+ EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("FOOBAR"));
+ EXPECT_EQ(stdAc::fanspeed_t::kMin,
+ IRac::strToFanspeed("FOOBAR", stdAc::fanspeed_t::kMin));
+}
+
+TEST(TestIRac, strToSwingV) {
+ EXPECT_EQ(stdAc::swingv_t::kAuto, IRac::strToSwingV("AUTO"));
+ EXPECT_EQ(stdAc::swingv_t::kLowest, IRac::strToSwingV("LOWEST"));
+ EXPECT_EQ(stdAc::swingv_t::kLow, IRac::strToSwingV("LOW"));
+ EXPECT_EQ(stdAc::swingv_t::kMiddle, IRac::strToSwingV("MIDDLE"));
+ EXPECT_EQ(stdAc::swingv_t::kHigh, IRac::strToSwingV("HIGH"));
+ EXPECT_EQ(stdAc::swingv_t::kHighest, IRac::strToSwingV("HIGHEST"));
+ EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("OFF"));
+ EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("FOOBAR"));
+ EXPECT_EQ(stdAc::swingv_t::kAuto,
+ IRac::strToSwingV("FOOBAR", stdAc::swingv_t::kAuto));
+}
+
+TEST(TestIRac, strToSwingH) {
+ EXPECT_EQ(stdAc::swingh_t::kAuto, IRac::strToSwingH("AUTO"));
+ EXPECT_EQ(stdAc::swingh_t::kLeftMax, IRac::strToSwingH("MAX LEFT"));
+ EXPECT_EQ(stdAc::swingh_t::kLeft, IRac::strToSwingH("LEFT"));
+ EXPECT_EQ(stdAc::swingh_t::kMiddle, IRac::strToSwingH("CENTRE"));
+ EXPECT_EQ(stdAc::swingh_t::kRight, IRac::strToSwingH("RIGHT"));
+ EXPECT_EQ(stdAc::swingh_t::kRightMax, IRac::strToSwingH("RIGHTMAX"));
+ EXPECT_EQ(stdAc::swingh_t::kOff, IRac::strToSwingH("OFF"));
+ EXPECT_EQ(stdAc::swingh_t::kOff, IRac::strToSwingH("FOOBAR"));
+ EXPECT_EQ(stdAc::swingh_t::kAuto,
+ IRac::strToSwingH("FOOBAR", stdAc::swingh_t::kAuto));
+}
+
+TEST(TestIRac, strToModel) {
+ EXPECT_EQ(panasonic_ac_remote_model_t::kPanasonicLke,
+ IRac::strToModel("LKE"));
+ EXPECT_EQ(panasonic_ac_remote_model_t::kPanasonicLke,
+ IRac::strToModel("PANASONICLKE"));
+ EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E,
+ IRac::strToModel("ARRAH2E"));
+ EXPECT_EQ(whirlpool_ac_remote_model_t::DG11J13A,
+ IRac::strToModel("DG11J13A"));
+ EXPECT_EQ(1, IRac::strToModel("1"));
+ EXPECT_EQ(10, IRac::strToModel("10"));
+ EXPECT_EQ(-1, IRac::strToModel("0"));
+ EXPECT_EQ(-1, IRac::strToModel("FOOBAR"));
+ EXPECT_EQ(0, IRac::strToModel("FOOBAR", 0));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRrecv_test.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/IRrecv_test.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.h b/lib/IRremoteESP8266-2.6.0/test/IRrecv_test.h
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRrecv_test.h
rename to lib/IRremoteESP8266-2.6.0/test/IRrecv_test.h
diff --git a/lib/IRremoteESP8266-2.6.0/test/IRsend_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.cpp
new file mode 100644
index 000000000000..ffd69cf71d11
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.cpp
@@ -0,0 +1,686 @@
+// Copyright 2017,2019 David Conran
+
+#include "IRsend_test.h"
+#include "IRsend.h"
+#include "IRutils.h"
+#include "gtest/gtest.h"
+
+// Tests sendData().
+
+// Test sending zero bits.
+TEST(TestSendData, SendZeroBits) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1, 0, true);
+ EXPECT_EQ("", irsend.outputStr());
+}
+
+// Test sending zero and one.
+TEST(TestSendData, SendSingleBit) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ("d50m1s2", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
+ EXPECT_EQ("d50m3s4", irsend.outputStr());
+}
+
+// Test sending bit order.
+TEST(TestSendData, TestingBitSendOrder) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b10, 2, true);
+ EXPECT_EQ("d50m1s2m3s4", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b10, 2, false);
+ EXPECT_EQ("d50m3s4m1s2", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b0001, 4, false);
+ EXPECT_EQ("d50m1s2m3s4m3s4m3s4", irsend.outputStr());
+}
+
+// Test sending typical data.
+TEST(TestSendData, SendTypicalData) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1010110011110000, 16, true);
+ EXPECT_EQ(
+ "d50m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4m3s4",
+ irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0x1234567890ABCDEF, 64, true);
+ EXPECT_EQ(
+ "d50"
+ "m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4"
+ "m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4"
+ "m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2"
+ "m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2",
+ irsend.outputStr());
+}
+
+// Test sending more than expected bits.
+TEST(TestSendData, SendOverLargeData) {
+ IRsendTest irsend(4);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0xFFFFFFFFFFFFFFFF, 70, true);
+ EXPECT_EQ(
+ "d50"
+ "m3s4m3s4m3s4m3s4m3s4m3s4"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
+ "m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2",
+ irsend.outputStr());
+}
+
+// Test inverting the output.
+TEST(TestIRSend, InvertedOutput) {
+ IRsendTest irsend(4, true);
+ irsend.begin();
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ("d50s1m2", irsend.outputStr());
+ irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
+ EXPECT_EQ("d50s3m4", irsend.outputStr());
+}
+
+// Test we correctly pick up frequency changes.
+TEST(TestIRSend, DetectFreqChanges) {
+ IRsendTest irsend(0);
+
+ irsend.begin();
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ(
+ "f40000d50"
+ "m1s2"
+ "f38000"
+ "m1s2"
+ "f40000"
+ "m1s2"
+ "f38000"
+ "m1s2",
+ irsend.outputStr());
+ irsend.reset();
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(40); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ irsend.enableIROut(38); // 40kHz
+ irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
+ EXPECT_EQ(
+ "f40000d50"
+ "m1s2m1s2"
+ "f38000m1s2m1s2",
+ irsend.outputStr());
+}
+
+// Test we correctly pick up duty cycle changes.
+TEST(TestIRSend, DetectDutyChanges) {
+ IRsendTest irsend(0);
+
+ irsend.begin();
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 33);
+ EXPECT_EQ(
+ "f38000d33"
+ "m1s2m3s4m7s8",
+ irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 50);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 33);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 25);
+ EXPECT_EQ(
+ "f38000d50"
+ "m1s2m3s4m7s8"
+ "d33"
+ "m1s2m3s4m7s8"
+ "d25"
+ "m1s2m3s4m7s8",
+ irsend.outputStr());
+}
+
+
+// Test we correctly pick up frequency AND duty changes.
+TEST(TestIRSend, DetectFreqAndDutyChanges) {
+ IRsendTest irsend(0);
+
+ irsend.begin();
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 50);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 38000, true, 0, 33);
+ irsend.sendGeneric(1, 2, 3, 4, 5, 6, 7, 8, 0b1, 1, 40000, true, 0, 25);
+ EXPECT_EQ(
+ "f38000d50"
+ "m1s2m3s4m7s8"
+ "d33"
+ "m1s2m3s4m7s8"
+ "f40000d25"
+ "m1s2m3s4m7s8",
+ irsend.outputStr());
+}
+
+// Test typical use of sendRaw().
+TEST(TestSendRaw, GeneralUse) {
+ IRsendTest irsend(4);
+ IRrecv irrecv(0);
+
+ irsend.begin();
+ // NEC C3E0E0E8 as measured in #204
+ uint16_t rawData[67] = {
+ 8950, 4500, 550, 1650, 600, 1650, 550, 550, 600, 500, 600, 550,
+ 550, 550, 600, 1650, 550, 1650, 600, 1650, 600, 1650, 550, 1700,
+ 550, 550, 600, 550, 550, 550, 600, 500, 600, 550, 550, 1650,
+ 600, 1650, 600, 1650, 550, 550, 600, 500, 600, 500, 600, 550,
+ 550, 550, 600, 1650, 550, 1650, 600, 1650, 600, 500, 650, 1600,
+ 600, 500, 600, 550, 550, 550, 600};
+
+ irsend.sendRaw(rawData, 67, 38);
+ EXPECT_EQ(
+ "f38000d50"
+ "m8950s4500"
+ "m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
+ "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
+ "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
+ "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
+ "m600",
+ irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 67, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, kNECBits, false));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(32, irsend.capture.bits);
+ EXPECT_EQ(0xC3E0E0E8, irsend.capture.value);
+ EXPECT_EQ(
+ "f38000d50"
+ "m8950s4500"
+ "m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
+ "m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
+ "m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
+ "m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
+ "m600",
+ irsend.outputStr());
+}
+
+// Incorrect handling of decodes from Raw. i.e. There is no gap recorded at
+// the end of a command when using the interrupt code. sendRaw() best emulates
+// this for unit testing purposes. sendGC() and sendXXX() will add the trailing
+// gap. Users won't see this in normal use.
+TEST(TestSendRaw, NoTrailingGap) {
+ IRsendTest irsend(4);
+ IRrecv irrecv(4);
+ irsend.begin();
+
+ irsend.reset();
+ uint16_t rawData[67] = {
+ 9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, 600, 1650,
+ 650, 550, 600, 1650, 650, 1650, 650, 1650, 600, 550, 650, 1650,
+ 650, 1650, 650, 550, 600, 1650, 650, 1650, 650, 550, 650, 550,
+ 650, 1650, 650, 550, 650, 550, 650, 550, 600, 550, 650, 550,
+ 650, 550, 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
+ 650, 1650, 650, 1650, 650, 1650, 600};
+ irsend.sendRaw(rawData, 67, 38);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(kNECBits, irsend.capture.bits);
+}
+
+TEST(TestLowLevelSend, MarkFrequencyModulationAt38kHz) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(38000, 50);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]10usecs[Off]11usecs[On]10usecs[Off]11usecs[On]10usecs[Off]11usecs"
+ "[On]10usecs[Off]11usecs[On]10usecs[Off]6usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 33);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]6usecs[Off]15usecs[On]6usecs[Off]15usecs[On]6usecs[Off]15usecs"
+ "[On]6usecs[Off]15usecs[On]6usecs[Off]10usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 100);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, MarkFrequencyModulationAt36_7kHz) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(36700, 50);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]11usecs[Off]11usecs[On]11usecs[Off]11usecs[On]11usecs[Off]11usecs"
+ "[On]11usecs[Off]11usecs[On]11usecs[Off]1usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 33);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]7usecs[Off]15usecs[On]7usecs[Off]15usecs[On]7usecs[Off]15usecs"
+ "[On]7usecs[Off]15usecs[On]7usecs[Off]5usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 100);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, MarkFrequencyModulationAt40kHz) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(40000, 50);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs"
+ "[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 33);
+ EXPECT_EQ(5, irsend.mark(100));
+ EXPECT_EQ(
+ "[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs"
+ "[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs",
+ irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 100);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, MarkNoModulation) {
+ IRsendLowLevelTest irsend(0, false, false);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(38000, 50);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 25);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 75);
+ EXPECT_EQ(1, irsend.mark(1000));
+ EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, SpaceFrequencyModulation) {
+ IRsendLowLevelTest irsend(0);
+
+ irsend.reset();
+ irsend.enableIROut(38000);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 75);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 100);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(38000, 33);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+}
+
+TEST(TestLowLevelSend, SpaceNoModulation) {
+ IRsendLowLevelTest irsend(0, false, false);
+
+ irsend.begin();
+
+ irsend.reset();
+ irsend.enableIROut(38000, 50);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(36700, 25);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+
+ irsend.reset();
+ irsend.enableIROut(40000, 75);
+ irsend.space(1000);
+ EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
+}
+
+// Test expected to work/produce a message for irsend:send()
+TEST(TestSend, GenericSimpleSendMethod) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(AIWA_RC_T501, 0x1234, kAiwaRcT501Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
+ EXPECT_EQ(kAiwaRcT501Bits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(CARRIER_AC, 0x1234, kCarrierAcBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(CARRIER_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kCarrierAcBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(COOLIX, 0x1234, kCoolixBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(COOLIX, irsend.capture.decode_type);
+ EXPECT_EQ(kCoolixBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(DENON, 0x1234, kDenonBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(DENON, irsend.capture.decode_type);
+ EXPECT_EQ(kDenonBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(DISH, 0x1234, kDishBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(DISH, irsend.capture.decode_type);
+ EXPECT_EQ(kDishBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(GICABLE, 0x1234, kGicableBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(GICABLE, irsend.capture.decode_type);
+ EXPECT_EQ(kGicableBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(GREE, 0x0009205000200050, kGreeBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(GREE, irsend.capture.decode_type);
+ EXPECT_EQ(kGreeBits, irsend.capture.bits);
+ // No simple value test for gree as it decodes to an Array.
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(JVC, 0x1234, kJvcBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(JVC, irsend.capture.decode_type);
+ EXPECT_EQ(kJvcBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LASERTAG, 0x123, kLasertagBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LASERTAG, irsend.capture.decode_type);
+ EXPECT_EQ(kLasertagBits, irsend.capture.bits);
+ EXPECT_EQ(0x123, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LG, 0x700992, kLgBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(kLgBits, irsend.capture.bits);
+ EXPECT_EQ(0x700992, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LG, 0x700992, kLg32Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(kLg32Bits, irsend.capture.bits);
+ EXPECT_EQ(0x700992, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LG2, 0x880094D, kLgBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG2, irsend.capture.decode_type);
+ EXPECT_EQ(kLgBits, irsend.capture.bits);
+ EXPECT_EQ(0x880094D, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(LUTRON, 0x1234, kLutronBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LUTRON, irsend.capture.decode_type);
+ EXPECT_EQ(kLutronBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MAGIQUEST, 0x560F40020455, kMagiquestBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MAGIQUEST, irsend.capture.decode_type);
+ EXPECT_EQ(kMagiquestBits, irsend.capture.bits);
+ EXPECT_EQ(0x560F40020455, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MIDEA, 0xA18263FFFF6E, kMideaBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MIDEA, irsend.capture.decode_type);
+ EXPECT_EQ(kMideaBits, irsend.capture.bits);
+ EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MITSUBISHI, 0x1234, kMitsubishiBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
+ EXPECT_EQ(kMitsubishiBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(MITSUBISHI2, 0x1234, kMitsubishiBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(MITSUBISHI2, irsend.capture.decode_type);
+ EXPECT_EQ(kMitsubishiBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(NIKAI, 0x1234, kNikaiBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NIKAI, irsend.capture.decode_type);
+ EXPECT_EQ(kNikaiBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(NEC, 0x4BB640BF, kNECBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(kNECBits, irsend.capture.bits);
+ EXPECT_EQ(0x4BB640BF, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(NEC_LIKE, 0x12345678, kNECBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NEC_LIKE, irsend.capture.decode_type);
+ EXPECT_EQ(kNECBits, irsend.capture.bits);
+ EXPECT_EQ(0x12345678, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(PANASONIC, 0x40040190ED7C, kPanasonicBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
+ EXPECT_EQ(kPanasonicBits, irsend.capture.bits);
+ EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(PIONEER, 0x659A05FAF50AC53A, kPioneerBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(PIONEER, irsend.capture.decode_type);
+ EXPECT_EQ(kPioneerBits, irsend.capture.bits);
+ EXPECT_EQ(0x659A05FAF50AC53A, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(RC5, 0x175, kRC5Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(RC5, irsend.capture.decode_type);
+ EXPECT_EQ(kRC5Bits, irsend.capture.bits);
+ EXPECT_EQ(0x175, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(RC6, 0xC800F740C, kRC6_36Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(RC6, irsend.capture.decode_type);
+ EXPECT_EQ(kRC6_36Bits, irsend.capture.bits);
+ EXPECT_EQ(0xC800F740C, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(RCMM, 0x1234, kRCMMBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(RCMM, irsend.capture.decode_type);
+ EXPECT_EQ(kRCMMBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SAMSUNG, 0xE0E09966, kSamsungBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SAMSUNG, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsungBits, irsend.capture.bits);
+ EXPECT_EQ(0xE0E09966, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SAMSUNG36, 0x1234, kSamsung36Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SANYO_LC7461, 0x2468DCB56A9, kSanyoLC7461Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type);
+ EXPECT_EQ(kSanyoLC7461Bits, irsend.capture.bits);
+ EXPECT_EQ(0x2468DCB56A9, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SHARP, 0x7266, kSharpBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SHARP, irsend.capture.decode_type);
+ EXPECT_EQ(kSharpBits, irsend.capture.bits);
+ EXPECT_EQ(0x7266, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SHERWOOD, 0x4BB640BF, kSherwoodBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(NEC, irsend.capture.decode_type);
+ EXPECT_EQ(kSherwoodBits, irsend.capture.bits);
+ EXPECT_EQ(0x4BB640BF, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(SONY, 0x1234, kSony20Bits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(SONY, irsend.capture.decode_type);
+ EXPECT_EQ(kSony20Bits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(TECO, 0x1234, kTecoBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(VESTEL_AC, 0xF4410001FF1201, kVestelAcBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kVestelAcBits, irsend.capture.bits);
+ EXPECT_EQ(0xF4410001FF1201, irsend.capture.value);
+
+ irsend.reset();
+ ASSERT_TRUE(irsend.send(WHYNTER, 0x1234, kWhynterBits));
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(WHYNTER, irsend.capture.decode_type);
+ EXPECT_EQ(kWhynterBits, irsend.capture.bits);
+ EXPECT_EQ(0x1234, irsend.capture.value);
+}
+
+// Test some expected types to NOT work/produce a message via irsend:send()
+TEST(TestSend, GenericSimpleSendMethodFailure) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // Check nothing is sent for unexpected protocols
+ irsend.reset();
+ ASSERT_FALSE(irsend.send(KELVINATOR, 0x1234, kKelvinatorBits));
+ irsend.makeDecodeResult();
+ ASSERT_FALSE(irrecv.decode(&irsend.capture));
+
+ // For every A/C protocol which decodes to having a state[].
+ for (int i = 0; i < 200; i++) {
+ if (hasACState((decode_type_t)i) && i != GREE) { // Gree is an exception.
+ // Check it fails.
+ ASSERT_FALSE(irsend.send((decode_type_t)i, 0, 0));
+ }
+ }
+
+ // Test some other special cases.
+ ASSERT_FALSE(irsend.send(UNKNOWN, 0, 0));
+ ASSERT_FALSE(irsend.send(UNUSED, 0, 0));
+ ASSERT_FALSE(irsend.send(RAW, 0, 0));
+ ASSERT_FALSE(irsend.send(PRONTO, 0, 0));
+ ASSERT_FALSE(irsend.send(GLOBALCACHE, 0, 0));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRsend_test.h b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.h
similarity index 82%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRsend_test.h
rename to lib/IRremoteESP8266-2.6.0/test/IRsend_test.h
index 6d9fe51b81ee..f434094332ee 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/IRsend_test.h
+++ b/lib/IRremoteESP8266-2.6.0/test/IRsend_test.h
@@ -17,12 +17,14 @@
#ifdef UNIT_TEST
// Used to help simulate elapsed time in unit tests.
-uint32_t _IRtimer_unittest_now = 0;
+extern uint32_t _IRtimer_unittest_now;
#endif // UNIT_TEST
class IRsendTest : public IRsend {
public:
uint32_t output[OUTPUT_BUF];
+ uint32_t freq[OUTPUT_BUF];
+ uint8_t duty[OUTPUT_BUF];
uint16_t last;
uint16_t rawbuf[RAW_BUF];
decode_results capture;
@@ -40,8 +42,22 @@ class IRsendTest : public IRsend {
std::string outputStr() {
std::stringstream result;
+ uint8_t lastduty = UINT8_MAX; // An impossible duty cycle value.
+ uint32_t lastfreq = 0; // An impossible frequency value.
if (last == 0 && output[0] == 0) return "";
for (uint16_t i = 0; i <= last; i++) {
+ // Display the frequency only if it changes.
+ if (freq[i] != lastfreq) {
+ result << "f";
+ result << freq[i];
+ lastfreq = freq[i];
+ }
+ // Display the duty cycle only if it changes.
+ if (duty[i] != lastduty) {
+ result << "d";
+ result << static_cast(duty[i]);
+ lastduty = duty[i];
+ }
if ((i & 1) != outputOff) // Odd XOR outputOff
result << "s";
else
@@ -92,6 +108,8 @@ class IRsendTest : public IRsend {
output[++last] = usec;
else
output[last] += usec;
+ duty[last] = _dutycycle;
+ freq[last] = _freq_unittest;
return 0;
}
@@ -103,6 +121,8 @@ class IRsendTest : public IRsend {
} else {
output[++last] = time;
}
+ duty[last] = _dutycycle;
+ freq[last] = _freq_unittest;
}
};
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.6.0/test/IRutils_test.cpp
similarity index 85%
rename from lib/IRremoteESP8266-2.5.2.03/test/IRutils_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/IRutils_test.cpp
index 91cf4725c5c5..4a490764977d 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/IRutils_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/IRutils_test.cpp
@@ -350,3 +350,68 @@ TEST(TestInvertBits, MoreThan64Bits) {
ASSERT_EQ(0xAAAA5555AAAA5555, invertBits(0x5555AAAA5555AAAA, 70));
ASSERT_EQ(0xFFFFFFFFFFFFFFFF, invertBits(0x0, 128));
}
+
+TEST(TestCountBits, Pointer) {
+ uint8_t data[14] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
+
+ ASSERT_EQ(0, countBits(data, 0));
+ ASSERT_EQ(0, countBits(data, 1));
+ ASSERT_EQ(0, countBits(data, 1, true));
+ ASSERT_EQ(8, countBits(data, 1, false));
+ ASSERT_EQ(1, countBits(data, 2));
+ ASSERT_EQ(15, countBits(data, 2, false));
+ ASSERT_EQ(1, countBits(data + 1, 1));
+ ASSERT_EQ(2, countBits(data, 3));
+ ASSERT_EQ(4, countBits(data, 4));
+ ASSERT_EQ(25, countBits(data, 14));
+ ASSERT_EQ(25, countBits(data, 14));
+ ASSERT_EQ(14 * 8, countBits(data, 14, true) + countBits(data, 14, false));
+ ASSERT_EQ(125, countBits(data, 14, true, 100));
+}
+
+TEST(TestCountBits, Integer) {
+ uint64_t data = 0xAAAAAAAAAAAAAAAA;
+
+ ASSERT_EQ(0, countBits(data, 0));
+ ASSERT_EQ(0, countBits(data, 1));
+ ASSERT_EQ(0, countBits(data, 1, true));
+ ASSERT_EQ(1, countBits(data, 1, false));
+ ASSERT_EQ(1, countBits(data, 3));
+ ASSERT_EQ(2, countBits(data, 3, false));
+ ASSERT_EQ(4, countBits(data, 8));
+ ASSERT_EQ(4, countBits(data, 8, false));
+ ASSERT_EQ(32, countBits(data, 64));
+ ASSERT_EQ(32, countBits(data, 64, false));
+
+ data = 0;
+ ASSERT_EQ(0, countBits(data, 1, true));
+ ASSERT_EQ(1, countBits(data, 1, false));
+ ASSERT_EQ(0, countBits(data, 64));
+ ASSERT_EQ(64, countBits(data, 64, false));
+
+ data = 0xFFFFFFFFFFFFFFFF;
+ ASSERT_EQ(1, countBits(data, 1, true));
+ ASSERT_EQ(0, countBits(data, 1, false));
+ ASSERT_EQ(64, countBits(data, 64));
+ ASSERT_EQ(0, countBits(data, 64, false));
+}
+
+TEST(TestStrToDecodeType, strToDecodeType) {
+ EXPECT_EQ(decode_type_t::NEC, strToDecodeType("NEC"));
+ EXPECT_EQ(decode_type_t::KELVINATOR, strToDecodeType("KELVINATOR"));
+ EXPECT_EQ(decode_type_t::UNKNOWN, strToDecodeType("foo"));
+}
+
+TEST(TestUtils, htmlEscape) {
+ EXPECT_EQ("", htmlEscape(""));
+ EXPECT_EQ("No Changes", htmlEscape("No Changes"));
+ EXPECT_EQ("No\tChanges+_%^$@~`\n:\\", htmlEscape("No\tChanges+_%^$@~`\n:\\"));
+ EXPECT_EQ(""With Changes"", htmlEscape("\"With Changes\""));
+ EXPECT_EQ(
+ "';!‐"<>equals;&#{}"
+ "()", htmlEscape("';!-\"<>={}()"));
+ EXPECT_EQ("""", htmlEscape("\"\""));
+ EXPECT_EQ(
+ "";<;&apos;>;&;",
+ htmlEscape(""<'>&"));
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/Makefile b/lib/IRremoteESP8266-2.6.0/test/Makefile
similarity index 71%
rename from lib/IRremoteESP8266-2.5.2.03/test/Makefile
rename to lib/IRremoteESP8266-2.6.0/test/Makefile
index d53014183d92..9a64aaaaa714 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/Makefile
+++ b/lib/IRremoteESP8266-2.6.0/test/Makefile
@@ -16,6 +16,7 @@ GTEST_DIR = ../lib/googletest/googletest
# Where to find user code.
USER_DIR = ../src
+INCLUDES = -I$(USER_DIR) -I.
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
@@ -23,7 +24,7 @@ USER_DIR = ../src
CPPFLAGS += -isystem $(GTEST_DIR)/include -DUNIT_TEST
# Flags passed to the C++ compiler.
-CXXFLAGS += -g -Wall -Wextra -pthread
+CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
@@ -36,7 +37,8 @@ TESTS = IRutils_test IRsend_test ir_NEC_test ir_GlobalCache_test \
ir_Toshiba_test ir_Midea_test ir_Magiquest_test ir_Lasertag_test \
ir_Carrier_test ir_Haier_test ir_Hitachi_test ir_GICable_test \
ir_Whirlpool_test ir_Lutron_test ir_Electra_test ir_Pioneer_test \
- ir_MWM_test
+ ir_MWM_test ir_Vestel_test ir_Teco_test ir_Tcl_test ir_Lego_test IRac_test \
+ ir_MitsubishiHeavy_test
# All Google Test headers. Usually you shouldn't change this
# definition.
@@ -80,7 +82,8 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_Kelvinator.o ir_Daikin.o ir_Gree.o ir_Pronto.o ir_Nikai.o ir_Toshiba.o \
ir_Midea.o ir_Magiquest.o ir_Lasertag.o ir_Carrier.o ir_Haier.o \
ir_Hitachi.o ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o \
- ir_Pioneer.o ir_MWM.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
# All the IR Protocol header files.
PROTOCOLS_H = $(USER_DIR)/ir_Argo.h \
@@ -93,19 +96,24 @@ PROTOCOLS_H = $(USER_DIR)/ir_Argo.h \
$(USER_DIR)/ir_Daikin.h \
$(USER_DIR)/ir_Kelvinator.h \
$(USER_DIR)/ir_Mitsubishi.h \
+ $(USER_DIR)/ir_MitsubishiHeavy.h \
$(USER_DIR)/ir_NEC.h \
$(USER_DIR)/ir_Samsung.h \
$(USER_DIR)/ir_Trotec.h \
$(USER_DIR)/ir_Fujitsu.h \
$(USER_DIR)/ir_LG.h \
- $(USER_DIR)/ir_Panasonic.h
+ $(USER_DIR)/ir_Panasonic.h \
+ $(USER_DIR)/ir_Whirlpool.h \
+ $(USER_DIR)/ir_Vestel.h \
+ $(USER_DIR)/ir_Tcl.h \
+ $(USER_DIR)/ir_Teco.h
# Common object files
-COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o ir_GlobalCache.o \
+COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRac.o ir_GlobalCache.o \
$(PROTOCOLS) gtest_main.a
# Common dependencies
COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \
$(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \
- $(PROTOCOLS_H)
+ $(USER_DIR)/IRac.h $(PROTOCOLS_H)
# Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) IRrecv_test.h IRsend_test.h
@@ -136,7 +144,7 @@ IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteES
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRutils.cpp
IRutils_test.o : IRutils_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRutils_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRutils_test.cpp
IRutils_test : IRutils_test.o ir_NEC.o ir_Nikai.o ir_Toshiba.o $(COMMON_OBJ) gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -148,7 +156,7 @@ IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP82
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRsend.cpp
IRsend_test.o : IRsend_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRsend_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRsend_test.cpp
IRsend_test : IRsend_test.o $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -157,16 +165,25 @@ IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP82
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp
IRrecv_test.o : IRrecv_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRrecv_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRrecv_test.cpp
IRrecv_test : IRrecv_test.o $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+IRac.o : $(USER_DIR)/IRac.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRac.cpp
+
+IRac_test.o : IRac_test.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRac_test.cpp
+
+IRac_test : IRac_test.o $(COMMON_OBJ)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
ir_NEC.o : $(USER_DIR)/ir_NEC.cpp $(USER_DIR)/ir_NEC.h $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_NEC.cpp
ir_NEC_test.o : ir_NEC_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_NEC_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_NEC_test.cpp
ir_NEC_test : $(COMMON_OBJ) ir_NEC_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -175,7 +192,7 @@ ir_GlobalCache.o : $(USER_DIR)/ir_GlobalCache.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GlobalCache.cpp
ir_GlobalCache_test.o : ir_GlobalCache_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_GlobalCache_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_GlobalCache_test.cpp
ir_GlobalCache_test : $(COMMON_OBJ) ir_GlobalCache_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -184,7 +201,7 @@ ir_Sherwood.o : $(USER_DIR)/ir_Sherwood.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sherwood.cpp
ir_Sherwood_test.o : ir_Sherwood_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sherwood_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sherwood_test.cpp
ir_Sherwood_test : $(COMMON_OBJ) ir_Sherwood_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -193,25 +210,25 @@ ir_Sony.o : $(USER_DIR)/ir_Sony.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sony.cpp
ir_Sony_test.o : ir_Sony_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sony_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sony_test.cpp
ir_Sony_test : $(COMMON_OBJ) ir_Sony_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Samsung.cpp
ir_Samsung_test.o : ir_Samsung_test.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Samsung_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Samsung_test.cpp
ir_Samsung_test : $(COMMON_OBJ) ir_Samsung_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Kelvinator.o : $(USER_DIR)/ir_Kelvinator.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Kelvinator.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Kelvinator.cpp
ir_Kelvinator_test.o : ir_Kelvinator_test.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Kelvinator_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Kelvinator_test.cpp
ir_Kelvinator_test : $(COMMON_OBJ) ir_Kelvinator_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -220,7 +237,7 @@ ir_JVC.o : $(USER_DIR)/ir_JVC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_JVC.cpp
ir_JVC_test.o : ir_JVC_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_JVC_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_JVC_test.cpp
ir_JVC_test : $(COMMON_OBJ) ir_JVC_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -229,7 +246,7 @@ ir_RCMM.o : $(USER_DIR)/ir_RCMM.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RCMM.cpp
ir_RCMM_test.o : ir_RCMM_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_RCMM_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_RCMM_test.cpp
ir_RCMM_test : $(COMMON_OBJ) ir_RCMM_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -238,25 +255,34 @@ ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp
ir_LG_test.o : ir_LG_test.cpp $(USER_DIR)/ir_LG.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_LG_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_LG_test.cpp
ir_LG_test : $(COMMON_OBJ) ir_LG_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Mitsubishi.o : $(USER_DIR)/ir_Mitsubishi.h $(USER_DIR)/ir_Mitsubishi.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Mitsubishi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Mitsubishi.cpp
ir_Mitsubishi_test.o : ir_Mitsubishi_test.cpp $(USER_DIR)/ir_Mitsubishi.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Mitsubishi_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Mitsubishi_test.cpp
ir_Mitsubishi_test : $(COMMON_OBJ) ir_Mitsubishi_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+ir_MitsubishiHeavy.o : $(USER_DIR)/ir_MitsubishiHeavy.h $(USER_DIR)/ir_MitsubishiHeavy.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_MitsubishiHeavy.cpp
+
+ir_MitsubishiHeavy_test.o : ir_MitsubishiHeavy_test.cpp $(USER_DIR)/ir_MitsubishiHeavy.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_MitsubishiHeavy_test.cpp
+
+ir_MitsubishiHeavy_test : $(COMMON_OBJ) ir_MitsubishiHeavy_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
ir_Fujitsu.o : $(USER_DIR)/ir_Fujitsu.h $(USER_DIR)/ir_Fujitsu.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Fujitsu.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Fujitsu.cpp
ir_Fujitsu_test.o : ir_Fujitsu_test.cpp $(USER_DIR)/ir_Fujitsu.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Fujitsu_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Fujitsu_test.cpp
ir_Fujitsu_test : $(COMMON_OBJ) ir_Fujitsu_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -265,7 +291,7 @@ ir_Sharp.o : $(USER_DIR)/ir_Sharp.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sharp.cpp
ir_Sharp_test.o : ir_Sharp_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sharp_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sharp_test.cpp
ir_Sharp_test : $(COMMON_OBJ) ir_Sharp_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -274,16 +300,16 @@ ir_RC5_RC6.o : $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RC5_RC6.cpp
ir_RC5_RC6_test.o : ir_RC5_RC6_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_RC5_RC6_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_RC5_RC6_test.cpp
ir_RC5_RC6_test : $(COMMON_OBJ) ir_RC5_RC6_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Panasonic.o : $(USER_DIR)/ir_Panasonic.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Panasonic.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Panasonic.cpp
ir_Panasonic_test.o : ir_Panasonic_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Panasonic_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Panasonic_test.cpp
ir_Panasonic_test : $(COMMON_OBJ) ir_Panasonic_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -292,7 +318,7 @@ ir_Dish.o : $(USER_DIR)/ir_Dish.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Dish.cpp
ir_Dish_test.o : ir_Dish_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Dish_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Dish_test.cpp
ir_Dish_test : $(COMMON_OBJ) ir_Dish_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -301,16 +327,16 @@ ir_Whynter.o : $(USER_DIR)/ir_Whynter.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whynter.cpp
ir_Whynter_test.o : ir_Whynter_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Whynter_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Whynter_test.cpp
ir_Whynter_test : $(COMMON_OBJ) ir_Whynter_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Coolix.o : $(USER_DIR)/ir_Coolix.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Coolix.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Coolix.cpp
ir_Coolix_test.o : ir_Coolix_test.cpp $(USER_DIR)/ir_Coolix.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Coolix_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Coolix_test.cpp
ir_Coolix_test : $(COMMON_OBJ) ir_Coolix_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -319,7 +345,7 @@ ir_Aiwa.o : $(USER_DIR)/ir_Aiwa.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Aiwa.cpp
ir_Aiwa_test.o : ir_Aiwa_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Aiwa_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Aiwa_test.cpp
ir_Aiwa_test : $(COMMON_OBJ) ir_Aiwa_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -328,7 +354,7 @@ ir_Denon.o : $(USER_DIR)/ir_Denon.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Denon.cpp
ir_Denon_test.o : ir_Denon_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Denon_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Denon_test.cpp
ir_Denon_test : $(COMMON_OBJ) ir_Denon_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -337,25 +363,25 @@ ir_Sanyo.o : $(USER_DIR)/ir_Sanyo.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sanyo.cpp
ir_Sanyo_test.o : ir_Sanyo_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sanyo_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Sanyo_test.cpp
ir_Sanyo_test : $(COMMON_OBJ) ir_Sanyo_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Daikin.o : $(USER_DIR)/ir_Daikin.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Daikin.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Daikin.cpp
ir_Daikin_test.o : ir_Daikin_test.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Daikin_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Daikin_test.cpp
ir_Daikin_test : $(COMMON_OBJ) ir_Daikin_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Gree.o : $(USER_DIR)/ir_Gree.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Gree.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Gree.cpp
ir_Gree_test.o : ir_Gree_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Gree_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Gree_test.cpp
ir_Gree_test : $(COMMON_OBJ) ir_Gree_test.o ir_Kelvinator.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -364,7 +390,7 @@ ir_Pronto.o : $(USER_DIR)/ir_Pronto.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pronto.cpp
ir_Pronto_test.o : ir_Pronto_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Pronto_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Pronto_test.cpp
ir_Pronto_test : $(COMMON_OBJ) ir_Pronto_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -373,25 +399,25 @@ ir_Nikai.o : $(USER_DIR)/ir_Nikai.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Nikai.cpp
ir_Nikai_test.o : ir_Nikai_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Nikai_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Nikai_test.cpp
ir_Nikai_test : $(COMMON_OBJ) ir_Nikai_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Toshiba.o : $(USER_DIR)/ir_Toshiba.cpp $(USER_DIR)/ir_Toshiba.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Toshiba.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Toshiba.cpp
ir_Toshiba_test.o : ir_Toshiba_test.cpp $(USER_DIR)/ir_Toshiba.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Toshiba_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Toshiba_test.cpp
ir_Toshiba_test : $(COMMON_OBJ) ir_Toshiba_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Midea.o : $(USER_DIR)/ir_Midea.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Midea.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Midea.cpp
ir_Midea_test.o : ir_Midea_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Midea_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Midea_test.cpp
ir_Midea_test : $(COMMON_OBJ) ir_Midea_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -400,7 +426,7 @@ ir_Magiquest.o : $(USER_DIR)/ir_Magiquest.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Magiquest.cpp
ir_Magiquest_test.o : ir_Magiquest_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Magiquest_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Magiquest_test.cpp
ir_Magiquest_test : $(COMMON_OBJ) ir_Magiquest_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -409,7 +435,7 @@ ir_Lasertag.o : $(USER_DIR)/ir_Lasertag.cpp $(USER_DIR)/ir_RC5_RC6.cpp $(GTEST_H
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lasertag.cpp
ir_Lasertag_test.o : ir_Lasertag_test.cpp $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Lasertag_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Lasertag_test.cpp
ir_Lasertag_test : $(COMMON_OBJ) ir_Lasertag_test.o ir_RC5_RC6.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -418,25 +444,25 @@ ir_Carrier.o : $(USER_DIR)/ir_Carrier.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Carrier.cpp
ir_Carrier_test.o : ir_Carrier_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Carrier_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Carrier_test.cpp
ir_Carrier_test : $(COMMON_OBJ) ir_Carrier_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Haier.o : $(USER_DIR)/ir_Haier.cpp $(USER_DIR)/ir_Haier.h $(COMMON_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Haier.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Haier.cpp
ir_Haier_test.o : ir_Haier_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Haier_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Haier_test.cpp
ir_Haier_test : $(COMMON_OBJ) ir_Haier_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Hitachi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Hitachi.cpp
ir_Hitachi_test.o : ir_Hitachi_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Hitachi_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Hitachi_test.cpp
ir_Hitachi_test : $(COMMON_OBJ) ir_Hitachi_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -445,16 +471,16 @@ ir_GICable.o : $(USER_DIR)/ir_GICable.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GICable.cpp
ir_GICable_test.o : ir_GICable_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_GICable_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_GICable_test.cpp
ir_GICable_test : $(COMMON_OBJ) ir_GICable_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Whirlpool.o : $(USER_DIR)/ir_Whirlpool.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whirlpool.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Whirlpool.cpp
ir_Whirlpool_test.o : ir_Whirlpool_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Whirlpool_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Whirlpool_test.cpp
ir_Whirlpool_test : $(COMMON_OBJ) ir_Whirlpool_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -463,7 +489,7 @@ ir_Lutron.o : $(USER_DIR)/ir_Lutron.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lutron.cpp
ir_Lutron_test.o : ir_Lutron_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Lutron_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Lutron_test.cpp
ir_Lutron_test : $(COMMON_OBJ) ir_Lutron_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -472,7 +498,7 @@ ir_Electra.o : $(USER_DIR)/ir_Electra.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Electra.cpp
ir_Electra_test.o : ir_Electra_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Electra_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Electra_test.cpp
ir_Electra_test : $(COMMON_OBJ) ir_Electra_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -481,7 +507,7 @@ ir_Pioneer.o : $(USER_DIR)/ir_Pioneer.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pioneer.cpp
ir_Pioneer_test.o : ir_Pioneer_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Pioneer_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Pioneer_test.cpp
ir_Pioneer_test : $(COMMON_OBJ) ir_Pioneer_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -490,7 +516,49 @@ ir_MWM.o : $(USER_DIR)/ir_MWM.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_MWM.cpp
ir_MWM_test.o : ir_MWM_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_MWM_test.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_MWM_test.cpp
ir_MWM_test : $(COMMON_OBJ) ir_MWM_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Vestel.o : $(USER_DIR)/ir_Vestel.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Vestel.cpp
+
+ir_Vestel_test.o : ir_Vestel_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Vestel_test.cpp
+
+ir_Vestel_test : $(COMMON_OBJ) ir_Vestel_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Teco.o : $(USER_DIR)/ir_Teco.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Teco.cpp
+
+ir_Teco_test.o : ir_Teco_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Teco_test.cpp
+
+ir_Teco_test : $(COMMON_OBJ) ir_Teco_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Tcl.o : $(USER_DIR)/ir_Tcl.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Tcl.cpp
+
+ir_Tcl_test.o : ir_Tcl_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Tcl_test.cpp
+
+ir_Tcl_test : $(COMMON_OBJ) ir_Tcl_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Lego.o : $(USER_DIR)/ir_Lego.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lego.cpp
+
+ir_Lego_test.o : ir_Lego_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_Lego_test.cpp
+
+ir_Lego_test : $(COMMON_OBJ) ir_Lego_test.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+
+ir_Argo.o : $(USER_DIR)/ir_Argo.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Argo.cpp
+
+ir_Trotec.o : $(USER_DIR)/ir_Trotec.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Trotec.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Aiwa_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Aiwa_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Aiwa_test.cpp
index c5469d4a5249..2fa63afe625e 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Aiwa_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Aiwa_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendAiwa, SendDataOnly) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F); // Aiwa Power Toggle.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -43,6 +44,7 @@ TEST(TestSendAiwa, SendWithRepeats) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 0); // No repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -54,6 +56,7 @@ TEST(TestSendAiwa, SendWithRepeats) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -66,6 +69,7 @@ TEST(TestSendAiwa, SendWithRepeats) {
irsend.reset();
irsend.sendAiwaRCT501(0x7F, kAiwaRcT501Bits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -86,6 +90,7 @@ TEST(TestSendAiwa, SendUnusualSize) {
irsend.reset();
irsend.sendAiwaRCT501(0x12, 8);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -98,6 +103,7 @@ TEST(TestSendAiwa, SendUnusualSize) {
irsend.reset();
irsend.sendAiwaRCT501(0x1234567890, 37);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Carrier_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Carrier_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Carrier_test.cpp
index 24bdc232ab59..053b31dd489b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Carrier_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Carrier_test.cpp
@@ -15,6 +15,7 @@ TEST(TestSendCarrierAC, SendDataOnly) {
irsend.reset();
irsend.sendCarrierAC(0x0);
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532"
"m628s532m628s532m628s532m628s532m628s532m628s532m628s532m628s532"
@@ -37,6 +38,7 @@ TEST(TestSendCarrierAC, SendDataOnly) {
irsend.reset();
irsend.sendCarrierAC(0x12345678);
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532"
"m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532"
@@ -60,6 +62,7 @@ TEST(TestSendCarrierAC, SendDataOnly) {
irsend.reset();
irsend.sendCarrierAC(0x4CCA541D);
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s1320m628s532m628s532m628s1320m628s1320m628s532m628s532"
"m628s1320m628s1320m628s532m628s532m628s1320m628s532m628s1320m628s532"
@@ -89,6 +92,7 @@ TEST(TestSendCarrierAC, SendWithRepeats) {
irsend.reset();
irsend.sendCarrierAC(0x12345678, kCarrierAcBits, 2); // two repeats.
EXPECT_EQ(
+ "f38000d50"
"m8532s4228"
"m628s532m628s532m628s532m628s1320m628s532m628s532m628s1320m628s532"
"m628s532m628s532m628s1320m628s1320m628s532m628s1320m628s532m628s532"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Coolix_test.cpp
similarity index 70%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Coolix_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Coolix_test.cpp
index 8b096ffca824..0f97c5eade54 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Coolix_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Coolix_test.cpp
@@ -15,6 +15,15 @@ TEST(TestSendCoolix, SendDataOnly) {
irsend.reset();
irsend.sendCOOLIX(0x0);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s5040"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -28,6 +37,15 @@ TEST(TestSendCoolix, SendDataOnly) {
irsend.reset();
irsend.sendCOOLIX(0xAA55AA);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
+ "m560s5040"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
@@ -41,6 +59,15 @@ TEST(TestSendCoolix, SendDataOnly) {
irsend.reset();
irsend.sendCOOLIX(0xFFFFFF);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s5040"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -60,6 +87,7 @@ TEST(TestSendCoolix, SendWithRepeats) {
irsend.reset();
irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
@@ -79,6 +107,7 @@ TEST(TestSendCoolix, SendWithRepeats) {
irsend.outputStr());
irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
@@ -114,6 +143,11 @@ TEST(TestSendCoolix, SendUnusualSize) {
irsend.reset();
irsend.sendCOOLIX(0x0, 8);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
+ "m560s5040"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -123,6 +157,25 @@ TEST(TestSendCoolix, SendUnusualSize) {
irsend.reset();
irsend.sendCOOLIX(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
+ "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680"
+ "m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
+ "m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s1680"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s560"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560m560s1680"
+ "m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560"
+ "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680"
+ "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560m560s560"
+ "m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680"
+ "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560"
+ "m560s1680m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680"
+ "m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560"
+ "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560"
+ "m560s5040"
"m4480s4480"
"m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
"m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680"
@@ -411,7 +464,7 @@ TEST(TestCoolixACClass, HumanReadable) {
// Initial starting point.
EXPECT_EQ(
- "Power: On, Fan: 5 (AUTO), Mode: 2 (AUTO), Temp: 25C, "
+ "Power: On, Mode: 2 (AUTO), Fan: 5 (AUTO), Temp: 25C, "
"Zone Follow: Off, Sensor Temp: Ignored",
ircoolix.toString());
@@ -420,11 +473,11 @@ TEST(TestCoolixACClass, HumanReadable) {
ircoolix.setMode(kCoolixCool);
ircoolix.setFan(kCoolixFanMin);
EXPECT_EQ(
- "Power: On, Fan: 4 (MIN), Mode: 0 (COOL), Temp: 22C, "
+ "Power: On, Mode: 0 (COOL), Fan: 4 (MIN), Temp: 22C, "
"Zone Follow: On, Sensor Temp: 24C",
ircoolix.toString());
ircoolix.setSwing();
- EXPECT_EQ("Power: On, Fan: 3 (UNKNOWN), Swing: Toggle", ircoolix.toString());
+ EXPECT_EQ("Power: On, Swing: Toggle", ircoolix.toString());
ircoolix.setPower(false);
EXPECT_EQ("Power: Off", ircoolix.toString());
}
@@ -434,12 +487,113 @@ TEST(TestCoolixACClass, KnownExamples) {
ircoolix.setRaw(0b101100101011111111100100);
EXPECT_EQ(
- "Power: On, Fan: 5 (AUTO), Mode: 4 (FAN), Zone Follow: Off, "
+ "Power: On, Mode: 4 (FAN), Fan: 5 (AUTO), Zone Follow: Off, "
"Sensor Temp: Ignored",
ircoolix.toString());
ircoolix.setRaw(0b101100101001111100000000);
EXPECT_EQ(
- "Power: On, Fan: 4 (MIN), Mode: 0 (COOL), Temp: 17C, "
+ "Power: On, Mode: 0 (COOL), Fan: 4 (MIN), Temp: 17C, "
"Zone Follow: Off, Sensor Temp: Ignored",
ircoolix.toString());
}
+
+TEST(TestCoolixACClass, Issue579FanAuto0) {
+ IRCoolixAC ircoolix(0);
+
+ ircoolix.setRaw(0xB21F28);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (AUTO), Fan: 0 (AUTO0), Temp: 20C, "
+ "Zone Follow: Off, Sensor Temp: Ignored",
+ ircoolix.toString());
+}
+
+TEST(TestCoolixACClass, RealCaptureExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+
+ // From Issue #579
+ uint16_t powerOffRawData[199] = {
+ 4444, 4434, 590, 1578, 698, 446, 590, 1578, 622, 1596, 622, 500,
+ 644, 476, 644, 1548, 588, 532, 594, 530, 612, 1578, 590, 532,
+ 588, 534, 672, 1518, 594, 1598, 590, 510, 612, 1580, 644, 480,
+ 612, 1578, 644, 1548, 644, 1548, 594, 1598, 642, 506, 644, 1550,
+ 644, 1548, 594, 1600, 644, 478, 644, 478, 642, 480, 644, 478,
+ 642, 1548, 594, 530, 590, 532, 614, 1578, 644, 1548, 594, 1600,
+ 588, 534, 566, 556, 588, 530, 590, 532, 586, 514, 612, 532,
+ 588, 532, 590, 534, 588, 1578, 642, 1576, 642, 1550, 588, 1602,
+ 588, 1580, 642, 4712, 4546, 4406, 588, 1606, 642, 478, 644, 1550,
+ 590, 1604, 588, 534, 586, 532, 586, 1582, 642, 480, 642, 480,
+ 668, 1550, 642, 480, 642, 478, 642, 1552, 612, 1578, 586, 538,
+ 588, 1580, 674, 472, 590, 1602, 586, 1580, 618, 1576, 642, 1548,
+ 594, 530, 590, 1584, 608, 1578, 644, 1550, 642, 480, 642, 478,
+ 642, 480, 642, 480, 642, 1550, 590, 530, 592, 528, 592, 1602,
+ 642, 1548, 592, 1604, 586, 584, 642, 480, 640, 480, 640, 480,
+ 642, 480, 642, 480, 642, 480, 642, 480, 642, 1552, 590, 1604,
+ 588, 1578, 642, 1552, 640, 1550, 592}; // COOLIX B27BE0
+
+ irsend.begin();
+
+ irsend.reset();
+
+ irsend.sendRaw(powerOffRawData, 199, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(COOLIX, irsend.capture.decode_type);
+ EXPECT_EQ(kCoolixBits, irsend.capture.bits);
+ EXPECT_EQ(kCoolixOff, irsend.capture.value);
+ EXPECT_EQ(0x0, irsend.capture.address);
+ EXPECT_EQ(0x0, irsend.capture.command);
+}
+
+
+// Tests to debug/fix:
+// https://github.com/markszabo/IRremoteESP8266/issues/624
+TEST(TestCoolixACClass, Issue624HandleSpecialStatesBetter) {
+ IRCoolixAC ac(0);
+ ac.begin();
+ // Default
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (AUTO), Fan: 5 (AUTO), Temp: 25C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BFC8, ac.getRaw());
+ // Change of settings.
+ ac.setPower(true);
+ ac.setTemp(24);
+ ac.setMode(kCoolixCool);
+ ac.setFan(kCoolixFanAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BF40, ac.getRaw());
+ // Turn the unit off.
+ ac.setPower(false);
+ EXPECT_EQ(
+ "Power: Off",
+ ac.toString());
+ EXPECT_EQ(kCoolixOff, ac.getRaw());
+ // Repeat change of settings.
+ ac.setPower(true);
+ ac.setTemp(24);
+ ac.setMode(kCoolixCool);
+ ac.setFan(kCoolixFanAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BF40, ac.getRaw());
+
+ // Now test if we setRaw() a special state first.
+ ac.setRaw(kCoolixSwing);
+ // Repeat change of settings.
+ ac.setPower(true);
+ ac.setTemp(24);
+ ac.setMode(kCoolixCool);
+ ac.setFan(kCoolixFanAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, "
+ "Sensor Temp: Ignored",
+ ac.toString());
+ EXPECT_EQ(0xB2BF40, ac.getRaw());
+}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Daikin_test.cpp
new file mode 100644
index 000000000000..67d144d54404
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Daikin_test.cpp
@@ -0,0 +1,1880 @@
+// Copyright 2017 David Conran
+#include "ir_Daikin.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for sendDaikin().
+
+// Test sending typical data only.
+TEST(TestSendDaikin, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ uint8_t daikin_code[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3};
+
+ irsend.reset();
+ irsend.sendDaikin(daikin_code);
+ EXPECT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428"
+ "m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428"
+ "m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428"
+ "m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Test sending with repeats.
+TEST(TestSendDaikin, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint8_t daikin_code[kDaikinStateLengthShort] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3};
+ irsend.reset();
+
+ irsend.sendDaikin(daikin_code, kDaikinStateLengthShort, 1);
+ EXPECT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Test sending atypical sizes.
+TEST(TestSendDaikin, SendUnexpectedSizes) {
+ IRsendTest irsend(4);
+ irsend.begin();
+
+ uint8_t daikin_short_code[kDaikinStateLengthShort - 1] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00};
+
+ irsend.reset();
+ irsend.sendDaikin(daikin_short_code, kDaikinStateLengthShort - 1);
+ ASSERT_EQ("", irsend.outputStr());
+
+ uint8_t daikin_long_code[kDaikinStateLengthShort + 1] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11, 0xDA,
+ 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3, 0x11};
+ irsend.reset();
+ irsend.sendDaikin(daikin_long_code, kDaikinStateLengthShort + 1);
+ ASSERT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Tests for IRDaikinESP class.
+
+TEST(TestDaikinClass, Power) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_FALSE(ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_FALSE(ac.getPower());
+}
+
+TEST(TestDaikinClass, Temperature) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp - 1);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp + 1);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp + 1);
+ EXPECT_EQ(kDaikinMinTemp + 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());
+}
+
+TEST(TestDaikinClass, OperatingMode) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikinAuto);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinCool);
+ EXPECT_EQ(kDaikinCool, ac.getMode());
+
+ ac.setMode(kDaikinHeat);
+ EXPECT_EQ(kDaikinHeat, ac.getMode());
+
+ ac.setMode(kDaikinDry);
+ EXPECT_EQ(kDaikinDry, ac.getMode());
+
+ ac.setMode(kDaikinFan);
+ EXPECT_EQ(kDaikinFan, ac.getMode());
+
+ ac.setMode(kDaikinFan + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinAuto + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+}
+
+TEST(TestDaikinClass, VaneSwing) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setSwingHorizontal(true);
+ ac.setSwingVertical(false);
+
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingHorizontal(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingVertical(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+}
+
+TEST(TestDaikinClass, QuietMode) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+
+ ac.setQuiet(false);
+ EXPECT_FALSE(ac.getQuiet());
+
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+
+ // Setting Econo mode should NOT change out of quiet mode.
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getQuiet());
+ ac.setEcono(false);
+ EXPECT_TRUE(ac.getQuiet());
+
+ // But setting Powerful mode should exit out of quiet mode.
+ ac.setPowerful(true);
+ EXPECT_FALSE(ac.getQuiet());
+}
+
+TEST(TestDaikinClass, PowerfulMode) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setPowerful(true);
+ EXPECT_TRUE(ac.getPowerful());
+
+ ac.setPowerful(false);
+ EXPECT_FALSE(ac.getPowerful());
+
+ ac.setPowerful(true);
+ EXPECT_TRUE(ac.getPowerful());
+
+ ac.setQuiet(true);
+ EXPECT_FALSE(ac.getPowerful());
+
+ ac.setPowerful(true);
+ ac.setEcono(true);
+ EXPECT_FALSE(ac.getPowerful());
+}
+
+TEST(TestDaikinClass, EconoMode) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEcono(false);
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ // Setting Quiet mode should NOT change out of Econo mode.
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getEcono());
+ ac.setQuiet(false);
+ EXPECT_TRUE(ac.getEcono());
+
+ // But setting Powerful mode should exit out of Econo mode.
+ ac.setPowerful(true);
+ EXPECT_FALSE(ac.getEcono());
+}
+
+TEST(TestDaikinClass, FanSpeed) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ // Unexpected value should default to Auto.
+ ac.setFan(0);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ // Unexpected value should default to Auto.
+ ac.setFan(255);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanMax);
+ EXPECT_EQ(kDaikinFanMax, ac.getFan());
+
+ // Beyond Max should default to Auto.
+ ac.setFan(kDaikinFanMax + 1);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanMax - 1);
+ EXPECT_EQ(kDaikinFanMax - 1, ac.getFan());
+
+ ac.setFan(kDaikinFanMin);
+ EXPECT_EQ(kDaikinFanMin, ac.getFan());
+
+ ac.setFan(kDaikinFanMin + 1);
+ EXPECT_EQ(kDaikinFanMin + 1, ac.getFan());
+
+ // Beyond Min should default to Auto.
+ ac.setFan(kDaikinFanMin - 1);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(3);
+ EXPECT_EQ(3, ac.getFan());
+
+ ac.setFan(kDaikinFanAuto);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanQuiet);
+ EXPECT_EQ(kDaikinFanQuiet, ac.getFan());
+}
+
+TEST(TestDaikinClass, CurrentTime) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setCurrentTime(0); // 00:00
+ EXPECT_EQ(0, ac.getCurrentTime());
+
+ ac.setCurrentTime(754); // 12:34
+ EXPECT_EQ(754, ac.getCurrentTime());
+
+ ac.setCurrentTime(1439); // 23:59
+ EXPECT_EQ(1439, ac.getCurrentTime());
+}
+
+TEST(TestDaikinClass, OnOffTimers) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ // Both timers turned off.
+ ac.disableOnTimer();
+ ac.disableOffTimer();
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+ EXPECT_FALSE(ac.getOffTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime());
+
+ // Turn on just the On Timer.
+ ac.enableOnTimer(123);
+ EXPECT_TRUE(ac.getOnTimerEnabled());
+ EXPECT_EQ(123, ac.getOnTime());
+ EXPECT_FALSE(ac.getOffTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime());
+
+ // Now turn on the Off Timer.
+ ac.enableOffTimer(754);
+ EXPECT_TRUE(ac.getOffTimerEnabled());
+ EXPECT_EQ(754, ac.getOffTime());
+ EXPECT_TRUE(ac.getOnTimerEnabled());
+ EXPECT_EQ(123, ac.getOnTime());
+
+ // Turn off the just the On Timer.
+ ac.disableOnTimer();
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+ EXPECT_TRUE(ac.getOffTimerEnabled());
+ EXPECT_EQ(754, ac.getOffTime());
+
+ // Now turn off the Off Timer.
+ ac.disableOffTimer();
+ EXPECT_FALSE(ac.getOffTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime());
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+
+ // Use some canary values around the timers to ensure no accidental
+ // bit flips happen. i.e. Neighbouring bytes in the state.
+ // (Found some during testing on systems with different endian-ness)
+ // Tests here to make sure it never happens again.
+ ac.setSwingHorizontal(true);
+ ac.setPowerful(true);
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_TRUE(ac.getSwingHorizontal());
+ ASSERT_TRUE(ac.getPowerful());
+ ac.enableOnTimer(123);
+ ac.enableOffTimer(456);
+ ASSERT_TRUE(ac.getSwingHorizontal());
+ ASSERT_TRUE(ac.getPowerful());
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_TRUE(ac.getSwingHorizontal());
+ ASSERT_TRUE(ac.getPowerful());
+
+ ac.setSwingHorizontal(false);
+ ac.setPowerful(false);
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_FALSE(ac.getSwingHorizontal());
+ ASSERT_FALSE(ac.getPowerful());
+ ac.enableOnTimer(123);
+ ac.enableOffTimer(456);
+ ASSERT_FALSE(ac.getSwingHorizontal());
+ ASSERT_FALSE(ac.getPowerful());
+ ac.disableOffTimer();
+ ac.disableOnTimer();
+ ASSERT_FALSE(ac.getSwingHorizontal());
+ ASSERT_FALSE(ac.getPowerful());
+}
+
+// Test Eye mode.
+TEST(TestDaikinClass, EyeSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ // The Eye setting is stored in the same byte as Econo mode.
+ // Econo mode tests are there to make sure it isn't harmed and vice-versa.
+ ac.setEcono(false);
+ ac.setEye(false);
+ ASSERT_FALSE(ac.getEye());
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEye(true);
+ ASSERT_TRUE(ac.getEye());
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(false);
+ ASSERT_TRUE(ac.getEye());
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ ASSERT_TRUE(ac.getEye());
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEye(false);
+ ASSERT_FALSE(ac.getEye());
+ EXPECT_TRUE(ac.getEcono());
+}
+
+// Test Mold mode.
+TEST(TestDaikinClass, MoldSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setMold(false);
+ ASSERT_FALSE(ac.getMold());
+
+ ac.setMold(true);
+ ASSERT_TRUE(ac.getMold());
+
+ ac.setMold(false);
+ ASSERT_FALSE(ac.getMold());
+}
+
+// Test Comfort mode.
+TEST(TestDaikinClass, ComfortSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setComfort(false);
+ ASSERT_FALSE(ac.getComfort());
+
+ ac.setComfort(true);
+ ASSERT_TRUE(ac.getComfort());
+
+ ac.setComfort(false);
+ ASSERT_FALSE(ac.getComfort());
+}
+
+// Test Sensor mode.
+TEST(TestDaikinClass, SensorSetting) {
+ IRDaikinESP ac(0);
+ ac.begin();
+
+ ac.setSensor(false);
+ ASSERT_FALSE(ac.getSensor());
+
+ ac.setSensor(true);
+ ASSERT_TRUE(ac.getSensor());
+
+ ac.setSensor(false);
+ ASSERT_FALSE(ac.getSensor());
+}
+
+TEST(TestDaikinClass, RenderTime) {
+ EXPECT_EQ("0:00", IRDaikinESP::renderTime(0));
+ EXPECT_EQ("0:10", IRDaikinESP::renderTime(10));
+ EXPECT_EQ("1:00", IRDaikinESP::renderTime(1 * 60 + 0));
+ EXPECT_EQ("23:59", IRDaikinESP::renderTime(23 * 60 + 59));
+}
+
+TEST(TestDaikinClass, SetAndGetRaw) {
+ IRDaikinESP ac(0);
+ uint8_t shortState[kDaikinStateLengthShort] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x49, 0x1E, 0x00, 0xB0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x4F};
+ uint8_t longState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x49, 0x1E, 0x00, 0xB0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x4F};
+ uint8_t expectedState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x48, 0x2A, 0x00, 0xB0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x02, 0x5C};
+
+ EXPECT_STATE_EQ(longState, ac.getRaw(), kDaikinBits);
+ // toggle the power state.
+ ac.setPower(!ac.getPower());
+ ac.setTemp(21);
+ ac.setMold(true);
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikinBits);
+ ac.setRaw(longState);
+ EXPECT_STATE_EQ(longState, ac.getRaw(), kDaikinBits);
+ ac.setRaw(shortState, kDaikinStateLengthShort);
+ EXPECT_STATE_EQ(longState, ac.getRaw(), kDaikinBits);
+}
+
+TEST(TestDaikinClass, ChecksumValidation) {
+ uint8_t daikin_code[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE1};
+
+ EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
+ // Change the array so the checksum is invalid.
+ daikin_code[0] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ // Restore the previous change, and change another byte.
+ daikin_code[0] ^= 0xFF;
+ daikin_code[4] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ daikin_code[4] ^= 0xFF;
+ // Change something in the 2nd block.
+ daikin_code[10] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ daikin_code[10] ^= 0xFF;
+ EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
+ // Change something in the 3rd block.
+ daikin_code[20] ^= 0xFF;
+ EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
+ daikin_code[20] ^= 0xFF;
+ EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
+}
+
+// Test human readable output.
+TEST(TestDaikinClass, HumanReadable) {
+ IRDaikinESP ac(0);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 15C, Fan: 11 (QUIET), "
+ "Powerful: Off, Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, "
+ "Comfort: Off, Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 0:00, On Time: Off, Off Time: Off",
+ ac.toString());
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(25);
+ ac.setFan(kDaikinFanAuto);
+ ac.setQuiet(true);
+ ac.setSensor(true);
+ ac.setEye(true);
+ ac.setMold(true);
+ ac.setSwingVertical(true);
+ ac.setSwingHorizontal(true);
+ ac.setCurrentTime(9 * 60 + 15);
+ ac.enableOnTimer(8 * 60 + 0);
+ ac.enableOffTimer(17 * 60 + 30);
+ ac.setComfort(true);
+ ac.off();
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 10 (AUTO), "
+ "Powerful: Off, Quiet: On, Sensor: On, Eye: On, Mold: On, Comfort: On, "
+ "Swing (Horizontal): On, Swing (Vertical): On, "
+ "Current Time: 9:15, On Time: 8:00, Off Time: 17:30",
+ ac.toString());
+}
+
+// Test general message construction after tweaking some settings.
+TEST(TestDaikinClass, MessageConstuction) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(4);
+ ac.begin();
+ irsend.begin();
+
+ ac.setFan(kDaikinFanMin);
+ ac.setMode(kDaikinCool);
+ ac.setTemp(27);
+ ac.setSwingVertical(false);
+ ac.setSwingHorizontal(true);
+ ac.setQuiet(false);
+ ac.setPower(true);
+
+ // Check everything for kicks.
+ EXPECT_EQ(kDaikinFanMin, ac.getFan());
+ EXPECT_EQ(kDaikinCool, ac.getMode());
+ EXPECT_EQ(27, ac.getTemp());
+ EXPECT_FALSE(ac.getSwingVertical());
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getQuiet());
+ EXPECT_TRUE(ac.getPower());
+
+ irsend.reset();
+ irsend.sendDaikin(ac.getRaw());
+ EXPECT_EQ(
+ "f38000d50"
+ "m428s428m428s428m428s428m428s428m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s428m428s428m428s428m428s1280m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s1280m428s428m428s1280m428s428m428s1280m428s428"
+ "m428s29428m3650s1623"
+ "m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
+ "m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
+ "m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s1280m428s428m428s428m428s1280m428s1280m428s1280m428s428m428s428"
+ "m428s428m428s1280m428s1280m428s428m428s1280m428s1280m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s428"
+ "m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s1280m428s1280m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
+ "m428s428m428s1280m428s1280m428s428m428s428m428s1280m428s1280m428s1280"
+ "m428s29428",
+ irsend.outputStr());
+}
+
+// Tests for decodeDaikin().
+
+// Test decoding a message captured from a real IR remote.
+TEST(TestDecodeDaikin, RealExample) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t expectedState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00,
+ 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32};
+ uint16_t rawData[583] = {
+ 416, 446, 416, 446, 416, 446, 418, 446, 416, 446, 416, 25434,
+ 3436, 1768, 390, 1336, 390, 446, 416, 446, 416, 446, 416, 1336,
+ 390, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 448,
+ 416, 1336, 390, 1336, 390, 448, 416, 1336, 390, 1336, 390, 1338,
+ 388, 1338, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446,
+ 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448,
+ 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, 416, 1336,
+ 390, 448, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446,
+ 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
+ 416, 446, 416, 446, 416, 448, 416, 446, 416, 446, 416, 446,
+ 416, 448, 414, 448, 416, 448, 416, 1336, 390, 1336, 390, 1336,
+ 390, 446, 414, 1336, 390, 448, 414, 1336, 390, 1336, 390, 34878,
+ 3436, 1768, 390, 1336, 390, 446, 416, 448, 416, 446, 416, 1336,
+ 390, 446, 416, 448, 416, 446, 416, 446, 416, 1336, 390, 446,
+ 416, 1336, 390, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336,
+ 390, 1336, 390, 1336, 392, 446, 414, 448, 416, 1336, 390, 446,
+ 416, 446, 416, 446, 416, 446, 414, 448, 416, 446, 416, 448,
+ 414, 448, 416, 446, 416, 446, 416, 446, 414, 1336, 390, 448,
+ 416, 446, 416, 446, 416, 448, 416, 1336, 390, 446, 416, 446,
+ 416, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336, 390, 446,
+ 416, 446, 414, 1338, 390, 446, 416, 1336, 390, 446, 416, 446,
+ 416, 446, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446,
+ 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1336, 390, 34876,
+ 3436, 1768, 388, 1336, 390, 446, 416, 446, 416, 448, 416, 1336,
+ 390, 446, 416, 446, 416, 446, 416, 448, 416, 1336, 390, 448,
+ 414, 1336, 390, 1336, 390, 446, 416, 1336, 388, 1338, 388, 1336,
+ 390, 1336, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446,
+ 420, 442, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
+ 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448,
+ 416, 446, 416, 448, 416, 446, 416, 448, 416, 446, 416, 1336,
+ 390, 1336, 390, 1336, 388, 1338, 390, 1336, 390, 1336, 392, 446,
+ 416, 446, 416, 448, 416, 1334, 390, 446, 416, 1338, 388, 1336,
+ 390, 1336, 390, 446, 416, 446, 416, 448, 414, 446, 416, 446,
+ 416, 446, 416, 448, 416, 446, 416, 446, 416, 446, 416, 446,
+ 416, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446,
+ 416, 1336, 390, 446, 414, 448, 416, 446, 416, 446, 416, 446,
+ 416, 448, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446,
+ 416, 1336, 390, 446, 416, 446, 416, 446, 416, 448, 416, 1338,
+ 390, 444, 418, 1336, 390, 448, 416, 446, 416, 1336, 390, 446,
+ 416, 446, 416, 1336, 390, 1336, 388, 1336, 390, 446, 416, 1336,
+ 390, 448, 414, 448, 414, 448, 416, 1334, 390, 446, 416, 446,
+ 416, 446, 416, 448, 416, 446, 416, 446, 416, 448, 416, 446,
+ 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
+ 416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
+ 416, 448, 416, 1336, 390, 1336, 390, 446, 416, 446, 416, 446,
+ 416, 446, 414, 446, 416, 448, 416, 446, 416, 448, 414, 446,
+ 418, 446, 416, 446, 416, 448, 416, 446, 416, 448, 416, 446,
+ 416, 448, 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1338,
+ 390, 1336, 390, 446, 416, 446, 416}; // Captured by @sillyfrog
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 583, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (AUTO), Powerful: On, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 22:18, On Time: 21:30, Off Time: 6:10", ac.toString());
+}
+
+// Decoding a message we entirely constructed based solely on a given state.
+TEST(TestDecodeDaikin, ShortSyntheticExample) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t shortState[kDaikinStateLengthShort] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00,
+ 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32};
+
+ uint8_t longState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11,
+ 0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00,
+ 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32};
+ irsend.reset();
+ irsend.sendDaikin(shortState, kDaikinStateLengthShort);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(longState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (AUTO), Powerful: On, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 22:18, On Time: 21:30, Off Time: 6:10", ac.toString());
+}
+
+// Decoding a message we entirely constructed based solely on a given state.
+TEST(TestDecodeDaikin, LongSyntheticExample) {
+ IRDaikinESP ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t expectedState[kDaikinStateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0xD7,
+ 0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00,
+ 0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32};
+
+ irsend.reset();
+ irsend.sendDaikin(expectedState);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decodeDaikin(&irsend.capture));
+ ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikinBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (AUTO), Powerful: On, "
+ "Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, Comfort: Off, "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, "
+ "Current Time: 22:18, On Time: 21:30, Off Time: 6:10", ac.toString());
+}
+
+// Test decoding a message captured from a real IR remote.
+TEST(TestDecodeDaikin2, RealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t expectedState[kDaikin2StateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x7A, 0xC3, 0x70, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD5, 0xF5,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x08, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x80, 0x60, 0xE7};
+ // "Off" Data from https://github.com/markszabo/IRremoteESP8266/issues/582
+ uint16_t rawData[633] = { // Data supplied by @sheppy99
+ 10024, 25180, 3494, 1732, 436, 1300, 436, 436, 432, 438, 430, 438,
+ 426, 1306, 430, 442, 430, 438, 428, 440, 430, 440, 430, 1304,
+ 432, 442, 428, 1308, 424, 1312, 428, 442, 428, 1306, 424, 1314,
+ 426, 1308, 434, 1306, 426, 1308, 428, 444, 426, 442, 428, 1310,
+ 428, 442, 424, 444, 426, 442, 426, 444, 424, 444, 426, 444,
+ 424, 446, 422, 446, 422, 446, 422, 446, 418, 1318, 418, 450,
+ 420, 448, 420, 448, 422, 448, 420, 450, 420, 448, 420, 450,
+ 420, 452, 418, 1318, 420, 450, 420, 1318, 420, 1314, 418, 1318,
+ 424, 1314, 424, 448, 422, 1316, 424, 1312, 426, 446, 422, 448,
+ 420, 448, 422, 448, 422, 1314, 418, 1320, 416, 452, 420, 448,
+ 420, 448, 422, 448, 422, 1314, 416, 1320, 422, 1316, 422, 450,
+ 418, 450, 420, 448, 420, 448, 416, 1320, 418, 452, 418, 1316,
+ 422, 448, 420, 450, 420, 450, 420, 448, 422, 1314, 418, 1320,
+ 418, 450, 420, 448, 420, 448, 420, 450, 420, 450, 418, 450,
+ 418, 450, 420, 450, 418, 452, 416, 452, 420, 450, 418, 1318,
+ 420, 452, 418, 452, 418, 1322, 416, 452, 416, 452, 418, 452,
+ 418, 452, 416, 454, 418, 452, 416, 456, 414, 452, 418, 454,
+ 416, 1320, 410, 1324, 418, 452, 418, 1320, 416, 452, 418, 1320,
+ 418, 1318, 420, 448, 420, 1316, 420, 450, 420, 450, 418, 450,
+ 420, 450, 418, 452, 418, 1320, 418, 450, 418, 450, 416, 1322,
+ 412, 458, 420, 450, 416, 452, 418, 452, 416, 452, 418, 452,
+ 416, 454, 416, 452, 418, 452, 416, 454, 414, 454, 416, 454,
+ 416, 454, 414, 456, 414, 454, 414, 456, 412, 454, 416, 456,
+ 414, 456, 412, 1326, 412, 1320, 412, 1322, 414, 1322, 418, 1320,
+ 420, 452, 418, 1318, 420, 1316, 422, 450, 420, 1314, 424, 448,
+ 422, 1314, 422, 448, 422, 1314, 418, 1318, 424, 1316, 422, 448,
+ 422, 1312, 424, 446, 422, 1314, 420, 1318, 422, 1316, 426, 1310,
+ 426, 35166, 3500, 1724, 446, 1296, 444, 432, 436, 432, 438, 432,
+ 436, 1296, 440, 434, 434, 436, 432, 436, 434, 436, 434, 1298,
+ 438, 438, 432, 1304, 428, 1304, 432, 442, 430, 1302, 430, 1308,
+ 430, 1306, 434, 1302, 432, 1306, 430, 440, 430, 438, 430, 1308,
+ 434, 438, 430, 440, 428, 440, 430, 440, 428, 442, 426, 444,
+ 428, 442, 426, 444, 426, 442, 426, 444, 424, 446, 422, 446,
+ 424, 446, 424, 446, 422, 446, 424, 448, 420, 448, 422, 446,
+ 422, 448, 422, 450, 420, 450, 414, 1320, 420, 450, 418, 450,
+ 418, 448, 420, 450, 418, 452, 418, 1320, 418, 1316, 422, 450,
+ 418, 452, 418, 1320, 420, 448, 418, 450, 420, 450, 418, 452,
+ 416, 452, 418, 450, 418, 452, 416, 452, 418, 452, 416, 454,
+ 416, 452, 416, 454, 416, 454, 414, 456, 416, 454, 414, 1322,
+ 416, 454, 416, 1320, 418, 452, 416, 454, 414, 454, 416, 454,
+ 414, 454, 414, 454, 414, 456, 414, 456, 412, 456, 414, 456,
+ 414, 456, 412, 456, 414, 458, 406, 464, 410, 458, 412, 458,
+ 410, 460, 410, 1326, 412, 1324, 414, 456, 412, 458, 412, 456,
+ 414, 456, 412, 458, 410, 458, 414, 458, 410, 458, 408, 460,
+ 410, 470, 400, 1324, 408, 1328, 410, 458, 410, 460, 414, 456,
+ 410, 456, 414, 458, 412, 460, 410, 458, 412, 458, 412, 460,
+ 408, 460, 410, 460, 408, 472, 396, 462, 408, 470, 402, 470,
+ 396, 472, 400, 470, 398, 1326, 412, 460, 408, 472, 396, 472,
+ 400, 470, 400, 472, 396, 1328, 410, 1324, 414, 458, 410, 458,
+ 410, 458, 412, 458, 412, 460, 408, 460, 410, 460, 410, 1324,
+ 414, 458, 410, 460, 408, 460, 410, 458, 410, 460, 410, 1326,
+ 412, 1322, 416, 456, 412, 1322, 412, 1326, 416, 1322, 418, 452,
+ 416, 454, 412, 1324, 418, 1320, 420, 1316, 420};
+ irsend.reset();
+ irsend.sendRaw(rawData, 633, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN2, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin2Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+}
+
+// Decoding a message we entirely constructed based solely on a given state.
+TEST(TestDecodeDaikin2, SyntheticExample) {
+ IRDaikin2 ac(0);
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ uint8_t expectedState[kDaikin2StateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x7A, 0xC3, 0x70, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD5, 0xF5,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x08, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x80, 0x60, 0xE7};
+
+ irsend.reset();
+ irsend.sendDaikin2(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN2, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin2Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), "
+ "Swing (V): 5, Swing (H): 190 (Auto), "
+ "Clock: 14:50, On Time: Off, Off Time: Off, Sleep Time: Off, "
+ "Beep: 1 (Quiet), Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, "
+ "Eye: Off, Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: Off, "
+ "Econo: Off",
+ ac.toString());
+}
+
+TEST(TestDaikin2Class, CurrentTime) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setCurrentTime(0); // 00:00
+ EXPECT_EQ(0, ac.getCurrentTime());
+
+ ac.setCurrentTime(754); // 12:34
+ EXPECT_EQ(754, ac.getCurrentTime());
+
+ ac.setCurrentTime(1439); // 23:59
+ EXPECT_EQ(1439, ac.getCurrentTime());
+}
+
+TEST(TestDaikin2Class, OnOffTimers) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ // Both timers turned off.
+ ac.disableOnTimer();
+ ac.disableOffTimer();
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+ EXPECT_FALSE(ac.getOffTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime());
+
+ // Turn on just the On Timer.
+ ac.enableOnTimer(123);
+ EXPECT_TRUE(ac.getOnTimerEnabled());
+ EXPECT_EQ(123, ac.getOnTime());
+ EXPECT_FALSE(ac.getOffTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime());
+
+ // Now turn on the Off Timer.
+ ac.enableOffTimer(754);
+ EXPECT_TRUE(ac.getOffTimerEnabled());
+ EXPECT_EQ(754, ac.getOffTime());
+ EXPECT_TRUE(ac.getOnTimerEnabled());
+ EXPECT_EQ(123, ac.getOnTime());
+
+ // Turn off the just the On Timer.
+ ac.disableOnTimer();
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+ EXPECT_TRUE(ac.getOffTimerEnabled());
+ EXPECT_EQ(754, ac.getOffTime());
+
+ // Now turn off the Off Timer.
+ ac.disableOffTimer();
+ EXPECT_FALSE(ac.getOffTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOffTime());
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+}
+
+TEST(TestDaikin2Class, LightAndBeep) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setLight(kDaikinLightOff);
+ EXPECT_EQ(kDaikinLightOff, ac.getLight());
+ ac.setBeep(kDaikinBeepOff);
+ EXPECT_EQ(kDaikinBeepOff, ac.getBeep());
+ ac.setLight(kDaikinLightBright);
+ EXPECT_EQ(kDaikinLightBright, ac.getLight());
+ EXPECT_EQ(kDaikinBeepOff, ac.getBeep());
+ ac.setBeep(kDaikinBeepLoud);
+ EXPECT_EQ(kDaikinBeepLoud, ac.getBeep());
+ EXPECT_EQ(kDaikinLightBright, ac.getLight());
+}
+
+TEST(TestDaikin2Class, FanSpeed) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ // Unexpected value should default to Auto.
+ ac.setFan(0);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ // Unexpected value should default to Auto.
+ ac.setFan(255);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanMax);
+ EXPECT_EQ(kDaikinFanMax, ac.getFan());
+
+ // Beyond Max should default to Auto.
+ ac.setFan(kDaikinFanMax + 1);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanMax - 1);
+ EXPECT_EQ(kDaikinFanMax - 1, ac.getFan());
+
+ ac.setFan(kDaikinFanMin);
+ EXPECT_EQ(kDaikinFanMin, ac.getFan());
+
+ ac.setFan(kDaikinFanMin + 1);
+ EXPECT_EQ(kDaikinFanMin + 1, ac.getFan());
+
+ // Beyond Min should default to Auto.
+ ac.setFan(kDaikinFanMin - 1);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(3);
+ EXPECT_EQ(3, ac.getFan());
+
+ ac.setFan(kDaikinFanAuto);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanQuiet);
+ EXPECT_EQ(kDaikinFanQuiet, ac.getFan());
+}
+
+// Test Mold mode.
+TEST(TestDaikin2Class, MoldSetting) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setMold(false);
+ ASSERT_FALSE(ac.getMold());
+
+ ac.setMold(true);
+ ASSERT_TRUE(ac.getMold());
+
+ ac.setMold(false);
+ ASSERT_FALSE(ac.getMold());
+}
+
+// Test Auto Clean setting.
+TEST(TestDaikin2Class, CleanSetting) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setClean(false);
+ ASSERT_FALSE(ac.getClean());
+
+ ac.setClean(true);
+ ASSERT_TRUE(ac.getClean());
+
+ ac.setClean(false);
+ ASSERT_FALSE(ac.getClean());
+}
+
+
+TEST(TestDaikin2Class, Temperature) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp - 1);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp + 1);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp + 1);
+ EXPECT_EQ(kDaikinMinTemp + 1, ac.getTemp());
+
+ // Now try it with Cool mode, which should set the temp to kDaikin2MinCoolTemp
+ ASSERT_TRUE(kDaikinMinTemp + 1 < kDaikin2MinCoolTemp);
+ ac.setMode(kDaikinCool);
+ EXPECT_EQ(kDaikin2MinCoolTemp, ac.getTemp());
+ ac.setTemp(kDaikin2MinCoolTemp - 1);
+ EXPECT_EQ(kDaikin2MinCoolTemp, ac.getTemp());
+ ac.setTemp(kDaikin2MinCoolTemp + 1);
+ EXPECT_EQ(kDaikin2MinCoolTemp + 1, ac.getTemp());
+ // Should be released from that requirement in other modes.
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(kDaikin2MinCoolTemp - 1);
+ EXPECT_EQ(kDaikin2MinCoolTemp - 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());
+}
+
+// Test Fresh Air settings.
+TEST(TestDaikin2Class, FreshAirSettings) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setFreshAir(false);
+ ac.setFreshAirHigh(false);
+ ASSERT_FALSE(ac.getFreshAir());
+ ASSERT_FALSE(ac.getFreshAirHigh());
+
+ ac.setFreshAir(true);
+ ASSERT_TRUE(ac.getFreshAir());
+ ASSERT_FALSE(ac.getFreshAirHigh());
+
+ ac.setFreshAirHigh(true);
+ ASSERT_TRUE(ac.getFreshAir());
+ ASSERT_TRUE(ac.getFreshAirHigh());
+
+ ac.setFreshAir(false);
+ ASSERT_FALSE(ac.getFreshAir());
+ ASSERT_TRUE(ac.getFreshAirHigh());
+
+ ac.setFreshAirHigh(false);
+ ASSERT_FALSE(ac.getFreshAir());
+ ASSERT_FALSE(ac.getFreshAirHigh());
+}
+
+// Test Eye mode.
+TEST(TestDaikin2Class, EyeSetting) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setEye(false);
+ ASSERT_FALSE(ac.getEye());
+ ac.setEye(true);
+ ASSERT_TRUE(ac.getEye());
+ ac.setEye(false);
+ ASSERT_FALSE(ac.getEye());
+}
+
+// Test Econo setting.
+TEST(TestDaikin2Class, EconoSetting) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setEcono(false);
+ ASSERT_FALSE(ac.getEcono());
+ ac.setEcono(true);
+ ASSERT_TRUE(ac.getEcono());
+ ac.setEcono(false);
+ ASSERT_FALSE(ac.getEcono());
+}
+
+TEST(TestDaikin2Class, SleepTimer) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ // NOTE: On & Sleep timer share the same time location.
+
+ // Both timers turned off.
+ ac.disableOnTimer();
+ ac.disableSleepTimer();
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+ EXPECT_FALSE(ac.getSleepTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getSleepTime());
+
+ // Turn on just the On Timer.
+ ac.enableOnTimer(123);
+ EXPECT_TRUE(ac.getOnTimerEnabled());
+ EXPECT_EQ(123, ac.getOnTime());
+ EXPECT_FALSE(ac.getSleepTimerEnabled());
+ EXPECT_EQ(123, ac.getSleepTime());
+
+ // Now turn on the Sleep Timer. This shoud disable the On Timer.
+ ac.enableSleepTimer(754);
+ EXPECT_TRUE(ac.getSleepTimerEnabled());
+ EXPECT_EQ(754, ac.getSleepTime());
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(754, ac.getOnTime());
+
+ // Turn off the just the On Timer.
+ ac.disableOnTimer();
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+ EXPECT_FALSE(ac.getSleepTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getSleepTime());
+
+ // Now turn on the On Timer and turn off the Sleep Timer.
+ // Both should be off afterwards.
+ ac.enableOnTimer(123);
+ ac.disableSleepTimer();
+ EXPECT_FALSE(ac.getSleepTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getSleepTime());
+ EXPECT_FALSE(ac.getOnTimerEnabled());
+ EXPECT_EQ(kDaikinUnusedTime, ac.getOnTime());
+}
+
+// Test Vertical Swing.
+TEST(TestDaikin2Class, Swing) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ // Vertical
+ ac.setSwingVertical(1);
+ ASSERT_EQ(1, ac.getSwingVertical());
+ ac.setSwingVertical(3);
+ ASSERT_EQ(3, ac.getSwingVertical());
+ ac.setSwingVertical(6);
+ ASSERT_EQ(6, ac.getSwingVertical());
+ ac.setSwingVertical(kDaikin2SwingVBreeze);
+ ASSERT_EQ(kDaikin2SwingVBreeze, ac.getSwingVertical());
+ ac.setSwingVertical(kDaikin2SwingVCirculate);
+ ASSERT_EQ(kDaikin2SwingVCirculate, ac.getSwingVertical());
+ ac.setSwingVertical(kDaikin2SwingVAuto);
+ ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical());
+ ac.setSwingVertical(0);
+ ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical());
+ ac.setSwingVertical(7);
+ ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical());
+ ac.setSwingVertical(255);
+ ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical());
+
+ // Horizontal
+ ac.setSwingHorizontal(kDaikin2SwingHAuto);
+ ASSERT_EQ(kDaikin2SwingHAuto, ac.getSwingHorizontal());
+ ac.setSwingHorizontal(kDaikin2SwingHSwing);
+ ASSERT_EQ(kDaikin2SwingHSwing, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(0);
+ ASSERT_EQ(0, ac.getSwingHorizontal());
+ ac.setSwingHorizontal(255);
+ ASSERT_EQ(255, ac.getSwingHorizontal());
+}
+
+TEST(TestDaikin2Class, QuietMode) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+
+ ac.setQuiet(false);
+ EXPECT_FALSE(ac.getQuiet());
+
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+
+ // But setting Powerful mode should exit out of quiet mode.
+ ac.setPowerful(true);
+ EXPECT_FALSE(ac.getQuiet());
+}
+
+TEST(TestDaikin2Class, PowerfulMode) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setPowerful(true);
+ EXPECT_TRUE(ac.getPowerful());
+
+ ac.setPowerful(false);
+ EXPECT_FALSE(ac.getPowerful());
+
+ ac.setPowerful(true);
+ EXPECT_TRUE(ac.getPowerful());
+
+ ac.setQuiet(true);
+ EXPECT_FALSE(ac.getPowerful());
+}
+
+// Test Purify mode.
+TEST(TestDaikin2Class, PurifySetting) {
+ IRDaikin2 ac(0);
+ ac.begin();
+
+ ac.setPurify(false);
+ ASSERT_FALSE(ac.getPurify());
+ ac.setPurify(true);
+ ASSERT_TRUE(ac.getPurify());
+ ac.setPurify(false);
+ ASSERT_FALSE(ac.getPurify());
+}
+
+TEST(TestDaikin2Class, HumanReadable) {
+ IRDaikin2 ac(0);
+ ac.begin();
+ ac.setPower(true);
+ ac.setMode(kDaikinCool);
+ ac.setTemp(21);
+ ac.setFan(kDaikinFanMax);
+ ac.setSwingVertical(kDaikin2SwingVAuto);
+ ac.setSwingHorizontal(kDaikin2SwingHSwing);
+ ac.setCurrentTime(12 * 60 + 34); // 12:34
+ ac.disableOnTimer();
+ ac.enableOffTimer(20 * 60); // 20:00
+ ac.enableSleepTimer(4 * 60); // 4:00
+ ac.setBeep(kDaikinBeepLoud);
+ ac.setLight(kDaikinLightDim);
+ ac.setMold(true);
+ ac.setClean(false);
+ ac.setFreshAir(true);
+ ac.setEye(true);
+ ac.setEyeAuto(true);
+ ac.setQuiet(false);
+ ac.setPowerful(true);
+ ac.setPurify(true);
+ ac.setEcono(false);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 21C, Fan: 5 (Max), "
+ "Swing (V): 14 (Auto), Swing (H): 191 (Swing), Clock: 12:34, "
+ "On Time: Off, Off Time: 20:00, Sleep Time: 4:00, Beep: 2 (Loud), "
+ "Light: 2 (Dim), Mold: On, Clean: Off, Fresh Air: On, Eye: On, "
+ "Eye Auto: On, Quiet: Off, Powerful: On, Purify: On, Econo: Off",
+ ac.toString());
+ ac.setQuiet(true);
+ ac.setMode(kDaikinHeat);
+ ac.setBeep(kDaikinBeepQuiet);
+ ac.setLight(kDaikinLightBright);
+ ac.setTemp(32);
+ ac.setFan(kDaikinFanMin);
+ ac.setCurrentTime(23 * 60 + 45); // 23:45
+ ac.enableOnTimer(9 * 60 + 11); // 9:11
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 32C, Fan: 1 (Min), "
+ "Swing (V): 14 (Auto), Swing (H): 191 (Swing), Clock: 23:45, "
+ "On Time: 9:11, Off Time: 20:00, Sleep Time: Off, Beep: 1 (Quiet), "
+ "Light: 1 (Bright), Mold: On, Clean: Off, Fresh Air: On, Eye: On, "
+ "Eye Auto: On, Quiet: On, Powerful: Off, Purify: On, Econo: Off",
+ ac.toString());
+}
+
+// See if we can construct a known state.
+TEST(TestDaikin2Class, KnownConstruction) {
+ IRDaikin2 ac(0);
+
+ uint8_t expectedState[kDaikin2StateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x7A, 0xC3, 0x70, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xD5, 0xF5,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x08, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x80, 0x60, 0xE7};
+
+ ac.begin();
+ ac.setPower(false);
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(19);
+ ac.setFan(kDaikinFanAuto);
+ ac.setSwingVertical(5);
+ ac.setSwingHorizontal(kDaikin2SwingHAuto);
+ ac.setCurrentTime(14 * 60 + 50); // 14:50
+ ac.disableOnTimer();
+ ac.disableOffTimer();
+ ac.disableSleepTimer();
+ ac.setBeep(kDaikinBeepQuiet);
+ ac.setLight(kDaikinLightOff);
+ ac.setMold(true);
+ ac.setClean(true);
+ ac.setFreshAir(false);
+ ac.setEye(false);
+ ac.setEyeAuto(false);
+ ac.setQuiet(false);
+ ac.setPowerful(false);
+ ac.setPurify(false);
+ ac.setEcono(false);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), "
+ "Swing (V): 5, Swing (H): 190 (Auto), "
+ "Clock: 14:50, On Time: Off, Off Time: Off, Sleep Time: Off, "
+ "Beep: 1 (Quiet), Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, "
+ "Eye: Off, Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: Off, "
+ "Econo: Off",
+ ac.toString());
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikin2Bits);
+}
+
+TEST(TestUtils, Housekeeping) {
+ ASSERT_EQ("DAIKIN", typeToString(decode_type_t::DAIKIN));
+ ASSERT_EQ(decode_type_t::DAIKIN, strToDecodeType("DAIKIN"));
+ ASSERT_TRUE(hasACState(decode_type_t::DAIKIN));
+
+ ASSERT_EQ("DAIKIN2", typeToString(decode_type_t::DAIKIN2));
+ ASSERT_EQ(decode_type_t::DAIKIN2, strToDecodeType("DAIKIN2"));
+ ASSERT_TRUE(hasACState(decode_type_t::DAIKIN2));
+
+ ASSERT_EQ("DAIKIN216", typeToString(decode_type_t::DAIKIN216));
+ ASSERT_EQ(decode_type_t::DAIKIN216, strToDecodeType("DAIKIN216"));
+ ASSERT_TRUE(hasACState(decode_type_t::DAIKIN216));
+}
+
+// https://github.com/markszabo/IRremoteESP8266/issues/582#issuecomment-453863879
+TEST(TestDecodeDaikin2, Issue582DeepDecodeExample) {
+ IRDaikin2 ac(0);
+
+ const uint8_t state[kDaikin2StateLength] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x30, 0x42, 0xF0, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xA3,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x09, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x92, 0x60, 0xFA};
+
+ ac.setRaw(state);
+ ASSERT_TRUE(ac.getMold());
+ ASSERT_TRUE(ac.getEye());
+ ASSERT_TRUE(ac.getPurify());
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), "
+ "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 9:20, On Time: Off, "
+ "Off Time: Off, Sleep Time: Off, Beep: 3 (Off), Light: 3 (Off), "
+ "Mold: On, Clean: On, Fresh Air: Off, Eye: On, Eye Auto: Off, "
+ "Quiet: Off, Powerful: Off, Purify: On, Econo: Off",
+ ac.toString());
+}
+
+// https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit?ts=5c317775#gid=1023395743
+TEST(TestDecodeDaikin2, Issue582PowerfulEconoFix) {
+ IRDaikin2 ac(0);
+
+ const uint8_t PowerfulOn[39] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3A, 0x43, 0xF0, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAE,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x01, 0x00, 0xC1, 0x90, 0x60, 0x2B};
+ const uint8_t PowerfulOff[39] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3A, 0x43, 0xF0, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAE,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x90, 0x60, 0x2A};
+ ac.setRaw(PowerfulOn);
+ ASSERT_TRUE(ac.getPowerful());
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), "
+ "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:46, "
+ "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), "
+ "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, "
+ "Eye Auto: Off, Quiet: Off, Powerful: On, Purify: On, Econo: Off",
+ ac.toString());
+ ac.setRaw(PowerfulOff);
+ ASSERT_FALSE(ac.getPowerful());
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), "
+ "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:46, "
+ "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), "
+ "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, "
+ "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off",
+ ac.toString());
+
+ const uint8_t EconoOn[39] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3B, 0x43, 0xF0, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAF,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x94, 0x60, 0x2E};
+ const uint8_t EconoOff[39] = {
+ 0x11, 0xDA, 0x27, 0x00, 0x01, 0x3B, 0x43, 0xF0, 0x28, 0x0C,
+ 0x80, 0x04, 0xB0, 0x16, 0x24, 0x00, 0x00, 0xBE, 0xCE, 0xAF,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x28, 0x00, 0xA0, 0x00,
+ 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x90, 0x60, 0x2A};
+ ac.setRaw(EconoOn);
+ ASSERT_TRUE(ac.getEcono());
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), "
+ "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:47, "
+ "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), "
+ "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, "
+ "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: On",
+ ac.toString());
+ ac.setRaw(EconoOff);
+ ASSERT_FALSE(ac.getEcono());
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), "
+ "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:47, "
+ "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), "
+ "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, "
+ "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off",
+ ac.toString());
+}
+
+// Tests for IRDaikin216 class.
+
+TEST(TestDaikin216Class, Power) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_FALSE(ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_FALSE(ac.getPower());
+}
+
+TEST(TestDaikin216Class, Temperature) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setTemp(0);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp - 1);
+ EXPECT_EQ(kDaikinMinTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMaxTemp + 1);
+ EXPECT_EQ(kDaikinMaxTemp, ac.getTemp());
+
+ ac.setTemp(kDaikinMinTemp + 1);
+ EXPECT_EQ(kDaikinMinTemp + 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());
+}
+
+TEST(TestDaikin216Class, OperatingMode) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setMode(kDaikinAuto);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinCool);
+ EXPECT_EQ(kDaikinCool, ac.getMode());
+
+ ac.setMode(kDaikinHeat);
+ EXPECT_EQ(kDaikinHeat, ac.getMode());
+
+ ac.setMode(kDaikinDry);
+ EXPECT_EQ(kDaikinDry, ac.getMode());
+
+ ac.setMode(kDaikinFan);
+ EXPECT_EQ(kDaikinFan, ac.getMode());
+
+ ac.setMode(kDaikinFan + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(kDaikinAuto + 1);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kDaikinAuto, ac.getMode());
+}
+
+
+TEST(TestDaikin216Class, VaneSwing) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setSwingHorizontal(true);
+ ac.setSwingVertical(false);
+
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingHorizontal(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_TRUE(ac.getSwingVertical());
+
+ ac.setSwingVertical(false);
+ EXPECT_FALSE(ac.getSwingHorizontal());
+ EXPECT_FALSE(ac.getSwingVertical());
+}
+
+TEST(TestDaikin216Class, FanSpeed) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ // Unexpected value should default to Auto.
+ ac.setFan(0);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ // Unexpected value should default to Auto.
+ ac.setFan(255);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanMax);
+ EXPECT_EQ(kDaikinFanMax, ac.getFan());
+
+ // Beyond Max should default to Auto.
+ ac.setFan(kDaikinFanMax + 1);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanMax - 1);
+ EXPECT_EQ(kDaikinFanMax - 1, ac.getFan());
+
+ ac.setFan(kDaikinFanMin);
+ EXPECT_EQ(kDaikinFanMin, ac.getFan());
+
+ ac.setFan(kDaikinFanMin + 1);
+ EXPECT_EQ(kDaikinFanMin + 1, ac.getFan());
+
+ // Beyond Min should default to Auto.
+ ac.setFan(kDaikinFanMin - 1);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(3);
+ EXPECT_EQ(3, ac.getFan());
+
+ ac.setFan(kDaikinFanAuto);
+ EXPECT_EQ(kDaikinFanAuto, ac.getFan());
+
+ ac.setFan(kDaikinFanQuiet);
+ EXPECT_EQ(kDaikinFanQuiet, ac.getFan());
+}
+
+TEST(TestDaikin216Class, Quiet) {
+ IRDaikin216 ac(0);
+ ac.begin();
+
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+
+ ac.setQuiet(false);
+ EXPECT_FALSE(ac.getQuiet());
+
+ ac.setQuiet(true);
+ EXPECT_TRUE(ac.getQuiet());
+}
+
+TEST(TestDaikin216Class, ExampleStates) {
+ IRDaikin216 ac(0);
+ ac.begin();
+ // https://github.com/markszabo/IRremoteESP8266/pull/690#issuecomment-487770194
+ uint8_t state[kDaikin216StateLength] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x21, 0xC0, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x53};
+ ac.setRaw(state);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (DRY), Temp: 32C, Fan: 10 (AUTO), "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, Quiet: Off",
+ ac.toString());
+}
+
+TEST(TestDaikin216Class, ReconstructKnownState) {
+ IRDaikin216 ac(0);
+ ac.begin();
+ // https://github.com/markszabo/IRremoteESP8266/issues/689#issue-438086949
+ uint8_t expectedState[kDaikin216StateLength] = {
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x98};
+ ac.setPower(false);
+ ac.setMode(kDaikinAuto);
+ ac.setTemp(19);
+ ac.setFan(kDaikinFanAuto);
+ ac.setSwingHorizontal(false);
+ ac.setSwingVertical(false);
+ ac.setQuiet(false);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (AUTO), "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, Quiet: Off",
+ ac.toString());
+
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikin216Bits);
+}
+
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+TEST(TestDecodeDaikin216, RealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ // https://github.com/markszabo/IRremoteESP8266/issues/689#issue-438086949
+ uint16_t rawData[439] = {
+ 3402, 1770, 382, 1340, 382, 480, 382, 478, 382, 480, 380, 1342, 382, 478,
+ 356, 504, 382, 480, 380, 478, 384, 1342, 380, 480, 380, 1342, 382, 1342,
+ 382, 478, 382, 1340, 382, 1340, 384, 1340, 382, 1342, 382, 1340, 380, 480,
+ 382, 480, 382, 1296, 426, 480, 380, 480, 382, 480, 380, 480, 382, 480,
+ 382, 478, 382, 1342, 382, 1342, 382, 1340, 356, 1368, 382, 478, 382, 480,
+ 382, 478, 380, 480, 382, 480, 382, 480, 382, 478, 382, 480, 382, 478, 358,
+ 504, 382, 480, 380, 480, 382, 480, 382, 480, 380, 480, 382, 478, 382, 480,
+ 382, 478, 382, 480, 354, 506, 354, 506, 380, 480, 382, 480, 382, 480, 382,
+ 480, 380, 1342, 382, 480, 382, 480, 382, 478, 382, 478, 382, 478, 384,
+ 478, 382, 29652, 3426, 1772, 382, 1340, 382, 480, 380, 478, 382, 480, 382,
+ 1342, 382, 480, 382, 480, 382, 478, 356, 506, 382, 1342, 380, 480, 382,
+ 1340, 382, 1340, 382, 478, 356, 1366, 382, 1340, 384, 1340, 382, 1340,
+ 382, 1342, 382, 478, 382, 478, 382, 1340, 382, 478, 382, 478, 382, 478,
+ 382, 480, 382, 480, 384, 478, 358, 504, 382, 478, 382, 480, 382, 478, 382,
+ 480, 382, 480, 382, 478, 382, 480, 382, 478, 382, 478, 382, 478, 382, 478,
+ 384, 478, 382, 478, 360, 500, 358, 504, 382, 478, 382, 480, 382, 480, 382,
+ 478, 382, 478, 382, 1340, 382, 1342, 382, 480, 380, 480, 382, 1342, 382,
+ 478, 382, 480, 356, 506, 382, 478, 382, 480, 382, 480, 356, 506, 382, 478,
+ 382, 480, 382, 478, 382, 480, 382, 478, 382, 480, 380, 480, 380, 480, 382,
+ 1342, 382, 478, 382, 1342, 382, 480, 382, 480, 382, 478, 382, 478, 382,
+ 480, 382, 478, 382, 480, 356, 504, 384, 478, 382, 480, 382, 480, 380, 480,
+ 382, 478, 382, 480, 382, 480, 382, 478, 356, 504, 384, 478, 380, 480, 382,
+ 480, 382, 480, 382, 478, 356, 506, 382, 478, 382, 480, 380, 480, 382, 478,
+ 382, 480, 382, 478, 382, 480, 358, 504, 382, 478, 382, 478, 356, 504, 382,
+ 478, 382, 480, 382, 478, 382, 478, 382, 478, 382, 480, 380, 480, 382, 480,
+ 380, 480, 356, 506, 356, 504, 382, 480, 382, 478, 382, 478, 382, 478, 382,
+ 478, 382, 480, 382, 478, 382, 480, 382, 480, 382, 1340, 382, 1342, 382,
+ 478, 384, 478, 382, 478, 382, 480, 380, 480, 382, 478, 382, 480, 356, 506,
+ 382, 478, 382, 480, 382, 478, 356, 506, 380, 480, 382, 478, 382, 478, 382,
+ 478, 382, 480, 382, 480, 380, 480, 382, 1342, 382, 1340, 382, 480, 356,
+ 504, 382, 1342, 382}; // UNKNOWN E0E32232
+ uint8_t expectedState[kDaikin216StateLength] = {
+ // 8 bytes
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ // 19 bytes
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x98};
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendRaw(rawData, 439, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN216, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin216Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+
+ IRDaikin216 ac(0);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (AUTO), "
+ "Swing (Horizontal): Off, Swing (Vertical): Off, Quiet: Off",
+ ac.toString());
+}
+
+// https://github.com/markszabo/IRremoteESP8266/issues/689
+TEST(TestDecodeDaikin216, SyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ // https://github.com/markszabo/IRremoteESP8266/issues/689#issue-438086949
+ uint8_t expectedState[kDaikin216StateLength] = {
+ // 8 bytes
+ 0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02,
+ // 19 bytes
+ 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0xA0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x98};
+
+ irsend.begin();
+ irsend.reset();
+ irsend.sendDaikin216(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(DAIKIN216, irsend.capture.decode_type);
+ ASSERT_EQ(kDaikin216Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Denon_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Denon_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Denon_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Denon_test.cpp
index 911fd75281e5..6b80eae027fe 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Denon_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Denon_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendDenon, SendDataOnly) {
irsend.reset();
irsend.sendDenon(0x2278); // Denon AVR Power On. (Sharp)
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
@@ -26,6 +27,7 @@ TEST(TestSendDenon, SendDataOnly) {
// Denon Eco Mode On. (Panasonic/Kaseikyo)
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
@@ -45,6 +47,7 @@ TEST(TestSendDenon, SendNormalWithRepeats) {
irsend.reset();
irsend.sendDenon(0x2278, DENON_BITS, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
@@ -60,6 +63,7 @@ TEST(TestSendDenon, SendNormalWithRepeats) {
irsend.outputStr());
irsend.sendDenon(0x2278, DENON_BITS, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
@@ -88,6 +92,7 @@ TEST(TestSendDenon, Send48BitWithRepeats) {
irsend.reset();
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 1); // 1 repeat.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
@@ -107,6 +112,7 @@ TEST(TestSendDenon, Send48BitWithRepeats) {
irsend.outputStr());
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 2); // 2 repeats.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
@@ -142,6 +148,7 @@ TEST(TestSendDenon, SendUnusualSize) {
irsend.reset();
irsend.sendDenon(0x12, 8);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s1820m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s780m260s1820m260s1820m260s780m260s1820"
@@ -151,6 +158,7 @@ TEST(TestSendDenon, SendUnusualSize) {
irsend.reset();
irsend.sendDenon(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s1296m432s432m432s432m432s1296m432s432"
"m432s432m432s432m432s1296m432s1296m432s432m432s1296m432s432m432s432"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Dish_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Dish_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Dish_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Dish_test.cpp
index 0c58496cedfc..21286b7ac672 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Dish_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Dish_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendDish, SendDataOnly) {
irsend.reset();
irsend.sendDISH(0x0);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -32,6 +33,7 @@ TEST(TestSendDish, SendDataOnly) {
irsend.reset();
irsend.sendDISH(0x9C00); // Power on.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -50,6 +52,7 @@ TEST(TestSendDish, SendDataOnly) {
irsend.reset();
irsend.sendDISH(0xFFFF);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
@@ -74,6 +77,7 @@ TEST(TestSendDish, SendWithRepeats) {
irsend.reset();
irsend.sendDISH(0x9C00, kDishBits, 0); // 0 repeats.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -83,6 +87,7 @@ TEST(TestSendDish, SendWithRepeats) {
irsend.reset();
irsend.sendDISH(0x9C00, kDishBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -94,6 +99,7 @@ TEST(TestSendDish, SendWithRepeats) {
irsend.sendDISH(0x9C00, kDishBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
@@ -115,6 +121,7 @@ TEST(TestSendDish, SendUnusualSize) {
irsend.reset();
irsend.sendDISH(0x0, 8);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
@@ -129,6 +136,7 @@ TEST(TestSendDish, SendUnusualSize) {
irsend.reset();
irsend.sendDISH(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f57600d50"
"m400s6100"
"m400s2800m400s2800m400s2800m400s1700m400s2800m400s2800m400s1700m400s2800"
"m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700m400s2800m400s2800"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Electra_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Electra_test.cpp
similarity index 84%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Electra_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Electra_test.cpp
index df5dd7a5c169..7d6d0c915d95 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Electra_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Electra_test.cpp
@@ -12,12 +12,13 @@
TEST(TestSendElectraAC, SendDataOnly) {
IRsendTest irsend(0);
irsend.begin();
- uint8_t data[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06,
- 0x00, 0x04, 0x00, 0x00, 0x04,
- 0x00, 0xA0, 0xB0};
+ uint8_t data[kElectraAcStateLength] = {0xC3, 0x87, 0xF6, 0x28, 0x60,
+ 0x00, 0x20, 0x00, 0x00, 0x20,
+ 0x00, 0x05, 0x0D};
irsend.sendElectraAC(data);
EXPECT_EQ(
+ "f38000d50"
"m9166s4470"
"m646s1647m646s1647m646s547m646s547m646s547m646s547m646s1647m646s1647"
"m646s1647m646s1647m646s1647m646s547m646s547m646s547m646s547m646s1647"
@@ -46,9 +47,9 @@ TEST(TestDecodeElectraAC, SyntheticDecode) {
// Synthesised Normal ElectraAC message.
irsend.reset();
- uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06,
- 0x00, 0x04, 0x00, 0x00, 0x04,
- 0x00, 0xA0, 0xB0};
+ uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0x87, 0xF6, 0x28, 0x60,
+ 0x00, 0x20, 0x00, 0x00, 0x20,
+ 0x00, 0x05, 0x0D};
irsend.sendElectraAC(expectedState);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
@@ -84,9 +85,9 @@ TEST(TestDecodeElectraAC, RealExampleDecode) {
662, 562, 642, 1686, 582, 570, 634, 566, 604, 576, 636, 566,
610, 578, 634, 1664, 584, 590, 660, 1636, 610, 1642, 664, 590,
610, 590, 636, 566, 634, 568, 686}; // UNKNOWN 9AD8CDB5
- uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0xE1, 0x6F, 0x14, 0x06,
- 0x00, 0x04, 0x00, 0x00, 0x04,
- 0x00, 0xA0, 0xB0};
+ uint8_t expectedState[kElectraAcStateLength] = {0xC3, 0x87, 0xF6, 0x28, 0x60,
+ 0x00, 0x20, 0x00, 0x00, 0x20,
+ 0x00, 0x05, 0x0D};
irsend.reset();
irsend.sendRaw(rawData, 211, 38000);
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Fujitsu_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Fujitsu_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Fujitsu_test.cpp
index 23fa3e7a7998..b895e4d9be3c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Fujitsu_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Fujitsu_test.cpp
@@ -183,6 +183,7 @@ TEST(TestSendFujitsuAC, GenerateMessage) {
irsend.reset();
irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLength);
EXPECT_EQ(
+ "f38000d50"
"m3324s1574"
"m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448s390"
"m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390"
@@ -217,6 +218,7 @@ TEST(TestSendFujitsuAC, GenerateShortMessage) {
irsend.reset();
irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLengthShort);
EXPECT_EQ(
+ "f38000d50"
"m3324s1574m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448"
"s390m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390"
"m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390m448s390"
@@ -238,6 +240,7 @@ TEST(TestSendFujitsuAC, Issue275) {
fujitsu.setCmd(kFujitsuAcCmdTurnOff);
irsend.sendFujitsuAC(fujitsu.getRaw(), kFujitsuAcStateLengthShort);
EXPECT_EQ(
+ "f38000d50"
// Header
"m3324s1574"
// 0 0 1 0 1 0 0 0 (0x28)
@@ -272,6 +275,7 @@ TEST(TestSendFujitsuAC, Issue275) {
450, 1250, 450};
irsend.sendRaw(off, 115, 38);
EXPECT_EQ(
+ "f38000d50"
// Header
"m3350s1650"
// 0 0 1 0 1 0 0 0 (0x28)
@@ -534,6 +538,7 @@ TEST(TestDecodeFujitsuAC, Issue414) {
ASSERT_EQ(kFujitsuAcBits, irsend.capture.bits);
EXPECT_TRUE(ArraysMatch(state, irsend.capture.state));
EXPECT_EQ(
+ "f38000d50"
"m3324s1574"
"m448s390m448s390m448s1182m448s390m448s1182m448s390m448s390m448s390"
"m448s1182m448s1182m448s390m448s390m448s390m448s1182m448s1182m448s390"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_GICable_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_GICable_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_GICable_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_GICable_test.cpp
index b9bfce997464..bad9bbdede9c 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_GICable_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_GICable_test.cpp
@@ -12,6 +12,7 @@ TEST(TestSendGICable, SendDataOnly) {
irsend.begin();
irsend.sendGICable(0);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200m550s2200"
@@ -20,6 +21,7 @@ TEST(TestSendGICable, SendDataOnly) {
irsend.outputStr());
irsend.sendGICable(0x8807);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
@@ -28,6 +30,7 @@ TEST(TestSendGICable, SendDataOnly) {
irsend.outputStr());
irsend.sendGICable(0xFFFF);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400"
"m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400m550s4400"
@@ -43,6 +46,7 @@ TEST(TestSendGICable, SendWithRepeats) {
// Send a command with 0 repeats.
irsend.sendGICable(0x8807, kGicableBits, 0);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
@@ -51,6 +55,7 @@ TEST(TestSendGICable, SendWithRepeats) {
// Send a command with 1 repeat.
irsend.sendGICable(0x8807, kGicableBits, 1);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
@@ -60,6 +65,7 @@ TEST(TestSendGICable, SendWithRepeats) {
// Send a command with 3 repeats.
irsend.sendGICable(0x8807, kGicableBits, 3);
EXPECT_EQ(
+ "f39000d50"
"m9000s4400"
"m550s4400m550s2200m550s2200m550s2200m550s4400m550s2200m550s2200m550s2200"
"m550s2200m550s2200m550s2200m550s2200m550s2200m550s4400m550s4400m550s4400"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_GlobalCache_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_GlobalCache_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_GlobalCache_test.cpp
index 16a556b57f95..00742aedac49 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_GlobalCache_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_GlobalCache_test.cpp
@@ -29,6 +29,7 @@ TEST(TestSendGlobalCache, NonRepeatingCode) {
EXPECT_EQ(0x4, irsend.capture.address);
EXPECT_EQ(0x41, irsend.capture.command);
EXPECT_EQ(
+ "f38000d50"
"m8892s4472m546s572m546s546m546s1690m546s546m546s572m546s572"
"m546s546m546s572m546s1690m546s1690m546s572m546s1690m546s1690"
"m546s1690m546s1690m546s1690m546s1690m546s572m546s572m546s546"
@@ -60,6 +61,7 @@ TEST(TestSendGlobalCache, RepeatCode) {
EXPECT_EQ(0x4583, irsend.capture.address);
EXPECT_EQ(0x11, irsend.capture.command);
EXPECT_EQ(
+ "f38000d50"
"m8866s4446m546s1664m546s1664m546s546m546s546m546s546m546s546"
"m546s546m546s1664m546s1664m546s546m546s1664m546s546m546s546"
"m546s546m546s1664m546s546m546s1664m546s546m546s546m546s546"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Gree_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Gree_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Gree_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Gree_test.cpp
index 6c7a1f637fdb..a05b0639172d 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Gree_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Gree_test.cpp
@@ -20,7 +20,8 @@ TEST(TestSendGreeChars, SendData) {
irsend.reset();
irsend.sendGree(gree_code);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -42,7 +43,8 @@ TEST(TestSendGreeUint64, SendData) {
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -69,7 +71,8 @@ TEST(TestSendGreeChars, SendWithRepeats) {
irsend.sendGree(gree_code, kGreeStateLength, 1);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -81,7 +84,7 @@ TEST(TestSendGreeChars, SendWithRepeats) {
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000"
- "m9000s4000"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -103,7 +106,8 @@ TEST(TestSendGreeUint64, SendWithRepeats) {
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF, kGreeBits, 1);
EXPECT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -115,7 +119,7 @@ TEST(TestSendGreeUint64, SendWithRepeats) {
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000"
- "m9000s4000"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -146,7 +150,8 @@ TEST(TestSendGreeChars, SendUnexpectedSizes) {
irsend.reset();
irsend.sendGree(gree_long_code, kGreeStateLength + 1);
ASSERT_EQ(
- "m9000s4000"
+ "f38000d50"
+ "m9000s4500"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
@@ -486,7 +491,7 @@ TEST(TestDecodeGree, NormalSynthetic) {
EXPECT_STATE_EQ(gree_code, irsend.capture.state, kGreeBits);
}
-// Decode a synthetic Gree message.
+// Decode a real Gree message.
TEST(TestDecodeGree, NormalRealExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Haier_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Haier_test.cpp
similarity index 90%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Haier_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Haier_test.cpp
index 11848e00a3ea..8d306cb0bb98 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Haier_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Haier_test.cpp
@@ -19,6 +19,7 @@ TEST(TestSendHaierAC, SendDataOnly) {
irsend.reset();
irsend.sendHaierAC(haier_zero);
EXPECT_EQ(
+ "f38000d50"
"m3000s3000m3000s4300"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s650"
@@ -37,6 +38,7 @@ TEST(TestSendHaierAC, SendDataOnly) {
irsend.reset();
irsend.sendHaierAC(haier_test);
EXPECT_EQ(
+ "f38000d50"
"m3000s3000m3000s4300"
"m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s650m520s1650"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s1650"
@@ -62,6 +64,7 @@ TEST(TestSendHaierAC, SendWithRepeats) {
irsend.reset();
irsend.sendHaierAC(haier_test, kHaierACStateLength, 2); // two repeats.
EXPECT_EQ(
+ "f38000d50"
"m3000s3000m3000s4300"
"m520s1650m520s650m520s1650m520s650m520s650m520s1650m520s650m520s1650"
"m520s650m520s650m520s650m520s650m520s650m520s650m520s650m520s1650"
@@ -404,7 +407,7 @@ TEST(TestHaierACClass, MessageConstuction) {
haier.toString());
uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x96, 0xEA, 0xCF, 0x32,
- 0x2D, 0x0D, 0x74, 0xD4};
+ 0xED, 0x2D, 0x74, 0xB4};
EXPECT_STATE_EQ(expectedState, haier.getRaw(), kHaierACBits);
// Check that the checksum is valid.
@@ -987,3 +990,91 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) {
" Health: On",
haier.toString());
}
+
+// Default state of the remote needed to include hidden data.
+// Ref: https://github.com/markszabo/IRremoteESP8266/issues/668
+TEST(TestHaierAcIssues, Issue668) {
+ IRHaierAC ac(0);
+ IRHaierAC acText(1);
+ IRrecv irrecv(0);
+ ac.begin();
+
+ // Turn on the AC.
+ ac._irsend.reset();
+ char expected_on[] =
+ "Command: 1 (On), Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), "
+ "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, "
+ "On Timer: Off, Off Timer: Off";
+ // State taken from real capture:
+ // https://github.com/markszabo/IRremoteESP8266/issues/668#issuecomment-483531895
+ uint8_t expected_on_state[9] = {
+ 0xA5, 0x91, 0x20, 0x00, 0x0C, 0xC0, 0x20, 0x00, 0x42};
+ ac.setCommand(kHaierAcCmdOn);
+ EXPECT_EQ(expected_on, ac.toString());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ EXPECT_STATE_EQ(expected_on_state,
+ ac._irsend.capture.state, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_on, acText.toString());
+
+ // Set the temp to 25C
+ ac._irsend.reset();
+ ac.setTemp(25);
+ EXPECT_EQ(expected_on, ac.toString());
+ ASSERT_EQ(25, ac.getTemp());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ EXPECT_STATE_EQ(expected_on_state,
+ ac._irsend.capture.state, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_on, acText.toString());
+
+ // Increase the temp by 1.
+ ac._irsend.reset();
+ char expected_temp_plus_one[] =
+ "Command: 6 (Temp Up), Mode: 0 (AUTO), Temp: 26C, Fan: 0 (AUTO), "
+ "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, "
+ "On Timer: Off, Off Timer: Off";
+ // State taken from real capture:
+ // https://github.com/markszabo/IRremoteESP8266/issues/668#issuecomment-483531895
+ uint8_t expected_temp_plus_one_state[9] = {
+ 0xA5, 0xA6, 0x20, 0x00, 0x0C, 0xC0, 0x20, 0x00, 0x57};
+ ASSERT_EQ(25, ac.getTemp());
+ ac.setTemp(ac.getTemp() + 1);
+ ASSERT_EQ(26, ac.getTemp());
+ EXPECT_EQ(expected_temp_plus_one, ac.toString());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ EXPECT_STATE_EQ(expected_temp_plus_one_state,
+ ac._irsend.capture.state, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_temp_plus_one, acText.toString());
+
+ // Decrease the temp by 1.
+ ac._irsend.reset();
+ char expected_temp_minus_one[] =
+ "Command: 7 (Temp Down), Mode: 0 (AUTO), Temp: 25C, Fan: 0 (AUTO), "
+ "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, "
+ "On Timer: Off, Off Timer: Off";
+ ASSERT_EQ(26, ac.getTemp());
+ ac.setTemp(ac.getTemp() - 1);
+ ASSERT_EQ(25, ac.getTemp());
+ EXPECT_EQ(expected_temp_minus_one, ac.toString());
+ ac.send();
+ ac._irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&ac._irsend.capture));
+ ASSERT_EQ(HAIER_AC, ac._irsend.capture.decode_type);
+ EXPECT_EQ(kHaierACBits, ac._irsend.capture.bits);
+ acText.setRaw(ac._irsend.capture.state);
+ EXPECT_EQ(expected_temp_minus_one, acText.toString());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Hitachi_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Hitachi_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Hitachi_test.cpp
index de0a4a2a186d..a2471c4aa10e 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Hitachi_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Hitachi_test.cpp
@@ -22,6 +22,7 @@ TEST(TestSendHitachiAC, SendData) {
irsend.reset();
irsend.sendHitachiAC(hitachi_code);
EXPECT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
@@ -68,6 +69,7 @@ TEST(TestSendHitachiAC, SendWithRepeats) {
irsend.sendHitachiAC(hitachi_code, kHitachiAcStateLength, 1);
EXPECT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
@@ -151,6 +153,7 @@ TEST(TestSendHitachiAC, SendUnexpectedSizes) {
irsend.reset();
irsend.sendHitachiAC(hitachi_long_code, kHitachiAcStateLength + 1);
ASSERT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
@@ -511,6 +514,7 @@ TEST(TestSendHitachiAC1, SendData) {
irsend.reset();
irsend.sendHitachiAC1(hitachi_code);
EXPECT_EQ(
+ "f38000d50"
"m3400s3400"
"m400s1250m400s500m400s1250m400s1250m400s500m400s500m400s1250m400s500"
"m400s1250m400s500m400s1250m400s500m400s1250m400s1250m400s1250m400s500"
@@ -585,6 +589,7 @@ TEST(TestSendHitachiAC2, SendData) {
irsend.reset();
irsend.sendHitachiAC2(hitachi_code);
EXPECT_EQ(
+ "f38000d50"
"m3300s1700"
"m400s1250m400s500m400s500m400s500m400s500m400s500m400s500m400s500"
"m400s500m400s500m400s500m400s500m400s1250m400s500m400s500m400s500"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_JVC_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_JVC_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_JVC_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_JVC_test.cpp
index c899fa8c60a9..3cd99c3aa326 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_JVC_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_JVC_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendJVC, SendDataOnly) {
irsend.reset();
irsend.sendJVC(0xC2B8); // JVC VCR Power On.
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
@@ -29,6 +30,7 @@ TEST(TestSendJVC, SendWithRepeats) {
irsend.reset();
irsend.sendJVC(0xC2B8, kJvcBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
@@ -39,6 +41,7 @@ TEST(TestSendJVC, SendWithRepeats) {
irsend.outputStr());
irsend.sendJVC(0xC2B8, kJvcBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
@@ -60,6 +63,7 @@ TEST(TestSendJVC, SendUnusualSize) {
irsend.reset();
irsend.sendJVC(0x0, 8);
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s525m525s525m525s525m525s525m525s525m525s525m525s525m525s525"
"m525s38475",
@@ -68,6 +72,7 @@ TEST(TestSendJVC, SendUnusualSize) {
irsend.reset();
irsend.sendJVC(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d33"
"m8400s4200"
"m525s525m525s525m525s525m525s1725m525s525m525s525m525s1725m525s525"
"m525s525m525s525m525s1725m525s1725m525s525m525s1725m525s525m525s525"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Kelvinator_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Kelvinator_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Kelvinator_test.cpp
index 001f8bcf242c..38a298e58baa 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Kelvinator_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Kelvinator_test.cpp
@@ -21,6 +21,7 @@ TEST(TestSendKelvinator, SendDataOnly) {
irsend.reset();
irsend.sendKelvinator(kelv_code);
EXPECT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
@@ -61,6 +62,7 @@ TEST(TestSendKelvinator, SendWithRepeats) {
irsend.sendKelvinator(kelv_code, kKelvinatorStateLength, 1);
EXPECT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
@@ -131,6 +133,7 @@ TEST(TestSendKelvinator, SendUnexpectedSizes) {
// extra data.
irsend.sendKelvinator(kelv_long_code, 17);
ASSERT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s510m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
@@ -472,6 +475,7 @@ TEST(TestKelvinatorClass, MessageConstuction) {
irsend.reset();
irsend.sendKelvinator(irkelv.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m9010s4505"
"m680s1530m680s510m680s510m680s1530m680s1530m680s510m680s1530m680s510"
"m680s1530m680s1530m680s510m680s1530m680s510m680s510m680s510m680s510"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_LG_test.cpp
similarity index 88%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_LG_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_LG_test.cpp
index 8ab24a7319e8..2925494b94c4 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_LG_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_LG_test.cpp
@@ -30,6 +30,7 @@ TEST(TestSendLG, SendDataOnly) {
irsend.reset();
irsend.sendLG(0x4B4AE51);
EXPECT_EQ(
+ "f38000d50"
"m8500s4250"
"m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550"
@@ -41,6 +42,7 @@ TEST(TestSendLG, SendDataOnly) {
irsend.reset();
irsend.sendLG(0xB4B4AE51, kLg32Bits);
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
@@ -59,6 +61,7 @@ TEST(TestSendLG, SendWithRepeats) {
irsend.reset();
irsend.sendLG(0x4B4AE51, kLgBits, 1);
EXPECT_EQ(
+ "f38000d50"
"m8500s4250"
"m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550"
@@ -71,6 +74,7 @@ TEST(TestSendLG, SendWithRepeats) {
irsend.reset();
irsend.sendLG(0xB4B4AE51, kLg32Bits, 1);
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
@@ -90,6 +94,7 @@ TEST(TestSendLG, SendUnusualSize) {
irsend.reset();
irsend.sendLG(0x0, 31);
EXPECT_EQ(
+ "f38000d50"
"m8500s4250"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
@@ -101,6 +106,7 @@ TEST(TestSendLG, SendUnusualSize) {
irsend.reset();
irsend.sendLG(0x0, 64);
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -373,6 +379,7 @@ TEST(TestSendLG2, SendDataOnly) {
irsend.reset();
irsend.sendLG2(0x880094D);
EXPECT_EQ(
+ "f38000d50"
"m3200s9850"
"m550s1600m550s550m550s550m550s550m550s1600m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
@@ -420,3 +427,54 @@ TEST(TestDecodeLG2, RealLG2Example) {
EXPECT_EQ(kLgBits, irsend.capture.bits);
EXPECT_EQ(0x880094D, irsend.capture.value);
}
+
+// Tests for issue reported in
+// https://github.com/markszabo/IRremoteESP8266/issues/620
+TEST(TestDecodeLG, Issue620) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // Raw data as reported in initial comment of Issue #620
+ uint16_t rawData[59] = {
+ 8886, 4152,
+ 560, 1538, 532, 502, 532, 504, 530, 484, 558, 1536,
+ 508, 516, 558, 502, 532, 484, 558, 502, 532, 500,
+ 534, 508, 532, 502, 532, 1518, 558, 510, 532, 484,
+ 556, 486, 556, 510, 532, 1518, 558, 1560, 532, 1528,
+ 556, 504, 530, 506, 530, 1520, 558, 508, 534, 500,
+ 532, 512, 530, 484, 556, 1536, 532}; // LG 8808721
+ irsend.sendRaw(rawData, 59, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(28, irsend.capture.bits);
+ EXPECT_EQ(0x8808721, irsend.capture.value);
+ EXPECT_EQ(0x88, irsend.capture.address);
+ EXPECT_EQ(0x872, irsend.capture.command);
+
+ irsend.reset();
+
+ // Resend the same code as the report is a sent code doesn't decode
+ // to the same message code.
+ irsend.sendLG(0x8808721);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LG, irsend.capture.decode_type);
+ EXPECT_EQ(28, irsend.capture.bits);
+ EXPECT_EQ(0x8808721, irsend.capture.value);
+ EXPECT_EQ(0x88, irsend.capture.address);
+ EXPECT_EQ(0x872, irsend.capture.command);
+ // The following seems to match the rawData above.
+ EXPECT_EQ(
+ "f38000d50"
+ "m8500s4250"
+ "m550s1600m550s550m550s550m550s550m550s1600"
+ "m550s550m550s550m550s550m550s550m550s550"
+ "m550s550m550s550m550s1600m550s550m550s550"
+ "m550s550m550s550m550s1600m550s1600m550s1600"
+ "m550s550m550s550m550s1600m550s550m550s550"
+ "m550s550m550s550m550s1600m550"
+ "s55550",
+ irsend.outputStr());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Lasertag_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Lasertag_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Lasertag_test.cpp
index 041109fb8e59..bad724f76d16 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lasertag_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Lasertag_test.cpp
@@ -20,6 +20,7 @@ TEST(TestSendLasertag, SendDataOnly) {
irsend.reset();
irsend.sendLasertag(0x1); // Red 1
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333"
"s333m333s333m333s333m333s666m333s100000",
irsend.outputStr());
@@ -27,6 +28,7 @@ TEST(TestSendLasertag, SendDataOnly) {
irsend.reset();
irsend.sendLasertag(0x2); // Red 2
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333"
"m333s333m333s333m333s333m333s666m666s100333",
irsend.outputStr());
@@ -38,6 +40,7 @@ TEST(TestSendLasertag, SendDataOnly) {
EXPECT_EQ(
// m364s364m332s336m384s276m332s364m332s304m416s584
// m692s724m640s360m304s332m392s612m380
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s666"
"m666s666m666s333m333s333m333s666m333s100000",
irsend.outputStr());
@@ -49,6 +52,7 @@ TEST(TestSendLasertag, SendDataOnly) {
EXPECT_EQ(
// m332s308m412s280m360s336m332s304m444s248m332s644
// m744s612m696s692m668s636m360
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s666"
"m666s666m666s666m666s666m333s100000",
irsend.outputStr());
@@ -61,6 +65,7 @@ TEST(TestSendLasertag, SendDataWithRepeat) {
irsend.reset();
irsend.sendLasertag(0x1, kLasertagBits, 1); // Red 1, one repeat.
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333"
"m333s333m333s333m333s333m333s666m333s100000"
"m333s333m333s333m333s333m333s333m333s333m333s333m333s333m333s333"
@@ -70,6 +75,7 @@ TEST(TestSendLasertag, SendDataWithRepeat) {
irsend.reset();
irsend.sendLasertag(0x52, kLasertagBits, 2); // Green 2, two repeats.
EXPECT_EQ(
+ "f36000d25"
"m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333"
"m333s666m666s100333"
"m333s333m333s333m333s333m333s333m333s333m333s666m666s666m666s333"
@@ -86,7 +92,8 @@ TEST(TestSendLasertag, SmallestMessageSize) {
irsend.reset();
irsend.sendLasertag(0x1555); // Alternating bit pattern will be the smallest.
// i.e. 7 actual 'mark' pulses, which is a rawlen of 13.
- EXPECT_EQ("m0s333m666s666m666s666m666s666m666s666m666s666m666s666m333s100000",
+ EXPECT_EQ("f36000d25"
+ "m0s333m666s666m666s666m666s666m666s666m666s666m666s666m333s100000",
irsend.outputStr());
}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Lego_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Lego_test.cpp
new file mode 100644
index 000000000000..4e859b170878
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Lego_test.cpp
@@ -0,0 +1,196 @@
+// Copyright 2019 David Conran
+
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestLego, Housekeeping) {
+ ASSERT_EQ("LEGOPF", typeToString(LEGOPF));
+ ASSERT_FALSE(hasACState(LEGOPF)); // Uses uint64_t, not uint8_t*.
+}
+
+// Tests for sendLego().
+
+// Test sending typical data only.
+TEST(TestSendLegoPf, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x1234);
+ EXPECT_EQ(
+ "f38000d50"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472", irsend.outputStr());
+
+ irsend.reset();
+ irsend.send(LEGOPF, 0x1234, kLegoPfBits);
+ EXPECT_EQ(
+ "f38000d50"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472", irsend.outputStr());
+}
+
+// Test sending typical repeat data.
+TEST(TestSendLegoPf, SendDataWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x1234, kLegoPfBits, 1);
+ EXPECT_EQ(
+ "f38000d50"
+ "m0s32000"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s70472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s150472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s150472"
+ "m158s1026"
+ "m158s263m158s263m158s263m158s553m158s263m158s263m158s553m158s263"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s150472", irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendLegoPf(0x2345, kLegoPfBits, 2);
+ EXPECT_EQ(
+ "f38000d50"
+ "m0s16000"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s70182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s70182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s182182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s182182"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s263m158s263m158s263m158s553m158s553"
+ "m158s263m158s553m158s263m158s263m158s263m158s553m158s263m158s553"
+ "m158s182182", irsend.outputStr());
+
+ irsend.reset();
+ irsend.sendLegoPf(0x3456, kLegoPfBits, 7);
+ EXPECT_EQ(
+ "f38000d50"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s69892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s69892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892"
+ "m158s1026"
+ "m158s263m158s263m158s553m158s553m158s263m158s553m158s263m158s263"
+ "m158s263m158s553m158s263m158s553m158s263m158s553m158s553m158s263"
+ "m158s213892", irsend.outputStr());
+}
+
+// Tests for decodeLego().
+
+// Decode normal "synthetic" messages.
+TEST(TestDecodeLegoPf, SyntheticDecode) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x000F);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x000F, irsend.capture.value);
+ EXPECT_EQ(1, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ irsend.reset();
+ irsend.sendLegoPf(0x100E);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x100E, irsend.capture.value);
+ EXPECT_EQ(2, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ irsend.reset();
+ irsend.sendLegoPf(0x221E);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x221E, irsend.capture.value);
+ EXPECT_EQ(3, irsend.capture.address);
+ EXPECT_EQ(0x21, irsend.capture.command);
+
+ // Test a bad LRC is not matched.
+ irsend.reset();
+ irsend.sendLegoPf(0x001F); // LRC should be 0xE, not 0xF.
+ irsend.makeDecodeResult();
+ irrecv.decode(&irsend.capture);
+ EXPECT_NE(LEGOPF, irsend.capture.decode_type);
+}
+
+// Decode normal "synthetic" message with releats.
+TEST(TestDecodeLegoPf, SyntheticDecodeWithRepeat) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendLegoPf(0x330F, kLegoPfBits, 1);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(LEGOPF, irsend.capture.decode_type);
+ EXPECT_EQ(kLegoPfBits, irsend.capture.bits);
+ EXPECT_EQ(0x330F, irsend.capture.value);
+ EXPECT_EQ(4, irsend.capture.address);
+ EXPECT_EQ(0x30, irsend.capture.command);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Lutron_test.cpp
similarity index 95%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Lutron_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Lutron_test.cpp
index 6c99b9904630..d682967ca4ef 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Lutron_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Lutron_test.cpp
@@ -11,17 +11,19 @@ TEST(TestSendLutron, SendDataOnly) {
IRsendTest irsend(0);
irsend.begin();
irsend.sendLutron(0);
- EXPECT_EQ("m2288s230080", irsend.outputStr());
+ EXPECT_EQ("f40000d40m2288s230080", irsend.outputStr());
irsend.sendLutron(0xAAAAAAAAA); // Longest possible sequence. (I think)
EXPECT_EQ(
+ "f40000d40"
"m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288"
"m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288m2288s2288"
"m2288s2288m2288s2288m2288s2288m2288s152288",
irsend.outputStr());
irsend.sendLutron(0x7FFFFFFFF);
- EXPECT_EQ("m82368s150000", irsend.outputStr());
+ EXPECT_EQ("f40000d40m82368s150000", irsend.outputStr());
irsend.sendLutron(0x7F88BD120);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440",
irsend.outputStr());
@@ -34,12 +36,14 @@ TEST(TestSendLutron, SendWithRepeats) {
// Send a command with 0 repeats.
irsend.sendLutron(0x7F88BD120, kLutronBits, 0);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440",
irsend.outputStr());
// Send a command with 1 repeat.
irsend.sendLutron(0x7F88BD120, kLutronBits, 1);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
@@ -48,6 +52,7 @@ TEST(TestSendLutron, SendWithRepeats) {
// Send a command with 3 repeats.
irsend.sendLutron(0x7F88BD120, kLutronBits, 3);
EXPECT_EQ(
+ "f40000d40"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
"s161440"
"m20592s6864m2288s6864m2288s2288m9152s2288m2288s6864m2288s4576m2288"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_MWM_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_MWM_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_MWM_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_MWM_test.cpp
index 9ecd0eac146a..2ca69ac833cd 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_MWM_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_MWM_test.cpp
@@ -36,6 +36,7 @@ TEST(TestSendMWM, SendDataOnly) {
*/
irsend.sendMWM(test1, sizeof(test1), 0);
EXPECT_EQ(
+ "f38000d25"
"m834s834m417s417m834s834"
"m417s417m834s834m1251s417"
"m2085s417m1251s417"
@@ -65,6 +66,7 @@ TEST(TestSendMWM, SendDataOnly) {
};
irsend.sendMWM(test2, sizeof(test2), 0);
EXPECT_EQ(
+ "f38000d25"
"m417s417m834s834m834s834"
"m834s834m834s417m834s417"
"m834s834m834s834m417s417"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Magiquest_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Magiquest_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Magiquest_test.cpp
index e1c3da83dede..bbc5f3366379 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Magiquest_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Magiquest_test.cpp
@@ -26,6 +26,7 @@ TEST(TestSendMagiQuest, SendDataOnly) {
irsend.reset();
irsend.sendMagiQuest(0x0);
EXPECT_EQ(
+ "f36000d50"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
@@ -37,6 +38,7 @@ TEST(TestSendMagiQuest, SendDataOnly) {
irsend.reset();
irsend.sendMagiQuest(0x123456789ABC);
EXPECT_EQ(
+ "f36000d50"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m580s600m280s850m280s850m580s600m280s850"
"m280s850m280s850m580s600m580s600m280s850m580s600m280s850m280s850"
@@ -55,6 +57,7 @@ TEST(TestSendMagiQuest, SendWithRepeats) {
irsend.reset();
irsend.sendMagiQuest(0x12345678ABCD, kMagiquestBits, 2); // two repeats.
EXPECT_EQ(
+ "f36000d50"
"m280s850m280s850m280s850m280s850m280s850m280s850m280s850m280s850"
"m280s850m280s850m280s850m580s600m280s850m280s850m580s600m280s850"
"m280s850m280s850m580s600m580s600m280s850m580s600m280s850m280s850"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Midea_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Midea_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Midea_test.cpp
index 5d5f5e932f44..ced3ea10cec9 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Midea_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Midea_test.cpp
@@ -15,6 +15,7 @@ TEST(TestSendMidea, SendDataOnly) {
irsend.reset();
irsend.sendMidea(0x0);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -36,6 +37,7 @@ TEST(TestSendMidea, SendDataOnly) {
irsend.reset();
irsend.sendMidea(0x55AA55AA55AA);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
@@ -57,6 +59,7 @@ TEST(TestSendMidea, SendDataOnly) {
irsend.reset();
irsend.sendMidea(0xFFFFFFFFFFFF);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -84,6 +87,7 @@ TEST(TestSendMidea, SendWithRepeats) {
irsend.reset();
irsend.sendMidea(0x55AA55AA55AA, kMideaBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
@@ -119,6 +123,7 @@ TEST(TestSendMidea, SendWithRepeats) {
irsend.outputStr());
irsend.sendMidea(0x55AA55AA55AA, kMideaBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
@@ -178,6 +183,7 @@ TEST(TestSendMidea, SendUnusualSize) {
irsend.reset();
irsend.sendMidea(0x0, 8);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s5600"
@@ -189,6 +195,7 @@ TEST(TestSendMidea, SendUnusualSize) {
irsend.reset();
irsend.sendMidea(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d50"
"m4480s4480"
"m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
"m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_MitsubishiHeavy_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_MitsubishiHeavy_test.cpp
new file mode 100644
index 000000000000..340a04078246
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_MitsubishiHeavy_test.cpp
@@ -0,0 +1,851 @@
+// Copyright 2019 David Conran
+
+#include "ir_MitsubishiHeavy.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRremoteESP8266.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestMitsubishiHeavy, Housekeeping) {
+ ASSERT_EQ("MITSUBISHI_HEAVY_88", typeToString(MITSUBISHI_HEAVY_88));
+ ASSERT_TRUE(hasACState(MITSUBISHI_HEAVY_88));
+ ASSERT_EQ("MITSUBISHI_HEAVY_152", typeToString(MITSUBISHI_HEAVY_152));
+ ASSERT_TRUE(hasACState(MITSUBISHI_HEAVY_152));
+}
+
+// Tests for IRMitsubishiHeavy152Ac class.
+
+TEST(TestMitsubishiHeavy152AcClass, Power) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_FALSE(ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_FALSE(ac.getPower());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Temperature) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyCool);
+
+ ac.setTemp(0);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp - 1);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp + 1);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(19);
+ EXPECT_EQ(19, 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());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, OperatingMode) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyAuto);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyCool);
+ EXPECT_EQ(kMitsubishiHeavyCool, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ EXPECT_EQ(kMitsubishiHeavyHeat, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyDry);
+ EXPECT_EQ(kMitsubishiHeavyDry, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyFan);
+ EXPECT_EQ(kMitsubishiHeavyFan, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat + 1);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+}
+
+
+TEST(TestMitsubishiHeavy152AcClass, Filter) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setFilter(true);
+ EXPECT_TRUE(ac.getFilter());
+
+ ac.setFilter(false);
+ EXPECT_FALSE(ac.getFilter());
+
+ ac.setFilter(true);
+ EXPECT_TRUE(ac.getFilter());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Turbo) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Econo) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEcono(false);
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, 3D) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+
+ ac.set3D(false);
+ EXPECT_FALSE(ac.get3D());
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Night) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setNight(true);
+ EXPECT_TRUE(ac.getNight());
+
+ ac.setNight(false);
+ EXPECT_FALSE(ac.getNight());
+
+ ac.setNight(true);
+ EXPECT_TRUE(ac.getNight());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Clean) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+
+ ac.setClean(false);
+ EXPECT_FALSE(ac.getClean());
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, FanSpeed) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ ac.setFan(kMitsubishiHeavy152FanLow);
+ EXPECT_EQ(kMitsubishiHeavy152FanLow, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanAuto);
+ EXPECT_EQ(kMitsubishiHeavy152FanAuto, ac.getFan());
+
+
+ ac.setFan(255);
+ EXPECT_EQ(kMitsubishiHeavy152FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanMax);
+ EXPECT_EQ(kMitsubishiHeavy152FanMax, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanMax + 1);
+ EXPECT_EQ(kMitsubishiHeavy152FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanMax - 1);
+ EXPECT_EQ(kMitsubishiHeavy152FanMax - 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanLow + 1);
+ EXPECT_EQ(kMitsubishiHeavy152FanLow + 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanEcono);
+ EXPECT_EQ(kMitsubishiHeavy152FanEcono, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy152FanTurbo);
+ EXPECT_EQ(kMitsubishiHeavy152FanTurbo, ac.getFan());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, VerticalSwing) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVAuto, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVHighest);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVHighest, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVHighest + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVHighest + 1, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVOff);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVOff, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVOff, ac.getSwingVertical());
+
+ // Out of bounds.
+ ac.setSwingVertical(255);
+ EXPECT_EQ(kMitsubishiHeavy152SwingVOff, ac.getSwingVertical());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, HorizontalSwing) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHAuto, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHLeftMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHLeftMax + 1, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHRightMax);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHRightMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHRightMax - 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHRightMax - 1, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHOff);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHOff, ac.getSwingHorizontal());
+
+ // Out of bounds.
+ ac.setSwingHorizontal(255);
+ EXPECT_EQ(kMitsubishiHeavy152SwingHOff, ac.getSwingHorizontal());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, Checksums) {
+ IRMitsubishiHeavy152Ac ac(0);
+ ac.begin();
+
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+ EXPECT_TRUE(IRMitsubishiHeavy152Ac::validChecksum(expected));
+
+ // Screw up the "checksum" to test it fails.
+ expected[kMitsubishiHeavy152StateLength - 1] = 0x55;
+ EXPECT_FALSE(IRMitsubishiHeavy152Ac::validChecksum(expected));
+ // getting the after getRaw() should repair it.
+ ac.setRaw(expected);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ EXPECT_TRUE(IRMitsubishiHeavy152Ac::validChecksum(ac.getRaw()));
+}
+
+TEST(TestMitsubishiHeavy152AcClass, HumanReadable) {
+ IRMitsubishiHeavy152Ac ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+ ac.on();
+ ac.setMode(kMitsubishiHeavyCool);
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ ac.setFan(kMitsubishiHeavy152FanMax);
+ ac.setFilter(true);
+ ac.setNight(true);
+ ac.setTurbo(false);
+ ac.setSilent(true);
+ ac.setEcono(false);
+ ac.set3D(true);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 4 (Max), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: On, Turbo: Off, "
+ "Econo: Off, Night: On, Filter: On, 3D: On, Clean: Off",
+ ac.toString());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ ac.setFilter(true);
+ ac.setNight(false);
+ ac.setTurbo(true);
+ ac.setEcono(false);
+ ac.setSilent(false);
+ ac.set3D(false);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVLowest);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 8 (Turbo), "
+ "Swing (V): 5 (Lowest), Swing (H): 1 (Max Left), Silent: Off, Turbo: On, "
+ "Econo: Off, Night: Off, Filter: On, 3D: Off, Clean: Off",
+ ac.toString());
+
+ ac.setClean(true);
+ ac.setEcono(true);
+ ac.setMode(kMitsubishiHeavyAuto);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVOff);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (Auto), Temp: 31C, Fan: 6 (Econo), "
+ "Swing (V): 6 (Off), Swing (H): 1 (Max Left), Silent: Off, "
+ "Turbo: Off, Econo: On, Night: Off, Filter: On, 3D: Off, Clean: On",
+ ac.toString());
+
+ ac.setClean(false);
+ ac.setTemp(25);
+ ac.setEcono(false);
+ ac.setMode(kMitsubishiHeavyDry);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftRight);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
+ "Swing (V): 6 (Off), Swing (H): 7 (Left Right), Silent: Off, "
+ "Turbo: Off, Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+}
+
+TEST(TestMitsubishiHeavy152AcClass, ReconstructKnownExample) {
+ IRMitsubishiHeavy152Ac ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, "
+ "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off",
+ ac.toString());
+ ac.on();
+ ac.setMode(kMitsubishiHeavyHeat);
+ ac.setTemp(24);
+ ac.setFan(kMitsubishiHeavy152FanMax);
+ ac.setFilter(true);
+ ac.setNight(false);
+ ac.setTurbo(false);
+ ac.setSilent(false);
+ ac.setEcono(false);
+ ac.set3D(false);
+ ac.setClean(false);
+ ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto);
+ ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto);
+ EXPECT_EQ(
+ "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());
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+ EXPECT_STATE_EQ(expected, ac.getRaw(), kMitsubishiHeavy152Bits);
+}
+
+// Tests for IRMitsubishiHeavy88Ac class.
+
+TEST(TestMitsubishiHeavy88AcClass, Power) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_FALSE(ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_FALSE(ac.getPower());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Temperature) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyCool);
+
+ ac.setTemp(0);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMinTemp - 1);
+ EXPECT_EQ(kMitsubishiHeavyMinTemp, ac.getTemp());
+
+ ac.setTemp(kMitsubishiHeavyMaxTemp + 1);
+ EXPECT_EQ(kMitsubishiHeavyMaxTemp, ac.getTemp());
+
+ ac.setTemp(19);
+ EXPECT_EQ(19, 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());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, OperatingMode) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kMitsubishiHeavyAuto);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyCool);
+ EXPECT_EQ(kMitsubishiHeavyCool, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ EXPECT_EQ(kMitsubishiHeavyHeat, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyDry);
+ EXPECT_EQ(kMitsubishiHeavyDry, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyFan);
+ EXPECT_EQ(kMitsubishiHeavyFan, ac.getMode());
+
+ ac.setMode(kMitsubishiHeavyHeat + 1);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kMitsubishiHeavyAuto, ac.getMode());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Turbo) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Econo) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+
+ ac.setEcono(false);
+ EXPECT_FALSE(ac.getEcono());
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, 3D) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+
+ ac.set3D(false);
+ EXPECT_FALSE(ac.get3D());
+
+ ac.set3D(true);
+ EXPECT_TRUE(ac.get3D());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Clean) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+
+ ac.setClean(false);
+ EXPECT_FALSE(ac.getClean());
+
+ ac.setClean(true);
+ EXPECT_TRUE(ac.getClean());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, FanSpeed) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ ac.setFan(kMitsubishiHeavy88FanLow);
+ EXPECT_EQ(kMitsubishiHeavy88FanLow, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanAuto);
+ EXPECT_EQ(kMitsubishiHeavy88FanAuto, ac.getFan());
+
+
+ ac.setFan(255);
+ EXPECT_EQ(kMitsubishiHeavy88FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanHigh);
+ EXPECT_EQ(kMitsubishiHeavy88FanHigh, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanHigh + 1);
+ EXPECT_EQ(kMitsubishiHeavy88FanAuto, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanHigh - 1);
+ EXPECT_EQ(kMitsubishiHeavy88FanHigh - 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanLow + 1);
+ EXPECT_EQ(kMitsubishiHeavy88FanLow + 1, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanEcono);
+ EXPECT_EQ(kMitsubishiHeavy88FanEcono, ac.getFan());
+
+ ac.setFan(kMitsubishiHeavy88FanTurbo);
+ EXPECT_EQ(kMitsubishiHeavy88FanTurbo, ac.getFan());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, VerticalSwing) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVAuto);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVAuto, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVHighest);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVHighest, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVOff);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVHighest + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+
+ // Out of bounds.
+ ac.setSwingVertical(255);
+ EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, HorizontalSwing) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHAuto);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHAuto, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHLeftMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHRightMax, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax - 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHOff);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHOff + 1);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+
+ // Out of bounds.
+ ac.setSwingHorizontal(255);
+ EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal());
+}
+
+TEST(TestMitsubishiHeavy88AcClass, Checksums) {
+ IRMitsubishiHeavy88Ac ac(0);
+ ac.begin();
+
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+
+ uint8_t expected[kMitsubishiHeavy88StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xD9, 0x26, 0x48, 0xB7, 0x00, 0xFF, 0x8A, 0x75};
+ EXPECT_TRUE(IRMitsubishiHeavy88Ac::validChecksum(expected));
+
+ // Screw up the "checksum" to test it fails.
+ expected[kMitsubishiHeavy88StateLength - 1] = 0x55;
+ EXPECT_FALSE(IRMitsubishiHeavy88Ac::validChecksum(expected));
+ // getting the after getRaw() should repair it.
+ ac.setRaw(expected);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ EXPECT_TRUE(IRMitsubishiHeavy88Ac::validChecksum(ac.getRaw()));
+}
+
+TEST(TestMitsubishiHeavy88AcClass, HumanReadable) {
+ IRMitsubishiHeavy88Ac ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Off), Swing (H): 0 (Off), "
+ "Turbo: Off, Econo: Off, 3D: Off, Clean: Off",
+ ac.toString());
+ ac.on();
+ ac.setMode(kMitsubishiHeavyCool);
+ ac.setTemp(kMitsubishiHeavyMinTemp);
+ ac.setFan(kMitsubishiHeavy88FanHigh);
+ ac.setTurbo(false);
+ ac.setEcono(false);
+ ac.set3D(true);
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVAuto);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 4 (High), "
+ "Swing (V): 16 (Auto), Swing (H): 200 (3D), "
+ "Turbo: Off, Econo: Off, 3D: On, Clean: Off",
+ ac.toString());
+
+ ac.setMode(kMitsubishiHeavyHeat);
+ ac.setTemp(kMitsubishiHeavyMaxTemp);
+ ac.setTurbo(true);
+ ac.setEcono(false);
+ ac.set3D(false);
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVLowest);
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 6 (Turbo), "
+ "Swing (V): 26 (Lowest), Swing (H): 4 (Max Left), Turbo: On, Econo: Off, "
+ "3D: Off, Clean: Off",
+ ac.toString());
+
+ ac.setClean(true);
+ ac.setEcono(true);
+ ac.setMode(kMitsubishiHeavyAuto);
+ ac.setSwingVertical(kMitsubishiHeavy88SwingVOff);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (Auto), Temp: 31C, Fan: 7 (Econo), "
+ "Swing (V): 0 (Off), Swing (H): 4 (Max Left), Turbo: Off, Econo: On, "
+ "3D: Off, Clean: On",
+ ac.toString());
+
+ ac.setClean(false);
+ ac.setTemp(25);
+ ac.setEcono(false);
+ ac.setMode(kMitsubishiHeavyDry);
+ ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftRight);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Off), Swing (H): 72 (Left Right), Turbo: Off, Econo: Off, "
+ "3D: Off, Clean: Off",
+ ac.toString());
+}
+
+// Tests for decodeMitsubishiHeavy().
+
+// Decode a real MitsubishiHeavy 152Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZmsRealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy152Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+
+ // Ref: https://github.com/markszabo/IRremoteESP8266/issues/660#issuecomment-480571466
+ uint16_t rawData[307] = {
+ 3136, 1638, 364, 428, 366, 1224, 362, 432, 364, 430, 364, 1226, 362, 432,
+ 364, 1224, 366, 428, 366, 430, 366, 1224, 362, 1228, 362, 1228, 362, 432,
+ 364, 1224, 364, 432, 364, 1226, 364, 1224, 366, 1226, 364, 428, 364, 430,
+ 364, 430, 364, 432, 366, 1226, 364, 1224, 364, 430, 364, 1226, 364, 428,
+ 364, 1224, 368, 1224, 364, 428, 364, 430, 366, 430, 364, 1158, 430, 432,
+ 366, 1222, 366, 430, 366, 430, 364, 1226, 364, 1224, 364, 1224, 364, 1224,
+ 366, 1224, 364, 430, 364, 430, 364, 1228, 362, 1226, 364, 1226, 366, 1222,
+ 366, 430, 364, 430, 364, 1224, 366, 1224, 364, 430, 364, 430, 364, 432,
+ 364, 430, 364, 428, 364, 430, 364, 430, 366, 1226, 362, 1154, 434, 1228,
+ 364, 1226, 362, 1226, 364, 1226, 364, 1228, 362, 1226, 362, 432, 364, 430,
+ 364, 428, 364, 430, 364, 430, 364, 1228, 362, 1228, 362, 432, 364, 1224,
+ 368, 1224, 364, 1226, 362, 1226, 364, 1226, 366, 428, 366, 430, 364, 1224,
+ 364, 430, 366, 430, 366, 430, 364, 430, 364, 430, 364, 1226, 364, 1226,
+ 366, 1224, 366, 1224, 366, 1226, 364, 1224, 366, 1224, 366, 1224, 366,
+ 428, 364, 430, 366, 428, 364, 430, 364, 430, 366, 428, 364, 430, 364, 432,
+ 364, 1226, 364, 1226, 364, 1226, 364, 1228, 364, 1222, 370, 1222, 362,
+ 1228, 362, 1226, 362, 430, 364, 430, 364, 430, 364, 432, 364, 428, 364,
+ 432, 364, 428, 364, 430, 366, 1226, 362, 1224, 364, 1226, 364, 1226, 364,
+ 1226, 362, 1226, 366, 1224, 366, 1224, 364, 430, 364, 432, 364, 428, 364,
+ 432, 364, 428, 364, 430, 366, 430, 364, 430, 364, 1226, 362, 1226, 364,
+ 1224, 366, 1226, 362, 1228, 364, 1224, 366, 1224, 364, 430, 364, 432, 364,
+ 428, 364, 430, 364, 430, 364, 430, 366, 430, 364, 430, 338, 1252, 362
+ }; // UNKNOWN 5138D49D
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 307, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "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());
+}
+
+// Decode a Synthetic MitsubishiHeavy 152Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZmsSyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy152Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x0C, 0xF3, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+
+ irsend.reset();
+ irsend.sendMitsubishiHeavy152(expected);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "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());
+}
+
+// Decode a real MitsubishiHeavy 152Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZmsRealExample2) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy152Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy152StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xE5, 0x1A, 0x04, 0xFB, 0x07,
+ 0xF8, 0x04, 0xFB, 0x00, 0xFF, 0x00, 0xFF, 0x00,
+ 0xFF, 0x80, 0x7F};
+
+ // Ref: https://github.com/markszabo/IRremoteESP8266/issues/660#issuecomment-480571466
+ uint16_t rawData[307] = {
+ 3196, 1580, 398, 390, 404, 1190, 400, 390, 402, 390, 402, 1192, 402, 388,
+ 402, 1192, 400, 390, 402, 392, 402, 1192, 400, 1188, 400, 1188, 400, 390,
+ 404, 1192, 398, 392, 400, 1192, 402, 1188, 400, 1190, 402, 388, 402, 392,
+ 404, 392, 402, 392, 404, 1188, 400, 1190, 398, 392, 404, 1188, 398, 392,
+ 402, 1192, 398, 1190, 400, 390, 404, 390, 402, 392, 404, 1188, 398, 392,
+ 404, 1190, 400, 392, 400, 394, 402, 1192, 398, 1190, 398, 1192, 398, 1190,
+ 400, 1190, 398, 392, 402, 1192, 398, 1190, 398, 1190, 398, 1192, 396,
+ 1192, 398, 396, 400, 394, 398, 1194, 396, 394, 400, 394, 398, 396, 398,
+ 396, 400, 402, 390, 394, 402, 392, 398, 396, 398, 1194, 396, 1194, 398,
+ 1192, 398, 1192, 396, 1194, 396, 1192, 396, 1196, 398, 1190, 398, 392,
+ 402, 392, 402, 394, 398, 394, 400, 394, 400, 1192, 398, 1192, 400, 390,
+ 402, 1190, 398, 1190, 398, 1192, 402, 1188, 398, 1190, 400, 390, 402, 392,
+ 402, 1190, 400, 390, 404, 390, 402, 394, 402, 392, 402, 390, 404, 1190,
+ 400, 1188, 400, 1190, 400, 1190, 402, 1188, 402, 1188, 400, 1188, 402,
+ 1190, 400, 388, 402, 394, 404, 392, 404, 388, 404, 390, 404, 392, 402,
+ 394, 402, 390, 402, 1190, 402, 1186, 402, 1190, 400, 1190, 398, 1190, 402,
+ 1186, 402, 1190, 400, 1188, 400, 390, 404, 392, 404, 390, 402, 392, 402,
+ 392, 400, 394, 402, 392, 402, 394, 400, 1192, 400, 1190, 400, 1188, 400,
+ 1192, 400, 1186, 402, 1190, 400, 1190, 400, 1188, 402, 388, 402, 390, 404,
+ 392, 402, 392, 402, 392, 402, 392, 404, 392, 402, 392, 404, 1190, 400,
+ 1190, 398, 1190, 400, 1190, 400, 1190, 400, 1188, 400, 1188, 400, 392,
+ 402, 392, 404, 390, 402, 392, 402, 392, 402, 392, 402, 390, 402, 392, 402,
+ 1192, 398}; // UNKNOWN A650F2C1
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 307, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_152, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy152Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: Off, 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());
+}
+
+// Decode a Synthetic MitsubishiHeavy 88 Bit message.
+TEST(TestDecodeMitsubishiHeavy, ZjsSyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRMitsubishiHeavy88Ac ac(0);
+ irsend.begin();
+
+ uint8_t expected[kMitsubishiHeavy88StateLength] = {
+ 0xAD, 0x51, 0x3C, 0xD9, 0x26, 0x48, 0xB7, 0x00, 0xFF, 0x8A, 0x75};
+
+ irsend.reset();
+ irsend.sendMitsubishiHeavy88(expected);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(MITSUBISHI_HEAVY_88, irsend.capture.decode_type);
+ ASSERT_EQ(kMitsubishiHeavy88Bits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), "
+ "Swing (V): 0 (Off), Swing (H): 72 (Left Right), Turbo: Off, Econo: Off, "
+ "3D: Off, Clean: Off",
+ ac.toString());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Mitsubishi_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Mitsubishi_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Mitsubishi_test.cpp
index 7b8eb2192fad..6c9480b319ae 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Mitsubishi_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Mitsubishi_test.cpp
@@ -17,6 +17,7 @@ TEST(TestSendMitsubishi, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi(0xE242);
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080"
@@ -28,6 +29,7 @@ TEST(TestSendMitsubishi, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi(0x0);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s34080"
@@ -39,6 +41,7 @@ TEST(TestSendMitsubishi, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi(0x4321);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s2100"
"m300s900m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100"
"m300s28080"
@@ -56,6 +59,7 @@ TEST(TestSendMitsubishi, SendWithRepeats) {
irsend.reset();
irsend.sendMitsubishi(0xE242, kMitsubishiBits, 0); // 0 repeat.
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080",
@@ -64,6 +68,7 @@ TEST(TestSendMitsubishi, SendWithRepeats) {
irsend.reset();
irsend.sendMitsubishi(0xE242, kMitsubishiBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080"
@@ -73,6 +78,7 @@ TEST(TestSendMitsubishi, SendWithRepeats) {
irsend.outputStr());
irsend.sendMitsubishi(0xE242, kMitsubishiBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f33000d50"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s28080"
@@ -93,6 +99,7 @@ TEST(TestSendMitsubishi, SendUnusualSize) {
irsend.reset();
irsend.sendMitsubishi(0x0, 8);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s43680"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
@@ -102,6 +109,7 @@ TEST(TestSendMitsubishi, SendUnusualSize) {
irsend.reset();
irsend.sendMitsubishi(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f33000d50"
"m300s900m300s900m300s900m300s2100m300s900m300s900m300s2100m300s900"
"m300s900m300s900m300s2100m300s2100m300s900m300s2100m300s900m300s900"
"m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100m300s900"
@@ -305,6 +313,7 @@ TEST(TestSendMitsubishiAC, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub_code);
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -360,6 +369,7 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) {
irsend.sendMitsubishiAC(mitsub_code, kMitsubishiACStateLength, 0);
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -385,6 +395,7 @@ TEST(TestSendMitsubishiAC, SendWithRepeats) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub_code, kMitsubishiACStateLength, 2);
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -466,6 +477,7 @@ TEST(TestSendMitsubishiAC, SendUnexpectedSizes) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub_long_code, 19);
ASSERT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -665,6 +677,7 @@ TEST(TestMitsubishiACClass, MessageConstuction) {
irsend.reset();
irsend.sendMitsubishiAC(mitsub.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
@@ -984,6 +997,7 @@ TEST(TestSendMitsubishi2, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi2(0xF82);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560"
"m560s4200"
@@ -999,6 +1013,7 @@ TEST(TestSendMitsubishi2, SendDataOnly) {
irsend.reset();
irsend.sendMitsubishi2(0x0);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s520m560s520m560s520m560s520"
"m560s4200"
@@ -1020,6 +1035,7 @@ TEST(TestSendMitsubishi2, Repeats) {
irsend.reset();
irsend.sendMitsubishi2(0xF82, kMitsubishiBits, 0);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560"
"m560s4200"
@@ -1030,6 +1046,7 @@ TEST(TestSendMitsubishi2, Repeats) {
irsend.reset();
irsend.sendMitsubishi2(0xF82, kMitsubishiBits, 2);
EXPECT_EQ(
+ "f33000d50"
"m8400s4200"
"m560s520m560s520m560s520m560s520m560s1560m560s1560m560s1560m560s1560"
"m560s4200"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_NEC_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_NEC_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_NEC_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_NEC_test.cpp
index 6b84b0ec9157..c881b7b44750 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_NEC_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_NEC_test.cpp
@@ -12,6 +12,7 @@ TEST(TestSendNEC, SendDataOnly) {
irsend.begin();
irsend.sendNEC(0);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -20,6 +21,7 @@ TEST(TestSendNEC, SendDataOnly) {
irsend.outputStr());
irsend.sendNEC(0xAA00FF55);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -33,15 +35,17 @@ TEST(TestSendNEC, SendSmallData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendNEC(0xA, 4); // Send only 4 data bits.
- EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s87360",
+ EXPECT_EQ("f38000d33m8960s4480m560s1680m560s560m560s1680m560s560m560s87360",
irsend.outputStr());
irsend.sendNEC(0, 8); // Send only 8 data bits.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s85120",
irsend.outputStr());
irsend.sendNEC(0x1234567890ABCDEF, 64); // Send 64 data bits.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s560m560s560m560s1680m560s1680m560s560"
"m560s1680m560s560m560s560m560s560m560s1680m560s560m560s1680"
@@ -61,17 +65,20 @@ TEST(TestSendNEC, SendWithRepeats) {
irsend.begin();
irsend.sendNEC(0, 8, 0); // Send a command with 0 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s85120",
irsend.outputStr());
irsend.sendNEC(0xAA, 8, 1); // Send a command with 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s80640"
"m8960s2240m560s96320",
irsend.outputStr());
irsend.sendNEC(0xAA, 8, 3); // Send a command with 3 repeats.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s80640"
"m8960s2240m560s96320"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Nikai_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Nikai_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Nikai_test.cpp
index 4a4ea05bb07a..fff242326e65 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Nikai_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Nikai_test.cpp
@@ -13,6 +13,7 @@ TEST(TestSendNikai, SendDataOnly) {
irsend.reset();
irsend.sendNikai(0xD5F2A); // Nikai TV Power Off.
EXPECT_EQ(
+ "f38000d33"
"m4000s4000"
"m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000"
"m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000"
@@ -31,6 +32,7 @@ TEST(TestSendNikai, SendWithRepeats) {
irsend.reset();
irsend.sendNikai(0xD5F2A, kNikaiBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m4000s4000"
"m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000"
"m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000"
@@ -44,6 +46,7 @@ TEST(TestSendNikai, SendWithRepeats) {
irsend.outputStr());
irsend.sendNikai(0xD5F2A, kNikaiBits, 2); // 2 repeat.
EXPECT_EQ(
+ "f38000d33"
"m4000s4000"
"m500s2000m500s2000m500s2000m500s2000m500s1000m500s1000m500s2000"
"m500s1000m500s2000m500s1000m500s2000m500s1000m500s1000m500s1000"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Panasonic_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Panasonic_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Panasonic_test.cpp
index a1d8a7979407..4d10f8fb18bb 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Panasonic_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Panasonic_test.cpp
@@ -32,6 +32,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
irsend.reset();
irsend.sendPanasonic64(0x0);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
@@ -45,6 +46,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -58,6 +60,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
irsend.reset();
irsend.sendPanasonic64(0xFFFFFFFFFFFF);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
@@ -77,6 +80,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 0); // 0 repeats.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -90,6 +94,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -110,6 +115,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
irsend.sendPanasonic64(0x40040190ED7C, kPanasonicBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -145,6 +151,7 @@ TEST(TestSendPanasonic64, SendUnusualSize) {
irsend.reset();
irsend.sendPanasonic64(0x0, 8);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s150768",
@@ -153,6 +160,7 @@ TEST(TestSendPanasonic64, SendUnusualSize) {
irsend.reset();
irsend.sendPanasonic64(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s432m432s432m432s1296m432s432m432s432m432s1296m432s432"
"m432s432m432s432m432s1296m432s1296m432s432m432s1296m432s432m432s432"
@@ -483,6 +491,7 @@ TEST(TestSendPanasonicAC, SendDataOnly) {
0x00, 0x06, 0x60, 0x00, 0x00, 0x80, 0x00, 0x06, 0x83};
irsend.sendPanasonicAC(state);
EXPECT_EQ(
+ "f36700d50"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Pioneer_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Pioneer_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Pioneer_test.cpp
index b78469adda1f..36d61c706f2a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pioneer_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Pioneer_test.cpp
@@ -13,6 +13,7 @@ TEST(TestSendPioneer, SendDataOnly) {
irsend.begin();
irsend.sendPioneer(0);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
@@ -28,6 +29,7 @@ TEST(TestSendPioneer, SendDataOnly) {
irsend.outputStr());
irsend.sendPioneer(0x55FF00AAAA00FF55);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
@@ -136,6 +138,7 @@ TEST(TestDecodePioneer, SyntheticPioneerMessage) {
irsend.reset();
irsend.sendPioneer(0x659A857AF50A3DC2, 64, 0);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Pronto_test.cpp
similarity index 96%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Pronto_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Pronto_test.cpp
index e52c6dd908f9..513f985da7e8 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Pronto_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Pronto_test.cpp
@@ -58,7 +58,8 @@ TEST(TestSendPronto, MoreDataThanNeededInNormal) {
uint16_t pronto_test[8] = {0x0000, 0x0067, 0x0001, 0x0000,
0x0001, 0x0002, 0x0003, 0x0004};
irsend.sendPronto(pronto_test, 8);
- EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
+ EXPECT_EQ("f40244d50m25s50",
+ irsend.outputStr()); // Only send the data required.
}
TEST(TestSendPronto, MoreDataThanNeededInRepeat) {
@@ -70,7 +71,8 @@ TEST(TestSendPronto, MoreDataThanNeededInRepeat) {
uint16_t pronto_test[8] = {0x0000, 0x0067, 0x0000, 0x0001,
0x0001, 0x0002, 0x0003, 0x0004};
irsend.sendPronto(pronto_test, 8);
- EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
+ EXPECT_EQ("f40244d50m25s50",
+ irsend.outputStr()); // Only send the data required.
}
TEST(TestSendPronto, MoreDataThanNeededInBoth) {
@@ -82,9 +84,11 @@ TEST(TestSendPronto, MoreDataThanNeededInBoth) {
uint16_t pronto_test[10] = {0x0000, 0x0067, 0x0001, 0x0001, 0x0001,
0x0002, 0x0003, 0x0004, 0x5, 0x6};
irsend.sendPronto(pronto_test, 10);
- EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
+ EXPECT_EQ("f40244d50m25s50",
+ irsend.outputStr()); // Only send the data required.
irsend.sendPronto(pronto_test, 10, 1);
- EXPECT_EQ("m25s50m75s100", irsend.outputStr()); // Only the data required.
+ EXPECT_EQ("f40244d50m25s50m75s100",
+ irsend.outputStr()); // Only the data required.
}
TEST(TestSendPronto, ShortestValidCodeThatSendsNothing) {
@@ -134,6 +138,7 @@ TEST(TestSendPronto, NonRepeatingCode) {
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
@@ -160,6 +165,7 @@ TEST(TestSendPronto, NonRepeatingCode) {
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
@@ -201,6 +207,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) {
EXPECT_EQ(0x1A, irsend.capture.address);
EXPECT_EQ(0x24AE, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
@@ -218,6 +225,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForSony) {
EXPECT_EQ(0x1A, irsend.capture.address);
EXPECT_EQ(0x24AE, irsend.capture.command);
EXPECT_EQ(
+ "f40244d50"
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
@@ -265,6 +273,7 @@ TEST(TestSendPronto, RepeatSequenceOnlyForPanasonic) {
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x1007C7D, irsend.capture.command);
EXPECT_EQ(
+ "f36682d50"
"m3456s1701"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
@@ -305,6 +314,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) {
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
EXPECT_EQ(
+ "f38028d50"
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
@@ -324,6 +334,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) {
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
EXPECT_EQ(
+ "f38028d50"
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
@@ -344,6 +355,7 @@ TEST(TestSendPronto, NormalPlusRepeatSequence) {
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
EXPECT_EQ(
+ "f38028d50"
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_RC5_RC6_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_RC5_RC6_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_RC5_RC6_test.cpp
index e8aa9bfc1a85..da9fa027cb62 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_RC5_RC6_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_RC5_RC6_test.cpp
@@ -79,6 +79,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x0, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s889m889s889m889s889m889"
"s889m889s889m889s889m889s889m889s889m889s889m889s90664",
irsend.outputStr());
@@ -86,6 +87,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x1AAA, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m889s889m1778s1778m1778s1778m1778s1778"
"m1778s1778m1778s1778m1778s90664",
irsend.outputStr());
@@ -93,6 +95,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x175, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s89775",
irsend.outputStr());
@@ -100,6 +103,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x3FFF, kRC5Bits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m889s889m889s889m889s889m889s889m889s889m889s889"
"m889s889m889s889m889s889m889s889m889s889m889s889m889s89775",
irsend.outputStr());
@@ -107,6 +111,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x0, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s889m889s889m889s889m889"
"s889m889s889m889s889m889s889m889s889m889s889m889s90664",
irsend.outputStr());
@@ -114,6 +119,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x1AAA, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m1778s1778m1778s1778m1778s1778m1778"
"s1778m1778s1778m1778s1778m1778s90664",
irsend.outputStr());
@@ -121,6 +127,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x175, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s89775",
irsend.outputStr());
@@ -128,6 +135,7 @@ TEST(TestSendRC5, SendDataOnly) {
irsend.reset();
irsend.sendRC5(0x3FFF, kRC5XBits);
EXPECT_EQ(
+ "f36000d25"
"m1778s1778m889s889m889s889m889s889m889s889m889s889m889"
"s889m889s889m889s889m889s889m889s889m889s889m889s89775",
irsend.outputStr());
@@ -141,6 +149,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x175, kRC5Bits, 1);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m889s889m1778s889m889s889m889s1778m1778s1778"
@@ -150,6 +159,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x175, kRC5Bits, 2);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m889s889m1778s889m889s889m889s1778m1778s1778"
@@ -161,6 +171,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x175, kRC5XBits, 1);
EXPECT_EQ(
+ "f36000d25"
"m889s889m1778s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m889s889m1778s889m889s889m889s1778m1778s1778"
@@ -170,6 +181,7 @@ TEST(TestSendRC5, SendWithRepeats) {
irsend.reset();
irsend.sendRC5(0x1175, kRC5XBits, 2);
EXPECT_EQ(
+ "f36000d25"
"m1778s889m889s889m889s889m889s1778m1778s1778"
"m889s889m889s889m1778s1778m1778s1778m889s90664"
"m1778s889m889s889m889s889m889s1778m1778s1778"
@@ -444,6 +456,7 @@ TEST(TestSendRC6, SendMode0DataOnly) {
irsend.reset();
irsend.sendRC6(0x0);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444s888m888s444m444s444m444s444"
"m444s444m444s444m444s444m444s444m444s444m444s444m444s444"
@@ -454,6 +467,7 @@ TEST(TestSendRC6, SendMode0DataOnly) {
irsend.reset();
irsend.sendRC6(0x1FFFF);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m1332s888m444s444m444s444m444s444"
"m444s444m444s444m444s444m444s444m444s444m444s444m444s444"
@@ -464,6 +478,7 @@ TEST(TestSendRC6, SendMode0DataOnly) {
irsend.reset();
irsend.sendRC6(0x15555);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m1332s1332m888s888m888s888"
"m888s888m888s888m888s888m888s888m888s888m888"
@@ -479,6 +494,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0x0, kRC6_36Bits);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -492,6 +508,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0xFFFFFFFFF, kRC6_36Bits);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s444m444s444m444s444m444s444"
"m888s888"
@@ -505,6 +522,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0xAAAAAAAAAA, kRC6_36Bits);
EXPECT_EQ(
+ "f36000d33"
"m2664s888m444s444m444s888m888"
"s1332m1332"
"s888m888s888m888s888m888s888m888s888m888s888m888s888m888s888m888s888m888"
@@ -514,6 +532,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.reset();
irsend.sendRC6(0xC800F740C, kRC6_36Bits); // Xbox 360 OnOff code
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s444m444s444m444s888m444"
"s888m1332"
@@ -526,6 +545,7 @@ TEST(TestSendRC6, Send36BitDataOnly) {
irsend.sendRC6(irsend.toggleRC6(0xC800F740C, kRC6_36Bits),
kRC6_36Bits); // Xbox 360 OnOff code (toggled)
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s444m444s444m444s888m444"
"s888m1332"
@@ -544,6 +564,7 @@ TEST(TestSendRC6, SendMode0WithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6Mode0Bits, 0);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -554,6 +575,7 @@ TEST(TestSendRC6, SendMode0WithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6Mode0Bits, 1);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -569,6 +591,7 @@ TEST(TestSendRC6, SendMode0WithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6Mode0Bits, 2);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -595,6 +618,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6_36Bits, 0);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -607,6 +631,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6_36Bits, 1);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
@@ -626,6 +651,7 @@ TEST(TestSendRC6, Send36BitWithRepeats) {
irsend.reset();
irsend.sendRC6(0x175, kRC6_36Bits, 2);
EXPECT_EQ(
+ "f36000d33"
"m2664s888"
"m444s888m444s444m444s444m444"
"s888m888"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_RCMM_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_RCMM_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_RCMM_test.cpp
index 028dbd8b3b6f..22306a59b996 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_RCMM_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_RCMM_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendRCMM, SendDataOnly) {
irsend.reset();
irsend.sendRCMM(0xe0a600);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
@@ -22,6 +23,7 @@ TEST(TestSendRCMM, SendDataOnly) {
irsend.reset();
irsend.sendRCMM(0x28e0a600UL, 32);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
@@ -37,6 +39,7 @@ TEST(TestSendRCMM, SendWithRepeats) {
irsend.reset();
irsend.sendRCMM(0x28e0a600, 32, 2); // 2 repeats.
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
@@ -60,6 +63,7 @@ TEST(TestSendRCMM, SendUnusualSize) {
irsend.reset();
irsend.sendRCMM(0xE0, 8);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s777m166s611m166s277m166s277"
"m166s24313",
@@ -67,6 +71,7 @@ TEST(TestSendRCMM, SendUnusualSize) {
irsend.reset();
irsend.sendRCMM(0x28e0a60000UL, 40);
EXPECT_EQ(
+ "f36000d33"
"m416s277"
"m166s277m166s611m166s611m166s277m166s777m166s611m166s277m166s277"
"m166s611m166s611m166s444m166s611m166s277m166s277m166s277m166s277"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Samsung_test.cpp
similarity index 77%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Samsung_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Samsung_test.cpp
index 9ee1fcabbc6a..8670ac4abbe0 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Samsung_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Samsung_test.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 David Conran
+// Copyright 2017, 2018, 2019 David Conran
#include "ir_Samsung.h"
#include "IRrecv.h"
@@ -7,6 +7,13 @@
#include "IRsend_test.h"
#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestSamsung, Housekeeping) {
+ ASSERT_EQ("SAMSUNG", typeToString(SAMSUNG));
+ ASSERT_FALSE(hasACState(SAMSUNG));
+}
+
// Tests for sendSAMSUNG().
// Test sending typical data only.
@@ -17,6 +24,7 @@ TEST(TestSendSamsung, SendDataOnly) {
irsend.reset();
irsend.sendSAMSUNG(0xE0E09966); // Samsung TV Power On.
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560"
@@ -36,6 +44,7 @@ TEST(TestSendSamsung, SendWithRepeats) {
irsend.reset();
irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560"
@@ -51,6 +60,7 @@ TEST(TestSendSamsung, SendWithRepeats) {
irsend.outputStr());
irsend.sendSAMSUNG(0xE0E09966, kSamsungBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d33"
"m4480s4480"
"m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s560"
@@ -281,17 +291,24 @@ TEST(TestDecodeSamsung, FailToDecodeNonSamsungExample) {
ASSERT_FALSE(irrecv.decodeSAMSUNG(&irsend.capture, kSamsungBits, false));
}
+// General housekeeping
+TEST(TestSamsungAC, Housekeeping) {
+ ASSERT_EQ("SAMSUNG_AC", typeToString(SAMSUNG_AC));
+ ASSERT_TRUE(hasACState(SAMSUNG_AC));
+}
+
// Tests for sendSamsungAC().
// Test sending typical data only.
TEST(TestSendSamsungAC, SendDataOnly) {
IRsendTest irsend(0);
irsend.begin();
- uint8_t data[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0x02, 0xAF,
- 0x71, 0x00, 0x15, 0xF0};
+ uint8_t data[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0};
irsend.sendSamsungAC(data);
EXPECT_EQ(
+ "f38000d50"
"m690s17844"
"m3086s8864"
"m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436"
@@ -320,10 +337,12 @@ TEST(TestSendSamsungAC, SendExtendedData) {
irsend.begin();
// "Off" message.
uint8_t data[kSamsungAcExtendedStateLength] = {
- 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xD2, 0x0F, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0};
+ 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0};
irsend.sendSamsungAC(data, kSamsungAcExtendedStateLength);
EXPECT_EQ(
+ "f38000d50"
"m690s17844"
"m3086s8864"
"m586s436m586s1432m586s436m586s436m586s436m586s436m586s436m586s436"
@@ -358,15 +377,16 @@ TEST(TestSendSamsungAC, SendExtendedData) {
// Tests for IRSamsungAc class.
TEST(TestIRSamsungAcClass, SetAndGetRaw) {
- uint8_t expectedState[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0xE2, 0xFE,
- 0x71, 0x40, 0x11, 0xF0};
+ uint8_t expectedState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
IRSamsungAc samsung(0);
samsung.setRaw(expectedState);
EXPECT_STATE_EQ(expectedState, samsung.getRaw(), kSamsungAcBits);
uint8_t extendedState[kSamsungAcExtendedStateLength] = {
- 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xD2, 0x0F, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
samsung.setRaw(extendedState, kSamsungAcExtendedStateLength);
// We should NOT get the extended state back.
EXPECT_STATE_EQ(expectedState, samsung.getRaw(), kSamsungAcBits);
@@ -496,9 +516,15 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) {
const uint8_t originalstate[kSamsungAcStateLength] = {
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0};
- uint8_t examplestate[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0x02, 0xAF,
- 0x71, 0x00, 0x15, 0xF0};
+ uint8_t examplestate[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0};
+
+ const uint8_t extendedstate[kSamsungAcExtendedStateLength] = {
+ 0x02, 0xA9, 0x0F, 0x00, 0x00, 0x00, 0xC0,
+ 0x01, 0xC9, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0xF9, 0xCE, 0x71, 0xE0, 0x41, 0xC0};
+
EXPECT_TRUE(IRSamsungAc::validChecksum(examplestate));
EXPECT_EQ(0, IRSamsungAc::calcChecksum(examplestate));
@@ -516,6 +542,9 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) {
examplestate[11] = 0x01;
EXPECT_FALSE(IRSamsungAc::validChecksum(examplestate));
EXPECT_EQ(0xF, IRSamsungAc::calcChecksum(examplestate));
+
+ // Check an extended state is valid.
+ EXPECT_TRUE(IRSamsungAc::validChecksum(extendedstate, 21));
}
TEST(TestIRSamsungAcClass, HumanReadable) {
@@ -585,9 +614,9 @@ TEST(TestDecodeSamsungAC, SyntheticDecode) {
IRrecv irrecv(0);
irsend.begin();
irsend.reset();
- uint8_t expectedState[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0x02, 0xAF,
- 0x71, 0x00, 0x15, 0xF0};
+ uint8_t expectedState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0};
// Synthesised Normal Samsung A/C message.
irsend.sendSamsungAC(expectedState);
irsend.makeDecodeResult();
@@ -626,9 +655,9 @@ TEST(TestDecodeSamsungAC, DecodeRealExample) {
584, 1406, 586, 410, 584, 1384, 606, 410, 586, 410, 584, 408,
586, 408, 586, 408, 586, 408, 588, 410, 584, 1408, 590, 1400,
592, 1398, 602, 1388, 612};
- uint8_t expectedState[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0x02, 0xAF,
- 0x71, 0x00, 0x15, 0xF0};
+ uint8_t expectedState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0x02, 0xAF, 0x71, 0x00, 0x15, 0xF0};
irsend.sendRaw(rawData, 233, 38000);
irsend.makeDecodeResult();
@@ -675,9 +704,9 @@ TEST(TestDecodeSamsungAC, DecodeRealExample2) {
560, 436, 486, 510, 566, 1400, 598, 420, 576, 418, 582, 414,
586, 410, 584, 410, 584, 410, 586, 410, 584, 1382, 608, 1384,
606, 1384, 606, 1408, 600};
- uint8_t expectedState[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0xE2, 0xFE,
- 0x71, 0x80, 0x11, 0xF0};
+ uint8_t expectedState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0};
irsend.sendRaw(rawData, 233, 38000);
irsend.makeDecodeResult();
@@ -735,8 +764,9 @@ TEST(TestDecodeSamsungAC, DecodePowerOnSample) {
518, 480, 520, 480, 520, 1454, 568, 1430, 566, 1432, 566, 1454,
594};
uint8_t expectedState[kSamsungAcExtendedStateLength] = {
- 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xD2, 0x0F, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0};
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0};
irsend.sendRaw(rawData, 349, 38000);
irsend.makeDecodeResult();
@@ -794,8 +824,9 @@ TEST(TestDecodeSamsungAC, DecodePowerOffSample) {
608};
uint8_t expectedState[kSamsungAcExtendedStateLength] = {
- 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0x01, 0xD2, 0x0F, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0};
+ 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
+ 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0};
irsend.sendRaw(rawData, 349, 38000);
irsend.makeDecodeResult();
@@ -840,9 +871,9 @@ TEST(TestDecodeSamsungAC, DecodeHeatSample) {
512, 482, 512, 482, 510, 484, 510, 484, 510, 1478, 512, 1504,
488, 1480, 560, 1454, 514};
- uint8_t expectedState[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0x02, 0xAF,
- 0x71, 0x10, 0x41, 0xF0};
+ uint8_t expectedState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0x02, 0xAF, 0x71, 0x10, 0x41, 0xF0};
irsend.sendRaw(rawData, 233, 38000);
irsend.makeDecodeResult();
@@ -887,9 +918,9 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) {
584, 412, 584, 408, 586, 410, 586, 408, 586, 1404, 586, 1408,
582, 1410, 562, 1426, 610};
- uint8_t expectedState[kSamsungAcStateLength] = {0x02, 0x92, 0x0F, 0x00, 0x00,
- 0x00, 0xF0, 0x01, 0xE2, 0xFE,
- 0x71, 0x40, 0x11, 0xF0};
+ uint8_t expectedState[kSamsungAcStateLength] = {
+ 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
+ 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
irsend.sendRaw(rawData, 233, 38000);
irsend.makeDecodeResult();
@@ -905,3 +936,195 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) {
"Beep: Off, Clean: Off, Quiet: Off",
samsung.toString());
}
+
+TEST(TestDecodeSamsungAC, Issue604DecodeExtended) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint16_t sendOff[349] = {
+ 642, 17730, 3056, 8916, 542, 448, 552, 1440, 552, 444, 552, 444,
+ 552, 444, 552, 440, 556, 440, 556, 440, 556, 1436, 552, 444,
+ 552, 444, 552, 1440, 548, 470, 526, 1464, 470, 526, 516, 1470,
+ 552, 1440, 552, 1440, 550, 1436, 556, 1434, 552, 444, 552, 444,
+ 552, 444, 552, 442, 552, 444, 546, 470, 526, 470, 526, 470,
+ 470, 524, 518, 474, 548, 448, 552, 444, 552, 442, 552, 444,
+ 550, 444, 552, 440, 556, 440, 556, 438, 556, 440, 552, 442,
+ 552, 444, 552, 442, 552, 444, 550, 470, 526, 466, 524, 470,
+ 470, 524, 470, 524, 518, 476, 548, 444, 552, 444, 556, 440,
+ 552, 442, 552, 444, 550, 1436, 556, 1436, 552, 2946, 3026, 8918,
+ 550, 1440, 552, 444, 548, 468, 526, 468, 470, 526, 470, 526,
+ 542, 452, 548, 444, 552, 1440, 550, 444, 552, 444, 552, 1436,
+ 556, 438, 552, 442, 552, 1440, 552, 1440, 552, 1460, 526, 1464,
+ 470, 1516, 548, 1444, 552, 444, 552, 442, 552, 444, 552, 438,
+ 556, 440, 556, 440, 552, 444, 552, 444, 552, 444, 552, 444,
+ 552, 444, 548, 448, 546, 470, 526, 468, 526, 470, 470, 524,
+ 520, 470, 548, 448, 552, 444, 552, 444, 552, 444, 552, 444,
+ 552, 438, 556, 440, 556, 438, 552, 444, 552, 442, 552, 444,
+ 552, 444, 552, 444, 552, 470, 526, 466, 526, 470, 470, 524,
+ 518, 478, 546, 448, 552, 2920, 3052, 8916, 552, 1434, 556, 440,
+ 556, 438, 552, 444, 552, 442, 552, 442, 552, 442, 552, 444,
+ 548, 1444, 548, 470, 526, 470, 522, 1466, 470, 1520, 548, 1438,
+ 556, 1436, 552, 1440, 552, 442, 552, 1436, 552, 1440, 552, 1440,
+ 552, 442, 552, 470, 522, 1466, 526, 1466, 470, 1516, 552, 444,
+ 552, 442, 552, 444, 552, 1436, 556, 1436, 552, 1440, 550, 444,
+ 552, 444, 552, 444, 548, 448, 546, 448, 548, 470, 526, 1462,
+ 474, 1518, 548, 1440, 552, 1438, 556, 440, 550, 444, 552, 444,
+ 552, 444, 552, 440, 556, 1436, 552, 444, 552, 444, 552, 444,
+ 550, 470, 522, 470, 524, 470, 470, 524, 518, 1474, 548, 1440,
+ 556};
+
+ uint8_t expectedState[kSamsungAcExtendedStateLength] = {
+ 0x02, 0xA9, 0x0F, 0x00, 0x00, 0x00, 0xC0,
+ 0x01, 0xC9, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0xF9, 0xCE, 0x71, 0xE0, 0x41, 0xC0};
+
+ irsend.sendRaw(sendOff, 349, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(SAMSUNG_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsungAcExtendedBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+
+ IRSamsungAc samsung(0);
+ 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",
+ samsung.toString());
+}
+
+TEST(TestSendSamsung36, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendSamsung36(0);
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.sendSamsung36(0x400E00FF);
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.reset();
+}
+
+// General housekeeping
+TEST(TestSamsung36, Housekeeping) {
+ ASSERT_EQ("SAMSUNG36", typeToString(SAMSUNG36));
+ ASSERT_FALSE(hasACState(SAMSUNG36));
+}
+
+// Test sending with different repeats.
+TEST(TestSendSamsung36, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 1); // 1 repeat.
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+ irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 2); // 2 repeats.
+ EXPECT_EQ(
+ "f38000d50"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880"
+ "m4480s4480"
+ "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
+ "m560s4480"
+ "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560"
+ "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
+ "m560s1680m560s1680m560s1680m560s1680"
+ "m560s26880",
+ irsend.outputStr());
+}
+
+TEST(TestDecodeSamsung36, RealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint16_t rawData[77] = {
+ 4542, 4438, 568, 432, 562, 436, 536, 462, 538, 460, 538, 460, 564, 1434,
+ 564, 434, 534, 464, 536, 462, 562, 436, 536, 464, 564, 432, 538, 462, 536,
+ 464, 534, 464, 564, 420, 566, 4414, 538, 1462, 566, 1432, 562, 1436, 536,
+ 462, 564, 436, 562, 436, 560, 436, 562, 436, 562, 436, 560, 438, 536, 462,
+ 562, 436, 562, 1436, 562, 1434, 536, 1462, 564, 1434, 562, 1436, 564,
+ 1436, 534, 1462, 534, 1464, 536}; // UNKNOWN E4CD1208
+
+ irsend.sendRaw(rawData, 77, 38000);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x400E00FF, irsend.capture.value);
+ EXPECT_EQ(0xE00FF, irsend.capture.command);
+ EXPECT_EQ(0x400, irsend.capture.address);
+}
+
+TEST(TestDecodeSamsung36, SyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+ irsend.reset();
+
+ irsend.sendSamsung36(0x400E00FF);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeSamsung36(&irsend.capture));
+ ASSERT_EQ(SAMSUNG36, irsend.capture.decode_type);
+ EXPECT_EQ(kSamsung36Bits, irsend.capture.bits);
+ EXPECT_EQ(0x400E00FF, irsend.capture.value);
+ EXPECT_EQ(0xE00FF, irsend.capture.command);
+ EXPECT_EQ(0x400, irsend.capture.address);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sanyo_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sanyo_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sanyo_test.cpp
index 14c1c7da08df..165e29f17dc2 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sanyo_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sanyo_test.cpp
@@ -27,6 +27,7 @@ TEST(TestEncodeSanyoLC7461, SendDataOnly) {
irsend.reset();
irsend.sendSanyoLC7461(0x1D8113F00FF);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
@@ -45,6 +46,7 @@ TEST(TestEncodeSanyoLC7461, SendWithRepeats) {
irsend.reset();
irsend.sendSanyoLC7461(0x1D8113F00FF, kSanyoLC7461Bits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sharp_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sharp_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sharp_test.cpp
index 8481a464997d..c9d3e851b21b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sharp_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sharp_test.cpp
@@ -47,6 +47,7 @@ TEST(TestSendSharp, SendDataOnly) {
irsend.reset();
irsend.sendSharp(0x11, 0x52);
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -64,6 +65,7 @@ TEST(TestSendSharp, SendWithRepeats) {
irsend.reset();
irsend.sendSharp(0x11, 0x52, kSharpBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -87,6 +89,7 @@ TEST(TestSendSharp, SendUnusualSize) {
irsend.reset();
irsend.sendSharp(0x0, 0x0, 8);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820"
@@ -96,6 +99,7 @@ TEST(TestSendSharp, SendUnusualSize) {
irsend.reset();
irsend.sendSharp(0x0, 0x0, 16);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s780m260s780"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
@@ -115,6 +119,7 @@ TEST(TestSendSharpRaw, SendDataOnly) {
irsend.reset();
irsend.sendSharpRaw(0x454A);
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -132,6 +137,7 @@ TEST(TestSendSharpRaw, SendWithRepeats) {
irsend.reset();
irsend.sendSharpRaw(0x454A, kSharpBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d33"
"m260s1820m260s780m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s1820m260s780m260s780m260s1820m260s780m260s1820m260s780"
"m260s43602"
@@ -155,6 +161,7 @@ TEST(TestSendSharpRaw, SendUnusualSize) {
irsend.reset();
irsend.sendSharpRaw(0x2, 8);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s1820m260s1820m260s1820m260s780m260s1820"
@@ -164,6 +171,7 @@ TEST(TestSendSharpRaw, SendUnusualSize) {
irsend.reset();
irsend.sendSharpRaw(0x2, 16);
EXPECT_EQ(
+ "f38000d33"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s780m260s780"
"m260s780m260s780m260s780m260s780m260s780m260s780m260s1820m260s780"
"m260s43602"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sherwood_test.cpp
similarity index 97%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sherwood_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sherwood_test.cpp
index 22d9ead3826d..f1f41d9c8ce8 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sherwood_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sherwood_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendSherwood, SendDataOnly) {
irsend.reset();
irsend.sendSherwood(0xC1A28877);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560"
@@ -31,6 +32,7 @@ TEST(TestSendSherwood, SendDataWithRepeats) {
irsend.reset();
irsend.sendSherwood(0xC1A28877, 32, 2);
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560"
@@ -50,6 +52,7 @@ TEST(TestSendSherwood, SendDataWithZeroRepeats) {
irsend.sendSherwood(0xC1A28877, 32, 0);
// Should have a single NEC repeat, as we always send one.
EXPECT_EQ(
+ "f38000d33"
"m8960s4480m560s1680m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560"
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sony_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Sony_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Sony_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Sony_test.cpp
index c79ff6175e26..35c3287b0f3b 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Sony_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Sony_test.cpp
@@ -15,6 +15,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0);
// We expect three 20-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m600s600m600s600m600s600m600s18600"
@@ -30,6 +31,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0x240C, kSony20Bits);
// We expect three 20-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200"
@@ -45,6 +47,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0x240C, kSony15Bits);
// We expect three 15-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600"
"m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600"
"m600s22200"
@@ -60,6 +63,7 @@ TEST(TestSendSony, SendDataOnly) {
irsend.sendSony(0xA90, kSony12Bits);
// We expect three 15-bit commands to be sent.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600"
"m600s600m1200s600m600s600m600s600m600s600m600s25800"
"m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600"
@@ -77,12 +81,14 @@ TEST(TestSendSony, SendWithDiffRepeats) {
irsend.reset();
irsend.sendSony(0x240C, kSony20Bits, 0); // Send a command with 0 repeats.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200",
irsend.outputStr());
irsend.sendSony(0x240C, kSony20Bits, 1); // Send a command with 1 repeat.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200"
@@ -92,6 +98,7 @@ TEST(TestSendSony, SendWithDiffRepeats) {
irsend.outputStr());
irsend.sendSony(0x240C, kSony20Bits, 3); // Send a command with 3 repeats.
EXPECT_EQ(
+ "f40000d33"
"m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600"
"m600s600m1200s600m1200s600m600s600m600s16200"
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Tcl_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Tcl_test.cpp
new file mode 100644
index 000000000000..249dcc63728a
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Tcl_test.cpp
@@ -0,0 +1,384 @@
+// Copyright 2019 David Conran
+
+#include "ir_Tcl.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestTcl112Ac, Housekeeping) {
+ ASSERT_EQ("TCL112AC", typeToString(TCL112AC));
+ ASSERT_TRUE(hasACState(TCL112AC));
+}
+
+// Tests for decodeTcl112Ac().
+
+// Decode a real Tcl112Ac A/C example from Issue #619
+TEST(TestDecodeTcl112Ac, DecodeRealExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ // Tcl112Ac A/C example from Issue #619 On.txt
+ uint16_t rawData[227] = {
+ 3030, 1658, 494, 1066, 494, 1068, 498, 320, 494,
+ 326, 498, 320, 494, 1068, 500, 320, 494, 332,
+ 494, 1068, 500, 1062, 496, 324, 492, 1044, 524,
+ 322, 492, 326, 498, 1062, 494, 1074, 494, 326,
+ 500, 1062, 496, 1066, 490, 328, 496, 322, 492,
+ 1070, 498, 322, 494, 332, 492, 1068, 498, 320,
+ 494, 326, 498, 320, 496, 324, 500, 320, 494,
+ 324, 490, 336, 500, 320, 496, 324, 490, 328,
+ 496, 322, 492, 328, 498, 322, 492, 326, 498,
+ 328, 496, 322, 492, 328, 498, 1064, 494, 326,
+ 498, 320, 494, 1066, 490, 330, 496, 330, 494,
+ 1066, 490, 1070, 498, 322, 492, 328, 498, 322,
+ 492, 326, 498, 322, 492, 332, 492, 1068, 498,
+ 1062, 494, 1066, 500, 318, 496, 324, 490, 328,
+ 496, 324, 492, 334, 490, 328, 496, 324, 492,
+ 328, 496, 322, 492, 328, 498, 320, 494, 1068,
+ 500, 326, 500, 320, 492, 326, 500, 320, 496,
+ 324, 500, 318, 496, 324, 490, 328, 496, 330,
+ 496, 324, 490, 328, 496, 324, 490, 328, 498,
+ 322, 492, 328, 498, 320, 492, 334, 492, 328,
+ 498, 322, 494, 326, 498, 320, 494, 324, 500,
+ 322, 492, 324, 490, 336, 498, 320, 494, 324,
+ 500, 320, 496, 324, 490, 328, 498, 322, 492,
+ 328, 496, 1070, 496, 1064, 492, 1070, 498, 322,
+ 494, 326, 500, 320, 494, 324, 500, 320, 494,
+ 324, 470}; // UNKNOWN CE60D6B9
+ uint8_t expectedState[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0x03};
+
+ irsend.sendRaw(rawData, 227, 38000);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(TCL112AC, irsend.capture.decode_type);
+ EXPECT_EQ(kTcl112AcBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+
+ IRTcl112Ac ac(0);
+ ac.setRaw(irsend.capture.state);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 24C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+}
+
+// Decode a synthetic Tcl112Ac A/C example from Issue #619
+TEST(TestDecodeTcl112Ac, DecodeSyntheticExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+
+ uint8_t expectedState[kTcl112AcStateLength] = {0x23, 0xCB, 0x26, 0x01, 0x00,
+ 0x24, 0x03, 0x07, 0x40, 0x00,
+ 0x00, 0x00, 0x80, 0x03};
+
+ irsend.sendTcl112Ac(expectedState);
+ irsend.makeDecodeResult();
+
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ ASSERT_EQ(TCL112AC, irsend.capture.decode_type);
+ EXPECT_EQ(kTcl112AcBits, irsend.capture.bits);
+ EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
+}
+
+TEST(TestTcl112AcClass, Temperature) {
+ const uint8_t temp16C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ const uint8_t temp16point5C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xEB};
+ const uint8_t temp19point5C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0C, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE8};
+ const uint8_t temp31C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC};
+ IRTcl112Ac ac(0);
+ ac.setRaw(temp16C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp16point5C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16.5C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp19point5C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 19.5C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp31C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 31C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+
+ ac.setTemp(kTcl112AcTempMin);
+ EXPECT_EQ(kTcl112AcTempMin, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMin + 1);
+ EXPECT_EQ(kTcl112AcTempMin + 1, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMax);
+ EXPECT_EQ(kTcl112AcTempMax, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMin - 1);
+ EXPECT_EQ(kTcl112AcTempMin, ac.getTemp());
+
+ ac.setTemp(kTcl112AcTempMax + 0.5);
+ EXPECT_EQ(kTcl112AcTempMax, ac.getTemp());
+
+ ac.setTemp(23);
+ EXPECT_EQ(23, ac.getTemp());
+
+ ac.setTemp(27.4);
+ EXPECT_EQ(27, ac.getTemp());
+
+ ac.setTemp(22.5);
+ EXPECT_EQ(22.5, ac.getTemp());
+
+ ac.setTemp(25.6);
+ EXPECT_EQ(25.5, ac.getTemp());
+
+ ac.setTemp(0);
+ EXPECT_EQ(kTcl112AcTempMin, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kTcl112AcTempMax, ac.getTemp());
+}
+
+TEST(TestTcl112AcClass, OperatingMode) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setMode(kTcl112AcAuto);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ EXPECT_EQ(kTcl112AcCool, ac.getMode());
+
+ ac.setMode(kTcl112AcHeat);
+ EXPECT_EQ(kTcl112AcHeat, ac.getMode());
+
+ ac.setFan(kTcl112AcFanAuto);
+ ac.setMode(kTcl112AcFan); // Should set fan speed to High.
+ EXPECT_EQ(kTcl112AcFan, ac.getMode());
+ EXPECT_EQ(kTcl112AcFanHigh, ac.getFan());
+
+ ac.setMode(kTcl112AcDry);
+ EXPECT_EQ(kTcl112AcDry, ac.getMode());
+
+ ac.setMode(kTcl112AcHeat - 1);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ EXPECT_EQ(kTcl112AcCool, ac.getMode());
+
+ ac.setMode(kTcl112AcAuto + 1);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ ac.setMode(255);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ ac.setMode(kTcl112AcCool);
+ ac.setMode(0);
+ EXPECT_EQ(kTcl112AcAuto, ac.getMode());
+
+ const uint8_t automode[] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x08,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48};
+ ac.setRaw(automode);
+ EXPECT_EQ(
+ "Power: On, Mode: 8 (AUTO), Temp: 24C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+}
+
+TEST(TestTcl112AcClass, Power) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_EQ(false, ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_EQ(false, ac.getPower());
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+
+ const uint8_t on[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ ac.setRaw(on);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+
+ const uint8_t off[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x03,
+ 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ ac.setRaw(off);
+ EXPECT_EQ(
+ "Power: Off, Mode: 3 (COOL), Temp: 24C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+}
+
+
+TEST(TestTcl112AcClass, Checksum) {
+ uint8_t temp16C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
+ uint8_t temp31C[kTcl112AcStateLength] = {
+ 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC};
+ IRTcl112Ac ac(0);
+ EXPECT_EQ(0xCB, ac.calcChecksum(temp16C));
+ ac.setRaw(temp16C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ ac.setRaw(temp31C);
+ EXPECT_EQ(
+ "Power: On, Mode: 3 (COOL), Temp: 31C, Fan: 0 (Auto), Econo: Off, "
+ "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off",
+ ac.toString());
+ EXPECT_EQ(0xBC, ac.calcChecksum(temp31C));
+
+ EXPECT_TRUE(IRTcl112Ac::validChecksum(temp16C));
+ EXPECT_TRUE(IRTcl112Ac::validChecksum(temp31C));
+ EXPECT_TRUE(ac.validChecksum(temp31C));
+ ac.setRaw(temp16C);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ ac.setTemp(31);
+ EXPECT_TRUE(ac.validChecksum(ac.getRaw()));
+ EXPECT_EQ(0xBC, ac.calcChecksum(ac.getRaw()));
+}
+
+TEST(TestTcl112AcClass, Econo) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+ ac.setEcono(false);
+ EXPECT_EQ(false, ac.getEcono());
+ ac.setEcono(true);
+ EXPECT_TRUE(ac.getEcono());
+}
+
+TEST(TestTcl112AcClass, Health) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setHealth(true);
+ EXPECT_TRUE(ac.getHealth());
+ ac.setHealth(false);
+ EXPECT_EQ(false, ac.getHealth());
+ ac.setHealth(true);
+ EXPECT_TRUE(ac.getHealth());
+}
+
+TEST(TestTcl112AcClass, Light) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setLight(true);
+ EXPECT_TRUE(ac.getLight());
+ ac.setLight(false);
+ EXPECT_EQ(false, ac.getLight());
+ ac.setLight(true);
+ EXPECT_TRUE(ac.getLight());
+}
+
+TEST(TestTcl112AcClass, SwingHorizontal) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+ ac.setSwingHorizontal(false);
+ EXPECT_EQ(false, ac.getSwingHorizontal());
+ ac.setSwingHorizontal(true);
+ EXPECT_TRUE(ac.getSwingHorizontal());
+}
+
+TEST(TestTcl112AcClass, SwingVertical) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingVertical());
+ ac.setSwingVertical(false);
+ EXPECT_EQ(false, ac.getSwingVertical());
+ ac.setSwingVertical(true);
+ EXPECT_TRUE(ac.getSwingVertical());
+}
+
+TEST(TestTcl112AcClass, Turbo) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ ac.setFan(kTcl112AcFanLow);
+ ac.setSwingHorizontal(false);
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+ EXPECT_FALSE(ac.getSwingVertical());
+ EXPECT_EQ(kTcl112AcFanLow, ac.getFan());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+ EXPECT_TRUE(ac.getSwingVertical());
+ EXPECT_EQ(kTcl112AcFanHigh, ac.getFan());
+
+ ac.setTurbo(false);
+ EXPECT_FALSE(ac.getTurbo());
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+}
+
+TEST(TestTcl112AcClass, FanSpeed) {
+ IRTcl112Ac ac(0);
+ ac.begin();
+
+ // Unexpected value should default to Auto.
+ ac.setFan(255);
+ EXPECT_EQ(kTcl112AcFanAuto, ac.getFan());
+
+ ac.setFan(kTcl112AcFanLow);
+ EXPECT_EQ(kTcl112AcFanLow, ac.getFan());
+ ac.setFan(kTcl112AcFanMed);
+ EXPECT_EQ(kTcl112AcFanMed, ac.getFan());
+ ac.setFan(kTcl112AcFanHigh);
+ EXPECT_EQ(kTcl112AcFanHigh, ac.getFan());
+ ac.setFan(kTcl112AcFanAuto);
+ EXPECT_EQ(kTcl112AcFanAuto, ac.getFan());
+
+ // Beyond High should default to Auto.
+ ac.setFan(kTcl112AcFanHigh + 1);
+ EXPECT_EQ(kTcl112AcFanAuto, ac.getFan());
+}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Teco_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Teco_test.cpp
new file mode 100644
index 000000000000..6b03a671de28
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Teco_test.cpp
@@ -0,0 +1,358 @@
+// Copyright 2019 David Conran
+
+#include "ir_Teco.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// General housekeeping
+TEST(TestTeco, Housekeeping) {
+ ASSERT_EQ("TECO", typeToString(TECO));
+ ASSERT_FALSE(hasACState(TECO)); // Uses uint64_t, not uint8_t*.
+}
+
+// Tests for sendTeco()
+
+// Test sending typical data only.
+TEST(TestSendTeco, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendTeco(0x250002BC9);
+ EXPECT_EQ(
+ "f38000d50"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000",
+ irsend.outputStr());
+}
+
+// Test sending typical data with repeats.
+TEST(TestSendTeco, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendTeco(0x250002BC9, kTecoBits, 2); // two repeats.
+ EXPECT_EQ(
+ "f38000d50"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000"
+ "m9000s4440"
+ "m620s1650m620s580m620s580m620s1650m620s580m620s580m620s1650m620s1650"
+ "m620s1650m620s1650m620s580m620s1650m620s580m620s1650m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s580m620s580m620s580m620s580"
+ "m620s580m620s580m620s580m620s580m620s1650m620s580m620s1650m620s580"
+ "m620s580m620s1650m620s580"
+ "m620s100000",
+ irsend.outputStr());
+}
+
+
+// Tests for IRTeco class.
+
+TEST(TestTecoACClass, Power) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_EQ(false, ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_EQ(false, ac.getPower());
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+}
+
+TEST(TestTecoACClass, OperatingMode) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setMode(kTecoAuto);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+
+ ac.setMode(kTecoCool);
+ EXPECT_EQ(kTecoCool, ac.getMode());
+
+ ac.setMode(kTecoHeat);
+ EXPECT_EQ(kTecoHeat, ac.getMode());
+
+ ac.setMode(kTecoFan);
+ EXPECT_EQ(kTecoFan, ac.getMode());
+
+ ac.setMode(kTecoDry);
+ EXPECT_EQ(kTecoDry, ac.getMode());
+
+ ac.setMode(kTecoAuto - 1);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+
+ ac.setMode(kTecoCool);
+ EXPECT_EQ(kTecoCool, ac.getMode());
+
+ ac.setMode(kTecoHeat + 1);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kTecoAuto, ac.getMode());
+}
+
+TEST(TestTecoACClass, Temperature) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setTemp(kTecoMinTemp);
+ EXPECT_EQ(kTecoMinTemp, ac.getTemp());
+
+ ac.setTemp(kTecoMinTemp + 1);
+ EXPECT_EQ(kTecoMinTemp + 1, ac.getTemp());
+
+ ac.setTemp(kTecoMaxTemp);
+ EXPECT_EQ(kTecoMaxTemp, ac.getTemp());
+
+ ac.setTemp(kTecoMinTemp - 1);
+ EXPECT_EQ(kTecoMinTemp, ac.getTemp());
+
+ ac.setTemp(kTecoMaxTemp + 1);
+ EXPECT_EQ(kTecoMaxTemp, ac.getTemp());
+
+ ac.setTemp(23);
+ EXPECT_EQ(23, ac.getTemp());
+
+ ac.setTemp(0);
+ EXPECT_EQ(kTecoMinTemp, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kTecoMaxTemp, ac.getTemp());
+}
+
+TEST(TestTecoACClass, FanSpeed) {
+ IRTecoAc ac(0);
+ ac.begin();
+ ac.setFan(kTecoFanLow);
+
+ ac.setFan(kTecoFanAuto);
+ EXPECT_EQ(kTecoFanAuto, ac.getFan());
+
+ ac.setFan(kTecoFanLow);
+ EXPECT_EQ(kTecoFanLow, ac.getFan());
+ ac.setFan(kTecoFanMed);
+ EXPECT_EQ(kTecoFanMed, ac.getFan());
+ ac.setFan(kTecoFanHigh);
+ EXPECT_EQ(kTecoFanHigh, ac.getFan());
+
+ ac.setFan(kTecoFanHigh);
+ EXPECT_EQ(kTecoFanHigh, ac.getFan());
+}
+
+TEST(TestTecoACClass, Swing) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setSwing(true);
+ EXPECT_TRUE(ac.getSwing());
+
+ ac.setSwing(false);
+ EXPECT_EQ(false, ac.getSwing());
+
+ ac.setSwing(true);
+ EXPECT_TRUE(ac.getSwing());
+}
+
+TEST(TestTecoACClass, Sleep) {
+ IRTecoAc ac(0);
+ ac.begin();
+
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+
+ ac.setSleep(false);
+ EXPECT_EQ(false, ac.getSleep());
+
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+}
+
+TEST(TestTecoACClass, MessageConstuction) {
+ IRTecoAc ac(0);
+
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+ ac.setPower(true);
+ ac.setMode(kTecoCool);
+ ac.setTemp(21);
+ ac.setFan(kTecoFanHigh);
+ ac.setSwing(false);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+ ac.setSwing(true);
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, "
+ "Swing: On",
+ ac.toString());
+ ac.setSwing(false);
+ ac.setFan(kTecoFanLow);
+ ac.setSleep(true);
+ ac.setMode(kTecoHeat);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: On, "
+ "Swing: Off",
+ ac.toString());
+ ac.setSleep(false);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+ ac.setTemp(25);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 1 (Low), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+}
+
+TEST(TestTecoACClass, ReconstructKnownMessage) {
+ IRTecoAc ac(0);
+
+ const uint64_t expected = 0x250002BC9;
+ ASSERT_FALSE(ac.getRaw() == expected);
+ ac.setPower(true);
+ ac.setMode(kTecoCool);
+ ac.setTemp(27);
+ ac.setFan(kTecoFanAuto);
+ ac.setSleep(true);
+ ac.setSwing(true);
+ EXPECT_EQ(expected, ac.getRaw());
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, "
+ "Swing: On",
+ ac.toString());
+}
+
+// Tests for decodeTeco().
+
+// Decode normal "synthetic" messages.
+TEST(TestDecodeTeco, NormalDecodeWithStrict) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // With the specific decoder.
+ uint64_t expectedState = kTecoReset;
+ irsend.reset();
+ irsend.sendTeco(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeTeco(&irsend.capture, kTecoBits, true));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(expectedState, irsend.capture.value);
+ EXPECT_EQ(0, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ // With the all the decoders.
+ irsend.reset();
+ irsend.sendTeco(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(expectedState, irsend.capture.value);
+ EXPECT_EQ(0, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ IRTecoAc ac(0);
+ ac.begin();
+ ac.setRaw(irsend.capture.value);
+ EXPECT_EQ(
+ "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, "
+ "Swing: Off",
+ ac.toString());
+}
+
+// Decode a real message from Raw Data.
+TEST(TestDecodeTeco, RealNormalExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRTecoAc ac(0);
+ irsend.begin();
+
+ uint16_t rawData1[73] = {
+ 9076, 4442, 670, 1620, 670, 516, 670, 516, 666, 1626, 670, 516,
+ 664, 520, 666, 1626, 666, 1626, 664, 1626, 666, 1626, 666, 520,
+ 666, 1626, 666, 520, 666, 1626, 666, 520, 666, 516, 670, 514,
+ 670, 516, 666, 520, 670, 516, 666, 520, 666, 516, 672, 514, 670,
+ 516, 666, 520, 666, 516, 672, 514, 670, 516, 666, 1624, 666, 520,
+ 666, 1626, 666, 520, 666, 516, 672, 1620, 670, 516, 670};
+ uint64_t expected1 = 0b01001010000000000000010101111001001; // 0x250002BC9
+ irsend.reset();
+ irsend.sendRaw(rawData1, 73, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ 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",
+ ac.toString());
+
+ uint16_t rawData2[73] = {
+ 9048, 4472, 636, 548, 636, 1654, 638, 546, 642, 1650, 642, 546, 638,
+ 1654, 638, 1654, 638, 546, 638, 1654, 636, 546, 642, 1650, 640, 548,
+ 636, 548, 638, 546, 636, 546, 642, 542, 642, 546, 638, 546, 638, 546,
+ 636, 548, 642, 542, 642, 546, 636, 548, 636, 546, 642, 542, 642, 546,
+ 638, 546, 638, 546, 636, 1654, 642, 542, 642, 1650, 642, 546, 638, 546,
+ 638, 1654, 638, 546, 642}; // TECO 25000056A
+ uint64_t expected2 = 0b01001010000000000000000010101101010; // 0x25000056A
+ irsend.reset();
+ irsend.sendRaw(rawData2, 73, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(TECO, irsend.capture.decode_type);
+ EXPECT_EQ(kTecoBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ 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 (Med), Sleep: Off, "
+ "Swing: On",
+ ac.toString());
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Toshiba_test.cpp
similarity index 99%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Toshiba_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Toshiba_test.cpp
index b5e1e07a988a..d74866f92f79 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Toshiba_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Toshiba_test.cpp
@@ -18,6 +18,7 @@ TEST(TestSendToshibaAC, SendDataOnly) {
irsend.reset();
irsend.sendToshibaAC(toshiba_code);
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -54,6 +55,7 @@ TEST(TestSendToshibaAC, SendWithRepeats) {
irsend.sendToshibaAC(toshiba_code, kToshibaACStateLength, 0);
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -70,6 +72,7 @@ TEST(TestSendToshibaAC, SendWithRepeats) {
irsend.reset();
irsend.sendToshibaAC(toshiba_code, kToshibaACStateLength, 2);
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -122,6 +125,7 @@ TEST(TestSendToshibaAC, SendUnexpectedSizes) {
irsend.reset();
irsend.sendToshibaAC(toshiba_long_code, kToshibaACStateLength + 1);
ASSERT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623"
"m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s472"
@@ -380,6 +384,7 @@ TEST(TestToshibaACClass, MessageConstuction) {
irsend.reset();
irsend.sendToshibaAC(toshiba.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -415,6 +420,7 @@ TEST(TestToshibaACClass, MessageConstuction) {
irsend.reset();
irsend.sendToshibaAC(toshiba.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
@@ -450,6 +456,7 @@ TEST(TestToshibaACClass, MessageConstuction) {
irsend.reset();
irsend.sendToshibaAC(toshiba.getRaw());
EXPECT_EQ(
+ "f38000d50"
"m4400s4300"
"m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472"
"m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623"
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Vestel_test.cpp
new file mode 100644
index 000000000000..077a0a25e772
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Vestel_test.cpp
@@ -0,0 +1,513 @@
+// Copyright 2019 David Conran
+
+#include "ir_Vestel.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for sendVestelAc()
+
+// Test sending typical data only.
+TEST(TestSendVestelAc, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendVestelAc(0x0F00D9001FEF201ULL);
+ EXPECT_EQ(
+ "f38000d50"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535"
+ "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s100000",
+ irsend.outputStr());
+}
+
+// Test sending typical data with repeats.
+TEST(TestSendVestelAc, SendWithRepeats) {
+ IRsendTest irsend(0);
+ irsend.begin();
+
+ irsend.reset();
+ irsend.sendVestelAc(0x0F00D9001FEF201ULL, kVestelAcBits, 2); // two repeats.
+ EXPECT_EQ(
+ "f38000d50"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535"
+ "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s100000"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535"
+ "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s100000"
+ "m3110s9066"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s1535m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s480m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535m520s1535"
+ "m520s1535m520s480m520s480m520s480m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s480m520s480m520s1535"
+ "m520s1535m520s480m520s1535m520s1535m520s480m520s480m520s480m520s480"
+ "m520s480m520s480m520s480m520s480m520s1535m520s1535m520s1535m520s1535"
+ "m520s100000",
+ irsend.outputStr());
+}
+
+// Tests for IRVestelAc class.
+
+TEST(TestVestelAcClass, Power) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.setPower(false);
+ EXPECT_EQ(false, ac.getPower());
+
+ ac.setPower(true);
+ EXPECT_TRUE(ac.getPower());
+
+ ac.off();
+ EXPECT_EQ(false, ac.getPower());
+
+ ac.on();
+ EXPECT_TRUE(ac.getPower());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, OperatingMode) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setMode(kVestelAcAuto);
+ EXPECT_EQ(kVestelAcAuto, ac.getMode());
+
+ ac.setMode(kVestelAcCool);
+ EXPECT_EQ(kVestelAcCool, ac.getMode());
+
+ ac.setMode(kVestelAcHeat);
+ EXPECT_EQ(kVestelAcHeat, ac.getMode());
+
+ ac.setMode(kVestelAcFan);
+ EXPECT_EQ(kVestelAcFan, ac.getMode());
+
+ ac.setMode(kVestelAcDry);
+ EXPECT_EQ(kVestelAcDry, ac.getMode());
+
+ ac.setMode(kVestelAcAuto - 1);
+ EXPECT_EQ(kVestelAcAuto, ac.getMode());
+
+ ac.setMode(kVestelAcCool);
+ EXPECT_EQ(kVestelAcCool, ac.getMode());
+
+ ac.setMode(kVestelAcHeat + 1);
+ EXPECT_EQ(kVestelAcAuto, ac.getMode());
+
+ ac.setMode(255);
+ EXPECT_EQ(kVestelAcAuto, ac.getMode());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, Temperature) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setTemp(kVestelAcMinTempC);
+ EXPECT_EQ(kVestelAcMinTempC, ac.getTemp());
+
+ ac.setTemp(kVestelAcMinTempC + 1);
+ EXPECT_EQ(kVestelAcMinTempC + 1, ac.getTemp());
+
+ ac.setTemp(kVestelAcMaxTemp);
+ EXPECT_EQ(kVestelAcMaxTemp, ac.getTemp());
+
+ ac.setTemp(kVestelAcMinTempC - 1);
+ EXPECT_EQ(kVestelAcMinTempC, ac.getTemp());
+
+ ac.setTemp(kVestelAcMaxTemp + 1);
+ EXPECT_EQ(kVestelAcMaxTemp, ac.getTemp());
+
+ ac.setTemp(23);
+ EXPECT_EQ(23, ac.getTemp());
+
+ ac.setTemp(0);
+ EXPECT_EQ(kVestelAcMinTempC, ac.getTemp());
+
+ ac.setTemp(255);
+ EXPECT_EQ(kVestelAcMaxTemp, ac.getTemp());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, FanSpeed) {
+ IRVestelAc ac(0);
+ ac.begin();
+ ac.setFan(kVestelAcFanLow);
+
+ ac.setFan(kVestelAcFanAuto);
+ EXPECT_EQ(kVestelAcFanAuto, ac.getFan());
+
+ ac.setFan(kVestelAcFanLow);
+ EXPECT_EQ(kVestelAcFanLow, ac.getFan());
+ ac.setFan(kVestelAcFanMed);
+ EXPECT_EQ(kVestelAcFanMed, ac.getFan());
+ ac.setFan(kVestelAcFanHigh);
+ EXPECT_EQ(kVestelAcFanHigh, ac.getFan());
+
+ ac.setFan(kVestelAcFanHigh);
+ EXPECT_EQ(kVestelAcFanHigh, ac.getFan());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, Swing) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setSwing(true);
+ EXPECT_TRUE(ac.getSwing());
+
+ ac.setSwing(false);
+ EXPECT_EQ(false, ac.getSwing());
+
+ ac.setSwing(true);
+ EXPECT_TRUE(ac.getSwing());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, Ion) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setIon(true);
+ EXPECT_TRUE(ac.getIon());
+
+ ac.setIon(false);
+ EXPECT_EQ(false, ac.getIon());
+
+ ac.setIon(true);
+ EXPECT_TRUE(ac.getIon());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, Turbo) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+
+ ac.setTurbo(false);
+ EXPECT_EQ(false, ac.getTurbo());
+
+ ac.setTurbo(true);
+ EXPECT_TRUE(ac.getTurbo());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, Sleep) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+
+ ac.setSleep(false);
+ EXPECT_EQ(false, ac.getSleep());
+
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+ EXPECT_FALSE(ac.isTimeCommand());
+}
+
+TEST(TestVestelAcClass, Time) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setTime(0);
+ EXPECT_EQ(0, ac.getTime());
+ EXPECT_TRUE(ac.isTimeCommand());
+
+ ac.setTime(1);
+ EXPECT_EQ(1, ac.getTime());
+
+ ac.setTime(1234);
+ EXPECT_EQ(1234, ac.getTime());
+
+ ac.setTime(23 * 60 + 59);
+ EXPECT_EQ(23 * 60 + 59, ac.getTime());
+}
+
+TEST(TestVestelAcClass, OnTimer) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setOnTimer(0);
+ EXPECT_EQ(0, ac.getOnTimer());
+ EXPECT_TRUE(ac.isTimeCommand());
+
+ ac.setOnTimer(1);
+ EXPECT_EQ(0, ac.getOnTimer());
+
+ ac.setOnTimer(10);
+ EXPECT_EQ(10, ac.getOnTimer());
+
+ ac.setOnTimer(12 * 60 + 15); // we will round down to 10 min increments.
+ EXPECT_EQ(12 * 60 + 10, ac.getOnTimer());
+
+ ac.setOnTimer(23 * 60 + 50);
+ EXPECT_EQ(23 * 60 + 50, ac.getOnTimer());
+}
+
+TEST(TestVestelAcClass, OffTimer) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setOffTimer(0);
+ EXPECT_EQ(0, ac.getOffTimer());
+ EXPECT_TRUE(ac.isTimeCommand());
+
+ ac.setOffTimer(1);
+ EXPECT_EQ(0, ac.getOffTimer());
+
+ ac.setOffTimer(10);
+ EXPECT_EQ(10, ac.getOffTimer());
+
+ ac.setOffTimer(12 * 60 + 15); // we will round down to 10 min increments.
+ EXPECT_EQ(12 * 60 + 10, ac.getOffTimer());
+
+ ac.setOffTimer(23 * 60 + 50);
+ EXPECT_EQ(23 * 60 + 50, ac.getOffTimer());
+}
+
+TEST(TestVestelAcClass, Timer) {
+ IRVestelAc ac(0);
+ ac.begin();
+
+ ac.setTimer(0);
+ EXPECT_EQ(0, ac.getTimer());
+ EXPECT_EQ(0, ac.getOnTimer());
+ EXPECT_TRUE(ac.isTimeCommand());
+
+ ac.setTimer(10);
+ EXPECT_EQ(10, ac.getTimer());
+ EXPECT_EQ(0, ac.getOnTimer());
+
+ ac.setTimer(12 * 60 + 15); // we will round down to 10 min increments.
+ EXPECT_EQ(12 * 60 + 10, ac.getTimer());
+ EXPECT_EQ(0, ac.getOnTimer());
+
+ ac.setTimer(23 * 60 + 50);
+ EXPECT_EQ(23 * 60 + 50, ac.getTimer());
+ EXPECT_EQ(0, ac.getOnTimer());
+}
+
+TEST(TestVestelAcClass, MessageConstuction) {
+ IRVestelAc ac(0);
+
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (AUTO), Temp: 25C, Fan: 13 (AUTO HOT), Sleep: Off, "
+ "Turbo: Off, Ion: Off, Swing: Off",
+ ac.toString());
+ ac.setMode(kVestelAcCool);
+ ac.setTemp(21);
+ ac.setFan(kVestelAcFanHigh);
+ EXPECT_FALSE(ac.isTimeCommand());
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 11 (HIGH), Sleep: Off, "
+ "Turbo: Off, Ion: Off, Swing: Off",
+ ac.toString());
+ ac.setSwing(true);
+ ac.setIon(true);
+ ac.setTurbo(true);
+ EXPECT_FALSE(ac.isTimeCommand());
+ EXPECT_EQ(
+ "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 11 (HIGH), Sleep: Off, "
+ "Turbo: On, Ion: On, Swing: On",
+ ac.toString());
+
+ // Now change a few already set things.
+ ac.setSleep(true);
+ ac.setMode(kVestelAcHeat);
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 11 (HIGH), Sleep: On, "
+ "Turbo: Off, Ion: On, Swing: On",
+ ac.toString());
+ EXPECT_FALSE(ac.isTimeCommand());
+
+ ac.setTemp(25);
+ ac.setPower(false);
+ EXPECT_EQ(
+ "Power: Off, Mode: 4 (HEAT), Temp: 25C, Fan: 11 (HIGH), Sleep: On, "
+ "Turbo: Off, Ion: On, Swing: On",
+ ac.toString());
+ EXPECT_FALSE(ac.isTimeCommand());
+
+ // Check that the checksum is valid.
+ EXPECT_TRUE(IRVestelAc::validChecksum(ac.getRaw()));
+ ac.setTime(23 * 60 + 59);
+ EXPECT_TRUE(ac.isTimeCommand());
+ EXPECT_EQ(
+ "Time: 23:59, Timer: Off, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.setTimer(8 * 60 + 0);
+ EXPECT_TRUE(ac.isTimeCommand());
+ EXPECT_EQ(
+ "Time: 23:59, Timer: 8:00, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.setOnTimer(7 * 60 + 40);
+ EXPECT_EQ(
+ "Time: 23:59, Timer: Off, On Timer: 7:40, Off Timer: Off",
+ ac.toString());
+ ac.setOffTimer(17 * 60 + 10);
+ EXPECT_EQ(
+ "Time: 23:59, Timer: Off, On Timer: 7:40, Off Timer: 17:10",
+ ac.toString());
+ ac.setTimer(8 * 60 + 0);
+ EXPECT_EQ(
+ "Time: 23:59, Timer: 8:00, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.setTimer(0);
+ EXPECT_EQ(
+ "Time: 23:59, Timer: Off, On Timer: Off, Off Timer: Off",
+ ac.toString());
+ ac.on();
+ EXPECT_FALSE(ac.isTimeCommand());
+ EXPECT_EQ(
+ "Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 11 (HIGH), Sleep: On, "
+ "Turbo: Off, Ion: On, Swing: On",
+ ac.toString());
+}
+
+// Tests for decodeVestelAc().
+
+// Decode normal "synthetic" messages.
+TEST(TestDecodeVestelAc, NormalDecodeWithStrict) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // With the specific decoder.
+ uint64_t expectedState = 0x0F00D9001FEF201ULL;
+ irsend.reset();
+ irsend.sendVestelAc(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decodeVestelAc(&irsend.capture, kVestelAcBits, true));
+ EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kVestelAcBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(expectedState, irsend.capture.value);
+ EXPECT_EQ(0, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ // With the all the decoders.
+ irsend.reset();
+ irsend.sendVestelAc(expectedState);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kVestelAcBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(expectedState, irsend.capture.value);
+ EXPECT_EQ(0, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+
+ IRVestelAc ac(0);
+ ac.begin();
+ ac.setRaw(irsend.capture.value);
+ EXPECT_EQ(
+ "Power: On, Mode: 0 (AUTO), Temp: 25C, Fan: 13 (AUTO HOT), Sleep: Off, "
+ "Turbo: Off, Ion: Off, Swing: Off",
+ ac.toString());
+}
+
+// Decode a real message from Raw Data.
+TEST(TestDecodeVestelAc, RealNormalExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRVestelAc ac(0);
+ irsend.begin();
+
+ uint16_t rawData[115] = {
+ 3098, 9080, 548, 1538, 526, 492, 526, 468, 524, 468, 526, 468,
+ 550, 466, 526, 466, 526, 504, 540, 466, 526, 1538, 526, 466,
+ 526, 466, 552, 1540, 522, 466, 526, 492, 526, 544, 526, 1536,
+ 526, 1536, 552, 1536, 526, 1536, 552, 1536, 552, 1536, 526, 1536,
+ 526, 1574, 542, 1536, 526, 492, 526, 466, 526, 494, 524, 468,
+ 524, 468, 526, 492, 526, 502, 540, 468, 524, 494, 524, 468,
+ 526, 468, 524, 468, 526, 492, 526, 468, 524, 520, 524, 1538,
+ 524, 468, 524, 468, 524, 468, 524, 468, 524, 468, 524, 1538,
+ 524, 506, 538, 468, 524, 468, 524, 1538, 524, 468, 550, 1538,
+ 550, 1538, 524, 1538, 534, 1528, 544}; // VESTEL_AC
+ irsend.reset();
+ irsend.sendRaw(rawData, 115, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kVestelAcBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ 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());
+}
+
+TEST(TestDecodeVestelAc, RealTimerExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ IRVestelAc ac(0);
+ irsend.begin();
+
+ uint16_t rawData[115] = {
+ 3022, 9080, 546, 1536, 526, 466, 526, 492, 526, 468, 526, 492,
+ 524, 468, 524, 494, 524, 504, 540, 492, 524, 1538, 526, 468,
+ 524, 492, 526, 466, 552, 1536, 526, 1536, 526, 1570, 542, 492,
+ 524, 1538, 550, 1538, 524, 1536, 526, 494, 524, 466, 526, 468,
+ 524, 1574, 540, 1536, 550, 1536, 526, 468, 550, 1536, 526, 492,
+ 526, 468, 524, 492, 526, 518, 526, 1536, 552, 1536, 550, 1536,
+ 526, 494, 550, 1538, 526, 492, 524, 1538, 526, 504, 540, 466,
+ 526, 1536, 526, 1536, 526, 468, 550, 1538, 524, 468, 524, 1538,
+ 550, 1574, 540, 468, 550, 1538, 526, 492, 524, 468, 526, 466,
+ 526, 468, 524, 494, 524, 468, 546}; // VESTEL_AC 2D6570B8EE201
+ irsend.reset();
+ irsend.sendRaw(rawData, 115, 38);
+ irsend.makeDecodeResult();
+ ASSERT_TRUE(irrecv.decode(&irsend.capture));
+ EXPECT_EQ(VESTEL_AC, irsend.capture.decode_type);
+ EXPECT_EQ(kVestelAcBits, irsend.capture.bits);
+ EXPECT_FALSE(irsend.capture.repeat);
+ EXPECT_EQ(0x2D6570B8EE201ULL, irsend.capture.value);
+ EXPECT_EQ(0, irsend.capture.address);
+ EXPECT_EQ(0, irsend.capture.command);
+ ac.begin();
+ ac.setRaw(irsend.capture.value);
+ EXPECT_EQ(
+ "Time: 5:45, Timer: Off, On Timer: 14:00, Off Timer: 23:00",
+ ac.toString());
+}
+
+// General housekeeping
+TEST(TestDecodeVestelAc, Housekeeping) {
+ ASSERT_EQ("VESTEL_AC", typeToString(VESTEL_AC));
+ ASSERT_FALSE(hasACState(VESTEL_AC)); // Uses uint64_t, not uint8_t*.
+}
diff --git a/lib/IRremoteESP8266-2.6.0/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Whirlpool_test.cpp
new file mode 100644
index 000000000000..e282989f04b3
--- /dev/null
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Whirlpool_test.cpp
@@ -0,0 +1,585 @@
+// Copyright 2018 David Conran
+
+#include "ir_Whirlpool.h"
+#include "IRrecv.h"
+#include "IRrecv_test.h"
+#include "IRsend.h"
+#include "IRsend_test.h"
+#include "gtest/gtest.h"
+
+// Tests for sendWhirlpoolAC().
+
+// Test sending typical data only.
+TEST(TestSendWhirlpoolAC, SendDataOnly) {
+ IRsendTest irsend(0);
+ irsend.begin();
+ uint8_t data[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
+
+ irsend.sendWhirlpoolAC(data);
+ EXPECT_EQ(
+ "f38000d50"
+ "m8950s4484"
+ "m597s1649m597s1649m597s533m597s533m597s533m597s533m597s533m597s1649"
+ "m597s533m597s1649m597s1649m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s1649m597s533m597s533m597s533"
+ "m597s1649m597s533m597s533m597s533m597s1649m597s1649m597s1649m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s7920"
+ "m597s1649m597s533m597s533m597s533m597s1649m597s533m597s533m597s1649"
+ "m597s1649m597s1649m597s1649m597s1649m597s1649m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s1649m597s1649m597s1649m597s1649m597s533m597s1649m597s1649m597s1649"
+ "m597s7920"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s1649m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s533m597s1649m597s533m597s533m597s533m597s533m597s533m597s533"
+ "m597s100000",
+ irsend.outputStr());
+}
+
+// Tests for decodeWhirlpoolAC().
+// Decode normal WhirlpoolAC messages.
+TEST(TestDecodeWhirlpoolAC, SyntheticDecode) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // Synthesised Normal WhirlpoolAC message.
+ irsend.reset();
+ uint8_t expectedState[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
+ irsend.sendWhirlpoolAC(expectedState);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ 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());
+}
+
+TEST(TestDecodeWhirlpoolAC, Real26CFanAutoCoolingSwingOnClock1918) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ uint8_t expectedState[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x80, 0x82, 0x00, 0x00, 0x93, 0x12, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0xC3, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07};
+ irsend.sendWhirlpoolAC(expectedState);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ 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: 2 (COOL), Temp: 26C, "
+ "Fan: 0 (AUTO), Swing: On, Light: On, Clock: 19:18, On Timer: Off, "
+ "Off Timer: Off, Sleep: Off, Super: Off, Command: 7 (SWING)",
+ ac.toString());
+}
+
+TEST(TestDecodeWhirlpoolAC, RealTimerExample) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ irsend.reset();
+ // Dehumidify timer on 7:40 off 8:05
+ uint16_t rawData[343] = {
+ 9092, 4556, 604, 1664, 604, 1674, 630, 514, 630, 518, 628, 522,
+ 604, 550, 628, 530, 602, 1680, 630, 508, 630, 1644, 604, 1674,
+ 604, 544, 604, 548, 630, 524, 604, 554, 620, 530, 630, 506,
+ 602, 538, 602, 542, 604, 542, 604, 546, 630, 524, 602, 556,
+ 628, 518, 604, 1666, 632, 1644, 604, 540, 602, 546, 604, 1680,
+ 604, 1684, 604, 1686, 630, 520, 602, 534, 606, 538, 602, 540,
+ 604, 544, 604, 548, 602, 552, 630, 528, 602, 546, 602, 536,
+ 628, 510, 606, 540, 604, 544, 630, 522, 604, 554, 600, 554,
+ 602, 528, 602, 8032, 604, 1666, 604, 1668, 602, 1676, 630, 518,
+ 630, 520, 602, 550, 604, 554, 604, 1678, 630, 1640, 602, 1672,
+ 602, 542, 602, 544, 628, 522, 630, 1658, 604, 554, 628, 1652,
+ 630, 508, 602, 538, 630, 514, 630, 1652, 602, 546, 604, 550,
+ 602, 554, 602, 546, 630, 1638, 604, 536, 630, 1646, 602, 544,
+ 628, 522, 632, 524, 628, 528, 602, 1686, 594, 1666, 604, 1670,
+ 602, 1674, 632, 516, 604, 546, 638, 518, 622, 534, 628, 518,
+ 604, 532, 604, 536, 600, 550, 622, 1652, 630, 520, 602, 1684,
+ 602, 554, 602, 544, 630, 506, 628, 512, 602, 540, 628, 518,
+ 602, 550, 602, 552, 604, 554, 602, 544, 628, 1642, 602, 536,
+ 632, 1646, 630, 516, 602, 1680, 630, 1656, 604, 1688, 602, 1660,
+ 602, 8030, 604, 532, 604, 536, 604, 540, 602, 544, 628, 522,
+ 602, 552, 602, 556, 602, 544, 602, 1666, 630, 510, 602, 1674,
+ 604, 544, 628, 522, 602, 552, 630, 526, 628, 520, 602, 534,
+ 630, 510, 604, 540, 602, 544, 606, 544, 604, 550, 604, 554,
+ 602, 544, 604, 534, 602, 538, 602, 542, 604, 542, 604, 546,
+ 604, 550, 632, 526, 604, 544, 630, 506, 604, 536, 604, 540,
+ 628, 518, 602, 548, 604, 550, 604, 552, 630, 516, 602, 534,
+ 604, 536, 630, 512, 604, 544, 602, 548, 630, 524, 602, 554,
+ 602, 542, 604, 1666, 606, 532, 630, 1644, 602, 544, 630, 520,
+ 604, 550, 604, 554, 602, 526, 598};
+ uint8_t expectedState[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x00, 0x73, 0x00, 0x00, 0x87, 0xA3, 0x08, 0x85, 0x07,
+ 0x28, 0x00, 0xF5, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05};
+ irsend.sendRaw(rawData, 343, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ 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: 3 (DRY), Temp: 25C, "
+ "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, "
+ "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)",
+ ac.toString());
+}
+
+// Decode a recorded example
+TEST(TestDecodeWhirlpoolAC, RealExampleDecode) {
+ IRsendTest irsend(0);
+ IRrecv irrecv(0);
+ irsend.begin();
+
+ // Real WhirlpoolAC message.
+ // Ref: https://github.com/markszabo/IRremoteESP8266/issues/509
+ uint16_t rawData[343] = {
+ 8950, 4484, 598, 1642, 598, 1646, 594, 534, 594, 538, 602, 532,
+ 598, 540, 600, 542, 598, 1650, 600, 522, 598, 1644, 596, 1650,
+ 600, 532, 598, 538, 602, 536, 594, 548, 592, 538, 602, 518,
+ 600, 524, 596, 532, 598, 532, 598, 1654, 596, 544, 596, 544,
+ 596, 536, 594, 1644, 596, 528, 600, 528, 592, 538, 602, 1648,
+ 602, 1654, 596, 1664, 598, 534, 594, 526, 594, 530, 598, 528,
+ 602, 530, 600, 534, 596, 542, 598, 542, 598, 534, 596, 526,
+ 594, 530, 600, 528, 602, 530, 600, 534, 596, 542, 598, 544,
+ 596, 518, 602, 7916, 598, 1642, 598, 528, 600, 528, 602, 530,
+ 600, 1652, 598, 542, 598, 544, 596, 1654, 596, 1644, 596, 1648,
+ 602, 1644, 596, 1654, 596, 1656, 604, 536, 594, 548, 602, 528,
+ 600, 520, 600, 524, 596, 532, 598, 532, 596, 538, 602, 536,
+ 594, 546, 594, 538, 602, 518, 600, 524, 596, 532, 598, 532,
+ 598, 536, 594, 544, 596, 544, 596, 536, 594, 526, 592, 530,
+ 600, 528, 600, 530, 602, 532, 596, 542, 598, 542, 598, 534,
+ 596, 524, 596, 528, 600, 526, 592, 538, 592, 542, 598, 540,
+ 600, 540, 600, 530, 598, 522, 598, 526, 594, 534, 596, 534,
+ 594, 540, 602, 536, 592, 548, 592, 538, 600, 1636, 594, 1648,
+ 602, 1642, 598, 1652, 598, 538, 602, 1680, 570, 1662, 598, 1634,
+ 596, 7924, 600, 520, 598, 526, 592, 534, 596, 534, 596, 540,
+ 600, 536, 604, 538, 602, 530, 600, 520, 598, 1640, 600, 528,
+ 600, 530, 600, 534, 594, 544, 596, 544, 596, 534, 596, 526,
+ 594, 528, 600, 526, 594, 536, 592, 542, 598, 538, 602, 538,
+ 602, 528, 600, 520, 600, 524, 596, 530, 600, 532, 598, 534,
+ 596, 542, 598, 542, 598, 532, 598, 524, 596, 528, 602, 526,
+ 594, 536, 594, 540, 600, 536, 594, 548, 592, 538, 602, 518,
+ 602, 522, 596, 530, 600, 530, 600, 534, 596, 542, 598, 544,
+ 596, 534, 596, 524, 594, 1644, 596, 532, 596, 534, 596, 538,
+ 602, 536, 594, 546, 594, 520, 600};
+ uint8_t expectedState[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
+
+ irsend.reset();
+ irsend.sendRaw(rawData, 343, 38000);
+ irsend.makeDecodeResult();
+ EXPECT_TRUE(irrecv.decode(&irsend.capture));
+ 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());
+}
+
+// Tests for IRWhirlpoolAc class.
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetRaw) {
+ uint8_t expectedState[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
+ IRWhirlpoolAc ac(0);
+ ac.setRaw(expectedState);
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits);
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetTemp) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0); // Clear the previous command.
+
+ ac.setModel(DG11J13A);
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+ EXPECT_EQ(kWhirlpoolAcCommandTemp, ac.getCommand());
+ ac.setTemp(kWhirlpoolAcMinTemp);
+ EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp());
+ ac.setTemp(kWhirlpoolAcMinTemp - 1);
+ EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp());
+ ac.setTemp(kWhirlpoolAcMaxTemp);
+ EXPECT_EQ(kWhirlpoolAcMaxTemp, ac.getTemp());
+ ac.setTemp(kWhirlpoolAcMaxTemp + 1);
+ EXPECT_EQ(kWhirlpoolAcMaxTemp, ac.getTemp());
+
+ ac.setModel(DG11J191); // Has a -2 offset on min/max temps.
+ ac.setTemp(25);
+ EXPECT_EQ(25, ac.getTemp());
+ EXPECT_EQ(kWhirlpoolAcCommandTemp, ac.getCommand());
+ ac.setTemp(kWhirlpoolAcMinTemp - 2);
+ EXPECT_EQ(kWhirlpoolAcMinTemp - 2, ac.getTemp());
+ ac.setTemp(kWhirlpoolAcMinTemp - 2 - 1);
+ EXPECT_EQ(kWhirlpoolAcMinTemp - 2 , ac.getTemp());
+ ac.setTemp(kWhirlpoolAcMaxTemp - 2);
+ EXPECT_EQ(kWhirlpoolAcMaxTemp - 2, ac.getTemp());
+ ac.setTemp(kWhirlpoolAcMaxTemp - 2 + 1);
+ EXPECT_EQ(kWhirlpoolAcMaxTemp - 2, ac.getTemp());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetMode) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0); // Clear the previous command.
+
+ ac.setMode(kWhirlpoolAcCool);
+ EXPECT_EQ(kWhirlpoolAcCool, ac.getMode());
+ EXPECT_EQ(kWhirlpoolAcCommandMode, ac.getCommand());
+ ac.setMode(kWhirlpoolAcHeat);
+ EXPECT_EQ(kWhirlpoolAcHeat, ac.getMode());
+ ac.setMode(kWhirlpoolAcAuto);
+ EXPECT_EQ(kWhirlpoolAcAuto, ac.getMode());
+ EXPECT_EQ(kWhirlpoolAcCommand6thSense, ac.getCommand());
+ ac.setMode(kWhirlpoolAcDry);
+ EXPECT_EQ(kWhirlpoolAcDry, ac.getMode());
+ EXPECT_EQ(kWhirlpoolAcCommandMode, ac.getCommand());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetFan) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0); // Clear the previous command.
+
+ ac.setFan(kWhirlpoolAcFanAuto);
+ EXPECT_EQ(kWhirlpoolAcFanAuto, ac.getFan());
+ EXPECT_EQ(kWhirlpoolAcCommandFanSpeed, ac.getCommand());
+ ac.setFan(kWhirlpoolAcFanLow);
+ EXPECT_EQ(kWhirlpoolAcFanLow, ac.getFan());
+ ac.setFan(kWhirlpoolAcFanMedium);
+ EXPECT_EQ(kWhirlpoolAcFanMedium, ac.getFan());
+ ac.setFan(kWhirlpoolAcFanHigh);
+ EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan());
+ ac.setFan(kWhirlpoolAcFanAuto);
+ EXPECT_EQ(kWhirlpoolAcFanAuto, ac.getFan());
+
+ // Known state with a non-auto fan mode.
+ const uint8_t state[21] = {0x83, 0x06, 0x0B, 0x82, 0x00, 0x00, 0x93,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
+ 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x0B};
+ ac.setRaw(state);
+ EXPECT_EQ(kWhirlpoolAcFanLow, ac.getFan());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetSwing) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0); // Clear the previous command.
+
+ ac.setSwing(true);
+ EXPECT_TRUE(ac.getSwing());
+ EXPECT_EQ(kWhirlpoolAcCommandSwing, ac.getCommand());
+ ac.setSwing(false);
+ EXPECT_FALSE(ac.getSwing());
+ ac.setSwing(true);
+ EXPECT_TRUE(ac.getSwing());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetLight) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0); // Clear the previous command.
+
+ ac.setLight(true);
+ EXPECT_TRUE(ac.getLight());
+ ac.setLight(false);
+ EXPECT_FALSE(ac.getLight());
+ ac.setLight(true);
+ EXPECT_TRUE(ac.getLight());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetClock) {
+ IRWhirlpoolAc ac(0);
+ ac.setClock(0);
+ EXPECT_EQ(0, ac.getClock());
+ EXPECT_EQ("00:00", ac.timeToString(ac.getClock()));
+ ac.setClock(1);
+ EXPECT_EQ(1, ac.getClock());
+ EXPECT_EQ("00:01", ac.timeToString(ac.getClock()));
+ ac.setClock(12 * 60 + 34);
+ EXPECT_EQ(12 * 60 + 34, ac.getClock());
+ EXPECT_EQ("12:34", ac.timeToString(ac.getClock()));
+ ac.setClock(7 * 60 + 5);
+ EXPECT_EQ(7 * 60 + 5, ac.getClock());
+ EXPECT_EQ("07:05", ac.timeToString(ac.getClock()));
+ ac.setClock(23 * 60 + 59);
+ EXPECT_EQ(23 * 60 + 59, ac.getClock());
+ EXPECT_EQ("23:59", ac.timeToString(ac.getClock()));
+ ac.setClock(24 * 60 + 0);
+ EXPECT_EQ(0, ac.getClock());
+ EXPECT_EQ("00:00", ac.timeToString(ac.getClock()));
+ ac.setClock(25 * 60 + 23);
+ EXPECT_EQ(1 * 60 + 23, ac.getClock());
+ EXPECT_EQ("01:23", ac.timeToString(ac.getClock()));
+}
+
+TEST(TestIRWhirlpoolAcClass, OnOffTimers) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0); // Clear the previous command.
+
+ // On Timer
+ ac.enableOnTimer(false);
+ ac.setOnTimer(0);
+ EXPECT_EQ(0, ac.getOnTimer());
+ EXPECT_EQ("00:00", ac.timeToString(ac.getOnTimer()));
+ EXPECT_FALSE(ac.isOnTimerEnabled());
+ EXPECT_EQ(kWhirlpoolAcCommandOnTimer, ac.getCommand());
+ ac.setOnTimer(1);
+ EXPECT_EQ(1, ac.getOnTimer());
+ EXPECT_EQ("00:01", ac.timeToString(ac.getOnTimer()));
+ ac.enableOnTimer(true);
+ ac.setOnTimer(12 * 60 + 34);
+ EXPECT_EQ(12 * 60 + 34, ac.getOnTimer());
+ EXPECT_EQ("12:34", ac.timeToString(ac.getOnTimer()));
+ EXPECT_TRUE(ac.isOnTimerEnabled());
+ ac.setOnTimer(7 * 60 + 5);
+ EXPECT_EQ(7 * 60 + 5, ac.getOnTimer());
+ EXPECT_EQ("07:05", ac.timeToString(ac.getOnTimer()));
+ ac.setOnTimer(23 * 60 + 59);
+ EXPECT_EQ(23 * 60 + 59, ac.getOnTimer());
+ EXPECT_EQ("23:59", ac.timeToString(ac.getOnTimer()));
+ ac.setOnTimer(24 * 60 + 0);
+ EXPECT_EQ(0, ac.getOnTimer());
+ EXPECT_EQ("00:00", ac.timeToString(ac.getOnTimer()));
+ ac.setOnTimer(25 * 60 + 23);
+ EXPECT_EQ(1 * 60 + 23, ac.getOnTimer());
+ EXPECT_EQ("01:23", ac.timeToString(ac.getOnTimer()));
+ // Off Timer
+ ac.enableOffTimer(false);
+ ac.setOffTimer(0);
+ EXPECT_EQ(0, ac.getOffTimer());
+ EXPECT_EQ("00:00", ac.timeToString(ac.getOffTimer()));
+ EXPECT_FALSE(ac.isOffTimerEnabled());
+ EXPECT_EQ(kWhirlpoolAcCommandOffTimer, ac.getCommand());
+ ac.setOffTimer(1);
+ EXPECT_EQ(1, ac.getOffTimer());
+ EXPECT_EQ("00:01", ac.timeToString(ac.getOffTimer()));
+ ac.enableOffTimer(true);
+ ac.setOffTimer(12 * 60 + 34);
+ EXPECT_EQ(12 * 60 + 34, ac.getOffTimer());
+ EXPECT_EQ("12:34", ac.timeToString(ac.getOffTimer()));
+ EXPECT_TRUE(ac.isOffTimerEnabled());
+ ac.setOffTimer(7 * 60 + 5);
+ EXPECT_EQ(7 * 60 + 5, ac.getOffTimer());
+ EXPECT_EQ("07:05", ac.timeToString(ac.getOffTimer()));
+ ac.setOffTimer(23 * 60 + 59);
+ EXPECT_EQ(23 * 60 + 59, ac.getOffTimer());
+ EXPECT_EQ("23:59", ac.timeToString(ac.getOffTimer()));
+ ac.setOffTimer(24 * 60 + 0);
+ EXPECT_EQ(0, ac.getOffTimer());
+ EXPECT_EQ("00:00", ac.timeToString(ac.getOffTimer()));
+ ac.setOffTimer(25 * 60 + 23);
+ EXPECT_EQ(1 * 60 + 23, ac.getOffTimer());
+ EXPECT_EQ("01:23", ac.timeToString(ac.getOffTimer()));
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetCommand) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0);
+ EXPECT_EQ(0, ac.getCommand());
+ ac.setCommand(kWhirlpoolAcCommandFanSpeed);
+ EXPECT_EQ(kWhirlpoolAcCommandFanSpeed, ac.getCommand());
+ ac.setCommand(255);
+ EXPECT_EQ(255, ac.getCommand());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetPowerToggle) {
+ IRWhirlpoolAc ac(0);
+ ac.setCommand(0);
+
+ ac.setPowerToggle(false);
+ EXPECT_FALSE(ac.getPowerToggle());
+ ac.setPowerToggle(true);
+ EXPECT_TRUE(ac.getPowerToggle());
+ ac.setPowerToggle(false);
+ EXPECT_FALSE(ac.getPowerToggle());
+
+ // Known state with a power toggle in it.
+ uint8_t state[21] = {0x83, 0x06, 0x07, 0x82, 0x00, 0x00, 0x93,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x09};
+ ac.setRaw(state);
+ EXPECT_TRUE(ac.getPowerToggle());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetModel) {
+ IRWhirlpoolAc ac(0);
+ ac.setTemp(19);
+ ac.setCommand(0); // Set model shouldn't change the command setting.
+
+ ac.setModel(DG11J191);
+ EXPECT_EQ(DG11J191, ac.getModel());
+ EXPECT_EQ(19, ac.getTemp());
+ EXPECT_EQ(0, ac.getCommand());
+ ac.setModel(DG11J13A);
+ EXPECT_EQ(DG11J13A, ac.getModel());
+ EXPECT_EQ(19, ac.getTemp());
+ ac.setModel(DG11J191);
+ EXPECT_EQ(DG11J191, ac.getModel());
+ EXPECT_EQ(19, ac.getTemp());
+ EXPECT_EQ(0, ac.getCommand());
+
+ // One of the models has a lower min temp. Check that desired temp is kept.
+ ac.setTemp(16);
+ ac.setCommand(0); // Set model shouldn't change the command setting.
+ EXPECT_EQ(16, ac.getTemp());
+ EXPECT_EQ(0, ac.getCommand());
+ ac.setModel(DG11J13A);
+ EXPECT_EQ(DG11J13A, ac.getModel());
+ EXPECT_EQ(18, ac.getTemp());
+ ac.setModel(DG11J191);
+ EXPECT_EQ(DG11J191, ac.getModel());
+ EXPECT_EQ(16, ac.getTemp());
+ EXPECT_EQ(0, ac.getCommand());
+
+ // Known states with different models.
+ uint8_t state_1[21] = {0x83, 0x06, 0x01, 0x30, 0x00, 0x00, 0x92,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95,
+ 0x00, 0x02, 0x00, 0x00, 0x08, 0x00, 0x0A};
+ uint8_t state_2[21] = {0x83, 0x06, 0x00, 0x30, 0x00, 0x00, 0x8B,
+ 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
+
+ ac.setRaw(state_1);
+ EXPECT_EQ(DG11J191, ac.getModel());
+ ac.setRaw(state_2);
+ EXPECT_EQ(DG11J13A, ac.getModel());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetSleep) {
+ IRWhirlpoolAc ac(0);
+ ac.setFan(kWhirlpoolAcFanAuto);
+ ac.setCommand(0);
+
+ ac.setSleep(false);
+ EXPECT_FALSE(ac.getSleep());
+ EXPECT_EQ(kWhirlpoolAcCommandSleep, ac.getCommand());
+ ac.setSleep(true);
+ EXPECT_TRUE(ac.getSleep());
+ EXPECT_EQ(kWhirlpoolAcCommandSleep, ac.getCommand());
+ EXPECT_EQ(kWhirlpoolAcFanLow, ac.getFan());
+ ac.setSleep(false);
+ EXPECT_FALSE(ac.getSleep());
+
+ // Known state with sleep mode in it.
+ uint8_t state[21] = {0x83, 0x06, 0x0B, 0x73, 0x00, 0x00, 0x90,
+ 0x9E, 0x00, 0xA0, 0x17, 0x3A, 0x00, 0xFB,
+ 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x0B};
+ ac.setRaw(state);
+ EXPECT_TRUE(ac.getSleep());
+}
+
+TEST(TestIRWhirlpoolAcClass, SetAndGetSuper) {
+ IRWhirlpoolAc ac(0);
+ ac.setFan(kWhirlpoolAcFanAuto);
+ ac.setMode(kWhirlpoolAcDry);
+ ac.setCommand(0);
+
+ ac.setSuper(false);
+ EXPECT_FALSE(ac.getSuper());
+ EXPECT_EQ(kWhirlpoolAcCommandSuper, ac.getCommand());
+ ac.setSuper(true);
+ EXPECT_TRUE(ac.getSuper());
+ EXPECT_EQ(kWhirlpoolAcCommandSuper, ac.getCommand());
+ EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan());
+ EXPECT_EQ(kWhirlpoolAcCool, ac.getMode());
+ EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp());
+
+ ac.setSuper(false);
+ EXPECT_FALSE(ac.getSuper());
+ EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan());
+ EXPECT_EQ(kWhirlpoolAcCool, ac.getMode());
+ EXPECT_EQ(kWhirlpoolAcMinTemp, ac.getTemp());
+
+ // When in heat mode, it should stay in heat mode.
+ ac.setFan(kWhirlpoolAcFanAuto);
+ ac.setMode(kWhirlpoolAcHeat);
+ ac.setSuper(true);
+ EXPECT_TRUE(ac.getSuper());
+ EXPECT_EQ(kWhirlpoolAcCommandSuper, ac.getCommand());
+ EXPECT_EQ(kWhirlpoolAcFanHigh, ac.getFan());
+ EXPECT_EQ(kWhirlpoolAcHeat, ac.getMode());
+ EXPECT_EQ(kWhirlpoolAcMaxTemp, ac.getTemp());
+
+ // Changing mode/temp/fan/power should cancel super,
+ ac.setMode(kWhirlpoolAcCool);
+ EXPECT_FALSE(ac.getSuper());
+ ac.setSuper(true);
+ ac.setTemp(25);
+ EXPECT_FALSE(ac.getSuper());
+ ac.setSuper(true);
+ ac.setFan(kWhirlpoolAcFanMedium);
+ EXPECT_FALSE(ac.getSuper());
+ ac.setSuper(true);
+ ac.setPowerToggle(true);
+ EXPECT_FALSE(ac.getSuper());
+
+ // Known state with Super mode in it.
+ uint8_t state[21] = {0x83, 0x06, 0x01, 0x02, 0x00, 0x90, 0x90,
+ 0x9F, 0x00, 0xA0, 0x17, 0x3A, 0x00, 0x11,
+ 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x0C};
+ ac.setRaw(state);
+ EXPECT_TRUE(ac.getSuper());
+}
+
+// Build a known good message from scratch.
+TEST(TestIRWhirlpoolAcClass, MessageConstruction) {
+ // Real example captured from a remote. (ref: RealTimerExample)
+ uint8_t expectedState[kWhirlpoolAcStateLength] = {
+ 0x83, 0x06, 0x00, 0x73, 0x00, 0x00, 0x87, 0xA3, 0x08, 0x85, 0x07,
+ 0x28, 0x00, 0xF5, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05};
+ IRWhirlpoolAc ac(0);
+ ac.setModel(DG11J13A);
+ ac.setTemp(25);
+ ac.setPowerToggle(false);
+ ac.setMode(kWhirlpoolAcDry);
+ ac.setFan(kWhirlpoolAcFanAuto);
+ ac.setSwing(false);
+ ac.setLight(true);
+ ac.setClock(7 * 60 + 35);
+ ac.setOnTimer(7 * 60 + 40);
+ ac.setOffTimer(8 * 60 + 5);
+ ac.enableOffTimer(true);
+ ac.setSleep(false);
+ ac.setSuper(false);
+ ac.enableOnTimer(true);
+
+ EXPECT_EQ(
+ "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, "
+ "Fan: 0 (AUTO), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, "
+ "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)",
+ ac.toString());
+ EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits);
+}
diff --git a/lib/IRremoteESP8266-2.5.2.03/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266-2.6.0/test/ir_Whynter_test.cpp
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/test/ir_Whynter_test.cpp
rename to lib/IRremoteESP8266-2.6.0/test/ir_Whynter_test.cpp
index 748a4c9bf460..92ced5cf613a 100644
--- a/lib/IRremoteESP8266-2.5.2.03/test/ir_Whynter_test.cpp
+++ b/lib/IRremoteESP8266-2.6.0/test/ir_Whynter_test.cpp
@@ -14,6 +14,7 @@ TEST(TestSendWhynter, SendDataOnly) {
irsend.reset();
irsend.sendWhynter(0x0);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750"
"m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750"
@@ -25,6 +26,7 @@ TEST(TestSendWhynter, SendDataOnly) {
irsend.reset();
irsend.sendWhynter(0xFFFFFFFF);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150"
"m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150m750s2150"
@@ -36,6 +38,7 @@ TEST(TestSendWhynter, SendDataOnly) {
irsend.reset();
irsend.sendWhynter(0x87654321);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -53,6 +56,7 @@ TEST(TestSendWhynter, SendWithRepeats) {
irsend.reset();
irsend.sendWhynter(0x87654321, kWhynterBits, 0); // 0 repeats.
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -64,6 +68,7 @@ TEST(TestSendWhynter, SendWithRepeats) {
irsend.reset();
irsend.sendWhynter(0x87654321, kWhynterBits, 1); // 1 repeat.
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -81,6 +86,7 @@ TEST(TestSendWhynter, SendWithRepeats) {
irsend.reset();
irsend.sendWhynter(0x87654321, kWhynterBits, 2); // 2 repeats.
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s2150m750s750m750s750m750s750m750s750m750s2150m750s2150m750s2150"
"m750s750m750s2150m750s2150m750s750m750s750m750s2150m750s750m750s2150"
@@ -110,6 +116,7 @@ TEST(TestSendWhynter, SendUnusualSize) {
irsend.reset();
irsend.sendWhynter(0x0, 8);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s750m750s750m750s750m750s750m750s750m750s750m750s750m750s750"
"m750s88050",
@@ -118,6 +125,7 @@ TEST(TestSendWhynter, SendUnusualSize) {
irsend.reset();
irsend.sendWhynter(0x1234567890ABCDEF, 64);
EXPECT_EQ(
+ "f38000d50"
"m750s750m2850s2850"
"m750s750m750s750m750s750m750s2150m750s750m750s750m750s2150m750s750"
"m750s750m750s750m750s2150m750s2150m750s750m750s2150m750s750m750s750"
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/Makefile b/lib/IRremoteESP8266-2.6.0/tools/Makefile
similarity index 76%
rename from lib/IRremoteESP8266-2.5.2.03/tools/Makefile
rename to lib/IRremoteESP8266-2.6.0/tools/Makefile
index c303e051db39..08488949c6a9 100644
--- a/lib/IRremoteESP8266-2.5.2.03/tools/Makefile
+++ b/lib/IRremoteESP8266-2.6.0/tools/Makefile
@@ -14,13 +14,14 @@ USER_DIR = ../src
# Where to find test code.
TEST_DIR = ../test
+INCLUDES = -I$(USER_DIR) -I$(TEST_DIR)
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -DUNIT_TEST
# Flags passed to the C++ compiler.
-CXXFLAGS += -g -Wall -Wextra -pthread
+CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11
all : gc_decode mode2_decode
@@ -48,25 +49,27 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_Pronto.o ir_GlobalCache.o ir_Nikai.o ir_Toshiba.o ir_Midea.o \
ir_Magiquest.o ir_Lasertag.o ir_Carrier.o ir_Haier.o ir_Hitachi.o \
ir_GICable.o ir_Whirlpool.o ir_Lutron.o ir_Electra.o ir_Pioneer.o \
- ir_MWM.o
+ ir_MWM.o ir_Vestel.o ir_Teco.o ir_Tcl.o ir_Lego.o \
+ ir_MitsubishiHeavy.o
# Common object files
COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o $(PROTOCOLS)
# Common dependencies
COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \
- $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h
+ $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \
+ $(TEST_DIR)/IRsend_test.h
# Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) $(TEST_DIR)/IRsend_test.h
gc_decode.o : gc_decode.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -I$(TEST_DIR) -c gc_decode.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c gc_decode.cpp
gc_decode : $(COMMON_OBJ) gc_decode.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
mode2_decode.o : mode2_decode.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -I$(TEST_DIR) -c mode2_decode.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c mode2_decode.cpp
mode2_decode : $(COMMON_OBJ) mode2_decode.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
@@ -83,7 +86,6 @@ IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP82
IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP8266.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp
-
ir_NEC.o : $(USER_DIR)/ir_NEC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_NEC.cpp
@@ -97,10 +99,10 @@ ir_Sony.o : $(USER_DIR)/ir_Sony.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sony.cpp
ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(USER_DIR)/ir_Samsung.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Samsung.cpp
ir_Kelvinator.o : $(USER_DIR)/ir_Kelvinator.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Kelvinator.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Kelvinator.cpp
ir_JVC.o : $(USER_DIR)/ir_JVC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_JVC.cpp
@@ -112,10 +114,13 @@ ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp
ir_Mitsubishi.o : $(USER_DIR)/ir_Mitsubishi.h $(USER_DIR)/ir_Mitsubishi.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Mitsubishi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Mitsubishi.cpp
+
+ir_MitsubishiHeavy.o : $(USER_DIR)/ir_MitsubishiHeavy.h $(USER_DIR)/ir_MitsubishiHeavy.cpp $(COMMON_DEPS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_MitsubishiHeavy.cpp
ir_Fujitsu.o : $(USER_DIR)/ir_Fujitsu.h $(USER_DIR)/ir_Fujitsu.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Fujitsu.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Fujitsu.cpp
ir_Sharp.o : $(USER_DIR)/ir_Sharp.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sharp.cpp
@@ -124,7 +129,7 @@ ir_RC5_RC6.o : $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RC5_RC6.cpp
ir_Panasonic.o : $(USER_DIR)/ir_Panasonic.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Panasonic.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Panasonic.cpp
ir_Dish.o : $(USER_DIR)/ir_Dish.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Dish.cpp
@@ -133,7 +138,7 @@ ir_Whynter.o : $(USER_DIR)/ir_Whynter.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whynter.cpp
ir_Coolix.o : $(USER_DIR)/ir_Coolix.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Coolix.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Coolix.cpp
ir_Aiwa.o : $(USER_DIR)/ir_Aiwa.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Aiwa.cpp
@@ -145,10 +150,10 @@ ir_Sanyo.o : $(USER_DIR)/ir_Sanyo.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sanyo.cpp
ir_Daikin.o : $(USER_DIR)/ir_Daikin.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Daikin.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Daikin.cpp
ir_Gree.o : $(USER_DIR)/ir_Gree.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Gree.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Gree.cpp
ir_Pronto.o : $(USER_DIR)/ir_Pronto.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pronto.cpp
@@ -157,10 +162,10 @@ ir_Nikai.o : $(USER_DIR)/ir_Nikai.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Nikai.cpp
ir_Toshiba.o : $(USER_DIR)/ir_Toshiba.h $(USER_DIR)/ir_Toshiba.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Toshiba.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Toshiba.cpp
ir_Midea.o : $(USER_DIR)/ir_Midea.cpp $(COMMON_DEPS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Midea.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Midea.cpp
ir_Magiquest.o : $(USER_DIR)/ir_Magiquest.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Magiquest.cpp
@@ -172,16 +177,16 @@ ir_Carrier.o : $(USER_DIR)/ir_Carrier.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Carrier.cpp
ir_Haier.o : $(USER_DIR)/ir_Haier.cpp $(USER_DIR)/ir_Haier.h $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Haier.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Haier.cpp
ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Hitachi.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Hitachi.cpp
ir_GICable.o : $(USER_DIR)/ir_GICable.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GICable.cpp
ir_Whirlpool.o : $(USER_DIR)/ir_Whirlpool.cpp $(GTEST_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whirlpool.cpp
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Whirlpool.cpp
ir_Lutron.o : $(USER_DIR)/ir_Lutron.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lutron.cpp
@@ -194,3 +199,15 @@ ir_Pioneer.o : $(USER_DIR)/ir_Pioneer.cpp $(GTEST_HEADERS)
ir_MWM.o : $(USER_DIR)/ir_MWM.cpp $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_MWM.cpp
+
+ir_Vestel.o : $(USER_DIR)/ir_Vestel.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Vestel.cpp
+
+ir_Teco.o : $(USER_DIR)/ir_Teco.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Teco.cpp
+
+ir_Tcl.o : $(USER_DIR)/ir_Tcl.cpp $(USER_DIR)/ir_Tcl.h $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Tcl.cpp
+
+ir_Lego.o : $(USER_DIR)/ir_Lego.cpp $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Lego.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.6.0/tools/RawToGlobalCache.sh
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/RawToGlobalCache.sh
rename to lib/IRremoteESP8266-2.6.0/tools/RawToGlobalCache.sh
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data.py
similarity index 98%
rename from lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data.py
rename to lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data.py
index 5fd399807a60..b23cdb46fecb 100644
--- a/lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data.py
+++ b/lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data.py
@@ -85,9 +85,9 @@ def display_binary(self, binary_str):
" %s (LSB first)\n"
" Bin: 0b%s (MSB first)\n"
" 0b%s (LSB first)\n" %
- (bits, "0x{0:0{1}X}".format(num, bits / 4),
- "0x{0:0{1}X}".format(rev_num, bits / 4), num, rev_num,
- binary_str, rev_binary_str))
+ (bits, ("0x{0:0%dX}" % (bits / 4)).format(num),
+ ("0x{0:0%dX}" % (bits / 4)).format(rev_num), num,
+ rev_num, binary_str, rev_binary_str))
def add_data_code(self, bin_str, footer=True):
"""Add the common "data" sequence of code to send the bulk of a message."""
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data_test.py
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/auto_analyse_raw_data_test.py
rename to lib/IRremoteESP8266-2.6.0/tools/auto_analyse_raw_data_test.py
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/gc_decode.cpp b/lib/IRremoteESP8266-2.6.0/tools/gc_decode.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/gc_decode.cpp
rename to lib/IRremoteESP8266-2.6.0/tools/gc_decode.cpp
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/mkkeywords b/lib/IRremoteESP8266-2.6.0/tools/mkkeywords
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/mkkeywords
rename to lib/IRremoteESP8266-2.6.0/tools/mkkeywords
diff --git a/lib/IRremoteESP8266-2.5.2.03/tools/mode2_decode.cpp b/lib/IRremoteESP8266-2.6.0/tools/mode2_decode.cpp
similarity index 100%
rename from lib/IRremoteESP8266-2.5.2.03/tools/mode2_decode.cpp
rename to lib/IRremoteESP8266-2.6.0/tools/mode2_decode.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py
deleted file mode 100644
index 1b0cc65bb432..000000000000
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_basic.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import unittest
-import settings
-
-import time
-import mosquitto
-
-import serial
-
-def on_message(mosq, obj, msg):
- obj.message_queue.append(msg)
-
-class mqtt_basic(unittest.TestCase):
-
- message_queue = []
-
- @classmethod
- def setUpClass(self):
- self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
- self.client.connect(settings.server_ip)
- self.client.on_message = on_message
- self.client.subscribe("outTopic",0)
-
- @classmethod
- def tearDownClass(self):
- self.client.disconnect()
-
- def test_one(self):
- i=30
- while len(self.message_queue) == 0 and i > 0:
- self.client.loop()
- time.sleep(0.5)
- i -= 1
- self.assertTrue(i>0, "message receive timed-out")
- self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
- msg = self.message_queue[0]
- self.assertEqual(msg.mid,0,"message id not 0")
- self.assertEqual(msg.topic,"outTopic","message topic incorrect")
- self.assertEqual(msg.payload,"hello world")
- self.assertEqual(msg.qos,0,"message qos not 0")
- self.assertEqual(msg.retain,False,"message retain flag incorrect")
-
-
-
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py
deleted file mode 100644
index 7989f7f17bed..000000000000
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/mqtt_publish_in_callback.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import unittest
-import settings
-
-import time
-import mosquitto
-
-import serial
-
-def on_message(mosq, obj, msg):
- obj.message_queue.append(msg)
-
-class mqtt_publish_in_callback(unittest.TestCase):
-
- message_queue = []
-
- @classmethod
- def setUpClass(self):
- self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self)
- self.client.connect(settings.server_ip)
- self.client.on_message = on_message
- self.client.subscribe("outTopic",0)
-
- @classmethod
- def tearDownClass(self):
- self.client.disconnect()
-
- def test_connect(self):
- i=30
- while len(self.message_queue) == 0 and i > 0:
- self.client.loop()
- time.sleep(0.5)
- i -= 1
- self.assertTrue(i>0, "message receive timed-out")
- self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
- msg = self.message_queue.pop(0)
- self.assertEqual(msg.mid,0,"message id not 0")
- self.assertEqual(msg.topic,"outTopic","message topic incorrect")
- self.assertEqual(msg.payload,"hello world")
- self.assertEqual(msg.qos,0,"message qos not 0")
- self.assertEqual(msg.retain,False,"message retain flag incorrect")
-
-
- def test_publish(self):
- self.assertEqual(len(self.message_queue), 0, "message queue not empty")
- payload = "abcdefghij"
- self.client.publish("inTopic",payload)
-
- i=30
- while len(self.message_queue) == 0 and i > 0:
- self.client.loop()
- time.sleep(0.5)
- i -= 1
-
- self.assertTrue(i>0, "message receive timed-out")
- self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
- msg = self.message_queue.pop(0)
- self.assertEqual(msg.mid,0,"message id not 0")
- self.assertEqual(msg.topic,"outTopic","message topic incorrect")
- self.assertEqual(msg.payload,payload)
- self.assertEqual(msg.qos,0,"message qos not 0")
- self.assertEqual(msg.retain,False,"message retain flag incorrect")
-
-
-
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py b/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py
deleted file mode 100644
index 0a8e70dfd986..000000000000
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/testsuite.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/env python
-import os
-import os.path
-import sys
-import shutil
-from subprocess import call
-import importlib
-import unittest
-import re
-
-from testcases import settings
-
-class Workspace(object):
-
- def __init__(self):
- self.root_dir = os.getcwd()
- self.build_dir = os.path.join(self.root_dir,"tmpbin");
- self.log_dir = os.path.join(self.root_dir,"logs");
- self.tests_dir = os.path.join(self.root_dir,"testcases");
- self.examples_dir = os.path.join(self.root_dir,"../PubSubClient/examples")
- self.examples = []
- self.tests = []
- if not os.path.isdir("../PubSubClient"):
- raise Exception("Cannot find PubSubClient library")
- try:
- import ino
- except:
- raise Exception("ino tool not installed")
-
- def init(self):
- if os.path.isdir(self.build_dir):
- shutil.rmtree(self.build_dir)
- os.mkdir(self.build_dir)
- if os.path.isdir(self.log_dir):
- shutil.rmtree(self.log_dir)
- os.mkdir(self.log_dir)
-
- os.chdir(self.build_dir)
- call(["ino","init"])
-
- shutil.copytree("../../PubSubClient","lib/PubSubClient")
-
- filenames = []
- for root, dirs, files in os.walk(self.examples_dir):
- filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
- filenames.sort()
- for e in filenames:
- self.examples.append(Sketch(self,e))
-
- filenames = []
- for root, dirs, files in os.walk(self.tests_dir):
- filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")]
- filenames.sort()
- for e in filenames:
- self.tests.append(Sketch(self,e))
-
- def clean(self):
- shutil.rmtree(self.build_dir)
-
-class Sketch(object):
- def __init__(self,wksp,fn):
- self.w = wksp
- self.filename = fn
- self.basename = os.path.basename(self.filename)
- self.build_log = os.path.join(self.w.log_dir,"%s.log"%(os.path.basename(self.filename),))
- self.build_err_log = os.path.join(self.w.log_dir,"%s.err.log"%(os.path.basename(self.filename),))
- self.build_upload_log = os.path.join(self.w.log_dir,"%s.upload.log"%(os.path.basename(self.filename),))
-
- def build(self):
- sys.stdout.write(" Build: ")
- sys.stdout.flush()
-
- # Copy sketch over, replacing IP addresses as necessary
- fin = open(self.filename,"r")
- lines = fin.readlines()
- fin.close()
- fout = open(os.path.join(self.w.build_dir,"src","sketch.ino"),"w")
- for l in lines:
- if re.match(r"^byte server\[\] = {",l):
- fout.write("byte server[] = { %s };\n"%(settings.server_ip.replace(".",", "),))
- elif re.match(r"^byte ip\[\] = {",l):
- fout.write("byte ip[] = { %s };\n"%(settings.arduino_ip.replace(".",", "),))
- else:
- fout.write(l)
- fout.flush()
- fout.close()
-
- # Run build
- fout = open(self.build_log, "w")
- ferr = open(self.build_err_log, "w")
- rc = call(["ino","build"],stdout=fout,stderr=ferr)
- fout.close()
- ferr.close()
- if rc == 0:
- sys.stdout.write("pass")
- sys.stdout.write("\n")
- return True
- else:
- sys.stdout.write("fail")
- sys.stdout.write("\n")
- with open(self.build_err_log) as f:
- for line in f:
- print " ",line,
- return False
-
- def upload(self):
- sys.stdout.write(" Upload: ")
- sys.stdout.flush()
- fout = open(self.build_upload_log, "w")
- rc = call(["ino","upload"],stdout=fout,stderr=fout)
- fout.close()
- if rc == 0:
- sys.stdout.write("pass")
- sys.stdout.write("\n")
- return True
- else:
- sys.stdout.write("fail")
- sys.stdout.write("\n")
- with open(self.build_upload_log) as f:
- for line in f:
- print " ",line,
- return False
-
-
- def test(self):
- # import the matching test case, if it exists
- try:
- basename = os.path.basename(self.filename)[:-4]
- i = importlib.import_module("testcases."+basename)
- except:
- sys.stdout.write(" Test: no tests found")
- sys.stdout.write("\n")
- return
- c = getattr(i,basename)
-
- testmethods = [m for m in dir(c) if m.startswith("test_")]
- testmethods.sort()
- tests = []
- for m in testmethods:
- tests.append(c(m))
-
- result = unittest.TestResult()
- c.setUpClass()
- if self.upload():
- sys.stdout.write(" Test: ")
- sys.stdout.flush()
- for t in tests:
- t.run(result)
- print "%d/%d"%(result.testsRun-len(result.failures)-len(result.errors),result.testsRun)
- if not result.wasSuccessful():
- if len(result.failures) > 0:
- for f in result.failures:
- print "-- %s"%(str(f[0]),)
- print f[1]
- if len(result.errors) > 0:
- print " Errors:"
- for f in result.errors:
- print "-- %s"%(str(f[0]),)
- print f[1]
- c.tearDownClass()
-
-if __name__ == '__main__':
- run_tests = True
-
- w = Workspace()
- w.init()
-
- for e in w.examples:
- print "--------------------------------------"
- print "[%s]"%(e.basename,)
- if e.build() and run_tests:
- e.test()
- for e in w.tests:
- print "--------------------------------------"
- print "[%s]"%(e.basename,)
- if e.build() and run_tests:
- e.test()
-
- w.clean()
diff --git a/lib/PubSubClient-EspEasy-2.6.09/.gitignore b/lib/PubSubClient-EspEasy-2.7.11/.gitignore
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/.gitignore
rename to lib/PubSubClient-EspEasy-2.7.11/.gitignore
diff --git a/lib/PubSubClient-EspEasy-2.6.09/.travis.yml b/lib/PubSubClient-EspEasy-2.7.11/.travis.yml
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/.travis.yml
rename to lib/PubSubClient-EspEasy-2.7.11/.travis.yml
diff --git a/lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt b/lib/PubSubClient-EspEasy-2.7.11/CHANGES.txt
similarity index 86%
rename from lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt
rename to lib/PubSubClient-EspEasy-2.7.11/CHANGES.txt
index 8c8bef64ec33..ff4da62ab1ae 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/CHANGES.txt
+++ b/lib/PubSubClient-EspEasy-2.7.11/CHANGES.txt
@@ -1,8 +1,16 @@
+2.7
+ * Fix remaining-length handling to prevent buffer overrun
+ * Add large-payload API - beginPublish/write/publish/endPublish
+ * Add yield call to improve reliability on ESP
+ * Add Clean Session flag to connect options
+ * Add ESP32 support for functional callback signature
+ * Various other fixes
+
2.4
* Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
whilst waiting for inbound data
* Fixed return code when publishing >256 bytes
-
+
2.3
* Add publish(topic,payload,retained) function
diff --git a/lib/PubSubClient-EspEasy-2.6.09/LICENSE.txt b/lib/PubSubClient-EspEasy-2.7.11/LICENSE.txt
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/LICENSE.txt
rename to lib/PubSubClient-EspEasy-2.7.11/LICENSE.txt
diff --git a/lib/PubSubClient-EspEasy-2.6.09/README.md b/lib/PubSubClient-EspEasy-2.7.11/README.md
similarity index 95%
rename from lib/PubSubClient-EspEasy-2.6.09/README.md
rename to lib/PubSubClient-EspEasy-2.7.11/README.md
index 83176919cd23..69cbb8f0ce50 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/README.md
+++ b/lib/PubSubClient-EspEasy-2.7.11/README.md
@@ -8,7 +8,7 @@ a server that supports MQTT.
The library comes with a number of example sketches. See File > Examples > PubSubClient
within the Arduino application.
-Full API documentation is available here: http://pubsubclient.knolleary.net
+Full API documentation is available here: https://pubsubclient.knolleary.net
## Limitations
@@ -37,6 +37,7 @@ boards and shields, including:
- TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library)
- Intel Galileo/Edison
- ESP8266
+ - ESP32
The library cannot currently be used with hardware based on the ENC28J60 chip –
such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_auth/mqtt_auth.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_auth/mqtt_auth.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_auth/mqtt_auth.ino
rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_auth/mqtt_auth.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_basic/mqtt_basic.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_basic/mqtt_basic.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_basic/mqtt_basic.ino
rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_basic/mqtt_basic.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_esp8266/mqtt_esp8266.ino
similarity index 92%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino
rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_esp8266/mqtt_esp8266.ino
index e46f85f3e412..e7357b507dbf 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_esp8266/mqtt_esp8266.ino
+++ b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_esp8266/mqtt_esp8266.ino
@@ -38,14 +38,6 @@ long lastMsg = 0;
char msg[50];
int value = 0;
-void setup() {
- pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
- Serial.begin(115200);
- setup_wifi();
- client.setServer(mqtt_server, 1883);
- client.setCallback(callback);
-}
-
void setup_wifi() {
delay(10);
@@ -61,6 +53,8 @@ void setup_wifi() {
Serial.print(".");
}
+ randomSeed(micros());
+
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
@@ -80,7 +74,7 @@ void callback(char* topic, byte* payload, unsigned int length) {
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
- // it is acive low on the ESP-01)
+ // it is active low on the ESP-01)
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
}
@@ -91,8 +85,11 @@ void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
+ // Create a random client ID
+ String clientId = "ESP8266Client-";
+ clientId += String(random(0xffff), HEX);
// Attempt to connect
- if (client.connect("ESP8266Client")) {
+ if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
@@ -107,6 +104,15 @@ void reconnect() {
}
}
}
+
+void setup() {
+ pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
+ Serial.begin(115200);
+ setup_wifi();
+ client.setServer(mqtt_server, 1883);
+ client.setCallback(callback);
+}
+
void loop() {
if (!client.connected()) {
@@ -118,7 +124,7 @@ void loop() {
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
- snprintf (msg, 75, "hello world #%ld", value);
+ snprintf (msg, 50, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
diff --git a/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_large_message/mqtt_large_message.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_large_message/mqtt_large_message.ino
new file mode 100644
index 000000000000..e048c3ed3630
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_large_message/mqtt_large_message.ino
@@ -0,0 +1,179 @@
+/*
+ Long message ESP8266 MQTT example
+
+ This sketch demonstrates sending arbitrarily large messages in combination
+ with the ESP8266 board/library.
+
+ It connects to an MQTT server then:
+ - publishes "hello world" to the topic "outTopic"
+ - subscribes to the topic "greenBottles/#", printing out any messages
+ it receives. NB - it assumes the received payloads are strings not binary
+ - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message
+ with a payload consisting of the lyrics to "10 green bottles", replacing
+ 10 with the number given in the sub-topic.
+
+ It will reconnect to the server if the connection is lost using a blocking
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
+ achieve the same result without blocking the main loop.
+
+ To install the ESP8266 board, (using Arduino 1.6.4+):
+ - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
+ http://arduino.esp8266.com/stable/package_esp8266com_index.json
+ - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
+ - Select your ESP8266 in "Tools -> Board"
+
+*/
+
+#include
+#include
+
+// Update these with values suitable for your network.
+
+const char* ssid = "........";
+const char* password = "........";
+const char* mqtt_server = "broker.mqtt-dashboard.com";
+
+WiFiClient espClient;
+PubSubClient client(espClient);
+long lastMsg = 0;
+char msg[50];
+int value = 0;
+
+void setup_wifi() {
+
+ delay(10);
+ // We start by connecting to a WiFi network
+ Serial.println();
+ Serial.print("Connecting to ");
+ Serial.println(ssid);
+
+ WiFi.begin(ssid, password);
+
+ while (WiFi.status() != WL_CONNECTED) {
+ delay(500);
+ Serial.print(".");
+ }
+
+ randomSeed(micros());
+
+ Serial.println("");
+ Serial.println("WiFi connected");
+ Serial.println("IP address: ");
+ Serial.println(WiFi.localIP());
+}
+
+void callback(char* topic, byte* payload, unsigned int length) {
+ Serial.print("Message arrived [");
+ Serial.print(topic);
+ Serial.print("] ");
+ for (int i = 0; i < length; i++) {
+ Serial.print((char)payload[i]);
+ }
+ Serial.println();
+
+ // Find out how many bottles we should generate lyrics for
+ String topicStr(topic);
+ int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic
+ if (topicStr.indexOf('/') >= 0) {
+ // The topic includes a '/', we'll try to read the number of bottles from just after that
+ topicStr.remove(0, topicStr.indexOf('/')+1);
+ // Now see if there's a number of bottles after the '/'
+ bottleCount = topicStr.toInt();
+ }
+
+ if (bottleCount > 0) {
+ // Work out how big our resulting message will be
+ int msgLen = 0;
+ for (int i = bottleCount; i > 0; i--) {
+ String numBottles(i);
+ msgLen += 2*numBottles.length();
+ if (i == 1) {
+ msgLen += 2*String(" green bottle, standing on the wall\n").length();
+ } else {
+ msgLen += 2*String(" green bottles, standing on the wall\n").length();
+ }
+ msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length();
+ switch (i) {
+ case 1:
+ msgLen += String("no green bottles, standing on the wall\n\n").length();
+ break;
+ case 2:
+ msgLen += String("1 green bottle, standing on the wall\n\n").length();
+ break;
+ default:
+ numBottles = i-1;
+ msgLen += numBottles.length();
+ msgLen += String(" green bottles, standing on the wall\n\n").length();
+ break;
+ };
+ }
+
+ // Now we can start to publish the message
+ client.beginPublish("greenBottles/lyrics", msgLen, false);
+ for (int i = bottleCount; i > 0; i--) {
+ for (int j = 0; j < 2; j++) {
+ client.print(i);
+ if (i == 1) {
+ client.print(" green bottle, standing on the wall\n");
+ } else {
+ client.print(" green bottles, standing on the wall\n");
+ }
+ }
+ client.print("And if one green bottle should accidentally fall\nThere'll be ");
+ switch (i) {
+ case 1:
+ client.print("no green bottles, standing on the wall\n\n");
+ break;
+ case 2:
+ client.print("1 green bottle, standing on the wall\n\n");
+ break;
+ default:
+ client.print(i-1);
+ client.print(" green bottles, standing on the wall\n\n");
+ break;
+ };
+ }
+ // Now we're done!
+ client.endPublish();
+ }
+}
+
+void reconnect() {
+ // Loop until we're reconnected
+ while (!client.connected()) {
+ Serial.print("Attempting MQTT connection...");
+ // Create a random client ID
+ String clientId = "ESP8266Client-";
+ clientId += String(random(0xffff), HEX);
+ // Attempt to connect
+ if (client.connect(clientId.c_str())) {
+ Serial.println("connected");
+ // Once connected, publish an announcement...
+ client.publish("outTopic", "hello world");
+ // ... and resubscribe
+ client.subscribe("greenBottles/#");
+ } else {
+ Serial.print("failed, rc=");
+ Serial.print(client.state());
+ Serial.println(" try again in 5 seconds");
+ // Wait 5 seconds before retrying
+ delay(5000);
+ }
+ }
+}
+
+void setup() {
+ pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
+ Serial.begin(115200);
+ setup_wifi();
+ client.setServer(mqtt_server, 1883);
+ client.setCallback(callback);
+}
+
+void loop() {
+
+ if (!client.connected()) {
+ reconnect();
+ }
+ client.loop();
+}
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_stream/mqtt_stream.ino b/lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_stream/mqtt_stream.ino
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/examples/mqtt_stream/mqtt_stream.ino
rename to lib/PubSubClient-EspEasy-2.7.11/examples/mqtt_stream/mqtt_stream.ino
diff --git a/lib/PubSubClient-EspEasy-2.6.09/keywords.txt b/lib/PubSubClient-EspEasy-2.7.11/keywords.txt
similarity index 91%
rename from lib/PubSubClient-EspEasy-2.6.09/keywords.txt
rename to lib/PubSubClient-EspEasy-2.7.11/keywords.txt
index b979588fe4cc..1ee23d0fadda 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/keywords.txt
+++ b/lib/PubSubClient-EspEasy-2.7.11/keywords.txt
@@ -16,6 +16,9 @@ connect KEYWORD2
disconnect KEYWORD2
publish KEYWORD2
publish_P KEYWORD2
+beginPublish KEYWORD2
+endPublish KEYWORD2
+write KEYWORD2
subscribe KEYWORD2
unsubscribe KEYWORD2
loop KEYWORD2
diff --git a/lib/PubSubClient-EspEasy-2.6.09/library.json b/lib/PubSubClient-EspEasy-2.7.11/library.json
similarity index 97%
rename from lib/PubSubClient-EspEasy-2.6.09/library.json
rename to lib/PubSubClient-EspEasy-2.7.11/library.json
index b96739078a98..8a36a1c5e214 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/library.json
+++ b/lib/PubSubClient-EspEasy-2.7.11/library.json
@@ -6,7 +6,7 @@
"type": "git",
"url": "https://github.com/knolleary/pubsubclient.git"
},
- "version": "2.6",
+ "version": "2.7",
"exclude": "tests",
"examples": "examples/*/*.ino",
"frameworks": "arduino",
diff --git a/lib/PubSubClient-EspEasy-2.6.09/library.properties b/lib/PubSubClient-EspEasy-2.7.11/library.properties
similarity index 98%
rename from lib/PubSubClient-EspEasy-2.6.09/library.properties
rename to lib/PubSubClient-EspEasy-2.7.11/library.properties
index 3ceeda81c093..1ae97882ebcb 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/library.properties
+++ b/lib/PubSubClient-EspEasy-2.7.11/library.properties
@@ -1,5 +1,5 @@
name=PubSubClient
-version=2.6
+version=2.7
author=Nick O'Leary
maintainer=Nick O'Leary
sentence=A client library for MQTT messaging.
diff --git a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.cpp
similarity index 79%
rename from lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.cpp
index 79eb2d52ee88..9fe15006aad9 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.cpp
@@ -102,30 +102,41 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN
}
boolean PubSubClient::connect(const char *id) {
- return connect(id,NULL,NULL,0,0,0,0);
+ return connect(id,NULL,NULL,0,0,0,0,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
- return connect(id,user,pass,0,0,0,0);
+ return connect(id,user,pass,0,0,0,0,1);
}
boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
- return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage);
+ return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
+ return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1);
+}
+
+boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) {
if (!connected()) {
int result = 0;
- if (domain.length() != 0) {
- result = _client->connect(this->domain.c_str(), this->port);
+ if (_client == nullptr) {
+ return false;
+ }
+ if (_client->connected()) {
+ result = 1;
} else {
- result = _client->connect(this->ip, this->port);
+ if (domain != NULL) {
+ result = _client->connect(this->domain.c_str(), this->port);
+ } else {
+ result = _client->connect(this->ip, this->port);
+ }
}
if (result == 1) {
nextMsgId = 1;
// Leave room in the buffer for header and variable length field
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
unsigned int j;
#if MQTT_VERSION == MQTT_VERSION_3_1
@@ -141,9 +152,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
uint8_t v;
if (willTopic) {
- v = 0x06|(willQos<<3)|(willRetain<<5);
+ v = 0x04|(willQos<<3)|(willRetain<<5);
} else {
- v = 0x02;
+ v = 0x00;
+ }
+ if (cleanSession) {
+ v = v|0x02;
}
if(user != NULL) {
@@ -158,24 +172,31 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
+
+ CHECK_STRING_LENGTH(length,id)
length = writeString(id,buffer,length);
if (willTopic) {
+ CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,buffer,length);
+ CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,buffer,length);
}
if(user != NULL) {
+ CHECK_STRING_LENGTH(length,user)
length = writeString(user,buffer,length);
if(pass != NULL) {
+ CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,buffer,length);
}
}
- write(MQTTCONNECT,buffer,length-5);
+ write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
lastInActivity = lastOutActivity = millis();
while (!_client->available()) {
+ delay(0); // Prevent watchdog crashes
unsigned long t = millis();
if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
_state = MQTT_CONNECTION_TIMEOUT;
@@ -207,9 +228,12 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass
// reads a byte into result
boolean PubSubClient::readByte(uint8_t * result) {
+ if (_client == nullptr) {
+ return false;
+ }
uint32_t previousMillis = millis();
while(!_client->available()) {
- delay(1); // Add esp8266 de-blocking (Tasmota #790, EspEasy #1943)
+ delay(1); // Prevent watchdog crashes
uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
return false;
@@ -241,7 +265,7 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint8_t start = 0;
do {
- if (len == 6) {
+ if (len == 5) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
@@ -353,11 +377,13 @@ boolean PubSubClient::loop() {
}
boolean PubSubClient::publish(const char* topic, const char* payload) {
- return publish(topic,(const uint8_t*)payload,strlen(payload),false);
+ size_t plength = (payload != nullptr) ? strlen(payload) : 0;
+ return publish(topic,(const uint8_t*)payload,plength,false);
}
boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) {
- return publish(topic,(const uint8_t*)payload,strlen(payload),retained);
+ size_t plength = (payload != nullptr) ? strlen(payload) : 0;
+ return publish(topic,(const uint8_t*)payload,plength,retained);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
@@ -366,12 +392,12 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
if (connected()) {
- if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) {
+ if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {
// Too long
return false;
}
// Leave room in the buffer for header and variable length field
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
uint16_t i;
for (i=0;iwrite(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
+ lastOutActivity = millis();
+ return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
+ }
+ return false;
+}
+
+int PubSubClient::endPublish() {
+ return 1;
+}
+
+size_t PubSubClient::write(uint8_t data) {
+ lastOutActivity = millis();
+ if (_client == nullptr) {
+ return 0;
+ }
+ return _client->write(data);
+}
+
+size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
+ lastOutActivity = millis();
+ if (_client == nullptr) {
+ return 0;
+ }
+ return _client->write(buffer,size);
+}
+
+size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t lenBuf[4];
uint8_t llen = 0;
uint8_t digit;
uint8_t pos = 0;
- uint16_t rc;
uint16_t len = length;
do {
digit = len % 128;
@@ -450,15 +519,22 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
buf[4-llen] = header;
for (int i=0;i 0) && result) {
+ delay(0); // Prevent watchdog crashes
bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
rc = _client->write(writeBuf,bytesToWrite);
result = (rc == bytesToWrite);
@@ -467,9 +543,9 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
}
return result;
#else
- rc = _client->write(buf+(4-llen),length+1+llen);
+ rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
lastOutActivity = millis();
- return (rc == 1+llen+length);
+ return (rc == hlen+length);
#endif
}
@@ -487,7 +563,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
}
if (connected()) {
// Leave room in the buffer for header and variable length field
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
@@ -496,7 +572,7 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
buffer[length++] = (nextMsgId & 0xFF);
length = writeString((char*)topic, buffer,length);
buffer[length++] = qos;
- return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5);
+ return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
@@ -507,7 +583,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
return false;
}
if (connected()) {
- uint16_t length = 5;
+ uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
@@ -515,7 +591,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
- return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5);
+ return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
}
return false;
}
@@ -523,7 +599,7 @@ boolean PubSubClient::unsubscribe(const char* topic) {
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
- if (_client != NULL) {
+ if (_client != nullptr) {
_client->write(buffer,2);
_client->flush();
_client->stop();
@@ -558,6 +634,8 @@ boolean PubSubClient::connected() {
_client->flush();
_client->stop();
}
+ } else {
+ return this->_state == MQTT_CONNECTED;
}
}
return rc;
diff --git a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.h
similarity index 76%
rename from lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h
rename to lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.h
index 003df770ed2d..a519f75d7df8 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/src/PubSubClient.h
+++ b/lib/PubSubClient-EspEasy-2.7.11/src/PubSubClient.h
@@ -75,6 +75,9 @@
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
+// Maximum size of fixed header and variable length size header
+#define MQTT_MAX_HEADER_SIZE 5
+
#if defined(ESP8266) || defined(ESP32)
#include
#define MQTT_CALLBACK_SIGNATURE std::function callback
@@ -82,7 +85,9 @@
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
-class PubSubClient {
+#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
+
+class PubSubClient : public Print {
private:
Client* _client;
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
@@ -96,6 +101,11 @@ class PubSubClient {
boolean readByte(uint8_t * result, uint16_t * index);
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
+ // Build up the header ready to send
+ // Returns the size of the header
+ // Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
+ // (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer
+ size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
IPAddress ip;
String domain;
uint16_t port;
@@ -129,12 +139,31 @@ class PubSubClient {
boolean connect(const char* id, const char* user, const char* pass);
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
+ boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
void disconnect();
boolean publish(const char* topic, const char* payload);
boolean publish(const char* topic, const char* payload, boolean retained);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
+ boolean publish_P(const char* topic, const char* payload, boolean retained);
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
+ // Start to publish a message.
+ // This API:
+ // beginPublish(...)
+ // one or more calls to write(...)
+ // endPublish()
+ // Allows for arbitrarily large payloads to be sent without them having to be copied into
+ // a new buffer and held in memory at one time
+ // Returns 1 if the message was started successfully, 0 if there was an error
+ boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
+ // Finish off this publish message (started with beginPublish)
+ // Returns 1 if the packet was sent successfully, 0 if there was an error
+ int endPublish();
+ // Write a single byte of payload (only to be used with beginPublish/endPublish)
+ virtual size_t write(uint8_t);
+ // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
+ // Returns the number of bytes written
+ virtual size_t write(const uint8_t *buffer, size_t size);
boolean subscribe(const char* topic);
boolean subscribe(const char* topic, uint8_t qos);
boolean unsubscribe(const char* topic);
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/.gitignore b/lib/PubSubClient-EspEasy-2.7.11/tests/.gitignore
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/.gitignore
rename to lib/PubSubClient-EspEasy-2.7.11/tests/.gitignore
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/Makefile b/lib/PubSubClient-EspEasy-2.7.11/tests/Makefile
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/Makefile
rename to lib/PubSubClient-EspEasy-2.7.11/tests/Makefile
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/README.md b/lib/PubSubClient-EspEasy-2.7.11/tests/README.md
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/README.md
rename to lib/PubSubClient-EspEasy-2.7.11/tests/README.md
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/connect_spec.cpp
similarity index 83%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/connect_spec.cpp
index 69f18646fb35..e27a1f59ff4d 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/connect_spec.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/connect_spec.cpp
@@ -98,6 +98,33 @@ int test_connect_fails_on_bad_rc() {
END_IT
}
+int test_connect_non_clean_session() {
+ IT("sends a properly formatted non-clean session connect packet and succeeds");
+ ShimClient shimClient;
+
+ shimClient.setAllowConnect(true);
+ byte expectServer[] = { 172, 16, 0, 2 };
+ shimClient.expectConnect(expectServer,1883);
+ byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x0,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31};
+ byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
+
+ shimClient.expect(connect,26);
+ shimClient.respond(connack,4);
+
+ PubSubClient client(server, 1883, callback, shimClient);
+ int state = client.state();
+ IS_TRUE(state == MQTT_DISCONNECTED);
+
+ int rc = client.connect((char*)"client_test1",0,0,0,0,0,0,0);
+ IS_TRUE(rc);
+ IS_FALSE(shimClient.error());
+
+ state = client.state();
+ IS_TRUE(state == MQTT_CONNECTED);
+
+ END_IT
+}
+
int test_connect_accepts_username_password() {
IT("accepts a username and password");
ShimClient shimClient;
@@ -133,6 +160,23 @@ int test_connect_accepts_username_no_password() {
END_IT
}
+int test_connect_accepts_username_blank_password() {
+ IT("accepts a username and blank password");
+ ShimClient shimClient;
+ shimClient.setAllowConnect(true);
+
+ byte connect[] = { 0x10,0x20,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x0};
+ byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
+ shimClient.expect(connect,0x26);
+ shimClient.respond(connack,4);
+
+ PubSubClient client(server, 1883, callback, shimClient);
+ int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass");
+ IS_TRUE(rc);
+ IS_FALSE(shimClient.error());
+
+ END_IT
+}
int test_connect_ignores_password_no_username() {
IT("ignores a password but no username");
@@ -239,10 +283,12 @@ int test_connect_disconnect_connect() {
int main()
{
SUITE("Connect");
+
test_connect_fails_no_network();
test_connect_fails_on_no_response();
test_connect_properly_formatted();
+ test_connect_non_clean_session();
test_connect_accepts_username_password();
test_connect_fails_on_bad_rc();
test_connect_properly_formatted_hostname();
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/keepalive_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/keepalive_spec.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/keepalive_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/keepalive_spec.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Arduino.h
similarity index 90%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Arduino.h
index c6752801a7be..2a00f24bceba 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Arduino.h
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Arduino.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include "Print.h"
extern "C"{
@@ -20,4 +21,6 @@ extern "C"{
#define PROGMEM
#define pgm_read_byte_near(x) *(x)
+#define yield(x) {}
+
#endif // Arduino_h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/BDDTest.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/BDDTest.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.cpp
similarity index 86%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.cpp
index 59a2fbbbdc53..f07759a3a523 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.cpp
@@ -2,9 +2,13 @@
#include "Arduino.h"
Buffer::Buffer() {
+ this->pos = 0;
+ this->length = 0;
}
Buffer::Buffer(uint8_t* buf, size_t size) {
+ this->pos = 0;
+ this->length = 0;
this->add(buf,size);
}
bool Buffer::available() {
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Buffer.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Buffer.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Client.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Client.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Client.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Client.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/IPAddress.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/IPAddress.h
diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Print.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Print.h
new file mode 100644
index 000000000000..02ef77c2cb76
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Print.h
@@ -0,0 +1,28 @@
+/*
+ Print.h - Base class that provides print() and println()
+ Copyright (c) 2008 David A. Mellis. 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
+ */
+
+#ifndef Print_h
+#define Print_h
+
+class Print {
+ public:
+ virtual size_t write(uint8_t) = 0;
+};
+
+#endif
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/ShimClient.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/ShimClient.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/Stream.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/Stream.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/trace.h b/lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/trace.h
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/lib/trace.h
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/lib/trace.h
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/publish_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/publish_spec.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/publish_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/publish_spec.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/receive_spec.cpp
similarity index 89%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/receive_spec.cpp
index 54a62ee5c9e6..9a18af042d8b 100644
--- a/lib/PubSubClient-EspEasy-2.6.09/tests/src/receive_spec.cpp
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/src/receive_spec.cpp
@@ -160,6 +160,35 @@ int test_receive_oversized_message() {
END_IT
}
+int test_drop_invalid_remaining_length_message() {
+ IT("drops invalid remaining length message");
+ reset_callback();
+
+ ShimClient shimClient;
+ shimClient.setAllowConnect(true);
+
+ byte connack[] = { 0x20, 0x02, 0x00, 0x00 };
+ shimClient.respond(connack,4);
+
+ PubSubClient client(server, 1883, callback, shimClient);
+ int rc = client.connect((char*)"client_test1");
+ IS_TRUE(rc);
+
+ byte publish[] = {0x30,0x92,0x92,0x92,0x92,0x01,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64};
+ shimClient.respond(publish,20);
+
+ rc = client.loop();
+
+ IS_FALSE(rc);
+
+ IS_FALSE(callback_called);
+
+ IS_FALSE(shimClient.error());
+
+ END_IT
+}
+
+
int test_receive_oversized_stream_message() {
IT("drops an oversized message");
reset_callback();
@@ -241,6 +270,7 @@ int main()
test_receive_callback();
test_receive_stream();
test_receive_max_sized_message();
+ test_drop_invalid_remaining_length_message();
test_receive_oversized_message();
test_receive_oversized_stream_message();
test_receive_qos1();
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/src/subscribe_spec.cpp b/lib/PubSubClient-EspEasy-2.7.11/tests/src/subscribe_spec.cpp
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/src/subscribe_spec.cpp
rename to lib/PubSubClient-EspEasy-2.7.11/tests/src/subscribe_spec.cpp
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/__init__.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/__init__.py
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/testcases/__init__.py
rename to lib/PubSubClient-EspEasy-2.7.11/tests/testcases/__init__.py
diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_basic.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_basic.py
new file mode 100644
index 000000000000..f23ef71c13ea
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_basic.py
@@ -0,0 +1,39 @@
+import unittest
+import settings
+import time
+import mosquitto
+
+
+def on_message(mosq, obj, msg):
+ obj.message_queue.append(msg)
+
+
+class mqtt_basic(unittest.TestCase):
+
+ message_queue = []
+
+ @classmethod
+ def setUpClass(self):
+ self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
+ self.client.connect(settings.server_ip)
+ self.client.on_message = on_message
+ self.client.subscribe("outTopic", 0)
+
+ @classmethod
+ def tearDownClass(self):
+ self.client.disconnect()
+
+ def test_one(self):
+ i = 30
+ while len(self.message_queue) == 0 and i > 0:
+ self.client.loop()
+ time.sleep(0.5)
+ i -= 1
+ self.assertTrue(i > 0, "message receive timed-out")
+ self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
+ msg = self.message_queue[0]
+ self.assertEqual(msg.mid, 0, "message id not 0")
+ self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
+ self.assertEqual(msg.payload, "hello world")
+ self.assertEqual(msg.qos, 0, "message qos not 0")
+ self.assertEqual(msg.retain, False, "message retain flag incorrect")
diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_publish_in_callback.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_publish_in_callback.py
new file mode 100644
index 000000000000..45b0a8515520
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/mqtt_publish_in_callback.py
@@ -0,0 +1,59 @@
+import unittest
+import settings
+import time
+import mosquitto
+
+
+def on_message(mosq, obj, msg):
+ obj.message_queue.append(msg)
+
+
+class mqtt_publish_in_callback(unittest.TestCase):
+
+ message_queue = []
+
+ @classmethod
+ def setUpClass(self):
+ self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True, obj=self)
+ self.client.connect(settings.server_ip)
+ self.client.on_message = on_message
+ self.client.subscribe("outTopic", 0)
+
+ @classmethod
+ def tearDownClass(self):
+ self.client.disconnect()
+
+ def test_connect(self):
+ i = 30
+ while len(self.message_queue) == 0 and i > 0:
+ self.client.loop()
+ time.sleep(0.5)
+ i -= 1
+ self.assertTrue(i > 0, "message receive timed-out")
+ self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
+ msg = self.message_queue.pop(0)
+ self.assertEqual(msg.mid, 0, "message id not 0")
+ self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
+ self.assertEqual(msg.payload, "hello world")
+ self.assertEqual(msg.qos, 0, "message qos not 0")
+ self.assertEqual(msg.retain, False, "message retain flag incorrect")
+
+ def test_publish(self):
+ self.assertEqual(len(self.message_queue), 0, "message queue not empty")
+ payload = "abcdefghij"
+ self.client.publish("inTopic", payload)
+
+ i = 30
+ while len(self.message_queue) == 0 and i > 0:
+ self.client.loop()
+ time.sleep(0.5)
+ i -= 1
+
+ self.assertTrue(i > 0, "message receive timed-out")
+ self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received")
+ msg = self.message_queue.pop(0)
+ self.assertEqual(msg.mid, 0, "message id not 0")
+ self.assertEqual(msg.topic, "outTopic", "message topic incorrect")
+ self.assertEqual(msg.payload, payload)
+ self.assertEqual(msg.qos, 0, "message qos not 0")
+ self.assertEqual(msg.retain, False, "message retain flag incorrect")
diff --git a/lib/PubSubClient-EspEasy-2.6.09/tests/testcases/settings.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testcases/settings.py
similarity index 100%
rename from lib/PubSubClient-EspEasy-2.6.09/tests/testcases/settings.py
rename to lib/PubSubClient-EspEasy-2.7.11/tests/testcases/settings.py
diff --git a/lib/PubSubClient-EspEasy-2.7.11/tests/testsuite.py b/lib/PubSubClient-EspEasy-2.7.11/tests/testsuite.py
new file mode 100644
index 000000000000..788fc5d97c7b
--- /dev/null
+++ b/lib/PubSubClient-EspEasy-2.7.11/tests/testsuite.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+import os
+import os.path
+import sys
+import shutil
+from subprocess import call
+import importlib
+import unittest
+import re
+
+from testcases import settings
+
+
+class Workspace(object):
+
+ def __init__(self):
+ self.root_dir = os.getcwd()
+ self.build_dir = os.path.join(self.root_dir, "tmpbin")
+ self.log_dir = os.path.join(self.root_dir, "logs")
+ self.tests_dir = os.path.join(self.root_dir, "testcases")
+ self.examples_dir = os.path.join(self.root_dir, "../PubSubClient/examples")
+ self.examples = []
+ self.tests = []
+ if not os.path.isdir("../PubSubClient"):
+ raise Exception("Cannot find PubSubClient library")
+ try:
+ return __import__('ino')
+ except ImportError:
+ raise Exception("ino tool not installed")
+
+ def init(self):
+ if os.path.isdir(self.build_dir):
+ shutil.rmtree(self.build_dir)
+ os.mkdir(self.build_dir)
+ if os.path.isdir(self.log_dir):
+ shutil.rmtree(self.log_dir)
+ os.mkdir(self.log_dir)
+
+ os.chdir(self.build_dir)
+ call(["ino", "init"])
+
+ shutil.copytree("../../PubSubClient", "lib/PubSubClient")
+
+ filenames = []
+ for root, dirs, files in os.walk(self.examples_dir):
+ filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
+ filenames.sort()
+ for e in filenames:
+ self.examples.append(Sketch(self, e))
+
+ filenames = []
+ for root, dirs, files in os.walk(self.tests_dir):
+ filenames += [os.path.join(root, f) for f in files if f.endswith(".ino")]
+ filenames.sort()
+ for e in filenames:
+ self.tests.append(Sketch(self, e))
+
+ def clean(self):
+ shutil.rmtree(self.build_dir)
+
+
+class Sketch(object):
+ def __init__(self, wksp, fn):
+ self.w = wksp
+ self.filename = fn
+ self.basename = os.path.basename(self.filename)
+ self.build_log = os.path.join(self.w.log_dir, "%s.log" % (os.path.basename(self.filename),))
+ self.build_err_log = os.path.join(self.w.log_dir, "%s.err.log" % (os.path.basename(self.filename),))
+ self.build_upload_log = os.path.join(self.w.log_dir, "%s.upload.log" % (os.path.basename(self.filename),))
+
+ def build(self):
+ sys.stdout.write(" Build: ")
+ sys.stdout.flush()
+
+ # Copy sketch over, replacing IP addresses as necessary
+ fin = open(self.filename, "r")
+ lines = fin.readlines()
+ fin.close()
+ fout = open(os.path.join(self.w.build_dir, "src", "sketch.ino"), "w")
+ for l in lines:
+ if re.match(r"^byte server\[\] = {", l):
+ fout.write("byte server[] = { %s };\n" % (settings.server_ip.replace(".", ", "),))
+ elif re.match(r"^byte ip\[\] = {", l):
+ fout.write("byte ip[] = { %s };\n" % (settings.arduino_ip.replace(".", ", "),))
+ else:
+ fout.write(l)
+ fout.flush()
+ fout.close()
+
+ # Run build
+ fout = open(self.build_log, "w")
+ ferr = open(self.build_err_log, "w")
+ rc = call(["ino", "build"], stdout=fout, stderr=ferr)
+ fout.close()
+ ferr.close()
+ if rc == 0:
+ sys.stdout.write("pass")
+ sys.stdout.write("\n")
+ return True
+ else:
+ sys.stdout.write("fail")
+ sys.stdout.write("\n")
+ with open(self.build_err_log) as f:
+ for line in f:
+ print(" " + line)
+ return False
+
+ def upload(self):
+ sys.stdout.write(" Upload: ")
+ sys.stdout.flush()
+ fout = open(self.build_upload_log, "w")
+ rc = call(["ino", "upload"], stdout=fout, stderr=fout)
+ fout.close()
+ if rc == 0:
+ sys.stdout.write("pass")
+ sys.stdout.write("\n")
+ return True
+ else:
+ sys.stdout.write("fail")
+ sys.stdout.write("\n")
+ with open(self.build_upload_log) as f:
+ for line in f:
+ print(" " + line)
+ return False
+
+ def test(self):
+ # import the matching test case, if it exists
+ try:
+ basename = os.path.basename(self.filename)[:-4]
+ i = importlib.import_module("testcases." + basename)
+ except:
+ sys.stdout.write(" Test: no tests found")
+ sys.stdout.write("\n")
+ return
+ c = getattr(i, basename)
+
+ testmethods = [m for m in dir(c) if m.startswith("test_")]
+ testmethods.sort()
+ tests = []
+ for m in testmethods:
+ tests.append(c(m))
+
+ result = unittest.TestResult()
+ c.setUpClass()
+ if self.upload():
+ sys.stdout.write(" Test: ")
+ sys.stdout.flush()
+ for t in tests:
+ t.run(result)
+ print(str(result.testsRun - len(result.failures) - len(result.errors)) + "/" + str(result.testsRun))
+ if not result.wasSuccessful():
+ if len(result.failures) > 0:
+ for f in result.failures:
+ print("-- " + str(f[0]))
+ print(f[1])
+ if len(result.errors) > 0:
+ print(" Errors:")
+ for f in result.errors:
+ print("-- " + str(f[0]))
+ print(f[1])
+ c.tearDownClass()
+
+
+if __name__ == '__main__':
+ run_tests = True
+
+ w = Workspace()
+ w.init()
+
+ for e in w.examples:
+ print("--------------------------------------")
+ print("[" + e.basename + "]")
+ if e.build() and run_tests:
+ e.test()
+ for e in w.tests:
+ print("--------------------------------------")
+ print("[" + e.basename + "]")
+ if e.build() and run_tests:
+ e.test()
+
+ w.clean()
diff --git a/lib/vl53l0x-arduino-1.02/.travis.yml b/lib/vl53l0x-arduino-1.02/.travis.yml
new file mode 100755
index 000000000000..f3ed70c21819
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/.travis.yml
@@ -0,0 +1,24 @@
+language: python
+
+cache:
+ directories:
+ - "~/.platformio"
+
+install:
+- pip install -U platformio
+
+env:
+- BOARD=uno
+- BOARD=leonardo
+- BOARD=micro
+- BOARD=megaatmega2560
+- BOARD=due
+- BOARD=yun
+- BOARD=genuino101
+- BOARD=zero
+
+script:
+- set -eo pipefail;
+ for e in examples/*; do
+ platformio ci --board=$BOARD --lib=. $e/*;
+ done
diff --git a/lib/vl53l0x-arduino-1.02/LICENSE.txt b/lib/vl53l0x-arduino-1.02/LICENSE.txt
new file mode 100755
index 000000000000..bea985af6629
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/LICENSE.txt
@@ -0,0 +1,71 @@
+Copyright (c) 2017 Pololu Corporation. For more information, see
+
+https://www.pololu.com/
+https://forum.pololu.com/
+
+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.
+
+=================================================================
+
+Most of the functionality of this library is based on the VL53L0X
+API provided by ST (STSW-IMG005), and some of the explanatory
+comments are quoted or paraphrased from the API source code, API
+user manual (UM2039), and the VL53L0X datasheet.
+
+The following applies to source code reproduced or derived from
+the API:
+
+-----------------------------------------------------------------
+
+Copyright © 2016, STMicroelectronics International N.V. All
+rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution.
+* Neither the name of STMicroelectronics nor the
+names of its contributors may be used to endorse or promote
+products derived from this software without specific prior
+written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+-----------------------------------------------------------------
diff --git a/lib/vl53l0x-arduino-1.02/README.md b/lib/vl53l0x-arduino-1.02/README.md
new file mode 100755
index 000000000000..917514d7080a
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/README.md
@@ -0,0 +1,164 @@
+# VL53L0X library for Arduino
+
+Version: 1.0.2
+Release date: 2017 Jun 27
+[![Build Status](https://travis-ci.org/pololu/vl53l0x-arduino.svg?branch=master)](https://travis-ci.org/pololu/vl53l0x-arduino)
+[www.pololu.com](https://www.pololu.com/)
+
+## Summary
+
+This is a library for the Arduino IDE that helps interface with ST's [VL53L0X time-of-flight distance sensor](https://www.pololu.com/product/2490). The library makes it simple to configure the sensor and read range data from it via I²C.
+
+## Supported platforms
+
+This library is designed to work with the Arduino IDE versions 1.6.x or later; we have not tested it with earlier versions. This library should support any Arduino-compatible board, including the [Pololu A-Star 32U4 controllers](https://www.pololu.com/category/149/a-star-programmable-controllers).
+
+## Getting started
+
+### Hardware
+
+A [VL53L0X carrier](https://www.pololu.com/product/2490) can be purchased from Pololu's website. Before continuing, careful reading of the [product page](https://www.pololu.com/product/2490) as well as the VL53L0X datasheet is recommended.
+
+Make the following connections between the Arduino and the VL53L0X board:
+
+#### 5V Arduino boards
+
+(including Arduino Uno, Leonardo, Mega; Pololu A-Star 32U4)
+
+ Arduino VL53L0X board
+ ------- -------------
+ 5V - VIN
+ GND - GND
+ SDA - SDA
+ SCL - SCL
+
+#### 3.3V Arduino boards
+
+(including Arduino Due)
+
+ Arduino VL53L0X board
+ ------- -------------
+ 3V3 - VIN
+ GND - GND
+ SDA - SDA
+ SCL - SCL
+
+### Software
+
+If you are using version 1.6.2 or later of the [Arduino software (IDE)](http://www.arduino.cc/en/Main/Software), you can use the Library Manager to install this library:
+
+1. In the Arduino IDE, open the "Sketch" menu, select "Include Library", then "Manage Libraries...".
+2. Search for "VL53L0X".
+3. Click the VL53L0X entry in the list.
+4. Click "Install".
+
+If this does not work, you can manually install the library:
+
+1. Download the [latest release archive from GitHub](https://github.com/pololu/vl53l0x-arduino/releases) and decompress it.
+2. Rename the folder "vl53l0x-arduino-master" to "VL53L0X".
+3. Move the "VL53L0X" folder into the "libraries" directory inside your Arduino sketchbook directory. You can view your sketchbook location by opening the "File" menu and selecting "Preferences" in the Arduino IDE. If there is not already a "libraries" folder in that location, you should make the folder yourself.
+4. After installing the library, restart the Arduino IDE.
+
+## Examples
+
+Several example sketches are available that show how to use the library. You can access them from the Arduino IDE by opening the "File" menu, selecting "Examples", and then selecting "VL53L0X". If you cannot find these examples, the library was probably installed incorrectly and you should retry the installation instructions above.
+
+## ST's VL53L0X API and this library
+
+Most of the functionality of this library is based on the [VL53L0X API](http://www.st.com/content/st_com/en/products/embedded-software/proximity-sensors-software/stsw-img005.html) provided by ST (STSW-IMG005), and some of the explanatory comments in the code are quoted or paraphrased from the API source code, API user manual (UM2039), and the VL53L0X datasheet. For more explanation about the library code and how it was derived from the API, see the comments in VL53L0X.cpp.
+
+This library is intended to provide a quicker and easier way to get started using the VL53L0X with an Arduino-compatible controller, in contrast to customizing and compiling ST's API for the Arduino. The library has a more streamlined interface, as well as smaller storage and memory footprints. However, it does not implement some of the more advanced functionality available in the API (for example, calibrating the sensor to work well under a cover glass), and it has less robust error checking. For advanced applications, especially when storage and memory are less of an issue, consider using the VL53L0X API directly.
+
+## Library reference
+
+* `uint8_t last_status`
+ The status of the last I²C write transmission. See the [`Wire.endTransmission()` documentation](http://arduino.cc/en/Reference/WireEndTransmission) for return values.
+
+* `VL53L0X(void)`
+ Constructor.
+
+* `void setAddress(uint8_t new_addr)`
+ Changes the I²C slave device address of the VL53L0X to the given value (7-bit).
+
+* `uint8_t getAddress(void)`
+ Returns the current I²C address.
+
+* `bool init(bool io_2v8 = true)`
+ Iniitializes and configures the sensor. If the optional argument `io_2v8` is true (the default if not specified), the sensor is configured for 2V8 mode (2.8 V I/O); if false, the sensor is left in 1V8 mode. The return value is a boolean indicating whether the initialization completed successfully.
+
+* `void writeReg(uint8_t reg, uint8_t value)`
+ Writes an 8-bit sensor register with the given value.
+
+ Register address constants are defined by the regAddr enumeration type in VL53L0X.h.
+ Example use: `sensor.writeReg(VL53L0X::SYSRANGE_START, 0x01);`
+
+* `void writeReg16Bit(uint8_t reg, uint16_t value)`
+ Writes a 16-bit sensor register with the given value.
+
+* `void writeReg32Bit(uint8_t reg, uint32_t value)`
+ Writes a 32-bit sensor register with the given value.
+
+* `uint8_t readReg(uint8_t reg)`
+ Reads an 8-bit sensor register and returns the value read.
+
+* `uint16_t readReg16Bit(uint8_t reg)`
+ Reads a 16-bit sensor register and returns the value read.
+
+* `uint32_t readReg32Bit(uint8_t reg)`
+ Reads a 32-bit sensor register and returns the value read.
+
+* `void writeMulti(uint8_t reg, uint8_t const * src, uint8_t count)`
+ Writes an arbitrary number of bytes from the given array to the sensor, starting at the given register.
+
+* `void readMulti(uint8_t reg, uint8_t * dst, uint8_t count)`
+ Reads an arbitrary number of bytes from the sensor, starting at the given register, into the given array.
+
+* `bool setSignalRateLimit(float limit_Mcps)`
+ Sets the return signal rate limit to the given value in units of MCPS (mega counts per second). This is the minimum amplitude of the signal reflected from the target and received by the sensor necessary for it to report a valid reading. Setting a lower limit increases the potential range of the sensor but also increases the likelihood of getting an inaccurate reading because of reflections from objects other than the intended target. This limit is initialized to 0.25 MCPS by default. The return value is a boolean indicating whether the requested limit was valid.
+
+* `float getSignalRateLimit(void)`
+ Returns the current return signal rate limit in MCPS.
+
+* `bool setMeasurementTimingBudget(uint32_t budget_us)`
+ Sets the measurement timing budget to the given value in microseconds. This is the time allowed for one range measurement; a longer timing budget allows for more accurate measurements. The default budget is about 33000 microseconds, or 33 ms; the minimum is 20 ms. The return value is a boolean indicating whether the requested budget was valid.
+
+* `uint32_t getMeasurementTimingBudget(void)`
+ Returns the current measurement timing budget in microseconds.
+
+* `bool setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks)`
+ Sets the VCSEL (vertical cavity surface emitting laser) pulse period for the given period type (`VL53L0X::VcselPeriodPreRange` or `VL53L0X::VcselPeriodFinalRange`) to the given value (in PCLKs). Longer periods increase the potential range of the sensor. Valid values are (even numbers only):
+
+ Pre: 12 to 18 (initialized to 14 by default)
+ Final: 8 to 14 (initialized to 10 by default)
+
+ The return value is a boolean indicating whether the requested period was valid.
+
+* `uint8_t getVcselPulsePeriod(vcselPeriodType type)`
+ Returns the current VCSEL pulse period for the given period type.
+
+* `void startContinuous(uint32_t period_ms = 0)`
+ Starts continuous ranging measurements. If the optional argument `period_ms` is 0 (the default if not specified), continuous back-to-back mode is used (the sensor takes measurements as often as possible); if it is nonzero, continuous timed mode is used, with the specified inter-measurement period in milliseconds determining how often the sensor takes a measurement.
+
+* `void stopContinuous(void)`
+ Stops continuous mode.
+
+* `uint16_t readRangeContinuousMillimeters(void)`
+ Returns a range reading in millimeters when continuous mode is active.
+
+* `uint16_t readRangeSingleMillimeters(void)`
+ Performs a single-shot ranging measurement and returns the reading in millimeters.
+
+* `void setTimeout(uint16_t timeout)`
+ Sets a timeout period in milliseconds after which read operations will abort if the sensor is not ready. A value of 0 disables the timeout.
+
+* `uint16_t getTimeout(void)`
+ Returns the current timeout period setting.
+
+* `bool timeoutOccurred(void)`
+ Indicates whether a read timeout has occurred since the last call to `timeoutOccurred()`.
+
+## Version history
+
+* 1.0.2 (2017 Jun 27): Fixed a typo in a register modification in `getSpadInfo()` (thanks @tridge).
+* 1.0.1 (2016 Dec 08): Fixed type error in `readReg32Bit()`.
+* 1.0.0 (2016 Aug 12): Original release.
diff --git a/lib/vl53l0x-arduino-1.02/VL53L0X.cpp b/lib/vl53l0x-arduino-1.02/VL53L0X.cpp
new file mode 100755
index 000000000000..fb2ed30286d4
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/VL53L0X.cpp
@@ -0,0 +1,1036 @@
+// Most of the functionality of this library is based on the VL53L0X API
+// provided by ST (STSW-IMG005), and some of the explanatory comments are quoted
+// or paraphrased from the API source code, API user manual (UM2039), and the
+// VL53L0X datasheet.
+
+#include
+#include
+
+// Defines /////////////////////////////////////////////////////////////////////
+
+// The Arduino two-wire interface uses a 7-bit number for the address,
+// and sets the last bit correctly based on reads and writes
+#define ADDRESS_DEFAULT 0b0101001
+
+// Record the current time to check an upcoming timeout against
+#define startTimeout() (timeout_start_ms = millis())
+
+// Check if timeout is enabled (set to nonzero value) and has expired
+#define checkTimeoutExpired() (io_timeout > 0 && ((uint16_t)millis() - timeout_start_ms) > io_timeout)
+
+// Decode VCSEL (vertical cavity surface emitting laser) pulse period in PCLKs
+// from register value
+// based on VL53L0X_decode_vcsel_period()
+#define decodeVcselPeriod(reg_val) (((reg_val) + 1) << 1)
+
+// Encode VCSEL pulse period register value from period in PCLKs
+// based on VL53L0X_encode_vcsel_period()
+#define encodeVcselPeriod(period_pclks) (((period_pclks) >> 1) - 1)
+
+// Calculate macro period in *nanoseconds* from VCSEL period in PCLKs
+// based on VL53L0X_calc_macro_period_ps()
+// PLL_period_ps = 1655; macro_period_vclks = 2304
+#define calcMacroPeriod(vcsel_period_pclks) ((((uint32_t)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000)
+
+// Constructors ////////////////////////////////////////////////////////////////
+
+VL53L0X::VL53L0X(void)
+ : address(ADDRESS_DEFAULT)
+ , io_timeout(0) // no timeout
+ , did_timeout(false)
+{
+}
+
+// Public Methods //////////////////////////////////////////////////////////////
+
+void VL53L0X::setAddress(uint8_t new_addr)
+{
+ writeReg(I2C_SLAVE_DEVICE_ADDRESS, new_addr & 0x7F);
+ address = new_addr;
+}
+
+// Initialize sensor using sequence based on VL53L0X_DataInit(),
+// VL53L0X_StaticInit(), and VL53L0X_PerformRefCalibration().
+// This function does not perform reference SPAD calibration
+// (VL53L0X_PerformRefSpadManagement()), since the API user manual says that it
+// is performed by ST on the bare modules; it seems like that should work well
+// enough unless a cover glass is added.
+// If io_2v8 (optional) is true or not given, the sensor is configured for 2V8
+// mode.
+bool VL53L0X::init(bool io_2v8)
+{
+ // VL53L0X_DataInit() begin
+
+ // sensor uses 1V8 mode for I/O by default; switch to 2V8 mode if necessary
+ if (io_2v8)
+ {
+ writeReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
+ readReg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01); // set bit 0
+ }
+
+ // "Set I2C standard mode"
+ writeReg(0x88, 0x00);
+
+ writeReg(0x80, 0x01);
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x00);
+ stop_variable = readReg(0x91);
+ writeReg(0x00, 0x01);
+ writeReg(0xFF, 0x00);
+ writeReg(0x80, 0x00);
+
+ // disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) limit checks
+ writeReg(MSRC_CONFIG_CONTROL, readReg(MSRC_CONFIG_CONTROL) | 0x12);
+
+ // set final range signal rate limit to 0.25 MCPS (million counts per second)
+ setSignalRateLimit(0.25);
+
+ writeReg(SYSTEM_SEQUENCE_CONFIG, 0xFF);
+
+ // VL53L0X_DataInit() end
+
+ // VL53L0X_StaticInit() begin
+
+ uint8_t spad_count;
+ bool spad_type_is_aperture;
+ if (!getSpadInfo(&spad_count, &spad_type_is_aperture)) { return false; }
+
+ // The SPAD map (RefGoodSpadMap) is read by VL53L0X_get_info_from_device() in
+ // the API, but the same data seems to be more easily readable from
+ // GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through _6, so read it from there
+ uint8_t ref_spad_map[6];
+ readMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);
+
+ // -- VL53L0X_set_reference_spads() begin (assume NVM values are valid)
+
+ writeReg(0xFF, 0x01);
+ writeReg(DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+ writeReg(DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+ writeReg(0xFF, 0x00);
+ writeReg(GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4);
+
+ uint8_t first_spad_to_enable = spad_type_is_aperture ? 12 : 0; // 12 is the first aperture spad
+ uint8_t spads_enabled = 0;
+
+ for (uint8_t i = 0; i < 48; i++)
+ {
+ if (i < first_spad_to_enable || spads_enabled == spad_count)
+ {
+ // This bit is lower than the first one that should be enabled, or
+ // (reference_spad_count) bits have already been enabled, so zero this bit
+ ref_spad_map[i / 8] &= ~(1 << (i % 8));
+ }
+ else if ((ref_spad_map[i / 8] >> (i % 8)) & 0x1)
+ {
+ spads_enabled++;
+ }
+ }
+
+ writeMulti(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);
+
+ // -- VL53L0X_set_reference_spads() end
+
+ // -- VL53L0X_load_tuning_settings() begin
+ // DefaultTuningSettings from vl53l0x_tuning.h
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x00);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x09, 0x00);
+ writeReg(0x10, 0x00);
+ writeReg(0x11, 0x00);
+
+ writeReg(0x24, 0x01);
+ writeReg(0x25, 0xFF);
+ writeReg(0x75, 0x00);
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x4E, 0x2C);
+ writeReg(0x48, 0x00);
+ writeReg(0x30, 0x20);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x30, 0x09);
+ writeReg(0x54, 0x00);
+ writeReg(0x31, 0x04);
+ writeReg(0x32, 0x03);
+ writeReg(0x40, 0x83);
+ writeReg(0x46, 0x25);
+ writeReg(0x60, 0x00);
+ writeReg(0x27, 0x00);
+ writeReg(0x50, 0x06);
+ writeReg(0x51, 0x00);
+ writeReg(0x52, 0x96);
+ writeReg(0x56, 0x08);
+ writeReg(0x57, 0x30);
+ writeReg(0x61, 0x00);
+ writeReg(0x62, 0x00);
+ writeReg(0x64, 0x00);
+ writeReg(0x65, 0x00);
+ writeReg(0x66, 0xA0);
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x22, 0x32);
+ writeReg(0x47, 0x14);
+ writeReg(0x49, 0xFF);
+ writeReg(0x4A, 0x00);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x7A, 0x0A);
+ writeReg(0x7B, 0x00);
+ writeReg(0x78, 0x21);
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x23, 0x34);
+ writeReg(0x42, 0x00);
+ writeReg(0x44, 0xFF);
+ writeReg(0x45, 0x26);
+ writeReg(0x46, 0x05);
+ writeReg(0x40, 0x40);
+ writeReg(0x0E, 0x06);
+ writeReg(0x20, 0x1A);
+ writeReg(0x43, 0x40);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x34, 0x03);
+ writeReg(0x35, 0x44);
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x31, 0x04);
+ writeReg(0x4B, 0x09);
+ writeReg(0x4C, 0x05);
+ writeReg(0x4D, 0x04);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x44, 0x00);
+ writeReg(0x45, 0x20);
+ writeReg(0x47, 0x08);
+ writeReg(0x48, 0x28);
+ writeReg(0x67, 0x00);
+ writeReg(0x70, 0x04);
+ writeReg(0x71, 0x01);
+ writeReg(0x72, 0xFE);
+ writeReg(0x76, 0x00);
+ writeReg(0x77, 0x00);
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x0D, 0x01);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x80, 0x01);
+ writeReg(0x01, 0xF8);
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x8E, 0x01);
+ writeReg(0x00, 0x01);
+ writeReg(0xFF, 0x00);
+ writeReg(0x80, 0x00);
+
+ // -- VL53L0X_load_tuning_settings() end
+
+ // "Set interrupt config to new sample ready"
+ // -- VL53L0X_SetGpioConfig() begin
+
+ writeReg(SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04);
+ writeReg(GPIO_HV_MUX_ACTIVE_HIGH, readReg(GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // active low
+ writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);
+
+ // -- VL53L0X_SetGpioConfig() end
+
+ measurement_timing_budget_us = getMeasurementTimingBudget();
+
+ // "Disable MSRC and TCC by default"
+ // MSRC = Minimum Signal Rate Check
+ // TCC = Target CentreCheck
+ // -- VL53L0X_SetSequenceStepEnable() begin
+
+ writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8);
+
+ // -- VL53L0X_SetSequenceStepEnable() end
+
+ // "Recalculate timing budget"
+ setMeasurementTimingBudget(measurement_timing_budget_us);
+
+ // VL53L0X_StaticInit() end
+
+ // VL53L0X_PerformRefCalibration() begin (VL53L0X_perform_ref_calibration())
+
+ // -- VL53L0X_perform_vhv_calibration() begin
+
+ writeReg(SYSTEM_SEQUENCE_CONFIG, 0x01);
+ if (!performSingleRefCalibration(0x40)) { return false; }
+
+ // -- VL53L0X_perform_vhv_calibration() end
+
+ // -- VL53L0X_perform_phase_calibration() begin
+
+ writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02);
+ if (!performSingleRefCalibration(0x00)) { return false; }
+
+ // -- VL53L0X_perform_phase_calibration() end
+
+ // "restore the previous Sequence Config"
+ writeReg(SYSTEM_SEQUENCE_CONFIG, 0xE8);
+
+ // VL53L0X_PerformRefCalibration() end
+
+ return true;
+}
+
+// Write an 8-bit register
+void VL53L0X::writeReg(uint8_t reg, uint8_t value)
+{
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ Wire.write(value);
+ last_status = Wire.endTransmission();
+}
+
+// Write a 16-bit register
+void VL53L0X::writeReg16Bit(uint8_t reg, uint16_t value)
+{
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ Wire.write((value >> 8) & 0xFF); // value high byte
+ Wire.write( value & 0xFF); // value low byte
+ last_status = Wire.endTransmission();
+}
+
+// Write a 32-bit register
+void VL53L0X::writeReg32Bit(uint8_t reg, uint32_t value)
+{
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ Wire.write((value >> 24) & 0xFF); // value highest byte
+ Wire.write((value >> 16) & 0xFF);
+ Wire.write((value >> 8) & 0xFF);
+ Wire.write( value & 0xFF); // value lowest byte
+ last_status = Wire.endTransmission();
+}
+
+// Read an 8-bit register
+uint8_t VL53L0X::readReg(uint8_t reg)
+{
+ uint8_t value;
+
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ last_status = Wire.endTransmission();
+
+ Wire.requestFrom(address, (uint8_t)1);
+ value = Wire.read();
+
+ return value;
+}
+
+// Read a 16-bit register
+uint16_t VL53L0X::readReg16Bit(uint8_t reg)
+{
+ uint16_t value;
+
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ last_status = Wire.endTransmission();
+
+ Wire.requestFrom(address, (uint8_t)2);
+ value = (uint16_t)Wire.read() << 8; // value high byte
+ value |= Wire.read(); // value low byte
+
+ return value;
+}
+
+// Read a 32-bit register
+uint32_t VL53L0X::readReg32Bit(uint8_t reg)
+{
+ uint32_t value;
+
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ last_status = Wire.endTransmission();
+
+ Wire.requestFrom(address, (uint8_t)4);
+ value = (uint32_t)Wire.read() << 24; // value highest byte
+ value |= (uint32_t)Wire.read() << 16;
+ value |= (uint16_t)Wire.read() << 8;
+ value |= Wire.read(); // value lowest byte
+
+ return value;
+}
+
+// Write an arbitrary number of bytes from the given array to the sensor,
+// starting at the given register
+void VL53L0X::writeMulti(uint8_t reg, uint8_t const * src, uint8_t count)
+{
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+
+ while (count-- > 0)
+ {
+ Wire.write(*(src++));
+ }
+
+ last_status = Wire.endTransmission();
+}
+
+// Read an arbitrary number of bytes from the sensor, starting at the given
+// register, into the given array
+void VL53L0X::readMulti(uint8_t reg, uint8_t * dst, uint8_t count)
+{
+ Wire.beginTransmission(address);
+ Wire.write(reg);
+ last_status = Wire.endTransmission();
+
+ Wire.requestFrom(address, count);
+
+ while (count-- > 0)
+ {
+ *(dst++) = Wire.read();
+ }
+}
+
+// Set the return signal rate limit check value in units of MCPS (mega counts
+// per second). "This represents the amplitude of the signal reflected from the
+// target and detected by the device"; setting this limit presumably determines
+// the minimum measurement necessary for the sensor to report a valid reading.
+// Setting a lower limit increases the potential range of the sensor but also
+// seems to increase the likelihood of getting an inaccurate reading because of
+// unwanted reflections from objects other than the intended target.
+// Defaults to 0.25 MCPS as initialized by the ST API and this library.
+bool VL53L0X::setSignalRateLimit(float limit_Mcps)
+{
+ if (limit_Mcps < 0 || limit_Mcps > 511.99) { return false; }
+
+ // Q9.7 fixed point format (9 integer bits, 7 fractional bits)
+ writeReg16Bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, limit_Mcps * (1 << 7));
+ return true;
+}
+
+// Get the return signal rate limit check value in MCPS
+float VL53L0X::getSignalRateLimit(void)
+{
+ return (float)readReg16Bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT) / (1 << 7);
+}
+
+// Set the measurement timing budget in microseconds, which is the time allowed
+// for one measurement; the ST API and this library take care of splitting the
+// timing budget among the sub-steps in the ranging sequence. A longer timing
+// budget allows for more accurate measurements. Increasing the budget by a
+// factor of N decreases the range measurement standard deviation by a factor of
+// sqrt(N). Defaults to about 33 milliseconds; the minimum is 20 ms.
+// based on VL53L0X_set_measurement_timing_budget_micro_seconds()
+bool VL53L0X::setMeasurementTimingBudget(uint32_t budget_us)
+{
+ SequenceStepEnables enables;
+ SequenceStepTimeouts timeouts;
+
+ uint16_t const StartOverhead = 1320; // note that this is different than the value in get_
+ uint16_t const EndOverhead = 960;
+ uint16_t const MsrcOverhead = 660;
+ uint16_t const TccOverhead = 590;
+ uint16_t const DssOverhead = 690;
+ uint16_t const PreRangeOverhead = 660;
+ uint16_t const FinalRangeOverhead = 550;
+
+ uint32_t const MinTimingBudget = 20000;
+
+ if (budget_us < MinTimingBudget) { return false; }
+
+ uint32_t used_budget_us = StartOverhead + EndOverhead;
+
+ getSequenceStepEnables(&enables);
+ getSequenceStepTimeouts(&enables, &timeouts);
+
+ if (enables.tcc)
+ {
+ used_budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead);
+ }
+
+ if (enables.dss)
+ {
+ used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
+ }
+ else if (enables.msrc)
+ {
+ used_budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
+ }
+
+ if (enables.pre_range)
+ {
+ used_budget_us += (timeouts.pre_range_us + PreRangeOverhead);
+ }
+
+ if (enables.final_range)
+ {
+ used_budget_us += FinalRangeOverhead;
+
+ // "Note that the final range timeout is determined by the timing
+ // budget and the sum of all other timeouts within the sequence.
+ // If there is no room for the final range timeout, then an error
+ // will be set. Otherwise the remaining time will be applied to
+ // the final range."
+
+ if (used_budget_us > budget_us)
+ {
+ // "Requested timeout too big."
+ return false;
+ }
+
+ uint32_t final_range_timeout_us = budget_us - used_budget_us;
+
+ // set_sequence_step_timeout() begin
+ // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
+
+ // "For the final range timeout, the pre-range timeout
+ // must be added. To do this both final and pre-range
+ // timeouts must be expressed in macro periods MClks
+ // because they have different vcsel periods."
+
+ uint16_t final_range_timeout_mclks =
+ timeoutMicrosecondsToMclks(final_range_timeout_us,
+ timeouts.final_range_vcsel_period_pclks);
+
+ if (enables.pre_range)
+ {
+ final_range_timeout_mclks += timeouts.pre_range_mclks;
+ }
+
+ writeReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ encodeTimeout(final_range_timeout_mclks));
+
+ // set_sequence_step_timeout() end
+
+ measurement_timing_budget_us = budget_us; // store for internal reuse
+ }
+ return true;
+}
+
+// Get the measurement timing budget in microseconds
+// based on VL53L0X_get_measurement_timing_budget_micro_seconds()
+// in us
+uint32_t VL53L0X::getMeasurementTimingBudget(void)
+{
+ SequenceStepEnables enables;
+ SequenceStepTimeouts timeouts;
+
+ uint16_t const StartOverhead = 1910; // note that this is different than the value in set_
+ uint16_t const EndOverhead = 960;
+ uint16_t const MsrcOverhead = 660;
+ uint16_t const TccOverhead = 590;
+ uint16_t const DssOverhead = 690;
+ uint16_t const PreRangeOverhead = 660;
+ uint16_t const FinalRangeOverhead = 550;
+
+ // "Start and end overhead times always present"
+ uint32_t budget_us = StartOverhead + EndOverhead;
+
+ getSequenceStepEnables(&enables);
+ getSequenceStepTimeouts(&enables, &timeouts);
+
+ if (enables.tcc)
+ {
+ budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead);
+ }
+
+ if (enables.dss)
+ {
+ budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
+ }
+ else if (enables.msrc)
+ {
+ budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
+ }
+
+ if (enables.pre_range)
+ {
+ budget_us += (timeouts.pre_range_us + PreRangeOverhead);
+ }
+
+ if (enables.final_range)
+ {
+ budget_us += (timeouts.final_range_us + FinalRangeOverhead);
+ }
+
+ measurement_timing_budget_us = budget_us; // store for internal reuse
+ return budget_us;
+}
+
+// Set the VCSEL (vertical cavity surface emitting laser) pulse period for the
+// given period type (pre-range or final range) to the given value in PCLKs.
+// Longer periods seem to increase the potential range of the sensor.
+// Valid values are (even numbers only):
+// pre: 12 to 18 (initialized default: 14)
+// final: 8 to 14 (initialized default: 10)
+// based on VL53L0X_set_vcsel_pulse_period()
+bool VL53L0X::setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks)
+{
+ uint8_t vcsel_period_reg = encodeVcselPeriod(period_pclks);
+
+ SequenceStepEnables enables;
+ SequenceStepTimeouts timeouts;
+
+ getSequenceStepEnables(&enables);
+ getSequenceStepTimeouts(&enables, &timeouts);
+
+ // "Apply specific settings for the requested clock period"
+ // "Re-calculate and apply timeouts, in macro periods"
+
+ // "When the VCSEL period for the pre or final range is changed,
+ // the corresponding timeout must be read from the device using
+ // the current VCSEL period, then the new VCSEL period can be
+ // applied. The timeout then must be written back to the device
+ // using the new VCSEL period.
+ //
+ // For the MSRC timeout, the same applies - this timeout being
+ // dependant on the pre-range vcsel period."
+
+
+ if (type == VcselPeriodPreRange)
+ {
+ // "Set phase check limits"
+ switch (period_pclks)
+ {
+ case 12:
+ writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18);
+ break;
+
+ case 14:
+ writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30);
+ break;
+
+ case 16:
+ writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40);
+ break;
+
+ case 18:
+ writeReg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50);
+ break;
+
+ default:
+ // invalid period
+ return false;
+ }
+ writeReg(PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
+
+ // apply new VCSEL period
+ writeReg(PRE_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg);
+
+ // update timeouts
+
+ // set_sequence_step_timeout() begin
+ // (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE)
+
+ uint16_t new_pre_range_timeout_mclks =
+ timeoutMicrosecondsToMclks(timeouts.pre_range_us, period_pclks);
+
+ writeReg16Bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ encodeTimeout(new_pre_range_timeout_mclks));
+
+ // set_sequence_step_timeout() end
+
+ // set_sequence_step_timeout() begin
+ // (SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC)
+
+ uint16_t new_msrc_timeout_mclks =
+ timeoutMicrosecondsToMclks(timeouts.msrc_dss_tcc_us, period_pclks);
+
+ writeReg(MSRC_CONFIG_TIMEOUT_MACROP,
+ (new_msrc_timeout_mclks > 256) ? 255 : (new_msrc_timeout_mclks - 1));
+
+ // set_sequence_step_timeout() end
+ }
+ else if (type == VcselPeriodFinalRange)
+ {
+ switch (period_pclks)
+ {
+ case 8:
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10);
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
+ writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
+ writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
+ writeReg(0xFF, 0x01);
+ writeReg(ALGO_PHASECAL_LIM, 0x30);
+ writeReg(0xFF, 0x00);
+ break;
+
+ case 10:
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28);
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
+ writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
+ writeReg(0xFF, 0x01);
+ writeReg(ALGO_PHASECAL_LIM, 0x20);
+ writeReg(0xFF, 0x00);
+ break;
+
+ case 12:
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38);
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
+ writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
+ writeReg(0xFF, 0x01);
+ writeReg(ALGO_PHASECAL_LIM, 0x20);
+ writeReg(0xFF, 0x00);
+ break;
+
+ case 14:
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48);
+ writeReg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
+ writeReg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ writeReg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
+ writeReg(0xFF, 0x01);
+ writeReg(ALGO_PHASECAL_LIM, 0x20);
+ writeReg(0xFF, 0x00);
+ break;
+
+ default:
+ // invalid period
+ return false;
+ }
+
+ // apply new VCSEL period
+ writeReg(FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg);
+
+ // update timeouts
+
+ // set_sequence_step_timeout() begin
+ // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
+
+ // "For the final range timeout, the pre-range timeout
+ // must be added. To do this both final and pre-range
+ // timeouts must be expressed in macro periods MClks
+ // because they have different vcsel periods."
+
+ uint16_t new_final_range_timeout_mclks =
+ timeoutMicrosecondsToMclks(timeouts.final_range_us, period_pclks);
+
+ if (enables.pre_range)
+ {
+ new_final_range_timeout_mclks += timeouts.pre_range_mclks;
+ }
+
+ writeReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ encodeTimeout(new_final_range_timeout_mclks));
+
+ // set_sequence_step_timeout end
+ }
+ else
+ {
+ // invalid type
+ return false;
+ }
+
+ // "Finally, the timing budget must be re-applied"
+
+ setMeasurementTimingBudget(measurement_timing_budget_us);
+
+ // "Perform the phase calibration. This is needed after changing on vcsel period."
+ // VL53L0X_perform_phase_calibration() begin
+
+ uint8_t sequence_config = readReg(SYSTEM_SEQUENCE_CONFIG);
+ writeReg(SYSTEM_SEQUENCE_CONFIG, 0x02);
+ performSingleRefCalibration(0x0);
+ writeReg(SYSTEM_SEQUENCE_CONFIG, sequence_config);
+
+ // VL53L0X_perform_phase_calibration() end
+
+ return true;
+}
+
+// Get the VCSEL pulse period in PCLKs for the given period type.
+// based on VL53L0X_get_vcsel_pulse_period()
+uint8_t VL53L0X::getVcselPulsePeriod(vcselPeriodType type)
+{
+ if (type == VcselPeriodPreRange)
+ {
+ return decodeVcselPeriod(readReg(PRE_RANGE_CONFIG_VCSEL_PERIOD));
+ }
+ else if (type == VcselPeriodFinalRange)
+ {
+ return decodeVcselPeriod(readReg(FINAL_RANGE_CONFIG_VCSEL_PERIOD));
+ }
+ else { return 255; }
+}
+
+// Start continuous ranging measurements. If period_ms (optional) is 0 or not
+// given, continuous back-to-back mode is used (the sensor takes measurements as
+// often as possible); otherwise, continuous timed mode is used, with the given
+// inter-measurement period in milliseconds determining how often the sensor
+// takes a measurement.
+// based on VL53L0X_StartMeasurement()
+void VL53L0X::startContinuous(uint32_t period_ms)
+{
+ writeReg(0x80, 0x01);
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x00);
+ writeReg(0x91, stop_variable);
+ writeReg(0x00, 0x01);
+ writeReg(0xFF, 0x00);
+ writeReg(0x80, 0x00);
+
+ if (period_ms != 0)
+ {
+ // continuous timed mode
+
+ // VL53L0X_SetInterMeasurementPeriodMilliSeconds() begin
+
+ uint16_t osc_calibrate_val = readReg16Bit(OSC_CALIBRATE_VAL);
+
+ if (osc_calibrate_val != 0)
+ {
+ period_ms *= osc_calibrate_val;
+ }
+
+ writeReg32Bit(SYSTEM_INTERMEASUREMENT_PERIOD, period_ms);
+
+ // VL53L0X_SetInterMeasurementPeriodMilliSeconds() end
+
+ writeReg(SYSRANGE_START, 0x04); // VL53L0X_REG_SYSRANGE_MODE_TIMED
+ }
+ else
+ {
+ // continuous back-to-back mode
+ writeReg(SYSRANGE_START, 0x02); // VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK
+ }
+}
+
+// Stop continuous measurements
+// based on VL53L0X_StopMeasurement()
+void VL53L0X::stopContinuous(void)
+{
+ writeReg(SYSRANGE_START, 0x01); // VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT
+
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x00);
+ writeReg(0x91, 0x00);
+ writeReg(0x00, 0x01);
+ writeReg(0xFF, 0x00);
+}
+
+// Returns a range reading in millimeters when continuous mode is active
+// (readRangeSingleMillimeters() also calls this function after starting a
+// single-shot range measurement)
+uint16_t VL53L0X::readRangeContinuousMillimeters(void)
+{
+ startTimeout();
+ while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
+ {
+ if (checkTimeoutExpired())
+ {
+ did_timeout = true;
+ return 65535;
+ }
+ }
+
+ // assumptions: Linearity Corrective Gain is 1000 (default);
+ // fractional ranging is not enabled
+ uint16_t range = readReg16Bit(RESULT_RANGE_STATUS + 10);
+
+ writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);
+
+ return range;
+}
+
+// Performs a single-shot range measurement and returns the reading in
+// millimeters
+// based on VL53L0X_PerformSingleRangingMeasurement()
+uint16_t VL53L0X::readRangeSingleMillimeters(void)
+{
+ writeReg(0x80, 0x01);
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x00);
+ writeReg(0x91, stop_variable);
+ writeReg(0x00, 0x01);
+ writeReg(0xFF, 0x00);
+ writeReg(0x80, 0x00);
+
+ writeReg(SYSRANGE_START, 0x01);
+
+ // "Wait until start bit has been cleared"
+ startTimeout();
+ while (readReg(SYSRANGE_START) & 0x01)
+ {
+ if (checkTimeoutExpired())
+ {
+ did_timeout = true;
+ return 65535;
+ }
+ }
+
+ return readRangeContinuousMillimeters();
+}
+
+// Did a timeout occur in one of the read functions since the last call to
+// timeoutOccurred()?
+bool VL53L0X::timeoutOccurred()
+{
+ bool tmp = did_timeout;
+ did_timeout = false;
+ return tmp;
+}
+
+// Private Methods /////////////////////////////////////////////////////////////
+
+// Get reference SPAD (single photon avalanche diode) count and type
+// based on VL53L0X_get_info_from_device(),
+// but only gets reference SPAD count and type
+bool VL53L0X::getSpadInfo(uint8_t * count, bool * type_is_aperture)
+{
+ uint8_t tmp;
+
+ writeReg(0x80, 0x01);
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x00);
+
+ writeReg(0xFF, 0x06);
+ writeReg(0x83, readReg(0x83) | 0x04);
+ writeReg(0xFF, 0x07);
+ writeReg(0x81, 0x01);
+
+ writeReg(0x80, 0x01);
+
+ writeReg(0x94, 0x6b);
+ writeReg(0x83, 0x00);
+ startTimeout();
+ while (readReg(0x83) == 0x00)
+ {
+ if (checkTimeoutExpired()) { return false; }
+ }
+ writeReg(0x83, 0x01);
+ tmp = readReg(0x92);
+
+ *count = tmp & 0x7f;
+ *type_is_aperture = (tmp >> 7) & 0x01;
+
+ writeReg(0x81, 0x00);
+ writeReg(0xFF, 0x06);
+ writeReg(0x83, readReg(0x83) & ~0x04);
+ writeReg(0xFF, 0x01);
+ writeReg(0x00, 0x01);
+
+ writeReg(0xFF, 0x00);
+ writeReg(0x80, 0x00);
+
+ return true;
+}
+
+// Get sequence step enables
+// based on VL53L0X_GetSequenceStepEnables()
+void VL53L0X::getSequenceStepEnables(SequenceStepEnables * enables)
+{
+ uint8_t sequence_config = readReg(SYSTEM_SEQUENCE_CONFIG);
+
+ enables->tcc = (sequence_config >> 4) & 0x1;
+ enables->dss = (sequence_config >> 3) & 0x1;
+ enables->msrc = (sequence_config >> 2) & 0x1;
+ enables->pre_range = (sequence_config >> 6) & 0x1;
+ enables->final_range = (sequence_config >> 7) & 0x1;
+}
+
+// Get sequence step timeouts
+// based on get_sequence_step_timeout(),
+// but gets all timeouts instead of just the requested one, and also stores
+// intermediate values
+void VL53L0X::getSequenceStepTimeouts(SequenceStepEnables const * enables, SequenceStepTimeouts * timeouts)
+{
+ timeouts->pre_range_vcsel_period_pclks = getVcselPulsePeriod(VcselPeriodPreRange);
+
+ timeouts->msrc_dss_tcc_mclks = readReg(MSRC_CONFIG_TIMEOUT_MACROP) + 1;
+ timeouts->msrc_dss_tcc_us =
+ timeoutMclksToMicroseconds(timeouts->msrc_dss_tcc_mclks,
+ timeouts->pre_range_vcsel_period_pclks);
+
+ timeouts->pre_range_mclks =
+ decodeTimeout(readReg16Bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI));
+ timeouts->pre_range_us =
+ timeoutMclksToMicroseconds(timeouts->pre_range_mclks,
+ timeouts->pre_range_vcsel_period_pclks);
+
+ timeouts->final_range_vcsel_period_pclks = getVcselPulsePeriod(VcselPeriodFinalRange);
+
+ timeouts->final_range_mclks =
+ decodeTimeout(readReg16Bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI));
+
+ if (enables->pre_range)
+ {
+ timeouts->final_range_mclks -= timeouts->pre_range_mclks;
+ }
+
+ timeouts->final_range_us =
+ timeoutMclksToMicroseconds(timeouts->final_range_mclks,
+ timeouts->final_range_vcsel_period_pclks);
+}
+
+// Decode sequence step timeout in MCLKs from register value
+// based on VL53L0X_decode_timeout()
+// Note: the original function returned a uint32_t, but the return value is
+// always stored in a uint16_t.
+uint16_t VL53L0X::decodeTimeout(uint16_t reg_val)
+{
+ // format: "(LSByte * 2^MSByte) + 1"
+ return (uint16_t)((reg_val & 0x00FF) <<
+ (uint16_t)((reg_val & 0xFF00) >> 8)) + 1;
+}
+
+// Encode sequence step timeout register value from timeout in MCLKs
+// based on VL53L0X_encode_timeout()
+// Note: the original function took a uint16_t, but the argument passed to it
+// is always a uint16_t.
+uint16_t VL53L0X::encodeTimeout(uint16_t timeout_mclks)
+{
+ // format: "(LSByte * 2^MSByte) + 1"
+
+ uint32_t ls_byte = 0;
+ uint16_t ms_byte = 0;
+
+ if (timeout_mclks > 0)
+ {
+ ls_byte = timeout_mclks - 1;
+
+ while ((ls_byte & 0xFFFFFF00) > 0)
+ {
+ ls_byte >>= 1;
+ ms_byte++;
+ }
+
+ return (ms_byte << 8) | (ls_byte & 0xFF);
+ }
+ else { return 0; }
+}
+
+// Convert sequence step timeout from MCLKs to microseconds with given VCSEL period in PCLKs
+// based on VL53L0X_calc_timeout_us()
+uint32_t VL53L0X::timeoutMclksToMicroseconds(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks)
+{
+ uint32_t macro_period_ns = calcMacroPeriod(vcsel_period_pclks);
+
+ return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000;
+}
+
+// Convert sequence step timeout from microseconds to MCLKs with given VCSEL period in PCLKs
+// based on VL53L0X_calc_timeout_mclks()
+uint32_t VL53L0X::timeoutMicrosecondsToMclks(uint32_t timeout_period_us, uint8_t vcsel_period_pclks)
+{
+ uint32_t macro_period_ns = calcMacroPeriod(vcsel_period_pclks);
+
+ return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns);
+}
+
+
+// based on VL53L0X_perform_single_ref_calibration()
+bool VL53L0X::performSingleRefCalibration(uint8_t vhv_init_byte)
+{
+ writeReg(SYSRANGE_START, 0x01 | vhv_init_byte); // VL53L0X_REG_SYSRANGE_MODE_START_STOP
+
+ startTimeout();
+ while ((readReg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
+ {
+ if (checkTimeoutExpired()) { return false; }
+ }
+
+ writeReg(SYSTEM_INTERRUPT_CLEAR, 0x01);
+
+ writeReg(SYSRANGE_START, 0x00);
+
+ return true;
+}
diff --git a/lib/vl53l0x-arduino-1.02/VL53L0X.h b/lib/vl53l0x-arduino-1.02/VL53L0X.h
new file mode 100755
index 000000000000..b531ff96a224
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/VL53L0X.h
@@ -0,0 +1,176 @@
+#ifndef VL53L0X_h
+#define VL53L0X_h
+
+#include
+
+class VL53L0X
+{
+ public:
+ // register addresses from API vl53l0x_device.h (ordered as listed there)
+ enum regAddr
+ {
+ SYSRANGE_START = 0x00,
+
+ SYSTEM_THRESH_HIGH = 0x0C,
+ SYSTEM_THRESH_LOW = 0x0E,
+
+ SYSTEM_SEQUENCE_CONFIG = 0x01,
+ SYSTEM_RANGE_CONFIG = 0x09,
+ SYSTEM_INTERMEASUREMENT_PERIOD = 0x04,
+
+ SYSTEM_INTERRUPT_CONFIG_GPIO = 0x0A,
+
+ GPIO_HV_MUX_ACTIVE_HIGH = 0x84,
+
+ SYSTEM_INTERRUPT_CLEAR = 0x0B,
+
+ RESULT_INTERRUPT_STATUS = 0x13,
+ RESULT_RANGE_STATUS = 0x14,
+
+ RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN = 0xBC,
+ RESULT_CORE_RANGING_TOTAL_EVENTS_RTN = 0xC0,
+ RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF = 0xD0,
+ RESULT_CORE_RANGING_TOTAL_EVENTS_REF = 0xD4,
+ RESULT_PEAK_SIGNAL_RATE_REF = 0xB6,
+
+ ALGO_PART_TO_PART_RANGE_OFFSET_MM = 0x28,
+
+ I2C_SLAVE_DEVICE_ADDRESS = 0x8A,
+
+ MSRC_CONFIG_CONTROL = 0x60,
+
+ PRE_RANGE_CONFIG_MIN_SNR = 0x27,
+ PRE_RANGE_CONFIG_VALID_PHASE_LOW = 0x56,
+ PRE_RANGE_CONFIG_VALID_PHASE_HIGH = 0x57,
+ PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT = 0x64,
+
+ FINAL_RANGE_CONFIG_MIN_SNR = 0x67,
+ FINAL_RANGE_CONFIG_VALID_PHASE_LOW = 0x47,
+ FINAL_RANGE_CONFIG_VALID_PHASE_HIGH = 0x48,
+ FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT = 0x44,
+
+ PRE_RANGE_CONFIG_SIGMA_THRESH_HI = 0x61,
+ PRE_RANGE_CONFIG_SIGMA_THRESH_LO = 0x62,
+
+ PRE_RANGE_CONFIG_VCSEL_PERIOD = 0x50,
+ PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x51,
+ PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO = 0x52,
+
+ SYSTEM_HISTOGRAM_BIN = 0x81,
+ HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT = 0x33,
+ HISTOGRAM_CONFIG_READOUT_CTRL = 0x55,
+
+ FINAL_RANGE_CONFIG_VCSEL_PERIOD = 0x70,
+ FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x71,
+ FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO = 0x72,
+ CROSSTALK_COMPENSATION_PEAK_RATE_MCPS = 0x20,
+
+ MSRC_CONFIG_TIMEOUT_MACROP = 0x46,
+
+ SOFT_RESET_GO2_SOFT_RESET_N = 0xBF,
+ IDENTIFICATION_MODEL_ID = 0xC0,
+ IDENTIFICATION_REVISION_ID = 0xC2,
+
+ OSC_CALIBRATE_VAL = 0xF8,
+
+ GLOBAL_CONFIG_VCSEL_WIDTH = 0x32,
+ GLOBAL_CONFIG_SPAD_ENABLES_REF_0 = 0xB0,
+ GLOBAL_CONFIG_SPAD_ENABLES_REF_1 = 0xB1,
+ GLOBAL_CONFIG_SPAD_ENABLES_REF_2 = 0xB2,
+ GLOBAL_CONFIG_SPAD_ENABLES_REF_3 = 0xB3,
+ GLOBAL_CONFIG_SPAD_ENABLES_REF_4 = 0xB4,
+ GLOBAL_CONFIG_SPAD_ENABLES_REF_5 = 0xB5,
+
+ GLOBAL_CONFIG_REF_EN_START_SELECT = 0xB6,
+ DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD = 0x4E,
+ DYNAMIC_SPAD_REF_EN_START_OFFSET = 0x4F,
+ POWER_MANAGEMENT_GO1_POWER_FORCE = 0x80,
+
+ VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV = 0x89,
+
+ ALGO_PHASECAL_LIM = 0x30,
+ ALGO_PHASECAL_CONFIG_TIMEOUT = 0x30,
+ };
+
+ enum vcselPeriodType { VcselPeriodPreRange, VcselPeriodFinalRange };
+
+ uint8_t last_status; // status of last I2C transmission
+
+ VL53L0X(void);
+
+ void setAddress(uint8_t new_addr);
+ inline uint8_t getAddress(void) { return address; }
+
+ bool init(bool io_2v8 = true);
+
+ void writeReg(uint8_t reg, uint8_t value);
+ void writeReg16Bit(uint8_t reg, uint16_t value);
+ void writeReg32Bit(uint8_t reg, uint32_t value);
+ uint8_t readReg(uint8_t reg);
+ uint16_t readReg16Bit(uint8_t reg);
+ uint32_t readReg32Bit(uint8_t reg);
+
+ void writeMulti(uint8_t reg, uint8_t const * src, uint8_t count);
+ void readMulti(uint8_t reg, uint8_t * dst, uint8_t count);
+
+ bool setSignalRateLimit(float limit_Mcps);
+ float getSignalRateLimit(void);
+
+ bool setMeasurementTimingBudget(uint32_t budget_us);
+ uint32_t getMeasurementTimingBudget(void);
+
+ bool setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks);
+ uint8_t getVcselPulsePeriod(vcselPeriodType type);
+
+ void startContinuous(uint32_t period_ms = 0);
+ void stopContinuous(void);
+ uint16_t readRangeContinuousMillimeters(void);
+ uint16_t readRangeSingleMillimeters(void);
+
+ inline void setTimeout(uint16_t timeout) { io_timeout = timeout; }
+ inline uint16_t getTimeout(void) { return io_timeout; }
+ bool timeoutOccurred(void);
+
+ private:
+ // TCC: Target CentreCheck
+ // MSRC: Minimum Signal Rate Check
+ // DSS: Dynamic Spad Selection
+
+ struct SequenceStepEnables
+ {
+ boolean tcc, msrc, dss, pre_range, final_range;
+ };
+
+ struct SequenceStepTimeouts
+ {
+ uint16_t pre_range_vcsel_period_pclks, final_range_vcsel_period_pclks;
+
+ uint16_t msrc_dss_tcc_mclks, pre_range_mclks, final_range_mclks;
+ uint32_t msrc_dss_tcc_us, pre_range_us, final_range_us;
+ };
+
+ uint8_t address;
+ uint16_t io_timeout;
+ bool did_timeout;
+ uint16_t timeout_start_ms;
+
+ uint8_t stop_variable; // read by init and used when starting measurement; is StopVariable field of VL53L0X_DevData_t structure in API
+ uint32_t measurement_timing_budget_us;
+
+ bool getSpadInfo(uint8_t * count, bool * type_is_aperture);
+
+ void getSequenceStepEnables(SequenceStepEnables * enables);
+ void getSequenceStepTimeouts(SequenceStepEnables const * enables, SequenceStepTimeouts * timeouts);
+
+ bool performSingleRefCalibration(uint8_t vhv_init_byte);
+
+ static uint16_t decodeTimeout(uint16_t value);
+ static uint16_t encodeTimeout(uint16_t timeout_mclks);
+ static uint32_t timeoutMclksToMicroseconds(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks);
+ static uint32_t timeoutMicrosecondsToMclks(uint32_t timeout_period_us, uint8_t vcsel_period_pclks);
+};
+
+#endif
+
+
+
diff --git a/lib/vl53l0x-arduino-1.02/examples/Continuous/Continuous.ino b/lib/vl53l0x-arduino-1.02/examples/Continuous/Continuous.ino
new file mode 100755
index 000000000000..33fcd05c48c7
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/examples/Continuous/Continuous.ino
@@ -0,0 +1,33 @@
+/* This example shows how to use continuous mode to take
+range measurements with the VL53L0X. It is based on
+vl53l0x_ContinuousRanging_Example.c from the VL53L0X API.
+
+The range readings are in units of mm. */
+
+#include
+#include
+
+VL53L0X sensor;
+
+void setup()
+{
+ Serial.begin(9600);
+ Wire.begin();
+
+ sensor.init();
+ sensor.setTimeout(500);
+
+ // Start continuous back-to-back mode (take readings as
+ // fast as possible). To use continuous timed mode
+ // instead, provide a desired inter-measurement period in
+ // ms (e.g. sensor.startContinuous(100)).
+ sensor.startContinuous();
+}
+
+void loop()
+{
+ Serial.print(sensor.readRangeContinuousMillimeters());
+ if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
+
+ Serial.println();
+}
diff --git a/lib/vl53l0x-arduino-1.02/examples/Single/Single.ino b/lib/vl53l0x-arduino-1.02/examples/Single/Single.ino
new file mode 100755
index 000000000000..9f24463fc620
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/examples/Single/Single.ino
@@ -0,0 +1,65 @@
+/* This example shows how to get single-shot range
+ measurements from the VL53L0X. The sensor can optionally be
+ configured with different ranging profiles, as described in
+ the VL53L0X API user manual, to get better performance for
+ a certain application. This code is based on the four
+ "SingleRanging" examples in the VL53L0X API.
+
+ The range readings are in units of mm. */
+
+#include
+#include
+
+VL53L0X sensor;
+
+
+// Uncomment this line to use long range mode. This
+// increases the sensitivity of the sensor and extends its
+// potential range, but increases the likelihood of getting
+// an inaccurate reading because of reflections from objects
+// other than the intended target. It works best in dark
+// conditions.
+
+//#define LONG_RANGE
+
+
+// Uncomment ONE of these two lines to get
+// - higher speed at the cost of lower accuracy OR
+// - higher accuracy at the cost of lower speed
+
+//#define HIGH_SPEED
+//#define HIGH_ACCURACY
+
+
+void setup()
+{
+ Serial.begin(9600);
+ Wire.begin();
+
+ sensor.init();
+ sensor.setTimeout(500);
+
+#if defined LONG_RANGE
+ // lower the return signal rate limit (default is 0.25 MCPS)
+ sensor.setSignalRateLimit(0.1);
+ // increase laser pulse periods (defaults are 14 and 10 PCLKs)
+ sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
+ sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
+#endif
+
+#if defined HIGH_SPEED
+ // reduce timing budget to 20 ms (default is about 33 ms)
+ sensor.setMeasurementTimingBudget(20000);
+#elif defined HIGH_ACCURACY
+ // increase timing budget to 200 ms
+ sensor.setMeasurementTimingBudget(200000);
+#endif
+}
+
+void loop()
+{
+ Serial.print(sensor.readRangeSingleMillimeters());
+ if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
+
+ Serial.println();
+}
diff --git a/lib/vl53l0x-arduino-1.02/keywords.txt b/lib/vl53l0x-arduino-1.02/keywords.txt
new file mode 100755
index 000000000000..437add908642
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/keywords.txt
@@ -0,0 +1,90 @@
+VL53L0X KEYWORD1
+
+setAddress KEYWORD2
+getAddress KEYWORD2
+init KEYWORD2
+writeReg KEYWORD2
+writeReg16Bit KEYWORD2
+writeReg32Bit KEYWORD2
+readReg KEYWORD2
+readReg16Bit KEYWORD2
+readReg32Bit KEYWORD2
+writeMulti KEYWORD2
+readMulti KEYWORD2
+setSignalRateLimit KEYWORD2
+getSignalRateLimit KEYWORD2
+setMeasurementTimingBudget KEYWORD2
+getMeasurementTimingBudget KEYWORD2
+setVcselPulsePeriod KEYWORD2
+getVcselPulsePeriod KEYWORD2
+startContinuous KEYWORD2
+stopContinuous KEYWORD2
+readRangeContinuousMillimeters KEYWORD2
+readRangeSingleMillimeters KEYWORD2
+setTimeout KEYWORD2
+getTimeout KEYWORD2
+timeoutOccurred KEYWORD2
+
+SYSRANGE_START LITERAL1
+SYSTEM_THRESH_HIGH LITERAL1
+SYSTEM_THRESH_LOW LITERAL1
+SYSTEM_SEQUENCE_CONFIG LITERAL1
+SYSTEM_RANGE_CONFIG LITERAL1
+SYSTEM_INTERMEASUREMENT_PERIOD LITERAL1
+SYSTEM_INTERRUPT_CONFIG_GPIO LITERAL1
+GPIO_HV_MUX_ACTIVE_HIGH LITERAL1
+SYSTEM_INTERRUPT_CLEAR LITERAL1
+RESULT_INTERRUPT_STATUS LITERAL1
+RESULT_RANGE_STATUS LITERAL1
+RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN LITERAL1
+RESULT_CORE_RANGING_TOTAL_EVENTS_RTN LITERAL1
+RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF LITERAL1
+RESULT_CORE_RANGING_TOTAL_EVENTS_REF LITERAL1
+RESULT_PEAK_SIGNAL_RATE_REF LITERAL1
+ALGO_PART_TO_PART_RANGE_OFFSET_MM LITERAL1
+I2C_SLAVE_DEVICE_ADDRESS LITERAL1
+MSRC_CONFIG_CONTROL LITERAL1
+PRE_RANGE_CONFIG_MIN_SNR LITERAL1
+PRE_RANGE_CONFIG_VALID_PHASE_LOW LITERAL1
+PRE_RANGE_CONFIG_VALID_PHASE_HIGH LITERAL1
+PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT LITERAL1
+FINAL_RANGE_CONFIG_MIN_SNR LITERAL1
+FINAL_RANGE_CONFIG_VALID_PHASE_LOW LITERAL1
+FINAL_RANGE_CONFIG_VALID_PHASE_HIGH LITERAL1
+FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT LITERAL1
+PRE_RANGE_CONFIG_SIGMA_THRESH_HI LITERAL1
+PRE_RANGE_CONFIG_SIGMA_THRESH_LO LITERAL1
+PRE_RANGE_CONFIG_VCSEL_PERIOD LITERAL1
+PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI LITERAL1
+PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO LITERAL1
+SYSTEM_HISTOGRAM_BIN LITERAL1
+HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT LITERAL1
+HISTOGRAM_CONFIG_READOUT_CTRL LITERAL1
+FINAL_RANGE_CONFIG_VCSEL_PERIOD LITERAL1
+FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI LITERAL1
+FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO LITERAL1
+CROSSTALK_COMPENSATION_PEAK_RATE_MCPS LITERAL1
+MSRC_CONFIG_TIMEOUT_MACROP LITERAL1
+SOFT_RESET_GO2_SOFT_RESET_N LITERAL1
+IDENTIFICATION_MODEL_ID LITERAL1
+IDENTIFICATION_REVISION_ID LITERAL1
+OSC_CALIBRATE_VAL LITERAL1
+GLOBAL_CONFIG_VCSEL_WIDTH LITERAL1
+GLOBAL_CONFIG_SPAD_ENABLES_REF_0 LITERAL1
+GLOBAL_CONFIG_SPAD_ENABLES_REF_1 LITERAL1
+GLOBAL_CONFIG_SPAD_ENABLES_REF_2 LITERAL1
+GLOBAL_CONFIG_SPAD_ENABLES_REF_3 LITERAL1
+GLOBAL_CONFIG_SPAD_ENABLES_REF_4 LITERAL1
+GLOBAL_CONFIG_SPAD_ENABLES_REF_5 LITERAL1
+GLOBAL_CONFIG_REF_EN_START_SELECT LITERAL1
+DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD LITERAL1
+DYNAMIC_SPAD_REF_EN_START_OFFSET LITERAL1
+POWER_MANAGEMENT_GO1_POWER_FORCE LITERAL1
+VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV LITERAL1
+ALGO_PHASECAL_LIM LITERAL1
+ALGO_PHASECAL_CONFIG_TIMEOUT LITERAL1
+
+VcselPeriodPreRange LITERAL1
+VcselPeriodFinalRange LITERAL1
+
+
diff --git a/lib/vl53l0x-arduino-1.02/library.properties b/lib/vl53l0x-arduino-1.02/library.properties
new file mode 100755
index 000000000000..43dd4d3a2d4f
--- /dev/null
+++ b/lib/vl53l0x-arduino-1.02/library.properties
@@ -0,0 +1,9 @@
+name=VL53L0X
+version=1.0.2
+author=Pololu
+maintainer=Pololu
+sentence=VL53L0X distance sensor library
+paragraph=This is a library for the Arduino IDE that helps interface with ST's VL53L0X distance sensor.
+category=Sensors
+url=https://github.com/pololu/vl53l0x-arduino
+architectures=*
diff --git a/platformio.ini b/platformio.ini
index 351d1ba02d84..a5c0946d14bb 100755
--- a/platformio.ini
+++ b/platformio.ini
@@ -67,7 +67,7 @@ build_flags = ${esp82xx_defaults.build_flags}
[core_2_5_2]
; *** Esp8266 core for Arduino version 2.5.2
-platform = espressif8266@~2.2.0
+platform = espressif8266@~2.2.1
build_flags = ${esp82xx_defaults.build_flags}
-Wl,-Teagle.flash.1m.ld
; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473
diff --git a/scripter.md b/scripter.md
index 5b9ac7840418..40ad3451e817 100644
--- a/scripter.md
+++ b/scripter.md
@@ -1,6 +1,6 @@
**Script Language for Tasmota**
-As an alternative to rules. (about 14,2k flash size, variable ram size)
+As an alternative to rules. (about 17k flash size, variable ram size)
In submenu Configuration =\> edit script
1535 bytes max script size (uses rules buffer)
@@ -39,7 +39,9 @@ numeric var=4 bytes, string var=lenght of string+1)
**i:**vname specifies auto increment counters if >=0 (in seconds)
**m:**vname specifies a median filter variable with 5 entries (for elimination of outliers)
**M:**vname specifies a moving average filter variable with 8 entries (for smoothing data)
-(max 5 filters in total m+M)
+(max 5 filters in total m+M) optional another filter lenght (1..127) can be given after the definition.
+filter vars can be accessed also in indexed mode vname[x] (index = 1...N, index 0 returns current array index pointer)
+by this filter vars can be used as arrays
>all variable names length taken together may not exceed 256 characters, so keep variable names as short as possible.
memory is dynamically allocated as a result of the D section.
@@ -84,7 +86,9 @@ special variables (read only):
**pow(x y)** = calculates the power of x^y
**med(n x)** = calculates a 5 value median filter of x (2 filters possible n=0,1)
**int(x)** = gets the integer part of x (like floor)
-**hn(x)** = converts x (0..255) zu a hex nibble string
+**hn(x)** = converts x (0..255) to a hex nibble string
+**st(svar c n)** = stringtoken gets the n th substring of svar separated by c
+**s(x)** = explicit conversion from number x to string
**mqtts** = state of mqtt disconnected=0, connected>0
**wifis** = state of wifi disconnected=0, connected>0
@@ -184,6 +188,24 @@ specifies a for next loop, (loop count must not be less then 1)
**ends**
specifies a switch case selector
+**sd card support**
+enable by CARD_CS = gpio pin of card chip select
+\#define USE_SCRIPT_FATFS CARD_CS
+sd card uses standard hardware spi gpios: mosi,miso,sclk
+max 4 files open at a time
+allows for e.g. logging sensors to a tab delimited file and then download (see example below)
+script itself is also stored on sdcard with a default size of 4096 chars
+requires additional 10k flash
+
+>**fr=fo("fname" m)** open file fname, mode 0=read, 1=write (returns file reference (0-3) or -1 for error)
+**res=fw("text" fr)** writes text to (the end of) file fr, returns number of bytes written
+**res=fr(svar fr)** reads a string into svar, returns bytes read (string is read until delimiter \t \n \r or eof)
+**fc(fr)** close file
+**fd("fname")** delete file fname
+**flx(fname)** create download link for file (x=1 or 2) fname = file name of file to download
+**fsm** return 1 if filesystem is mounted, (valid sd card found)
+
+
**konsole script cmds**
>**script 1 or 0** switch script on or off
**script >cmdline** executes the script cmdline
@@ -226,6 +248,8 @@ hour=0
state=1
m:med5=0
M:movav=0
+; define array with 10 entries
+m:array=0 10
**\>B**
@@ -258,15 +282,14 @@ delay(100)
=>power 0
**\>T**
-
hum=BME280#Humidity
temp=BME280#Temperature
rssi=Wifi#RSSI
string=SleepMode
-; add to median filter
+; add to median filter
median=temp
-; add to moving average filter
+; add to moving average filter
movav=hum
; show filtered results
@@ -274,7 +297,7 @@ movav=hum
if chg[rssi]>0
then =>print rssi changed to %rssi%
-endif
+endif
if temp\>30
and hum\>70
@@ -286,6 +309,11 @@ endif
; every second but not completely reliable time here
; use upsecs and uptime or best t: for reliable timers
+; arrays
+array[1]=4
+array[2]=5
+tmp=array[1]+array[2]
+
; call subrountines with parameters
=#sub1("hallo")
=#sub2(999)
@@ -427,6 +455,8 @@ ends
**\>E**
=\>print event executed!
+; get HSBColor 1. component
+tmp=st(HSBColor , 1)
; check if switch changed state
sw=sw[1]
@@ -462,11 +492,54 @@ col=hn(255)+hn(0)+hn(0)
**\>R**
=\>print restarting now
+**a log sensor example**
+; define all vars here
+; reserve large strings
+**\>D** 48
+hum=0
+temp=0
+fr=0
+res=0
+; moving average for 60 seconds
+M:mhum=0 60
+M:mtemp=0 60
+str=""
+
+**\>B**
+; open file for write
+fr=fo("slog.txt" 1)
+; set sensor file download link
+fl1("slog.txt")
+
+**\>T**
+; get sensor values
+temp=BME280#Temperature
+hum=BME280#Humidity
+
+**\>S**
+; average sensor values every second
+mhum=hum
+mtemp=temp
+
+; write average to sensor log every minute
+if upsecs%60==0
+then
+; compose string for tab delimited file entry
+str=s(upsecs)+"\t"+s(mhum)+"\t"+s(mtemp)+"\n"
+; write string to log file
+res=fw(str fr)
+endif
+
+**\>R**
+; close file
+fc(fr)
+
+
**a real example**
epaper 29 with sgp30 and bme280
some vars are set from iobroker
DisplayText substituted to save script space
-\>D
+**\>D**
hum=0
temp=0
press=0
@@ -485,13 +558,13 @@ DT="DisplayText"
punit="hPa"
tunit="C"
-\>B
+**\>B**
;reset auto draw
=>%DT% [zD0]
;clr display and draw a frame
=>%DT% [x0y20h296x0y40h296]
-\>T
+**\>T**
; get tele vars
temp=BME280#Temperature
hum=BME280#Humidity
@@ -502,7 +575,7 @@ ahum=SGP30#aHumidity
tunit=TempUnit
punit=PressureUnit
-\>S
+**\>S**
// update display every teleperiod time
if upsecs%tper==0
then
@@ -525,9 +598,9 @@ dprec0
endif
-\>E
+**\>E**
-\>R
+**\>R**
**another real example**
ILI 9488 color LCD Display shows various energy graphs
diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino
index 450ef78592ed..6bed2c3b55fa 100644
--- a/sonoff/_changelog.ino
+++ b/sonoff/_changelog.ino
@@ -1,9 +1,19 @@
-/* 6.5.0.12 20190521
+/* 6.5.0.13 20190527
+ * Add command SetOption38 6..255 to set IRReceive protocol detection sensitivity mimizing UNKNOWN protocols (#5853)
+ * Fix missing white channel for WS2812 (#5869)
+ * Add reset of Energy values when connection to sensor is lost for over 4 seconds (#5874, #5881)
+ * Work-around for Philips Hue emulation issue by using part of MAC address for LightId (#5849)
+ * Add support to Stage Arduino Core (next 2.6.0)
+ *
+ * 6.5.0.12 20190521
* Add AriLux RF control GPIO option "ALux IrSel" (159) replacing "Led4i" (59) for full LED control (#5709)
* Add LED GPIO option "LedLink" (157) and "LedLinki" (158) to select dedicated link status LED (#5709)
* Add support for up to four LEDs related to four power outputs. Enabled when "LedLink(i)" is configured too (#5709)
* Add extended LED power control using command LedPowerX where X is 1 to 4. Enabled when "LedLink(i)" is configured too (#5709)
* Fix core 2.5.x ISR not in IRAM exception (#5837)
+ * Add support for VL53L0x time of flight sensor. Might interfere with TSL2561 using same I2C address (#5845)
+ * Add command AdcParam to control ADC0 Temperature and Light formula parameters
+ * Change default PowerDelta from 80% to 0% on new installations (#5858, #5028, #4813, #4130, #4145, #3795, #3778, #3660, #3648)
*
* 6.5.0.11 20190517
* Add command SetOption64 0/1 to switch between "-" or "_" as sensor index separator impacting DS18X20, DHT, BMP and SHT3X sensor names (#5689)
diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h
index 6786f755bac6..2dce8ed845b4 100644
--- a/sonoff/my_user_config.h
+++ b/sonoff/my_user_config.h
@@ -279,7 +279,7 @@
#define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem common)
// -- mDNS ----------------------------------------
-#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem)
+#define USE_DISCOVERY // Enable mDNS for the following services (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
#define WEBSERVER_ADVERTISE // Provide access to webserver by name .local/
#define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found)
@@ -292,7 +292,8 @@
// -- Rules or Script ----------------------------
// Select none or only one of the below defines
#define USE_RULES // Add support for rules (+8k code)
-//#define USE_SCRIPT // Add support for script (+15k code)
+//#define USE_SCRIPT // Add support for script (+17k code)
+ #define USE_SCRIPT_FATFS 4
// #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem)
// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code)
@@ -348,6 +349,7 @@
// #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code)
#define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code)
#define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5)
+ #define USE_VL53L0X // Enable VL53L0x time of flight sensor (I2C address 0x29) (+4k code)
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
@@ -416,7 +418,7 @@
#define USE_IR_RECEIVE // Support for IR receiver (+7k2 code, 264 iram)
#define IR_RCV_BUFFER_SIZE 100 // Max number of packets allowed in capture buffer (default 100 (*2 bytes ram))
#define IR_RCV_TIMEOUT 15 // Number of milli-Seconds of no-more-data before we consider a message ended (default 15)
- #define IR_RCV_MIN_UNKNOWN_SIZE 6 // Set the smallest sized "UNKNOWN" message packets we actually care about (default 6)
+ #define IR_RCV_MIN_UNKNOWN_SIZE 6 // Set the smallest sized "UNKNOWN" message packets we actually care about (default 6, max 255)
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
#define USE_WS2812_CTYPE NEO_GRB // WS2812 Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
diff --git a/sonoff/settings.h b/sonoff/settings.h
index 03529e8faa13..5f635011615c 100644
--- a/sonoff/settings.h
+++ b/sonoff/settings.h
@@ -210,8 +210,9 @@ struct SYSCFG {
uint8_t webserver; // 1AB
uint8_t weblog_level; // 1AC
uint8_t mqtt_fingerprint[2][20]; // 1AD
+ uint8_t adc_param_type; // 1D5
- uint8_t free_1D5[19]; // 1D5 Free since 5.12.0e
+ uint8_t free_1D6[18]; // 1D6 Free since 5.12.0e
uint8_t sps30_inuse_hours; // 1E8
char mqtt_host[33]; // 1E9 - Keep together with below as being copied as one chunck with reset 6
@@ -336,7 +337,10 @@ struct SYSCFG {
uint8_t free_774[32]; // 774
- uint32_t drivers[3]; // 794
+// uint32_t drivers[3]; // 794 - 6.5.0.12 replaced by below three entries
+ uint32_t adc_param1; // 794
+ uint32_t adc_param2; // 798
+ int adc_param3; // 79C
uint32_t monitors; // 7A0
uint32_t sensors[3]; // 7A4
uint32_t displays; // 7B0
diff --git a/sonoff/settings.ino b/sonoff/settings.ino
index a8445b232c3c..f2bf1290e7aa 100644
--- a/sonoff/settings.ino
+++ b/sonoff/settings.ino
@@ -235,11 +235,20 @@ extern "C" {
}
#include "eboot_command.h"
-extern "C" uint32_t _SPIFFS_end;
+#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) || defined(ARDUINO_ESP8266_RELEASE_2_5_0) || defined(ARDUINO_ESP8266_RELEASE_2_5_1) || defined(ARDUINO_ESP8266_RELEASE_2_5_2)
+extern "C" uint32_t _SPIFFS_end;
// From libraries/EEPROM/EEPROM.cpp EEPROMClass
const uint32_t SPIFFS_END = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
+#else // Core > 2.5.2 and STAGE
+
+extern "C" uint32_t _FS_end;
+// From libraries/EEPROM/EEPROM.cpp EEPROMClass
+const uint32_t SPIFFS_END = ((uint32_t)&_FS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
+
+#endif
+
// Version 4.2 config = eeprom area
const uint32_t SETTINGS_LOCATION = SPIFFS_END; // No need for SPIFFS as it uses EEPROM area
// Version 5.2 allow for more flash space
@@ -789,7 +798,7 @@ void SettingsDefaultSet2(void)
// Settings.flag2.wattage_resolution = 0;
Settings.flag2.energy_resolution = ENERGY_RESOLUTION;
Settings.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY;
- Settings.energy_power_delta = DEFAULT_POWER_DELTA;
+// Settings.energy_power_delta = 0;
Settings.energy_power_calibration = HLW_PREF_PULSE;
Settings.energy_voltage_calibration = HLW_UREF_PULSE;
Settings.energy_current_calibration = HLW_IREF_PULSE;
@@ -813,6 +822,9 @@ void SettingsDefaultSet2(void)
// Settings.energy_kWhtotal = 0;
RtcSettings.energy_kWhtotal = 0;
+ // IRRemote
+ Settings.param[P_IR_UNKNOW_THRESHOLD] = IR_RCV_MIN_UNKNOWN_SIZE;
+
// RF Bridge
// for (uint8_t i = 0; i < 17; i++) { Settings.rf_code[i][0] = 0; }
memcpy_P(Settings.rf_code[0], kDefaultRfCode, 9);
@@ -908,7 +920,7 @@ void SettingsDefaultSet2(void)
SettingsDefaultWebColor();
- memset(&Settings.drivers, 0xFF, 32); // Enable all possible monitors, displays, drivers and sensors
+ memset(&Settings.monitors, 0xFF, 20); // Enable all possible monitors, displays and sensors
}
/********************************************************************************************/
@@ -1047,7 +1059,7 @@ void SettingsDelta(void)
}
if (Settings.version < 0x050C0005) {
Settings.light_rotation = 0;
- Settings.energy_power_delta = DEFAULT_POWER_DELTA;
+ Settings.energy_power_delta = 0;
char fingerprint[60];
memcpy(fingerprint, Settings.mqtt_fingerprint, sizeof(fingerprint));
char *p = fingerprint;
@@ -1129,7 +1141,7 @@ void SettingsDelta(void)
Settings.timezone_minutes = 0;
}
if (Settings.version < 0x06030004) {
- memset(&Settings.drivers, 0xFF, 32); // Enable all possible monitors, displays, drivers and sensors
+ memset(&Settings.monitors, 0xFF, 20); // Enable all possible monitors, displays and sensors
}
if (Settings.version < 0x0603000E) {
Settings.flag2.calc_resolution = CALC_RESOLUTION;
@@ -1168,6 +1180,9 @@ void SettingsDelta(void)
if (Settings.version < 0x0605000A) {
Settings.my_adc0 = ADC0_NONE;
}
+ if (Settings.version < 0x0605000D) {
+ Settings.param[P_IR_UNKNOW_THRESHOLD] = IR_RCV_MIN_UNKNOWN_SIZE;
+ }
Settings.version = VERSION;
SettingsSave(1);
diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h
index 9b3ed00206fe..d7d4ef9050e1 100644
--- a/sonoff/sonoff.h
+++ b/sonoff/sonoff.h
@@ -99,7 +99,6 @@ const uint16_t PWM_MIN = 100; // [PWM_MIN] Minimum frequency - Def
// For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS)
//#define PWM_LIGHTSCHEME0_IGNORE_SLEEP // Do not change sleep value for LightAnimate() scheme 0
-const uint8_t DEFAULT_POWER_DELTA = 80; // Power change percentage
const uint16_t MAX_POWER_HOLD = 10; // Time in SECONDS to allow max agreed power
const uint16_t MAX_POWER_WINDOW = 30; // Time in SECONDS to disable allow max agreed power
const uint16_t SAFE_POWER_HOLD = 10; // Time in SECONDS to allow max unit safe power
@@ -237,7 +236,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED };
enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER };
-enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
+enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, P_MAX_PARAM8}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_MAX_SENSORS};
diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino
index ef9845c81262..38f28df0e2c0 100755
--- a/sonoff/sonoff.ino
+++ b/sonoff/sonoff.ino
@@ -125,7 +125,7 @@ int blinks = 201; // Number of LED blinks
uint32_t uptime = 0; // Counting every second until 4294967295 = 130 year
uint32_t loop_load_avg = 0; // Indicative loop load average
uint32_t global_update = 0; // Timestamp of last global temperature and humidity update
-float global_temperature = 0; // Provide a global temperature to be used by some sensors
+float global_temperature = 9999; // Provide a global temperature to be used by some sensors
float global_humidity = 0; // Provide a global humidity to be used by some sensors
float global_pressure = 0; // Provide a global pressure to be used by some sensors
char *ota_url; // OTA url string pointer
@@ -851,6 +851,11 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
case P_RGB_REMAP:
LightUpdateColorMapping();
break;
+#if defined(USE_IR_REMOTE) && defined(USE_IR_RECEIVE)
+ case P_IR_UNKNOW_THRESHOLD:
+ IrReceiveUpdateThreshold();
+ break;
+#endif
}
}
}
diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h
index e06fab8d0e3d..8b7c27bfcb90 100644
--- a/sonoff/sonoff_version.h
+++ b/sonoff/sonoff_version.h
@@ -20,6 +20,6 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
-const uint32_t VERSION = 0x0605000C;
+const uint32_t VERSION = 0x0605000D;
#endif // _SONOFF_VERSION_H_
diff --git a/sonoff/support.ino b/sonoff/support.ino
index da79be0e02b4..f3faa1798426 100644
--- a/sonoff/support.ino
+++ b/sonoff/support.ino
@@ -644,7 +644,7 @@ void ResetGlobalValues(void)
{
if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes
global_update = 0;
- global_temperature = 0;
+ global_temperature = 9999;
global_humidity = 0;
global_pressure = 0;
}
diff --git a/sonoff/support_rotary.ino b/sonoff/support_rotary.ino
index 35974251b572..64a7bc738b85 100644
--- a/sonoff/support_rotary.ino
+++ b/sonoff/support_rotary.ino
@@ -62,7 +62,7 @@ void update_position(void)
}
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0 // Fix core 2.5.x ISR not in IRAM Exception
-void update_rotary(void) ICACHE_RAM_ATTR; // As iram is tight and it works this way too
+void update_rotary(void) ICACHE_RAM_ATTR;
#endif // ARDUINO_ESP8266_RELEASE_2_3_0
void update_rotary(void)
diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino
index fc5ffa467236..28250adf116d 100644
--- a/sonoff/xdrv_01_webserver.ino
+++ b/sonoff/xdrv_01_webserver.ino
@@ -480,7 +480,8 @@ void StartWebserver(int type, IPAddress ipweb)
WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA
WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop);
WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest);
- WebServer->on("/cs", HandleConsole);
+ WebServer->on("/cs", HTTP_GET, HandleConsole);
+ WebServer->on("/cs", HTTP_OPTIONS, HandlePreflightRequest);
WebServer->on("/cm", HandleHttpCommand);
#ifndef FIRMWARE_MINIMAL
WebServer->on("/cn", HandleConfiguration);
@@ -1293,17 +1294,28 @@ void ModuleSaveSettings(void)
/*-------------------------------------------------------------------------------------------*/
-String htmlEscape(String s)
-{
- s.replace("&", "&");
- s.replace("<", "<");
- s.replace(">", ">");
- s.replace("\"", """);
- s.replace("'", "'");
- s.replace("/", "/");
- return s;
+const char kUnescapeCode[] = "&><\"\'";
+const char kEscapeCode[] PROGMEM = "&|>|<|"|'";
+
+String HtmlEscape(const String unescaped) {
+ char escaped[10];
+ uint16_t ulen = unescaped.length();
+ String result = "";
+ for (size_t i = 0; i < ulen; i++) {
+ char c = unescaped[i];
+ char *p = strchr(kUnescapeCode, c);
+ if (p != nullptr) {
+ result += GetTextIndexed(escaped, sizeof(escaped), p - kUnescapeCode, kEscapeCode);
+ } else {
+ result += c;
+ }
+ }
+ return result;
}
+// Indexed by enum wl_enc_type in file wl_definitions.h starting from -1
+const char kEncryptionType[] PROGMEM = "|||" D_WPA_PSK "||" D_WPA2_PSK "|" D_WEP "||" D_NONE "|" D_AUTO;
+
void HandleWifiConfiguration(void)
{
if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; }
@@ -1370,11 +1382,12 @@ void HandleWifiConfiguration(void)
int quality = WifiGetRssiAsQuality(WiFi.RSSI(indices[i]));
if (minimum_signal_quality == -1 || minimum_signal_quality < quality) {
- uint8_t auth = WiFi.encryptionType(indices[i]);
+ int auth = WiFi.encryptionType(indices[i]);
+ char encryption[20];
WSContentSend_P(PSTR(""),
- htmlEscape(WiFi.SSID(indices[i])).c_str(),
+ HtmlEscape(WiFi.SSID(indices[i])).c_str(),
WiFi.channel(indices[i]),
- (ENC_TYPE_WEP == auth) ? D_WEP : (ENC_TYPE_TKIP == auth) ? D_WPA_PSK : (ENC_TYPE_CCMP == auth) ? D_WPA2_PSK : (ENC_TYPE_AUTO == auth) ? D_AUTO : "",
+ GetTextIndexed(encryption, sizeof(encryption), auth +1, kEncryptionType),
quality
);
delay(0);
diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino
index 2793c36633da..52585a632b80 100644
--- a/sonoff/xdrv_03_energy.ino
+++ b/sonoff/xdrv_03_energy.ino
@@ -28,6 +28,7 @@
#define ENERGY_NONE 0
#define ENERGY_OVERTEMP 73.0 // Industry standard lowest overtemp in Celsius
+#define ENERGY_WATCHDOG 4 // Allow up to 4 seconds before deciding no valid data present
#define FEATURE_POWER_LIMIT true
@@ -71,6 +72,7 @@ unsigned long energy_period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hour
float energy_power_last[3] = { 0 };
uint8_t energy_power_delta = 0;
+uint8_t energy_data_valid = 0;
bool energy_voltage_available = true; // Enable if voltage is measured
bool energy_current_available = true; // Enable if current is measured
@@ -323,10 +325,22 @@ void EnergyMqttShow(void)
void EnergyOverTempCheck()
{
if (global_update) {
- if (power && (global_temperature > ENERGY_OVERTEMP)) { // Device overtemp, turn off relays
+ if (power && (global_temperature != 9999) && (global_temperature > ENERGY_OVERTEMP)) { // Device overtemp, turn off relays
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
}
}
+ if (energy_data_valid <= ENERGY_WATCHDOG) {
+ energy_data_valid++;
+ if (energy_data_valid > ENERGY_WATCHDOG) {
+ // Reset energy registers
+ energy_voltage = 0;
+ energy_current = 0;
+ energy_active_power = 0;
+ if (!isnan(energy_frequency)) { energy_frequency = 0; }
+ if (!isnan(energy_power_factor)) { energy_power_factor = 0; }
+ energy_start = 0;
+ }
+ }
}
/*********************************************************************************************\
@@ -349,7 +363,7 @@ bool EnergyCommand(void)
}
else if (CMND_POWERDELTA == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 101)) {
- Settings.energy_power_delta = (1 == XdrvMailbox.payload) ? DEFAULT_POWER_DELTA : XdrvMailbox.payload;
+ Settings.energy_power_delta = XdrvMailbox.payload;
}
nvalue = Settings.energy_power_delta;
unit = UNIT_PERCENTAGE;
diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino
index 17a0806bb249..b737fcc1dfd4 100644
--- a/sonoff/xdrv_04_light.ino
+++ b/sonoff/xdrv_04_light.ino
@@ -1326,6 +1326,12 @@ void LightInit(void)
light_device = devices_present;
light_subtype = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7); // Always 0 - LST_MAX (5)
+#if defined(USE_WS2812) && (USE_WS2812_CTYPE > NEO_3LED)
+ if (LT_WS2812 == light_type) {
+ light_subtype++; // from RGB to RGBW
+ }
+#endif
+
light_controller.setSubType(light_subtype);
light_controller.loadSettings();
@@ -1362,9 +1368,6 @@ void LightInit(void)
}
#ifdef USE_WS2812 // ************************************************************************
else if (LT_WS2812 == light_type) {
-#if (USE_WS2812_CTYPE > NEO_3LED)
- light_subtype++; // from RGB to RGBW
-#endif
Ws2812Init();
max_scheme = LS_MAX + WS2812_SCHEMES;
}
diff --git a/sonoff/xdrv_05_irremote.ino b/sonoff/xdrv_05_irremote.ino
index 9f1c33a10f3e..9bd0694e3b7d 100644
--- a/sonoff/xdrv_05_irremote.ino
+++ b/sonoff/xdrv_05_irremote.ino
@@ -116,11 +116,17 @@ IRrecv *irrecv = nullptr;
unsigned long ir_lasttime = 0;
+void IrReceiveUpdateThreshold()
+{
+ if (Settings.param[P_IR_UNKNOW_THRESHOLD] < 6) { Settings.param[P_IR_UNKNOW_THRESHOLD] = 6; }
+ irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]);
+}
+
void IrReceiveInit(void)
{
// an IR led is at GPIO_IRRECV
irrecv = new IRrecv(pin[GPIO_IRRECV], IR_RCV_BUFFER_SIZE, IR_RCV_TIMEOUT, IR_RCV_SAVE_BUFFER);
- irrecv->setUnknownThreshold(IR_RCV_MIN_UNKNOWN_SIZE);
+ irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]);
irrecv->enableIRIn(); // Start the receiver
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("IrReceive initialized"));
diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino
index 9edd27a9f8cc..3b21603de586 100644
--- a/sonoff/xdrv_10_scripter.ino
+++ b/sonoff/xdrv_10_scripter.ino
@@ -20,17 +20,14 @@
#ifdef USE_SCRIPT
#ifndef USE_RULES
/*********************************************************************************************\
-
for documentation see up to date docs in file SCRIPTER.md
-
-uses about 14,2 k of flash
-more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap
-
+uses about 17 k of flash
to do
optimize code for space
remarks
+
goal is fast execution time, minimal use of ram and intuitive syntax
therefore =>
case sensitive cmds and vars (lowercase uses time and code)
@@ -38,6 +35,14 @@ no math hierarchy (costs ram and execution time, better group with brackets, an
(will probably make math hierarchy an ifdefed option)
keywords if then else endif, or, and are better readable for beginners (others may use {})
+changelog after merging to Tasmota
+1 show remaining chars in webui,
+2 now can expand script space to 2048 chars by setting MAX_RULE_SETS to 4
+3 at24256 eeprom support #ifdef defaults to 4095 bytes script size (reduces heap by this amount)
+4 some housekeeping
+5 sd card support #ifdef allows eg for sensor logging
+6 download link for sdcard files
+
\*********************************************************************************************/
#define XDRV_10 10
@@ -53,11 +58,18 @@ keywords if then else endif, or, and are better readable for beginners (others m
#define SCRIPT_EOL '\n'
#define SCRIPT_FLOAT_PRECISION 2
#define SCRIPT_MAXPERM (MAX_RULE_MEMS*10)-4/sizeof(float)
-
+#define MAX_SCRIPT_SIZE MAX_RULE_SIZE*MAX_RULE_SETS
enum {OPER_EQU=1,OPER_PLS,OPER_MIN,OPER_MUL,OPER_DIV,OPER_PLSEQU,OPER_MINEQU,OPER_MULEQU,OPER_DIVEQU,OPER_EQUEQU,OPER_NOTEQU,OPER_GRTEQU,OPER_LOWEQU,OPER_GRT,OPER_LOW,OPER_PERC,OPER_XOR,OPER_AND,OPER_OR,OPER_ANDEQU,OPER_OREQU,OPER_XOREQU,OPER_PERCEQU};
enum {SCRIPT_LOGLEVEL=1,SCRIPT_TELEPERIOD};
+#ifdef USE_SCRIPT_FATFS
+#include
+#include
+#define FAT_SCRIPT_SIZE 4096
+#define FAT_SCRIPT_NAME "script.txt"
+#endif
+
typedef union {
uint8_t data;
struct {
@@ -84,6 +96,7 @@ struct M_FILT {
float rbuff[1];
};
+#define SFS_MAX 4
// global memory
struct SCRIPT_MEM {
float *fvars; // number var pointer
@@ -94,6 +107,10 @@ struct SCRIPT_MEM {
uint8_t *vnp_offset;
char *glob_snp; // string vars pointer
char *scriptptr;
+ char *script_ram;
+ uint16_t script_size;
+ uint8_t *script_pram;
+ uint16_t script_pram_size;
uint8_t numvars;
void *script_mem;
uint16_t script_mem_size;
@@ -102,13 +119,26 @@ struct SCRIPT_MEM {
uint8_t glob_error;
uint8_t max_ssize;
uint8_t script_loglevel;
+ uint8_t flags;
+#ifdef USE_SCRIPT_FATFS
+ File files[SFS_MAX];
+ uint8_t file_flags[SFS_MAX];
+ uint8_t script_sd_found;
+ char flink[2][14];
+#endif
} glob_script_mem;
+
+int16_t last_findex;
uint8_t tasm_cmd_activ=0;
uint32_t script_lastmillis;
+
char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo);
+char *GetStringResult(char *lp,uint8_t lastop,char *cp,JsonObject *jo);
+char *ForceStringVar(char *lp,char *dstr);
+void send_download(void);
void ScriptEverySecond(void) {
@@ -142,11 +172,31 @@ void RulesTeleperiod(void) {
if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">T",2, mqtt_data);
}
+//#define USE_24C256
+
+// EEPROM MACROS
+#ifdef USE_24C256
+// i2c eeprom
+#include
+#define EEPROM_ADDRESS 0x50
+// strange bug, crashes with powers of 2 ??? 4096 crashes
+#define EEP_SCRIPT_SIZE 4095
+static Eeprom24C128_256 eeprom(EEPROM_ADDRESS);
+// eeprom.writeBytes(address, length, buffer);
+#define EEP_WRITE(A,B,C) eeprom.writeBytes(A,B,(uint8_t*)C);
+// eeprom.readBytes(address, length, buffer);
+#define EEP_READ(A,B,C) eeprom.readBytes(A,B,(uint8_t*)C);
+#endif
+
#define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++;
#define SCRIPT_SKIP_EOL while (*lp==SCRIPT_EOL) lp++;
-// allocates all variable and presets them
-int16_t Init_Scripter(char *script) {
+// allocates all variables and presets them
+int16_t Init_Scripter(void) {
+char *script;
+
+ script=glob_script_mem.script_ram;
+
// scan lines for >DEF
uint16_t lines=0,nvars=0,svars=0,vars=0;
char *lp=script;
@@ -243,6 +293,19 @@ int16_t Init_Scripter(char *script) {
if (nvars>MAXNVARS) {
return -1;
}
+ if (vtypes[vars].bits.is_filter) {
+ while (isdigit(*op) || *op=='.' || *op=='-') {
+ op++;
+ }
+ while (*op==' ') op++;
+ if (isdigit(*op)) {
+ // lenght define follows
+ uint8_t flen=atoi(op);
+ mfilt[numflt-1].numvals&=0x7f;
+ mfilt[numflt-1].numvals|=flen&0x7f;
+ }
+ }
+
} else {
// string vars
op++;
@@ -399,10 +462,7 @@ int16_t Init_Scripter(char *script) {
#endif
// now preset permanent vars
- uint32_t lptr=(uint32_t)Settings.mems[0];
- lptr&=0xfffffffc;
- float *fp=(float*)lptr;
- fp++;
+ float *fp=(float*)glob_script_mem.script_pram;
struct T_INDEX *vtp=glob_script_mem.type;
for (uint8_t count=0; count0
ClaimSerial();
SetSerialBaudrate(9600);
@@ -445,9 +518,70 @@ int16_t Init_Scripter(char *script) {
#define NTYPE 0
#define STYPE 0x80
+#define FLT_MAX 99999999
+
+float median_array(float *array,uint8_t len) {
+ uint8_t ind[len];
+ uint8_t mind=0,index=0,flg;
+ float min=FLT_MAX;
+
+ for (uint8_t hcnt=0; hcntnumvals&0x7f;
+ if (!bind) {
+ return mflp->index;
+ }
+ if (bind<1 || bind>maxind) bind=maxind;
+ return mflp->rbuff[bind-1];
+ }
+ mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float);
+ }
+ return 0;
+}
+
+void Set_MFVal(uint8_t index,uint8_t bind,float val) {
+ uint8_t *mp=(uint8_t*)glob_script_mem.mfilt;
+ for (uint8_t count=0; countnumvals&0x7f;
+ if (!bind) {
+ mflp->index=val;
+ } else {
+ if (bind<1 || bind>maxind) bind=maxind;
+ mflp->rbuff[bind-1]=val;
+ }
+ return;
+ }
+ mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float);
+ }
+}
-//Settings.seriallog_level
-//Settings.weblog_level
float Get_MFilter(uint8_t index) {
uint8_t *mp=(uint8_t*)glob_script_mem.mfilt;
@@ -458,23 +592,8 @@ float Get_MFilter(uint8_t index) {
// moving average
return mflp->maccu/(mflp->numvals&0x7f);
} else {
- // median, sort array
- float tbuff[mflp->numvals],tmp;
- uint8_t flag;
- memmove(tbuff,mflp->rbuff,sizeof(tbuff));
- for (uint8_t ocnt=0; ocntnumvals; ocnt++) {
- flag=0;
- for (uint8_t count=0; countnumvals-1; count++) {
- if (tbuff[count]>tbuff[count+1]) {
- tmp=tbuff[count];
- tbuff[count]=tbuff[count+1];
- tbuff[count+1]=tmp;
- flag=1;
- }
- }
- if (!flag) break;
- }
- return mflp->rbuff[mflp->numvals/2];
+ // median, sort array indices
+ return median_array(mflp->rbuff,mflp->numvals);
}
}
mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float);
@@ -519,27 +638,10 @@ float DoMedian5(uint8_t index, float in) {
if (index>=MEDIAN_FILTER_NUM) index=0;
struct MEDIAN_FILTER* mf=&script_mf[index];
-
- float tbuff[MEDIAN_SIZE],tmp;
- uint8_t flag;
mf->buffer[mf->index]=in;
mf->index++;
if (mf->index>=MEDIAN_SIZE) mf->index=0;
- // sort list and take median
- memmove(tbuff,mf->buffer,sizeof(tbuff));
- for (uint8_t ocnt=0; ocnttbuff[count+1]) {
- tmp=tbuff[count];
- tbuff[count]=tbuff[count+1];
- tbuff[count+1]=tmp;
- flag=1;
- }
- }
- if (!flag) break;
- }
- return tbuff[MEDIAN_SIZE/2];
+ return median_array(mf->buffer,MEDIAN_SIZE);
}
@@ -570,7 +672,24 @@ char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,Jso
lp++;
while (*lp!='"') {
if (*lp==0 || *lp==SCRIPT_EOL) break;
- if (sp) *sp++=*lp;
+ uint8_t iob=*lp;
+ if (iob=='\\') {
+ lp++;
+ if (*lp=='t') {
+ iob='\t';
+ } else if (*lp=='n') {
+ iob='\n';
+ } else if (*lp=='r') {
+ iob='\r';
+ } else if (*lp=='\\') {
+ iob='\\';
+ } else {
+ lp--;
+ }
+ if (sp) *sp++=iob;
+ } else {
+ if (sp) *sp++=iob;
+ }
lp++;
}
if (sp) *sp=0;
@@ -606,19 +725,35 @@ char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,Jso
}
struct T_INDEX *vtp=glob_script_mem.type;
+ char dvnam[32];
+ strcpy (dvnam,vname);
+ uint8_t olen=len;
+ last_findex=-1;
+ char *ja=strchr(dvnam,'[');
+ if (ja) {
+ *ja=0;
+ ja++;
+ olen=strlen(dvnam);
+ }
for (count=0; countindex=count; // overwrite with global var index
if (vtp[count].bits.is_string==0) {
*vtype=NTYPE|index;
if (vtp[count].bits.is_filter) {
- fvar=Get_MFilter(index);
+ if (ja) {
+ GetNumericResult(ja,OPER_EQU,&fvar,0);
+ last_findex=fvar;
+ fvar=Get_MFVal(index,fvar);
+ len++;
+ } else {
+ fvar=Get_MFilter(index);
+ }
} else {
fvar=glob_script_mem.fvars[index];
}
@@ -741,6 +876,141 @@ chknext:
goto exit;
}
break;
+#ifdef USE_SCRIPT_FATFS
+ case 'f':
+ if (!strncmp(vname,"fo(",3)) {
+ lp+=3;
+ char str[SCRIPT_MAXSSIZE];
+ lp=GetStringResult(lp,OPER_EQU,str,0);
+ while (*lp==' ') lp++;
+ lp=GetNumericResult(lp,OPER_EQU,&fvar,0);
+ uint8_t mode=fvar;
+ fvar=-1;
+ for (uint8_t cnt=0;cnt=SFS_MAX) ind=SFS_MAX-1;
+ glob_script_mem.files[ind].close();
+ glob_script_mem.file_flags[ind]=0;
+ fvar=0;
+ lp++;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"fw(",3)) {
+ lp+=3;
+ char str[SCRIPT_MAXSSIZE];
+ lp=ForceStringVar(lp,str);
+ while (*lp==' ') lp++;
+ lp=GetNumericResult(lp,OPER_EQU,&fvar,0);
+ uint8_t ind=fvar;
+ if (ind>=SFS_MAX) ind=SFS_MAX-1;
+ if (glob_script_mem.file_flags[ind]&1) {
+ fvar=glob_script_mem.files[ind].print(str);
+ } else {
+ fvar=0;
+ }
+ lp++;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"fr(",3)) {
+ lp+=3;
+ struct T_INDEX ind;
+ uint8_t vtype;
+ uint8_t sindex=0;
+ lp=isvar(lp,&vtype,&ind,0,0,0);
+ if (vtype!=VAR_NV) {
+ // found variable as result
+ if ((vtype&STYPE)==0) {
+ // error
+ fvar=0;
+ goto exit;
+ } else {
+ // string result
+ sindex=glob_script_mem.type[ind.index].index;
+ }
+ } else {
+ // error
+ fvar=0;
+ goto exit;
+ }
+ while (*lp==' ') lp++;
+ lp=GetNumericResult(lp,OPER_EQU,&fvar,0);
+ uint8_t find=fvar;
+ if (find>=SFS_MAX) find=SFS_MAX-1;
+ uint8_t index=0;
+ char str[glob_script_mem.max_ssize+1];
+ char *cp=str;
+ if (glob_script_mem.file_flags[find]&1) {
+ while (glob_script_mem.files[find].available()) {
+ uint8_t buf[1];
+ glob_script_mem.files[find].read(buf,1);
+ if (buf[0]=='\t' || buf[0]==',' || buf[0]=='\n' || buf[0]=='\r') {
+ break;
+ } else {
+ *cp++=buf[0];
+ index++;
+ if (index>=glob_script_mem.max_ssize-1) break;
+ }
+ }
+ *cp=0;
+ } else {
+ strcpy(str,"file error");
+ }
+ lp++;
+ strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize);
+ fvar=index;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"fd(",3)) {
+ lp+=3;
+ char str[glob_script_mem.max_ssize+1];
+ lp=GetStringResult(lp,OPER_EQU,str,0);
+ SD.remove(str);
+ lp++;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"fl1(",4) || !strncmp(vname,"fl2(",4) ) {
+ uint8_t lknum=*(lp+2)&3;
+ lp+=4;
+ char str[glob_script_mem.max_ssize+1];
+ lp=GetStringResult(lp,OPER_EQU,str,0);
+ if (lknum<1 || lknum>2) lknum=1;
+ strlcpy(glob_script_mem.flink[lknum-1],str,14);
+ lp++;
+ fvar=0;
+ len=0;
+ goto exit;
+ }
+ if (!strncmp(vname,"fsm",3)) {
+ fvar=glob_script_mem.script_sd_found;
+ //card_init();
+ goto exit;
+ }
+ break;
+
+#endif //USE_SCRIPT_FATFS
case 'g':
if (!strncmp(vname,"gtmp",4)) {
fvar=global_temperature;
@@ -918,7 +1188,7 @@ chknext:
break;
case 'r':
if (!strncmp(vname,"ram",3)) {
- fvar=glob_script_mem.script_mem_size+(MAX_RULE_SETS*MAX_RULE_SIZE)+(MAX_RULE_MEMS*10);
+ fvar=glob_script_mem.script_mem_size+(glob_script_mem.script_size)+(MAX_RULE_MEMS*10);
goto exit;
}
break;
@@ -940,9 +1210,53 @@ chknext:
goto exit;
}
if (!strncmp(vname,"slen",4)) {
- fvar=strlen(Settings.rules[0]);
+ fvar=strlen(glob_script_mem.script_ram);
goto exit;
}
+ if (!strncmp(vname,"st(",3)) {
+ lp+=3;
+ char str[SCRIPT_MAXSSIZE];
+ lp=GetStringResult(lp,OPER_EQU,str,0);
+ while (*lp==' ') lp++;
+ char token[2];
+ token[0]=*lp++;
+ token[1]=0;
+ while (*lp==' ') lp++;
+ lp=GetNumericResult(lp,OPER_EQU,&fvar,0);
+ // skip ) bracket
+ lp++;
+ len=0;
+ if (sp) {
+ // get stringtoken
+ char *st=strtok(str,token);
+ if (!st) {
+ *sp=0;
+ } else {
+ for (uint8_t cnt=1; cnt<=fvar; cnt++) {
+ if (cnt==fvar) {
+ strcpy(sp,st);
+ break;
+ }
+ st=strtok(NULL,token);
+ if (!st) {
+ *sp=0;
+ break;
+ }
+ }
+ }
+ }
+ goto strexit;
+ }
+ if (!strncmp(vname,"s(",2)) {
+ lp+=2;
+ lp=GetNumericResult(lp,OPER_EQU,&fvar,0);
+ char str[glob_script_mem.max_ssize+1];
+ dtostrfd(fvar,glob_script_mem.script_dprec,str);
+ if (sp) strlcpy(sp,str,glob_script_mem.max_ssize);
+ lp++;
+ len=0;
+ goto strexit;
+ }
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
if (!strncmp(vname,"sunrise",7)) {
fvar=SunMinutes(0);
@@ -1326,6 +1640,20 @@ struct T_INDEX ind;
}
+char *ForceStringVar(char *lp,char *dstr) {
+ float fvar;
+ char *slp=lp;
+ glob_script_mem.var_not_found=0;
+ lp=GetStringResult(lp,OPER_EQU,dstr,0);
+ if (glob_script_mem.var_not_found) {
+ // mismatch
+ lp=GetNumericResult(slp,OPER_EQU,&fvar,0);
+ dtostrfd(fvar,6,dstr);
+ glob_script_mem.var_not_found=0;
+ }
+ return lp;
+}
+
// replace vars in cmd %var%
void Replace_Cmd_Vars(char *srcbuf,char *dstbuf,uint16_t dstsize) {
char *cp;
@@ -1416,10 +1744,13 @@ void toSLog(const char *str) {
#endif
}
+
+
+
#define IF_NEST 8
// execute section of scripter
int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
- uint8_t vtype=0,sindex,xflg,floop=0,globvindex;
+ uint8_t vtype=0,sindex,xflg,floop=0,globvindex,globaindex;
struct T_INDEX ind;
uint8_t operand,lastop,numeric=1,if_state[IF_NEST],if_result[IF_NEST],and_or,ifstck=0,s_ifstck=0;
if_state[ifstck]=0;
@@ -1681,7 +2012,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
toLog(&tmp[5]);
} else {
snprintf_P(log_data, sizeof(log_data), PSTR("Script: performs \"%s\""), tmp);
- AddLog(glob_script_mem.script_loglevel);
+ AddLog(glob_script_mem.script_loglevel&0x7f);
tasm_cmd_activ=1;
ExecuteCommand((char*)tmp, SRC_RULE);
tasm_cmd_activ=0;
@@ -1726,6 +2057,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
if (vtype!=VAR_NV) {
// found variable as result
globvindex=ind.index; // save destination var index here
+ globaindex=last_findex;
uint8_t index=glob_script_mem.type[ind.index].index;
if ((vtype&STYPE)==0) {
// numeric result
@@ -1860,7 +2192,11 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
// var was changed
glob_script_mem.type[globvindex].bits.changed=1;
if (glob_script_mem.type[globvindex].bits.is_filter) {
- Set_MFilter(glob_script_mem.type[globvindex].index,*dfvar);
+ if (globaindex>=0) {
+ Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar);
+ } else {
+ Set_MFilter(glob_script_mem.type[globvindex].index,*dfvar);
+ }
}
if (sysv_type) {
@@ -1980,8 +2316,8 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
uint8_t script_xsns_index = 0;
-void ScripterEvery100ms(void)
-{
+void ScripterEvery100ms(void) {
+
if (Settings.rule_enabled && (uptime > 4)) {
mqtt_data[0] = '\0';
uint16_t script_tele_period_save = tele_period;
@@ -2000,11 +2336,8 @@ void ScripterEvery100ms(void)
// can hold 11 floats or floats + strings
// should report overflow later
void Scripter_save_pvars(void) {
- uint32_t lptr=(uint32_t)Settings.mems[0];
int16_t mlen=0;
- lptr&=0xfffffffc;
- float *fp=(float*)lptr;
- fp++;
+ float *fp=(float*)glob_script_mem.script_pram;
mlen+=sizeof(float);
struct T_INDEX *vtp=glob_script_mem.type;
for (uint8_t count=0; count " D_RULEVARS " "
+ " " D_SCRIPT " "
"