From df1aa6dc98d79f131e0e2d9a6c7621ee1bd92143 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:54:39 +0100 Subject: [PATCH] Update Irremote lib to latest master commit ca474a6 (#24226) --- .../.github/workflows/Build.yml | 13 +- .../.github/workflows/codeql-analysis.yml | 6 +- .../IRremoteESP8266/CPPLINT.cfg | 1 + .../IRremoteESP8266/IRremoteESP8266/README.md | 5 + .../examples/IRMQTTServer/IRMQTTServer.ino | 38 +- .../examples/IRMQTTServer/platformio.ini | 2 +- .../examples/IRrecvDump/IRrecvDump.ino | 2 +- .../examples/IRrecvDumpV2/IRrecvDumpV2.ino | 2 + .../examples/IRrecvDumpV3/IRrecvDumpV3.ino | 2 + .../IRremoteESP8266/library.json | 1 + .../IRremoteESP8266/src/IRac.cpp | 1768 +++++++++-------- .../IRremoteESP8266/src/IRac.h | 17 +- .../IRremoteESP8266/src/IRrecv.cpp | 117 +- .../IRremoteESP8266/src/IRrecv.h | 16 +- .../IRremoteESP8266/src/IRremoteESP8266.h | 46 +- .../IRremoteESP8266/src/IRsend.cpp | 26 +- .../IRremoteESP8266/src/IRsend.h | 23 +- .../IRremoteESP8266/src/IRtext.cpp | 8 + .../IRremoteESP8266/src/IRtext.h | 2 + .../IRremoteESP8266/src/IRutils.cpp | 1738 ++++++++-------- .../IRremoteESP8266/src/IRutils.h | 197 +- .../IRremoteESP8266/src/ir_Airton.h | 2 +- .../IRremoteESP8266/src/ir_Argo.cpp | 54 +- .../IRremoteESP8266/src/ir_BluestarHeavy.cpp | 72 + .../IRremoteESP8266/src/ir_Bosch.cpp | 1 + .../IRremoteESP8266/src/ir_Coolix.cpp | 91 +- .../IRremoteESP8266/src/ir_Coolix.h | 44 + .../IRremoteESP8266/src/ir_Daikin.cpp | 27 +- .../IRremoteESP8266/src/ir_Daikin.h | 8 +- .../IRremoteESP8266/src/ir_Ecoclim.cpp | 2 +- .../IRremoteESP8266/src/ir_Electra.cpp | 15 +- .../IRremoteESP8266/src/ir_Electra.h | 5 +- .../IRremoteESP8266/src/ir_Eurom.cpp | 489 +++++ .../IRremoteESP8266/src/ir_Eurom.h | 244 +++ .../IRremoteESP8266/src/ir_Fujitsu.h | 1 + .../IRremoteESP8266/src/ir_GlobalCache.cpp | 3 +- .../IRremoteESP8266/src/ir_Goodweather.cpp | 2 +- .../IRremoteESP8266/src/ir_Gree.cpp | 4 +- .../IRremoteESP8266/src/ir_Haier.cpp | 38 +- .../IRremoteESP8266/src/ir_Kelon.cpp | 5 +- .../IRremoteESP8266/src/ir_Lego.cpp | 2 +- .../IRremoteESP8266/src/ir_Lutron.cpp | 2 +- .../IRremoteESP8266/src/ir_Midea.cpp | 4 +- .../IRremoteESP8266/src/ir_Mirage.cpp | 7 +- .../IRremoteESP8266/src/ir_Panasonic.cpp | 9 +- .../IRremoteESP8266/src/ir_Panasonic.h | 2 + .../IRremoteESP8266/src/ir_Pioneer.cpp | 2 +- .../IRremoteESP8266/src/ir_Pronto.cpp | 3 +- .../IRremoteESP8266/src/ir_RC5_RC6.cpp | 7 +- .../IRremoteESP8266/src/ir_RCMM.cpp | 7 +- .../IRremoteESP8266/src/ir_Samsung.cpp | 2 +- .../IRremoteESP8266/src/ir_Sanyo.cpp | 3 +- .../IRremoteESP8266/src/ir_Sharp.cpp | 8 +- .../IRremoteESP8266/src/ir_Sherwood.cpp | 3 +- .../IRremoteESP8266/src/ir_Tcl.h | 1 + .../IRremoteESP8266/src/ir_Teco.cpp | 3 +- .../IRremoteESP8266/src/ir_Toshiba.cpp | 33 +- .../IRremoteESP8266/src/ir_Toshiba.h | 11 +- .../IRremoteESP8266/src/ir_Voltas.cpp | 4 +- .../IRremoteESP8266/src/ir_Xmp.cpp | 139 +- .../IRremoteESP8266/src/locale/defaults.h | 12 + .../IRremoteESP8266/src/locale/ru-RU.h | 2 +- .../IRremoteESP8266/src/locale/sk-SK.h | 190 ++ .../IRremoteESP8266/test/IRac_test.cpp | 45 +- .../IRremoteESP8266/test/IRsend_test.cpp | 12 +- .../IRremoteESP8266/test/IRsend_test.h | 2 +- .../IRremoteESP8266/test/IRutils_test.cpp | 33 +- .../IRremoteESP8266/test/ir_Argo_test.cpp | 6 + .../IRremoteESP8266/test/ir_Coolix_test.cpp | 73 + .../IRremoteESP8266/test/ir_Electra_test.cpp | 20 +- .../IRremoteESP8266/test/ir_Eurom_test.cpp | 377 ++++ .../IRremoteESP8266/test/ir_Gorenje_test.cpp | 2 + .../IRremoteESP8266/test/ir_Gree_test.cpp | 7 +- .../IRremoteESP8266/test/ir_Toshiba_test.cpp | 43 +- .../tools/auto_analyse_raw_data.py | 11 +- .../tools/auto_analyse_raw_data_test.py | 77 +- .../IRremoteESP8266/tools/code_to_raw.cpp | 1 + .../IRremoteESP8266/tools/gc_decode.cpp | 4 +- .../IRremoteESP8266/tools/mode2_decode.cpp | 3 +- .../tools/raw_to_pronto_code.py | 10 +- .../tools/raw_to_pronto_code_test.py | 24 +- 81 files changed, 4157 insertions(+), 2186 deletions(-) create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_BluestarHeavy.cpp create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.cpp create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.h create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sk-SK.h create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Eurom_test.cpp diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml index dd4504361..f80a566bb 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml @@ -25,7 +25,7 @@ jobs: JSONI=${JSONI//$'\n'} echo $JSONI # Set output - echo "::set-output name=matrix::[${JSONI}]" + echo "matrix=[${JSONI}]" >> $GITHUB_OUTPUT Build_Example: needs: Gen_Matrix runs-on: ubuntu-latest @@ -36,19 +36,19 @@ jobs: steps: - uses: actions/checkout@v2 - name: Cache pip - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/platformio.ini') }} - name: Cache PlatformIO build - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: .pio key: pio-${{ runner.os }}-${{ matrix.project }} @@ -56,10 +56,13 @@ jobs: pio-${{ runner.os }}- pio- - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 + with: + python-version: '3.13' - name: Install PlatformIO run: | python -m pip install --upgrade pip + pip install --upgrade intelhex pip install --upgrade platformio - name: Build example env: diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/codeql-analysis.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/codeql-analysis.yml index 48500339a..10b7ebc6a 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/codeql-analysis.yml +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -56,7 +56,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -69,4 +69,4 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/CPPLINT.cfg b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/CPPLINT.cfg index 181f5204d..00d58a7ac 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/CPPLINT.cfg +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/CPPLINT.cfg @@ -1,3 +1,4 @@ set noparent root=src linelength=80 +filter=-whitespace/indent_namespace diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md index 5eac39e4b..ac3be9a54 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md @@ -77,6 +77,8 @@ If you want to [contribute](.github/CONTRIBUTING.md#how-can-i-contribute) to thi - Improve our documentation - [Creating issues](.github/CONTRIBUTING.md#reporting-bugs) and [pull requests](.github/CONTRIBUTING.md#pull-requests) - Tell other people about this library +- Updated documentation formatting and clarified installation steps (Hacktoberfest contribution by Prerna Utage) + ## Contributors Available [here](.github/Contributors.md) @@ -87,3 +89,6 @@ This library was originally based on Ken Shirriff's work (https://github.com/shi [Mark Szabo](https://github.com/crankyoldgit/IRremoteESP8266) has updated the IRsend class to work on ESP8266 and [Sebastien Warin](https://github.com/sebastienwarin/IRremoteESP8266) the receiving & decoding part (IRrecv class). As of v2.0, the library was almost entirely re-written with the ESP8266's resources in mind. + +## About This Project +This project allows decoding and encoding of IR signals for controlling Air Conditioners and other devices using ESP8266 or ESP32 boards. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino index 35a528107..8c74ccce3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino @@ -593,7 +593,7 @@ bool mountSpiffs(void) { bool saveConfig(void) { debug("Saving the config."); bool success = false; - DynamicJsonDocument json(kJsonConfigMaxSize); + JsonDocument json; #if MQTT_ENABLE json[kMqttServerKey] = MqttServer; json[kMqttPortKey] = MqttPort; @@ -611,6 +611,8 @@ bool saveConfig(void) { const String key = KEY_TX_GPIO + String(i); json[key] = static_cast(txGpioTable[i]); } + if (json.overflowed()) + debug("ERROR: no enough memory to store the entire json document"); if (mountSpiffs()) { File configFile = FILESYSTEM.open(kConfigFile, "w"); @@ -642,7 +644,7 @@ bool loadConfigFile(void) { std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); - DynamicJsonDocument json(kJsonConfigMaxSize); + JsonDocument json; if (!deserializeJson(json, buf.get(), kJsonConfigMaxSize)) { debug("Json config file parsed ok."); #if MQTT_ENABLE @@ -1659,11 +1661,13 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType, stateSize = inputLength / 2; // Every two hex chars is a byte. // Use at least the minimum size. stateSize = std::max(stateSize, - (uint16_t) (kFujitsuAcStateLengthShort - 1)); + static_cast(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)); + stateSize = std::max(stateSize, + static_cast(kFujitsuAcStateLength - 1)); // Lastly, it should never exceed the maximum "normal" size. stateSize = std::min(stateSize, kFujitsuAcStateLength); break; @@ -1675,12 +1679,12 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType, stateSize = inputLength / 2; // Every two hex chars is a byte. // Use at least the minimum size. stateSize = std::max(stateSize, - (uint16_t) (kHitachiAc3MinStateLength)); + static_cast(kHitachiAc3MinStateLength)); // If we think it isn't a "short" message. if (stateSize > kHitachiAc3MinStateLength) // Then it probably the "normal" size. stateSize = std::max(stateSize, - (uint16_t) (kHitachiAc3StateLength)); + static_cast(kHitachiAc3StateLength)); // Lastly, it should never exceed the maximum "normal" size. stateSize = std::min(stateSize, kHitachiAc3StateLength); break; @@ -1691,7 +1695,7 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType, // 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); + stateSize = std::max(stateSize, static_cast(3)); // Cap the maximum size. stateSize = std::min(stateSize, kStateSizeMax); break; @@ -1702,12 +1706,13 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType, // 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)); + stateSize = std::max(stateSize, + static_cast(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)); + stateSize = std::max( + stateSize, static_cast(kSamsungAcExtendedStateLength)); // Lastly, it should never exceed the maximum "extended" size. stateSize = std::min(stateSize, kSamsungAcExtendedStateLength); break; @@ -2671,7 +2676,8 @@ void receivingMQTT(String const topic_name, String const callback_str) { switch (ircommand[0]) { case kPauseChar: { // It's a pause. Everything after the 'P' should be a number. - int32_t msecs = std::min((int32_t) strtoul(ircommand + 1, NULL, 10), + int32_t msecs = std::min(static_cast(strtoul(ircommand + 1, + NULL, 10)), kMaxPauseMs); delay(msecs); mqtt_client.publish(MqttAck.c_str(), @@ -3142,7 +3148,7 @@ bool sendFloat(const String topic, const float_t temp, const bool retain) { #if MQTT_CLIMATE_JSON void sendJsonState(const stdAc::state_t state, const String topic, const bool retain, const bool ha_mode) { - DynamicJsonDocument json(kJsonAcStateMaxSize); + JsonDocument json; json[KEY_PROTOCOL] = typeToString(state.protocol); json[KEY_MODEL] = state.model; json[KEY_COMMAND] = IRac::commandToString(state.command); @@ -3168,6 +3174,8 @@ void sendJsonState(const stdAc::state_t state, const String topic, json[KEY_CLEAN] = IRac::boolToString(state.clean); json[KEY_BEEP] = IRac::boolToString(state.beep); json[KEY_SLEEP] = state.sleep; + if (json.overflowed()) + debug("ERROR: no enough memory to store the entire json document"); String payload = ""; payload.reserve(200); @@ -3175,16 +3183,16 @@ void sendJsonState(const stdAc::state_t state, const String topic, sendString(topic, payload, retain); } -bool validJsonStr(DynamicJsonDocument doc, const char* key) { +bool validJsonStr(JsonDocument doc, const char* key) { return doc.containsKey(key) && doc[key].is(); } -bool validJsonInt(DynamicJsonDocument doc, const char* key) { +bool validJsonInt(JsonDocument doc, const char* key) { return doc.containsKey(key) && doc[key].is(); } stdAc::state_t jsonToState(const stdAc::state_t current, const char *str) { - DynamicJsonDocument json(kJsonAcStateMaxSize); + JsonDocument json; if (deserializeJson(json, str, kJsonAcStateMaxSize)) { debug("json MQTT message did not parse. Skipping!"); return current; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/platformio.ini b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/platformio.ini index a20250c67..b43c8f87d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/platformio.ini +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/platformio.ini @@ -14,7 +14,7 @@ monitor_speed = 115200 lib_deps_builtin = lib_deps_external = PubSubClient@>=2.8.0 - ArduinoJson@>=6.0 + ArduinoJson@>=7.0 # Uncomment the following to enable SHT-3x support. # https://github.com/wemos/WEMOS_SHT3x_Arduino_Library.git diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino index 2a65cb624..cb4c9eacd 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDump/IRrecvDump.ino @@ -87,7 +87,7 @@ void dump(decode_results *results) { Serial.print(results->rawbuf[i] * kRawTick, DEC); } else { Serial.print(", "); - Serial.print((uint32_t) results->rawbuf[i] * kRawTick, DEC); + Serial.print(static_cast(results->rawbuf[i] * kRawTick), DEC); } } Serial.println("};"); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino index f0bebff12..24281677d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino @@ -130,6 +130,8 @@ decode_results results; // Somewhere to store the results void setup() { #if defined(ESP8266) Serial.begin(kBaudRate, SERIAL_8N1, SERIAL_TX_ONLY); +#elif ARDUINO_USB_CDC_ON_BOOT + Serial.begin(kBaudRate); #else // ESP8266 Serial.begin(kBaudRate, SERIAL_8N1); #endif // ESP8266 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino index 6bc054a3c..d1ec8c314 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino @@ -138,6 +138,8 @@ void setup() { OTAwifi(); // start default wifi (previously saved on the ESP) for OTA #if defined(ESP8266) Serial.begin(kBaudRate, SERIAL_8N1, SERIAL_TX_ONLY); +#elif ARDUINO_USB_CDC_ON_BOOT + Serial.begin(kBaudRate); #else // ESP8266 Serial.begin(kBaudRate, SERIAL_8N1); #endif // ESP8266 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json index 60c481152..06d0b7570 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json @@ -46,5 +46,6 @@ ], "exclude": [".github", "extras", "docs", "assets"], "frameworks": "arduino", + "libCompatMode": "strict", "platforms": ["espressif8266", "espressif32"] } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp index f6b736cdb..ea9bcbbd3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp @@ -13,6 +13,7 @@ #include #endif #include +#include #if __cplusplus >= 201103L && defined(_GLIBCXX_USE_C99_MATH_TR1) using std::roundf; #else @@ -33,6 +34,7 @@ #include "ir_Daikin.h" #include "ir_Ecoclim.h" #include "ir_Electra.h" +#include "ir_Eurom.h" #include "ir_Fujitsu.h" #include "ir_Haier.h" #include "ir_Hitachi.h" @@ -243,6 +245,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_ELECTRA_AC case decode_type_t::ELECTRA_AC: #endif +#if SEND_EUROM + case decode_type_t::EUROM: +#endif #if SEND_FUJITSU_AC case decode_type_t::FUJITSU_AC: #endif @@ -402,10 +407,8 @@ void IRac::airton(IRAirtonAc *ac, const int16_t sleep) { ac->begin(); ac->setPower(on); - ac->setTemp(degrees); - // Mode needs to be set after temp as Fan-only uses a special temp. ac->setMode(ac->convertMode(mode)); - // Fan needs to be set after mode, as setMode can change the fan speed. + ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); ac->setSwingV(swingv != stdAc::swingv_t::kOff); // No Quiet setting available. @@ -592,13 +595,19 @@ void IRac::argoWrem3_ConfigSet(IRArgoAC_WREM3 *ac, const uint8_t param, if (safe) { switch (param) { case 5: // temp. scale (note this is likely excess as not transmitted) - if (value > 1) { return; /* invalid */ } + if (value > 1) { + return; /* invalid */ + } break; case 6: // channel (note this is likely excess as not transmitted) - if (value > 3) { return; /* invalid */ } + if (value > 3) { + return; /* invalid */ + } break; case 12: // eco power limit - if (value < 30 || value > 99) { return; /* invalid */ } + if (value < 30 || value > 99) { + return; /* invalid */ + } break; default: return; /* invalid */ @@ -738,8 +747,10 @@ void IRac::coolix(IRCoolixAC *ac, ac->send(); return; } - ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); + // Mode needs to be set after temp as Fan-only uses a special temp. + ac->setMode(ac->convertMode(mode)); + // Fan needs to be set after mode, as setMode can change the fan speed. ac->setFan(ac->convertFan(fan)); // No Filter setting available. // No Beep setting available. @@ -1169,6 +1180,7 @@ void IRac::ecoclim(IREcoclimAc *ac, /// @param[in] swingv The vertical swing setting. /// @param[in] swingh The horizontal swing setting. /// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit. +/// @param[in] quiet Run the device in quiet/silent mode. /// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] lighttoggle Should we toggle the LED/Display? /// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc @@ -1177,7 +1189,8 @@ void IRac::electra(IRElectraAc *ac, const float degrees, const float sensorTemp, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool iFeel, - const bool turbo, const bool lighttoggle, const bool clean) { + const bool quiet, const bool turbo, const bool lighttoggle, + const bool clean) { ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); @@ -1188,7 +1201,7 @@ void IRac::electra(IRElectraAc *ac, ac->setFan(ac->convertFan(fan)); ac->setSwingV(swingv != stdAc::swingv_t::kOff); ac->setSwingH(swingh != stdAc::swingh_t::kOff); - // No Quiet setting available. + ac->setQuiet(quiet); ac->setTurbo(turbo); ac->setLightToggle(lighttoggle); // No Econo setting available. @@ -1202,6 +1215,31 @@ void IRac::electra(IRElectraAc *ac, } #endif // SEND_ELECTRA_AC +#if SEND_EUROM +/// Send an Eurom A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IREuromAc object to use. +/// @param[in] power The power setting. +/// @param[in] mode The operation mode setting. +/// @param[in] degrees The temperature setting in degrees, normally Celsius. +/// @param[in] fahrenheit If the given temperature is in Fahrenheit instead. +/// @param[in] fan The speed setting for the fan. +/// @param[in] swingv The swing setting. +/// @param[in] sleep The sleep mode setting. +void IRac::eurom(IREuromAc *ac, const bool power, const stdAc::opmode_t mode, + const float degrees, const bool fahrenheit, + const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, + const bool sleep) { + ac->begin(); + ac->setPower(power); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees, fahrenheit); + ac->setFan(ac->convertFan(fan)); + ac->setSwing(ac->convertSwing(swingv)); + ac->setSleep(sleep); + ac->send(); +} +#endif // SEND_EUROM + #if SEND_FUJITSU_AC /// Send a Fujitsu A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRFujitsuAC object to use. @@ -3225,11 +3263,20 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRElectraAc ac(_pin, _inverted, _modulation); electra(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed, - send.swingv, send.swingh, send.iFeel, send.turbo, send.light, - send.clean); + send.swingv, send.swingh, send.iFeel, send.quiet, send.turbo, + send.light, send.clean); break; } #endif // SEND_ELECTRA_AC +#if SEND_EUROM + case EUROM: + { + IREuromAc ac(_pin, _inverted, _modulation); + eurom(&ac, send.power, send.mode, send.degrees, !send.celsius, + send.fanspeed, send.swingv, send.sleep); + break; + } +#endif // SEND_EUROM #if SEND_FUJITSU_AC case FUJITSU_AC: { @@ -3277,8 +3324,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRHaierAC160 ac(_pin, _inverted, _modulation); haier160(&ac, send.power, send.mode, send.celsius, send.degrees, - send.fanspeed, send.swingv, send.turbo, send.filter, send.clean, - send.light, prev_light, send.sleep); + send.fanspeed, send.swingv, send.turbo, send.quiet, + send.filter, send.clean, send.light, prev_light, send.sleep); break; } #endif // SEND_HAIER_AC160 @@ -3288,7 +3335,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { IRHaierAC176 ac(_pin, _inverted, _modulation); haier176(&ac, (haier_ac176_remote_model_t)send.model, send.power, send.mode, send.celsius, send.degrees, send.fanspeed, - send.swingv, send.swingh, send.turbo, send.filter, send.sleep); + send.swingv, send.swingh, send.turbo, send.quiet, send.filter, + send.sleep); break; } #endif // SEND_HAIER_AC176 @@ -3298,7 +3346,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { IRHaierACYRW02 ac(_pin, _inverted, _modulation); haierYrwo2(&ac, send.power, send.mode, send.celsius, send.degrees, send.fanspeed, send.swingv, send.swingh, send.turbo, - send.filter, send.sleep); + send.quiet, send.filter, send.sleep); break; } #endif // SEND_HAIER_AC_YRW02 @@ -4055,1011 +4103,1035 @@ String IRac::swinghToString(const stdAc::swingh_t swingh) { } namespace IRAcUtils { - /// Display the human readable state of an A/C message if we can. - /// @param[in] result A Ptr to the captured `decode_results` that contains an - /// A/C mesg. - /// @return A string with the human description of the A/C message. - /// An empty string if we can't. - String resultAcToString(const decode_results * const result) { - switch (result->decode_type) { +/// Display the human readable state of an A/C message if we can. +/// @param[in] result A Ptr to the captured `decode_results` that contains an +/// A/C mesg. +/// @return A string with the human description of the A/C message. +/// An empty string if we can't. +String resultAcToString(const decode_results * const result) { + switch (result->decode_type) { #if DECODE_AIRTON - case decode_type_t::AIRTON: { - IRAirtonAc ac(kGpioUnused); - ac.setRaw(result->value); // AIRTON uses value instead of state. - return ac.toString(); - } + case decode_type_t::AIRTON: { + IRAirtonAc ac(kGpioUnused); + ac.setRaw(result->value); // AIRTON uses value instead of state. + return ac.toString(); + } #endif // DECODE_AIRTON #if DECODE_AIRWELL - case decode_type_t::AIRWELL: { - IRAirwellAc ac(kGpioUnused); - ac.setRaw(result->value); // AIRWELL uses value instead of state. - return ac.toString(); - } + case decode_type_t::AIRWELL: { + IRAirwellAc ac(kGpioUnused); + ac.setRaw(result->value); // AIRWELL uses value instead of state. + return ac.toString(); + } #endif // DECODE_AIRWELL #if DECODE_AMCOR - case decode_type_t::AMCOR: { - IRAmcorAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_AMCOR -#if DECODE_ARGO - case decode_type_t::ARGO: { - if (IRArgoAC_WREM3::isValidWrem3Message(result->state, result->bits, - true)) { - IRArgoAC_WREM3 ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } - IRArgoAC ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } -#endif // DECODE_ARGO -#if DECODE_BOSCH144 - case decode_type_t::BOSCH144: { - IRBosch144AC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_BOSCH144 -#if DECODE_CARRIER_AC64 - case decode_type_t::CARRIER_AC64: { - IRCarrierAc64 ac(kGpioUnused); - ac.setRaw(result->value); // CARRIER_AC64 uses value instead of state. - return ac.toString(); - } -#endif // DECODE_CARRIER_AC64 -#if DECODE_COOLIX - case decode_type_t::COOLIX: { - IRCoolixAC ac(kGpioUnused); - ac.on(); - ac.setRaw(result->value); // Coolix uses value instead of state. - return ac.toString(); - } -#endif // DECODE_COOLIX -#if DECODE_CORONA_AC - case decode_type_t::CORONA_AC: { - IRCoronaAc ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } -#endif // DECODE_CORONA_AC -#if DECODE_DAIKIN - case decode_type_t::DAIKIN: { - IRDaikinESP ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN -#if DECODE_DAIKIN128 - case decode_type_t::DAIKIN128: { - IRDaikin128 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN128 -#if DECODE_DAIKIN152 - case decode_type_t::DAIKIN152: { - IRDaikin152 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN152 -#if DECODE_DAIKIN160 - case decode_type_t::DAIKIN160: { - IRDaikin160 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN160 -#if DECODE_DAIKIN176 - case decode_type_t::DAIKIN176: { - IRDaikin176 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN160 -#if DECODE_DAIKIN2 - case decode_type_t::DAIKIN2: { - IRDaikin2 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN2 -#if DECODE_DAIKIN216 - case decode_type_t::DAIKIN216: { - IRDaikin216 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_DAIKIN216 -#if DECODE_DAIKIN64 - case decode_type_t::DAIKIN64: { - IRDaikin64 ac(kGpioUnused); - ac.setRaw(result->value); // Daikin64 uses value instead of state. - return ac.toString(); - } -#endif // DECODE_DAIKIN64 -#if DECODE_DELONGHI_AC - case decode_type_t::DELONGHI_AC: { - IRDelonghiAc ac(kGpioUnused); - ac.setRaw(result->value); // DelonghiAc uses value instead of state. - return ac.toString(); - } -#endif // DECODE_DELONGHI_AC -#if DECODE_ECOCLIM - case decode_type_t::ECOCLIM: { - if (result->bits == kEcoclimBits) { - IREcoclimAc ac(kGpioUnused); - ac.setRaw(result->value); // EcoClim uses value instead of state. - return ac.toString(); - } - return ""; - } -#endif // DECODE_ECOCLIM -#if DECODE_ELECTRA_AC - case decode_type_t::ELECTRA_AC: { - IRElectraAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_ELECTRA_AC -#if DECODE_FUJITSU_AC - case decode_type_t::FUJITSU_AC: { - IRFujitsuAC ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } -#endif // DECODE_FUJITSU_AC -#if DECODE_GOODWEATHER - case decode_type_t::GOODWEATHER: { - IRGoodweatherAc ac(kGpioUnused); - ac.setRaw(result->value); // Goodweather uses value instead of state. - return ac.toString(); - } -#endif // DECODE_GOODWEATHER -#if DECODE_GREE - case decode_type_t::GREE: { - IRGreeAC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_GREE -#if DECODE_HAIER_AC - case decode_type_t::HAIER_AC: { - IRHaierAC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC -#if DECODE_HAIER_AC160 - case decode_type_t::HAIER_AC160: { - IRHaierAC160 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC160 -#if DECODE_HAIER_AC176 - case decode_type_t::HAIER_AC176: { - IRHaierAC176 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC176 -#if DECODE_HAIER_AC_YRW02 - case decode_type_t::HAIER_AC_YRW02: { - IRHaierACYRW02 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC_YRW02 -#if DECODE_HITACHI_AC - case decode_type_t::HITACHI_AC: { - IRHitachiAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC -#if DECODE_HITACHI_AC1 - case decode_type_t::HITACHI_AC1: { - IRHitachiAc1 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC1 -#if DECODE_HITACHI_AC264 - case decode_type_t::HITACHI_AC264: { - IRHitachiAc264 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC264 -#if DECODE_HITACHI_AC296 - case decode_type_t::HITACHI_AC296: { - IRHitachiAc296 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC296 -#if DECODE_HITACHI_AC344 - case decode_type_t::HITACHI_AC344: { - IRHitachiAc344 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC344 -#if DECODE_HITACHI_AC424 - case decode_type_t::HITACHI_AC424: { - IRHitachiAc424 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC424 -#if DECODE_KELON - case decode_type_t::KELON: { - IRKelonAc ac(kGpioUnused); - ac.setRaw(result->value); - return ac.toString(); - } -#endif // DECODE_KELON -#if DECODE_KELVINATOR - case decode_type_t::KELVINATOR: { - IRKelvinatorAC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_KELVINATOR -#if DECODE_LG - case decode_type_t::LG: - case decode_type_t::LG2: { - IRLgAc ac(kGpioUnused); - ac.setRaw(result->value, result->decode_type); // Use value, not state. - return ac.isValidLgAc() ? ac.toString() : ""; - } -#endif // DECODE_LG -#if DECODE_MIDEA - case decode_type_t::MIDEA: { - IRMideaAC ac(kGpioUnused); - ac.setRaw(result->value); // Midea uses value instead of state. - return ac.toString(); - } -#endif // DECODE_MIDEA -#if DECODE_MIRAGE - case decode_type_t::MIRAGE: { - IRMirageAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_MIRAGE -#if DECODE_MITSUBISHI_AC - case decode_type_t::MITSUBISHI_AC: { - IRMitsubishiAC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_MITSUBISHI_AC -#if DECODE_MITSUBISHI112 - case decode_type_t::MITSUBISHI112: { - IRMitsubishi112 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_MITSUBISHI112 -#if DECODE_MITSUBISHI136 - case decode_type_t::MITSUBISHI136: { - IRMitsubishi136 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_MITSUBISHI136 -#if DECODE_MITSUBISHIHEAVY - case decode_type_t::MITSUBISHI_HEAVY_88: { - IRMitsubishiHeavy88Ac ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } - case decode_type_t::MITSUBISHI_HEAVY_152: { - IRMitsubishiHeavy152Ac ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_MITSUBISHIHEAVY -#if DECODE_NEOCLIMA - case decode_type_t::NEOCLIMA: { - IRNeoclimaAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_NEOCLIMA -#if DECODE_PANASONIC_AC - case decode_type_t::PANASONIC_AC: { - if (result->bits > kPanasonicAcShortBits) { - IRPanasonicAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } - return ""; - } -#endif // DECODE_PANASONIC_AC -#if DECODE_PANASONIC_AC32 - case decode_type_t::PANASONIC_AC32: { - if (result->bits >= kPanasonicAc32Bits) { - IRPanasonicAc32 ac(kGpioUnused); - ac.setRaw(result->value); // Uses value instead of state. - return ac.toString(); - } - return ""; - } -#endif // DECODE_PANASONIC_AC -#if DECODE_RHOSS - case decode_type_t::RHOSS: { - IRRhossAc ac(kGpioUnused); + case decode_type_t::AMCOR: { + IRAmcorAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } +#endif // DECODE_AMCOR +#if DECODE_ARGO + case decode_type_t::ARGO: { + if (IRArgoAC_WREM3::isValidWrem3Message(result->state, result->bits, + true)) { + IRArgoAC_WREM3 ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } + IRArgoAC ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } +#endif // DECODE_ARGO +#if DECODE_BOSCH144 + case decode_type_t::BOSCH144: { + IRBosch144AC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_BOSCH144 +#if DECODE_CARRIER_AC64 + case decode_type_t::CARRIER_AC64: { + IRCarrierAc64 ac(kGpioUnused); + ac.setRaw(result->value); // CARRIER_AC64 uses value instead of state. + return ac.toString(); + } +#endif // DECODE_CARRIER_AC64 +#if DECODE_COOLIX + case decode_type_t::COOLIX: { + IRCoolixAC ac(kGpioUnused); + ac.on(); + ac.setRaw(result->value); // Coolix uses value instead of state. + return ac.toString(); + } +#endif // DECODE_COOLIX +#if DECODE_COOLIX48 + case decode_type_t::COOLIX48: { + IRCoolixAC ac(kGpioUnused); + ac.on(); + // Coolix uses value instead of state. + ac.setRawFromCoolix48(result->value); + return ac.toString(); + } +#endif // DECODE_COOLIX +#if DECODE_CORONA_AC + case decode_type_t::CORONA_AC: { + IRCoronaAc ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } +#endif // DECODE_CORONA_AC +#if DECODE_DAIKIN + case decode_type_t::DAIKIN: { + IRDaikinESP ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN +#if DECODE_DAIKIN128 + case decode_type_t::DAIKIN128: { + IRDaikin128 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN128 +#if DECODE_DAIKIN152 + case decode_type_t::DAIKIN152: { + IRDaikin152 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN152 +#if DECODE_DAIKIN160 + case decode_type_t::DAIKIN160: { + IRDaikin160 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN160 +#if DECODE_DAIKIN176 + case decode_type_t::DAIKIN176: { + IRDaikin176 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN160 +#if DECODE_DAIKIN2 + case decode_type_t::DAIKIN2: { + IRDaikin2 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN2 +#if DECODE_DAIKIN216 + case decode_type_t::DAIKIN216: { + IRDaikin216 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN216 +#if DECODE_DAIKIN64 + case decode_type_t::DAIKIN64: { + IRDaikin64 ac(kGpioUnused); + ac.setRaw(result->value); // Daikin64 uses value instead of state. + return ac.toString(); + } +#endif // DECODE_DAIKIN64 +#if DECODE_DELONGHI_AC + case decode_type_t::DELONGHI_AC: { + IRDelonghiAc ac(kGpioUnused); + ac.setRaw(result->value); // DelonghiAc uses value instead of state. + return ac.toString(); + } +#endif // DECODE_DELONGHI_AC +#if DECODE_ECOCLIM + case decode_type_t::ECOCLIM: { + if (result->bits == kEcoclimBits) { + IREcoclimAc ac(kGpioUnused); + ac.setRaw(result->value); // EcoClim uses value instead of state. + return ac.toString(); + } + return ""; + } +#endif // DECODE_ECOCLIM +#if DECODE_ELECTRA_AC + case decode_type_t::ELECTRA_AC: { + IRElectraAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_ELECTRA_AC +#if DECODE_EUROM + case decode_type_t::EUROM: { + IREuromAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_EUROM +#if DECODE_FUJITSU_AC + case decode_type_t::FUJITSU_AC: { + IRFujitsuAC ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } +#endif // DECODE_FUJITSU_AC +#if DECODE_GOODWEATHER + case decode_type_t::GOODWEATHER: { + IRGoodweatherAc ac(kGpioUnused); + ac.setRaw(result->value); // Goodweather uses value instead of state. + return ac.toString(); + } +#endif // DECODE_GOODWEATHER +#if DECODE_GREE + case decode_type_t::GREE: { + IRGreeAC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_GREE +#if DECODE_HAIER_AC + case decode_type_t::HAIER_AC: { + IRHaierAC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC +#if DECODE_HAIER_AC160 + case decode_type_t::HAIER_AC160: { + IRHaierAC160 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC160 +#if DECODE_HAIER_AC176 + case decode_type_t::HAIER_AC176: { + IRHaierAC176 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC176 +#if DECODE_HAIER_AC_YRW02 + case decode_type_t::HAIER_AC_YRW02: { + IRHaierACYRW02 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC_YRW02 +#if DECODE_HITACHI_AC + case decode_type_t::HITACHI_AC: { + IRHitachiAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC +#if DECODE_HITACHI_AC1 + case decode_type_t::HITACHI_AC1: { + IRHitachiAc1 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC1 +#if DECODE_HITACHI_AC264 + case decode_type_t::HITACHI_AC264: { + IRHitachiAc264 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC264 +#if DECODE_HITACHI_AC296 + case decode_type_t::HITACHI_AC296: { + IRHitachiAc296 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC296 +#if DECODE_HITACHI_AC344 + case decode_type_t::HITACHI_AC344: { + IRHitachiAc344 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC344 +#if DECODE_HITACHI_AC424 + case decode_type_t::HITACHI_AC424: { + IRHitachiAc424 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC424 +#if DECODE_KELON + case decode_type_t::KELON: { + IRKelonAc ac(kGpioUnused); + ac.setRaw(result->value); + return ac.toString(); + } +#endif // DECODE_KELON +#if DECODE_KELVINATOR + case decode_type_t::KELVINATOR: { + IRKelvinatorAC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_KELVINATOR +#if DECODE_LG + case decode_type_t::LG: + case decode_type_t::LG2: { + IRLgAc ac(kGpioUnused); + ac.setRaw(result->value, result->decode_type); // Use value, not state. + return ac.isValidLgAc() ? ac.toString() : ""; + } +#endif // DECODE_LG +#if DECODE_MIDEA + case decode_type_t::MIDEA: { + IRMideaAC ac(kGpioUnused); + ac.setRaw(result->value); // Midea uses value instead of state. + return ac.toString(); + } +#endif // DECODE_MIDEA +#if DECODE_MIRAGE + case decode_type_t::MIRAGE: { + IRMirageAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MIRAGE +#if DECODE_MITSUBISHI_AC + case decode_type_t::MITSUBISHI_AC: { + IRMitsubishiAC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MITSUBISHI_AC +#if DECODE_MITSUBISHI112 + case decode_type_t::MITSUBISHI112: { + IRMitsubishi112 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MITSUBISHI112 +#if DECODE_MITSUBISHI136 + case decode_type_t::MITSUBISHI136: { + IRMitsubishi136 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MITSUBISHI136 +#if DECODE_MITSUBISHIHEAVY + case decode_type_t::MITSUBISHI_HEAVY_88: { + IRMitsubishiHeavy88Ac ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } + case decode_type_t::MITSUBISHI_HEAVY_152: { + IRMitsubishiHeavy152Ac ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MITSUBISHIHEAVY +#if DECODE_NEOCLIMA + case decode_type_t::NEOCLIMA: { + IRNeoclimaAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_NEOCLIMA +#if DECODE_PANASONIC_AC + case decode_type_t::PANASONIC_AC: { + if (result->bits > kPanasonicAcShortBits) { + IRPanasonicAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } + return ""; + } +#endif // DECODE_PANASONIC_AC +#if DECODE_PANASONIC_AC32 + case decode_type_t::PANASONIC_AC32: { + if (result->bits >= kPanasonicAc32Bits) { + IRPanasonicAc32 ac(kGpioUnused); + ac.setRaw(result->value); // Uses value instead of state. + return ac.toString(); + } + return ""; + } +#endif // DECODE_PANASONIC_AC +#if DECODE_RHOSS + case decode_type_t::RHOSS: { + IRRhossAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_RHOSS #if DECODE_SAMSUNG_AC - case decode_type_t::SAMSUNG_AC: { - IRSamsungAc ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } + case decode_type_t::SAMSUNG_AC: { + IRSamsungAc ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } #endif // DECODE_SAMSUNG_AC #if DECODE_SANYO_AC - case decode_type_t::SANYO_AC: { - IRSanyoAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::SANYO_AC: { + IRSanyoAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_SANYO_AC #if DECODE_SANYO_AC88 - case decode_type_t::SANYO_AC88: { - IRSanyoAc88 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::SANYO_AC88: { + IRSanyoAc88 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_SANYO_AC88 #if DECODE_SHARP_AC - case decode_type_t::SHARP_AC: { - IRSharpAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::SHARP_AC: { + IRSharpAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_SHARP_AC #if (DECODE_TCL112AC || DECODE_TEKNOPOINT) - case decode_type_t::TCL112AC: - case decode_type_t::TEKNOPOINT: { - IRTcl112Ac ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::TCL112AC: + case decode_type_t::TEKNOPOINT: { + IRTcl112Ac ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // (DECODE_TCL112AC || DECODE_TEKNOPOINT) #if DECODE_TECHNIBEL_AC - case decode_type_t::TECHNIBEL_AC: { - IRTechnibelAc ac(kGpioUnused); - ac.setRaw(result->value); // TechnibelAc uses value instead of state. - return ac.toString(); - } + case decode_type_t::TECHNIBEL_AC: { + IRTechnibelAc ac(kGpioUnused); + ac.setRaw(result->value); // TechnibelAc uses value instead of state. + return ac.toString(); + } #endif // DECODE_TECHNIBEL_AC #if DECODE_TECO - case decode_type_t::TECO: { - IRTecoAc ac(kGpioUnused); - ac.setRaw(result->value); // Like Coolix, use value instead of state. - return ac.toString(); - } + case decode_type_t::TECO: { + IRTecoAc ac(kGpioUnused); + ac.setRaw(result->value); // Like Coolix, use value instead of state. + return ac.toString(); + } #endif // DECODE_TECO #if DECODE_TOSHIBA_AC - case decode_type_t::TOSHIBA_AC: { - IRToshibaAC ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } + case decode_type_t::TOSHIBA_AC: { + IRToshibaAC ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } #endif // DECODE_TOSHIBA_AC #if DECODE_TRANSCOLD - case decode_type_t::TRANSCOLD: { - IRTranscoldAc ac(kGpioUnused); - ac.on(); - ac.setRaw(result->value); // TRANSCOLD uses value instead of state. - return ac.toString(); - } + case decode_type_t::TRANSCOLD: { + IRTranscoldAc ac(kGpioUnused); + ac.on(); + ac.setRaw(result->value); // TRANSCOLD uses value instead of state. + return ac.toString(); + } #endif // DECODE_TRANSCOLD #if DECODE_TROTEC - case decode_type_t::TROTEC: { - IRTrotecESP ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::TROTEC: { + IRTrotecESP ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_TROTEC #if DECODE_TROTEC_3550 - case decode_type_t::TROTEC_3550: { - IRTrotec3550 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::TROTEC_3550: { + IRTrotec3550 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_TROTEC_3550 #if DECODE_TRUMA - case decode_type_t::TRUMA: { - IRTrumaAc ac(kGpioUnused); - ac.setRaw(result->value); // Truma uses value instead of state. - return ac.toString(); - } + case decode_type_t::TRUMA: { + IRTrumaAc ac(kGpioUnused); + ac.setRaw(result->value); // Truma uses value instead of state. + return ac.toString(); + } #endif // DECODE_TRUMA #if DECODE_VESTEL_AC - case decode_type_t::VESTEL_AC: { - IRVestelAc ac(kGpioUnused); - ac.setRaw(result->value); // Like Coolix, use value instead of state. - return ac.toString(); - } + case decode_type_t::VESTEL_AC: { + IRVestelAc ac(kGpioUnused); + ac.setRaw(result->value); // Like Coolix, use value instead of state. + return ac.toString(); + } #endif // DECODE_VESTEL_AC #if DECODE_VOLTAS - case decode_type_t::VOLTAS: { - IRVoltas ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::VOLTAS: { + IRVoltas ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_VOLTAS #if DECODE_WHIRLPOOL_AC - case decode_type_t::WHIRLPOOL_AC: { - IRWhirlpoolAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } + case decode_type_t::WHIRLPOOL_AC: { + IRWhirlpoolAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } #endif // DECODE_WHIRLPOOL_AC #if DECODE_YORK - case decode_type_t::YORK: { - IRYorkAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_YORK - default: - return ""; + case decode_type_t::YORK: { + IRYorkAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); } +#endif // DECODE_YORK + default: + return ""; } +} - /// Convert a valid IR A/C remote message that we understand enough into a - /// Common A/C state. - /// @param[in] decode A PTR to a successful raw IR decode object. - /// @param[in] result A PTR to a state structure to store the result in. - /// @param[in] prev A PTR to a state structure which has the prev. state. - /// @return A boolean indicating success or failure. - bool decodeToState(const decode_results *decode, stdAc::state_t *result, - const stdAc::state_t *prev +/// Convert a valid IR A/C remote message that we understand enough into a +/// Common A/C state. +/// @param[in] decode A PTR to a successful raw IR decode object. +/// @param[in] result A PTR to a state structure to store the result in. +/// @param[in] prev A PTR to a state structure which has the prev. state. +/// @return A boolean indicating success or failure. +bool decodeToState(const decode_results *decode, stdAc::state_t *result, + const stdAc::state_t *prev /// @cond IGNORE // *prev flagged as "unused" due to potential compiler warning when some // protocols that use it are disabled. It really is used. - __attribute__((unused)) + __attribute__((unused)) /// @endcond - ) { - if (decode == NULL || result == NULL) return false; // Safety check. - switch (decode->decode_type) { + ) { + if (decode == NULL || result == NULL) return false; // Safety check. + switch (decode->decode_type) { #if DECODE_AIRTON - case decode_type_t::AIRTON: { - IRAirtonAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::AIRTON: { + IRAirtonAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_AIRTON #if DECODE_AIRWELL - case decode_type_t::AIRWELL: { - IRAirwellAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(prev); - break; - } + case decode_type_t::AIRWELL: { + IRAirwellAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(prev); + break; + } #endif // DECODE_AIRWELL #if DECODE_AMCOR - case decode_type_t::AMCOR: { - IRAmcorAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::AMCOR: { + IRAmcorAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_AMCOR #if DECODE_ARGO - case decode_type_t::ARGO: { - const uint16_t length = decode->bits / 8; - if (IRArgoAC_WREM3::isValidWrem3Message(decode->state, - decode->bits, true)) { - IRArgoAC_WREM3 ac(kGpioUnused); - ac.setRaw(decode->state, length); - *result = ac.toCommon(); - } else { - IRArgoAC ac(kGpioUnused); - switch (length) { - case kArgoStateLength: - case kArgoShortStateLength: - ac.setRaw(decode->state, length); - *result = ac.toCommon(); - break; - default: - return false; - } + case decode_type_t::ARGO: { + const uint16_t length = decode->bits / 8; + if (IRArgoAC_WREM3::isValidWrem3Message(decode->state, + decode->bits, true)) { + IRArgoAC_WREM3 ac(kGpioUnused); + ac.setRaw(decode->state, length); + *result = ac.toCommon(); + } else { + IRArgoAC ac(kGpioUnused); + switch (length) { + case kArgoStateLength: + case kArgoShortStateLength: + ac.setRaw(decode->state, length); + *result = ac.toCommon(); + break; + default: + return false; } - break; } + break; + } #endif // DECODE_ARGO #if DECODE_BOSCH144 - case decode_type_t::BOSCH144: { - IRBosch144AC ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::BOSCH144: { + IRBosch144AC ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_BOSCH144 #if DECODE_CARRIER_AC64 - case decode_type_t::CARRIER_AC64: { - IRCarrierAc64 ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::CARRIER_AC64: { + IRCarrierAc64 ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_CARRIER_AC64 #if DECODE_COOLIX - case decode_type_t::COOLIX: { - IRCoolixAC ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(prev); - break; - } + case decode_type_t::COOLIX: { + IRCoolixAC ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(prev); + break; + } #endif // DECODE_COOLIX #if DECODE_CORONA_AC - case decode_type_t::CORONA_AC: { - IRCoronaAc ac(kGpioUnused); - ac.setRaw(decode->state, decode->bits / 8); - *result = ac.toCommon(); - break; - } + case decode_type_t::CORONA_AC: { + IRCoronaAc ac(kGpioUnused); + ac.setRaw(decode->state, decode->bits / 8); + *result = ac.toCommon(); + break; + } #endif // DECODE_CARRIER_AC64 #if DECODE_DAIKIN - case decode_type_t::DAIKIN: { - IRDaikinESP ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::DAIKIN: { + IRDaikinESP ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_DAIKIN #if DECODE_DAIKIN128 - case decode_type_t::DAIKIN128: { - IRDaikin128 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::DAIKIN128: { + IRDaikin128 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_DAIKIN128 #if DECODE_DAIKIN152 - case decode_type_t::DAIKIN152: { - IRDaikin152 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::DAIKIN152: { + IRDaikin152 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_DAIKIN152 #if DECODE_DAIKIN160 - case decode_type_t::DAIKIN160: { - IRDaikin160 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::DAIKIN160: { + IRDaikin160 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_DAIKIN160 #if DECODE_DAIKIN176 - case decode_type_t::DAIKIN176: { - IRDaikin176 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::DAIKIN176: { + IRDaikin176 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_DAIKIN160 #if DECODE_DAIKIN2 - case decode_type_t::DAIKIN2: { - IRDaikin2 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::DAIKIN2: { + IRDaikin2 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_DAIKIN2 #if DECODE_DAIKIN216 - case decode_type_t::DAIKIN216: { - IRDaikin216 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::DAIKIN216: { + IRDaikin216 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_DAIKIN216 #if DECODE_DAIKIN64 - case decode_type_t::DAIKIN64: { - IRDaikin64 ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(prev); - break; - } + case decode_type_t::DAIKIN64: { + IRDaikin64 ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(prev); + break; + } #endif // DECODE_DAIKIN64 #if DECODE_DELONGHI_AC - case decode_type_t::DELONGHI_AC: { - IRDelonghiAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::DELONGHI_AC: { + IRDelonghiAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_DELONGHI_AC #if DECODE_ECOCLIM - case decode_type_t::ECOCLIM: { - if (decode->bits == kEcoclimBits) { - IREcoclimAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - } else { - return false; - } - break; + case decode_type_t::ECOCLIM: { + if (decode->bits == kEcoclimBits) { + IREcoclimAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + } else { + return false; } + break; + } #endif // DECODE_ECOCLIM #if DECODE_ELECTRA_AC - case decode_type_t::ELECTRA_AC: { - IRElectraAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::ELECTRA_AC: { + IRElectraAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_ELECTRA_AC +#if DECODE_EUROM + case decode_type_t::EUROM: { + IREuromAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_EUROM #if DECODE_FUJITSU_AC - case decode_type_t::FUJITSU_AC: { - IRFujitsuAC ac(kGpioUnused); - ac.setRaw(decode->state, decode->bits / 8); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::FUJITSU_AC: { + IRFujitsuAC ac(kGpioUnused); + ac.setRaw(decode->state, decode->bits / 8); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_FUJITSU_AC #if DECODE_GOODWEATHER - case decode_type_t::GOODWEATHER: { - IRGoodweatherAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::GOODWEATHER: { + IRGoodweatherAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_GOODWEATHER #if DECODE_GREE - case decode_type_t::GREE: { - IRGreeAC ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::GREE: { + IRGreeAC ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_GREE #if DECODE_HAIER_AC - case decode_type_t::HAIER_AC: { - IRHaierAC ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HAIER_AC: { + IRHaierAC ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HAIER_AC #if DECODE_HAIER_AC160 - case decode_type_t::HAIER_AC160: { - IRHaierAC160 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::HAIER_AC160: { + IRHaierAC160 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_HAIER_AC160 #if DECODE_HAIER_AC176 - case decode_type_t::HAIER_AC176: { - IRHaierAC176 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HAIER_AC176: { + IRHaierAC176 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HAIER_AC176 #if DECODE_HAIER_AC_YRW02 - case decode_type_t::HAIER_AC_YRW02: { - IRHaierACYRW02 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HAIER_AC_YRW02: { + IRHaierACYRW02 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HAIER_AC_YRW02 #if (DECODE_HITACHI_AC || DECODE_HITACHI_AC2) - case decode_type_t::HITACHI_AC: { - IRHitachiAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HITACHI_AC: { + IRHitachiAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // (DECODE_HITACHI_AC || DECODE_HITACHI_AC2) #if DECODE_HITACHI_AC1 - case decode_type_t::HITACHI_AC1: { - IRHitachiAc1 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HITACHI_AC1: { + IRHitachiAc1 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HITACHI_AC1 #if DECODE_HITACHI_AC264 - case decode_type_t::HITACHI_AC264: { - IRHitachiAc264 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HITACHI_AC264: { + IRHitachiAc264 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HITACHI_AC264 #if DECODE_HITACHI_AC296 - case decode_type_t::HITACHI_AC296: { - IRHitachiAc296 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HITACHI_AC296: { + IRHitachiAc296 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HITACHI_AC296 #if DECODE_HITACHI_AC344 - case decode_type_t::HITACHI_AC344: { - IRHitachiAc344 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HITACHI_AC344: { + IRHitachiAc344 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HITACHI_AC344 #if DECODE_HITACHI_AC424 - case decode_type_t::HITACHI_AC424: { - IRHitachiAc424 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::HITACHI_AC424: { + IRHitachiAc424 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_HITACHI_AC424 #if DECODE_KELON - case decode_type_t::KELON: { - IRKelonAc ac(kGpioUnused); - ac.setRaw(decode->value); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::KELON: { + IRKelonAc ac(kGpioUnused); + ac.setRaw(decode->value); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_KELON #if DECODE_KELVINATOR - case decode_type_t::KELVINATOR: { - IRKelvinatorAC ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::KELVINATOR: { + IRKelvinatorAC ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_KELVINATOR #if DECODE_LG - case decode_type_t::LG: - case decode_type_t::LG2: { - IRLgAc ac(kGpioUnused); - ac.setRaw(decode->value, decode->decode_type); // Use value, not state. - if (!ac.isValidLgAc()) return false; - *result = ac.toCommon(prev); - break; - } + case decode_type_t::LG: + case decode_type_t::LG2: { + IRLgAc ac(kGpioUnused); + ac.setRaw(decode->value, decode->decode_type); // Use value, not state. + if (!ac.isValidLgAc()) return false; + *result = ac.toCommon(prev); + break; + } #endif // DECODE_LG #if DECODE_MIDEA - case decode_type_t::MIDEA: { - IRMideaAC ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(prev); - break; - } + case decode_type_t::MIDEA: { + IRMideaAC ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(prev); + break; + } #endif // DECODE_MIDEA #if DECODE_MIRAGE - case decode_type_t::MIRAGE: { - IRMirageAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::MIRAGE: { + IRMirageAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_MIRAGE #if DECODE_MITSUBISHI_AC - case decode_type_t::MITSUBISHI_AC: { - IRMitsubishiAC ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::MITSUBISHI_AC: { + IRMitsubishiAC ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_MITSUBISHI_AC #if DECODE_MITSUBISHI112 - case decode_type_t::MITSUBISHI112: { - IRMitsubishi112 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::MITSUBISHI112: { + IRMitsubishi112 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_MITSUBISHI112 #if DECODE_MITSUBISHI136 - case decode_type_t::MITSUBISHI136: { - IRMitsubishi136 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::MITSUBISHI136: { + IRMitsubishi136 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_MITSUBISHI136 #if DECODE_MITSUBISHIHEAVY - case decode_type_t::MITSUBISHI_HEAVY_88: { - IRMitsubishiHeavy88Ac ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } - case decode_type_t::MITSUBISHI_HEAVY_152: { - IRMitsubishiHeavy152Ac ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::MITSUBISHI_HEAVY_88: { + IRMitsubishiHeavy88Ac ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } + case decode_type_t::MITSUBISHI_HEAVY_152: { + IRMitsubishiHeavy152Ac ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_MITSUBISHIHEAVY #if DECODE_NEOCLIMA - case decode_type_t::NEOCLIMA: { - IRNeoclimaAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::NEOCLIMA: { + IRNeoclimaAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_NEOCLIMA #if DECODE_PANASONIC_AC - case decode_type_t::PANASONIC_AC: { - IRPanasonicAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::PANASONIC_AC: { + IRPanasonicAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_PANASONIC_AC #if DECODE_PANASONIC_AC32 - case decode_type_t::PANASONIC_AC32: { - IRPanasonicAc32 ac(kGpioUnused); - if (decode->bits >= kPanasonicAc32Bits) { - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(prev); - } else { - return false; - } - break; + case decode_type_t::PANASONIC_AC32: { + IRPanasonicAc32 ac(kGpioUnused); + if (decode->bits >= kPanasonicAc32Bits) { + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(prev); + } else { + return false; } + break; + } #endif // DECODE_PANASONIC_AC32 #if DECODE_RHOSS - case decode_type_t::RHOSS: { - IRRhossAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::RHOSS: { + IRRhossAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_RHOSS #if DECODE_SAMSUNG_AC - case decode_type_t::SAMSUNG_AC: { - IRSamsungAc ac(kGpioUnused); - ac.setRaw(decode->state, decode->bits / 8); - *result = ac.toCommon(); - break; - } + case decode_type_t::SAMSUNG_AC: { + IRSamsungAc ac(kGpioUnused); + ac.setRaw(decode->state, decode->bits / 8); + *result = ac.toCommon(); + break; + } #endif // DECODE_SAMSUNG_AC #if DECODE_SANYO_AC - case decode_type_t::SANYO_AC: { - IRSanyoAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::SANYO_AC: { + IRSanyoAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_SANYO_AC #if DECODE_SANYO_AC88 - case decode_type_t::SANYO_AC88: { - IRSanyoAc88 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::SANYO_AC88: { + IRSanyoAc88 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_SANYO_AC88 #if DECODE_SHARP_AC - case decode_type_t::SHARP_AC: { - IRSharpAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::SHARP_AC: { + IRSharpAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_SHARP_AC #if (DECODE_TCL112AC || DECODE_TEKNOPOINT) - case decode_type_t::TCL112AC: - case decode_type_t::TEKNOPOINT: { - IRTcl112Ac ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - // Teknopoint uses the TCL protocol, but with a different model number. - // Just keep the original protocol type ... for now. - result->protocol = decode->decode_type; - break; - } + case decode_type_t::TCL112AC: + case decode_type_t::TEKNOPOINT: { + IRTcl112Ac ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + // Teknopoint uses the TCL protocol, but with a different model number. + // Just keep the original protocol type ... for now. + result->protocol = decode->decode_type; + break; + } #endif // (DECODE_TCL112AC || DECODE_TEKNOPOINT) #if DECODE_TECHNIBEL_AC - case decode_type_t::TECHNIBEL_AC: { - IRTechnibelAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::TECHNIBEL_AC: { + IRTechnibelAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_TECHNIBEL_AC #if DECODE_TECO - case decode_type_t::TECO: { - IRTecoAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::TECO: { + IRTecoAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_TECO #if DECODE_TOSHIBA_AC - case decode_type_t::TOSHIBA_AC: { - IRToshibaAC ac(kGpioUnused); - ac.setRaw(decode->state, decode->bits / 8); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::TOSHIBA_AC: { + IRToshibaAC ac(kGpioUnused); + ac.setRaw(decode->state, decode->bits / 8); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_TOSHIBA_AC #if DECODE_TRANSCOLD - case decode_type_t::TRANSCOLD: { - IRTranscoldAc ac(kGpioUnused); - ac.setRaw(decode->value); // TRANSCOLD Uses value instead of state. - *result = ac.toCommon(prev); - break; - } + case decode_type_t::TRANSCOLD: { + IRTranscoldAc ac(kGpioUnused); + ac.setRaw(decode->value); // TRANSCOLD Uses value instead of state. + *result = ac.toCommon(prev); + break; + } #endif // DECODE_TRANSCOLD #if DECODE_TROTEC - case decode_type_t::TROTEC: { - IRTrotecESP ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::TROTEC: { + IRTrotecESP ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_TROTEC #if DECODE_TROTEC_3550 - case decode_type_t::TROTEC_3550: { - IRTrotec3550 ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } + case decode_type_t::TROTEC_3550: { + IRTrotec3550 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } #endif // DECODE_TROTEC_3550 #if DECODE_TRUMA - case decode_type_t::TRUMA: { - IRTrumaAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::TRUMA: { + IRTrumaAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_TRUMA #if DECODE_VESTEL_AC - case decode_type_t::VESTEL_AC: { - IRVestelAc ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } + case decode_type_t::VESTEL_AC: { + IRVestelAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } #endif // DECODE_VESTEL_AC #if DECODE_VOLTAS - case decode_type_t::VOLTAS: { - IRVoltas ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::VOLTAS: { + IRVoltas ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_VOLTAS #if DECODE_WHIRLPOOL_AC - case decode_type_t::WHIRLPOOL_AC: { - IRWhirlpoolAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - break; - } + case decode_type_t::WHIRLPOOL_AC: { + IRWhirlpoolAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + break; + } #endif // DECODE_WHIRLPOOL_AC #if DECODE_YORK - case decode_type_t::YORK: { - IRYorkAc ac(kGpioUnused); - ac.setRaw(decode->state); - *result = ac.toCommon(prev); - break; - } -#endif // DECODE_YORK - default: - return false; + case decode_type_t::YORK: { + IRYorkAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + break; } - return true; +#endif // DECODE_YORK + default: + return false; } + return true; +} } // namespace IRAcUtils diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h index 7f4a3cf01..b95bd724b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h @@ -22,6 +22,7 @@ #include "ir_Fujitsu.h" #include "ir_Ecoclim.h" #include "ir_Electra.h" +#include "ir_Eurom.h" #include "ir_Goodweather.h" #include "ir_Gree.h" #include "ir_Haier.h" @@ -264,9 +265,15 @@ void electra(IRElectraAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const float sensorTemp, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, - const stdAc::swingh_t swingh, const bool iFeel, const bool turbo, - const bool lighttoggle, const bool clean); + const stdAc::swingh_t swingh, const bool iFeel, const bool quiet, + const bool turbo, const bool lighttoggle, const bool clean); #endif // SEND_ELECTRA_AC +#if SEND_EUROM + void eurom(IREuromAc *ac, const bool power, const stdAc::opmode_t mode, + const float degrees, const bool fahrenheit, + const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, + const bool sleep); +#endif // SEND_EUROM #if SEND_FUJITSU_AC void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, @@ -574,8 +581,8 @@ static stdAc::state_t handleToggles(const stdAc::state_t desired, /// Common functions for use with all A/Cs supported by the IRac class. namespace IRAcUtils { - String resultAcToString(const decode_results * const results); - bool decodeToState(const decode_results *decode, stdAc::state_t *result, - const stdAc::state_t *prev = NULL); +String resultAcToString(const decode_results * const results); +bool decodeToState(const decode_results *decode, stdAc::state_t *result, + const stdAc::state_t *prev = NULL); } // namespace IRAcUtils #endif // IRAC_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp index 67238bf69..8b54d981f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp @@ -13,11 +13,6 @@ extern "C" { } #endif // ESP8266 #include -#if defined(ESP32) -#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) -#include -#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 -#endif #endif // UNIT_TEST #include #ifdef UNIT_TEST @@ -61,20 +56,24 @@ static ETSTimer timer; } // namespace _IRrecv #endif // ESP8266 #if defined(ESP32) +#if ( defined(ESP_ARDUINO_VERSION) && \ + (ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)) ) +#define _ESP32_ARDUINO_CORE_V3PLUS +#endif // ESP_ARDUINO_VERSION >= 3 // We need a horrible timer hack for ESP32 Arduino framework < v2.0.0 -#if !defined(_ESP32_IRRECV_TIMER_HACK) +#if !defined(_ESP32_ARDUINO_CORE_V2PLUS) // Version check #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) // No need for the hack if we are running version >= 2.0.0 -#define _ESP32_IRRECV_TIMER_HACK false +#define _ESP32_ARDUINO_CORE_V2PLUS false #else // Version check // If no ESP_ARDUINO_VERSION_MAJOR is defined, or less than 2, then we are // using an old ESP32 core, so we need the hack. -#define _ESP32_IRRECV_TIMER_HACK true +#define _ESP32_ARDUINO_CORE_V2PLUS true #endif // Version check -#endif // !defined(_ESP32_IRRECV_TIMER_HACK) +#endif // !defined(_ESP32_ARDUINO_CORE_V2PLUS) -#if _ESP32_IRRECV_TIMER_HACK +#if _ESP32_ARDUINO_CORE_V2PLUS // Required structs/types from: // https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L28-L58 // These are needed to be able to directly manipulate the timer registers from @@ -136,10 +135,10 @@ typedef struct hw_timer_s { uint8_t timer; portMUX_TYPE lock; } hw_timer_t; -#endif // _ESP32_IRRECV_TIMER_HACK / End of Horrible Hack. +#endif // _ESP32_ARDUINO_CORE_V2PLUS / End of Horrible Hack. namespace _IRrecv { -static hw_timer_t * timer = NULL; +static hw_timer_t *timer = NULL; } // namespace _IRrecv #endif // ESP32 using _IRrecv::timer; @@ -230,31 +229,31 @@ static void USE_IRAM_ATTR gpio_intr() { #if defined(ESP32) // Reset the timeout. // -#if _ESP32_IRRECV_TIMER_HACK - // The following three lines of code are the equiv of: +#if _ESP32_ARDUINO_CORE_V2PLUS + // The following three lines of code are the equivalent of: // `timerWrite(timer, 0);` // We can't call that routine safely from inside an ISR as that procedure // is not stored in IRAM. Hence, we do it manually so that it's covered by // USE_IRAM_ATTR in this ISR. // @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1350 // @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L106-L110 - timer->dev->load_high = (uint32_t) 0; - timer->dev->load_low = (uint32_t) 0; + timer->dev->load_high = static_cast(0); + timer->dev->load_low = static_cast(0); timer->dev->reload = 1; // The next line is the same, but instead replaces: // `timerAlarmEnable(timer);` // @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1350 // @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178 timer->dev->config.alarm_en = 1; -#else // _ESP32_IRRECV_TIMER_HACK -#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) +#elif defined(_ESP32_ARDUINO_CORE_V3PLUS) + // For ESP32 core version 3.x, replace `timerAlarmEnable` timerWrite(timer, 0); - timerStart(timer); -#else // ESP_ARDUINO_VERSION_MAJOR >= 3 + uint64_t alarm_value = 50000; // Example value (50ms) + timerAlarm(timer, alarm_value, false, 0); +#else // !_ESP32_ARDUINO_CORE_V3PLUS timerWrite(timer, 0); timerAlarmEnable(timer); -#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 -#endif // _ESP32_IRRECV_TIMER_HACK +#endif // _ESP32_ARDUINO_CORE_V2PLUS #endif // ESP32 } #endif // UNIT_TEST @@ -344,10 +343,7 @@ IRrecv::IRrecv(const uint16_t recvpin, const uint16_t bufsize, IRrecv::~IRrecv(void) { disableIRIn(); #if defined(ESP32) - if (timer != NULL) { - timerEnd(timer); // Cleanup the ESP32 timeout timer. - timer = NULL; - } + if (timer != NULL) timerEnd(timer); // Cleanup the ESP32 timeout timer. #endif // ESP32 delete[] params.rawbuf; if (params_save != NULL) { @@ -371,12 +367,15 @@ void IRrecv::enableIRIn(const bool pullup) { } #if defined(ESP32) // Initialise the ESP32 timer. +#if defined(_ESP32_ARDUINO_CORE_V3PLUS) + // Use newer timerBegin signature for ESP32 core version 3.x + timer = timerBegin(1000000); // Initialize with 1MHz (1us per tick) +#else // _ESP32_ARDUINO_CORE_V3PLUS // 80MHz / 80 = 1 uSec granularity. -#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) - timer = timerBegin(1000000); // 1 MHz -#else // ESP_ARDUINO_VERSION_MAJOR >= 3 - timer = timerBegin(_timer_num, 80, true); // 1 MHz : 80 MHz with divider 80 -#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 + timer = timerBegin(_timer_num, 80, true); +#endif // _ESP32_ARDUINO_CORE_V3PLUS + + // Ensure the timer is successfully initialized #ifdef DEBUG if (timer == NULL) { DPRINT("FATAL: Unable enable system timer: "); @@ -384,17 +383,17 @@ void IRrecv::enableIRIn(const bool pullup) { } #endif // DEBUG assert(timer != NULL); // Check we actually got the timer. -#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) + // Set the timer so it only fires once, and set its trigger in microseconds. +#if defined(_ESP32_ARDUINO_CORE_V3PLUS) + timerWrite(timer, 0); // Reset the timer for ESP32 core version 3.x timerAttachInterrupt(timer, &read_timeout); - timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0); -#else // ESP_ARDUINO_VERSION_MAJOR >= 3 - // Set the timer so it only fires once, and set it's trigger in uSeconds. +#else // _ESP32_ARDUINO_CORE_V3PLUS timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE); // Note: Interrupt needs to be attached before it can be enabled or disabled. // Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713 // See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227 timerAttachInterrupt(timer, &read_timeout, false); -#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 +#endif // _ESP32_ARDUINO_CORE_V3PLUS #endif // ESP32 // Initialise state machine variables @@ -418,16 +417,14 @@ void IRrecv::disableIRIn(void) { #ifndef UNIT_TEST #if defined(ESP8266) os_timer_disarm(&timer); -#endif // ESP8266 -#if defined(ESP32) -#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) +#elif defined(_ESP32_ARDUINO_CORE_V3PLUS) + timerWrite(timer, 0); // Reset the timer timerDetachInterrupt(timer); timerEnd(timer); -#else // ESP_ARDUINO_VERSION_MAJOR >= 3 +#elif defined(ESP32) timerAlarmDisable(timer); timerDetachInterrupt(timer); timerEnd(timer); -#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 #endif // ESP32 detachInterrupt(params.recvpin); #endif // UNIT_TEST @@ -453,11 +450,13 @@ void IRrecv::resume(void) { params.rawlen = 0; params.overflow = false; #if defined(ESP32) -#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) - timerStop(timer); -#else // ESP_ARDUINO_VERSION_MAJOR >= 3 + // Check for ESP32 core version and handle timer functions differently +#if defined(_ESP32_ARDUINO_CORE_V3PLUS) + timerWrite(timer, 0); // Reset the timer (no need for timerAlarmDisable) +#else // _ESP32_ARDUINO_CORE_V3PLUS timerAlarmDisable(timer); -#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 +#endif // _ESP32_ARDUINO_CORE_V3PLUS + // Re-enable GPIO interrupt in both versions gpio_intr_enable((gpio_num_t)params.recvpin); #endif // ESP32 } @@ -1216,6 +1215,14 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting York decode"); if (decodeYork(results, offset, kYorkBits)) return true; #endif // DECODE_YORK +#if DECODE_BLUESTARHEAVY + DPRINTLN("Attempting BluestarHeavy decode"); + if (decodeBluestarHeavy(results, offset, kBluestarHeavyBits)) return true; +#endif // DECODE_BLUESTARHEAVY +#if DECODE_EUROM + DPRINTLN("Attempting Eurom decode"); + if (decodeEurom(results, offset, kEuromBits)) return true; +#endif // DECODE_EUROM // Typically new protocols are added above this line. } #if DECODE_HASH @@ -1246,9 +1253,10 @@ uint8_t IRrecv::_validTolerance(const uint8_t percentage) { uint32_t IRrecv::ticksLow(const uint32_t usecs, const uint8_t tolerance, const uint16_t delta) { // max() used to ensure the result can't drop below 0 before the cast. - return ((uint32_t)std::max( - (int32_t)(usecs * (1.0 - _validTolerance(tolerance) / 100.0) - delta), - (int32_t)0)); + return (static_cast(std::max( + static_cast(usecs * (1.0 - _validTolerance(tolerance) / 100.0) - + delta), + static_cast(0)))); } /// Calculate the upper bound of the nr. of ticks. @@ -1258,8 +1266,8 @@ uint32_t IRrecv::ticksLow(const uint32_t usecs, const uint8_t tolerance, /// @return Nr. of ticks. uint32_t IRrecv::ticksHigh(const uint32_t usecs, const uint8_t tolerance, const uint16_t delta) { - return ((uint32_t)(usecs * (1.0 + _validTolerance(tolerance) / 100.0)) + 1 + - delta); + return (static_cast(usecs * (1.0 + _validTolerance(tolerance) / + 100.0)) + 1 + delta); } /// Check if we match a pulse(measured) with the desired within @@ -1310,7 +1318,8 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired, DPRINT(". Matching: "); DPRINT(measured); DPRINT(" >= "); - DPRINT(ticksLow(std::min(desired, (uint32_t)MS_TO_USEC(params.timeout)), + DPRINT(ticksLow(std::min(desired, + static_cast(MS_TO_USEC(params.timeout))), tolerance, delta)); DPRINT(" [min("); DPRINT(ticksLow(desired, tolerance, delta)); @@ -1331,9 +1340,9 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired, // We really should never get a value of 0, except as the last value // in the buffer. If that is the case, then assume infinity and return true. if (measured == 0) return true; - return measured >= ticksLow(std::min(desired, - (uint32_t)MS_TO_USEC(params.timeout)), - tolerance, delta); + return measured >= ticksLow(std::min( + desired, static_cast(MS_TO_USEC(params.timeout))), tolerance, + delta); } /// Check if we match a mark signal(measured) with the desired within diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h index 7adf5eb1b..dabf95815 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h @@ -879,10 +879,22 @@ class IRrecv { #endif // DECODE_WOWWEE #if DECODE_YORK bool decodeYork(decode_results *results, - uint16_t kStartOffset, - const uint16_t kYorkBits, + uint16_t offset = kStartOffset, + const uint16_t nbits = kYorkBits, const bool strict = true); #endif // DECODE_YORK +#if DECODE_BLUESTARHEAVY + bool decodeBluestarHeavy(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kBluestarHeavyBits, + const bool strict = true); +#endif // DECODE_BLUESTARHEAVY +#if DECODE_EUROM + bool decodeEurom(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kEuromBits, + const bool strict = true); +#endif // DECODE_EUROM }; #endif // IRRECV_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h index 949de1ecf..4eae39076 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h @@ -952,6 +952,20 @@ #define SEND_YORK _IR_ENABLE_DEFAULT_ #endif // SEND_YORK +#ifndef DECODE_BLUESTARHEAVY +#define DECODE_BLUESTARHEAVY _IR_ENABLE_DEFAULT_ +#endif // DECODE_BLUESTARHEAVY +#ifndef SEND_BLUESTARHEAVY +#define SEND_BLUESTARHEAVY _IR_ENABLE_DEFAULT_ +#endif // SEND_BLUESTARHEAVY + +#ifndef DECODE_EUROM +#define DECODE_EUROM _IR_ENABLE_DEFAULT_ +#endif // DECODE_EUROM +#ifndef SEND_EUROM +#define SEND_EUROM _IR_ENABLE_DEFAULT_ +#endif // SEND_EUROM + #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 || \ @@ -970,7 +984,8 @@ DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \ DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \ DECODE_BOSCH144 || DECODE_SANYO_AC152 || DECODE_DAIKIN312 || \ - DECODE_CARRIER_AC84 || DECODE_YORK || \ + DECODE_CARRIER_AC84 || DECODE_YORK || DECODE_BLUESTARHEAVY || \ + DECODE_EUROM || \ false) // Add any DECODE to the above if it uses result->state (see kStateSizeMax) // you might also want to add the protocol to hasACState function @@ -1137,8 +1152,10 @@ enum decode_type_t { WOWWEE, CARRIER_AC84, // 125 YORK, + BLUESTARHEAVY, + EUROM, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = YORK, + kLastDecodeType = EUROM, }; // Message lengths & required repeat values @@ -1165,6 +1182,8 @@ const uint16_t kArgo3TimerStateLength = 9; // Bytes const uint16_t kArgo3ConfigStateLength = 4; // Bytes const uint16_t kArgoDefaultRepeat = kNoRepeat; const uint16_t kArrisBits = 32; +const uint16_t kBluestarHeavyStateLength = 13; +const uint16_t kBluestarHeavyBits = kBluestarHeavyStateLength * 8; const uint16_t kBosch144StateLength = 18; const uint16_t kBosch144Bits = kBosch144StateLength * 8; const uint16_t kCoolixBits = 24; @@ -1435,7 +1454,8 @@ const uint16_t kRhossDefaultRepeat = 0; const uint16_t kClimaButlerBits = 52; const uint16_t kYorkBits = 136; const uint16_t kYorkStateLength = 17; - +const uint16_t kEuromStateLength = 12; +const uint16_t kEuromBits = kEuromStateLength * 8; // Legacy defines. (Deprecated) #define AIWA_RC_T501_BITS kAiwaRcT501Bits @@ -1498,12 +1518,24 @@ const uint16_t kYorkStateLength = 17; #ifdef DEBUG #ifdef UNIT_TEST -#define DPRINT(x) do { std::cout << x; } while (0) -#define DPRINTLN(x) do { std::cout << x << std::endl; } while (0) +#define DPRINT(x) do { \ + std::cout << x; \ + } \ + while (0) +#define DPRINTLN(x) do { \ + std::cout << x << std::endl; \ + } \ + while (0) #endif // UNIT_TEST #ifdef ARDUINO -#define DPRINT(x) do { Serial.print(x); } while (0) -#define DPRINTLN(x) do { Serial.println(x); } while (0) +#define DPRINT(x) do { \ + Serial.print(x); \ + } \ + while (0) +#define DPRINTLN(x) do { \ + Serial.println(x); \ + } \ + while (0) #endif // ARDUINO #else // DEBUG #define DPRINT(x) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp index 10e440b32..e2427eb88 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp @@ -74,9 +74,9 @@ uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) { (1000000UL + hz / 2) / hz; // The equiv of round(1000000/hz). // Apply the offset and ensure we don't result in a <= 0 value. if (use_offset) - return std::max((uint32_t)1, period + periodOffset); + return std::max(static_cast(1), period + periodOffset); else - return std::max((uint32_t)1, period); + return std::max(static_cast(1), period); } /// Set the output frequency modulation and duty cycle. @@ -174,14 +174,16 @@ uint16_t IRsend::mark(uint16_t usec) { ledOn(); // Calculate how long we should pulse on for. // e.g. Are we to close to the end of our requested mark time (usec)? - _delayMicroseconds(std::min((uint32_t)onTimePeriod, usec - elapsed)); + _delayMicroseconds(std::min(static_cast(onTimePeriod), + usec - elapsed)); ledOff(); counter++; if (elapsed + onTimePeriod >= usec) return counter; // LED is now off & we've passed our allotted time. // Wait for the lesser of the rest of the duty cycle, or the time remaining. _delayMicroseconds( - std::min(usec - elapsed - onTimePeriod, (uint32_t)offTimePeriod)); + std::min(usec - elapsed - onTimePeriod, + static_cast(offTimePeriod))); elapsed = usecTimer.elapsed(); // Update & recache the actual elapsed time. } return counter; @@ -214,7 +216,7 @@ int8_t IRsend::calibrate(uint16_t hz) { uint32_t timeTaken = usecTimer.elapsed(); // Record the time it took. // While it shouldn't be necessary, assume at least 1 pulse, to avoid a // divide by 0 situation. - pulses = std::max(pulses, (uint16_t)1U); + pulses = std::max(pulses, static_cast(1U)); uint32_t calcPeriod = calcUSecPeriod(hz); // e.g. @38kHz it should be 26us. // Assuming 38kHz for the example calculations: // In a 65535us pulse, we should have 2520.5769 pulses @ 26us periods. @@ -719,6 +721,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kDaikin64Bits; case ELECTRA_AC: return kElectraAcBits; + case EUROM: + return kEuromBits; case GREE: return kGreeBits; case HAIER_AC: @@ -798,6 +802,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kXmpBits; case YORK: return kYorkBits; + case BLUESTARHEAVY: + return kBluestarHeavyBits; // No default amount of bits. case FUJITSU_AC: case MWM: @@ -1241,6 +1247,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendElectraAC(state, nbytes); break; #endif // SEND_ELECTRA_AC +#if SEND_EUROM + case EUROM: + sendEurom(state, nbytes); + break; +#endif // SEND_EUROM #if SEND_FUJITSU_AC case FUJITSU_AC: sendFujitsuAC(state, nbytes); @@ -1434,6 +1445,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendYork(state, nbytes); break; #endif // SEND_YORK +#if SEND_BLUESTARHEAVY + case BLUESTARHEAVY: + sendBluestarHeavy(state, nbytes); + break; +#endif // SEND_BLUESTARHEAVY default: return false; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h index 38491372a..a558001ad 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h @@ -228,6 +228,13 @@ enum argo_ac_remote_model_t { SAC_WREM3 // (2) ARGO WREM3 remote (touch buttons), bit-len vary by cmd }; +/// Toshiba A/C model numbers +enum toshiba_ac_remote_model_t { + kToshibaGenericRemote_A = 0, // Default from existing codebase + kToshibaGenericRemote_B = 1, // Newly discovered remote control b, applies to + // many remote models such as WA-TH03A, WA-TH04A etc. +}; + // Classes /// Class for sending all basic IR protocols. @@ -619,11 +626,13 @@ class IRsend { uint16_t nbytes = kCarrierAc128StateLength, uint16_t repeat = kCarrierAc128MinRepeat); #endif // SEND_CARRIER_AC128 -#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) +#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC160 || \ + SEND_HAIER_AC176) void sendHaierAC(const unsigned char data[], const uint16_t nbytes = kHaierACStateLength, const uint16_t repeat = kHaierAcDefaultRepeat); -#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) +#endif // (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC160 || + // SEND_HAIER_AC176) #if SEND_HAIER_AC_YRW02 void sendHaierACYRW02(const unsigned char data[], const uint16_t nbytes = kHaierACYRW02StateLength, @@ -885,6 +894,16 @@ class IRsend { const uint16_t nbytes = kYorkStateLength, const uint16_t repeat = kNoRepeat); #endif // SEND_YORK +#if SEND_BLUESTARHEAVY + void sendBluestarHeavy(const unsigned char data[], + const uint16_t nbytes = kBluestarHeavyStateLength, + const uint16_t repeat = kNoRepeat); +#endif // SEND_BLUESTARHEAVY +#if SEND_EUROM + void sendEurom(const uint8_t data[], + const uint16_t nbytes = kEuromStateLength, + const uint16_t repeat = kNoRepeat); +#endif // SEND_EUROM protected: #ifdef UNIT_TEST diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp index 9cb39b772..bf179da24 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp @@ -295,6 +295,10 @@ IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104" IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191" IRTEXT_CONST_STRING(kArgoWrem2Str, D_STR_ARGO_WREM2); ///< "WREM3" IRTEXT_CONST_STRING(kArgoWrem3Str, D_STR_ARGO_WREM3); ///< "WREM3" +IRTEXT_CONST_STRING(kToshibaGenericRemoteAStr, D_STR_TOSHIBAGENERICREMOTEA); +// "TOSHIBA REMOTE A" +IRTEXT_CONST_STRING(kToshibaGenericRemoteBStr, D_STR_TOSHIBAGENERICREMOTEB); +// "TOSHIBA REMOTE B" #define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as // a question mark, check for length > 1 @@ -555,6 +559,10 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) { D_STR_CARRIER_AC84, D_STR_UNSUPPORTED) "\x0" COND(DECODE_YORK || SEND_YORK, D_STR_YORK, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_BLUESTARHEAVY || SEND_BLUESTARHEAVY, + D_STR_BLUESTARHEAVY, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_EUROM || SEND_EUROM, + D_STR_EUROM, D_STR_UNSUPPORTED) "\x0" ///< New protocol (macro) strings should be added just above this line. "\x0" ///< This string requires double null termination. }; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h index 15d2690b7..cc7e900f6 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h @@ -229,6 +229,8 @@ extern IRTEXT_CONST_PTR(kSetTimerCommandStr); extern IRTEXT_CONST_PTR(kTimerStr); extern IRTEXT_CONST_PTR(kToggleStr); extern IRTEXT_CONST_PTR(kTopStr); +extern IRTEXT_CONST_PTR(kToshibaGenericRemoteAStr); +extern IRTEXT_CONST_PTR(kToshibaGenericRemoteBStr); extern IRTEXT_CONST_PTR(kTrueStr); extern IRTEXT_CONST_PTR(kTurboStr); extern IRTEXT_CONST_PTR(kTurboToggleStr); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp index e9af0b28f..a85f90d1c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp @@ -46,7 +46,7 @@ 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)); + nbits = std::min(nbits, static_cast((sizeof(input) * 8))); uint64_t output = 0; for (uint16_t i = 0; i < nbits; i++) { output <<= 1; @@ -169,6 +169,7 @@ bool hasACState(const decode_type_t protocol) { // This is kept sorted by name case AMCOR: case ARGO: + case BLUESTARHEAVY: case BOSCH144: case CARRIER_AC84: case CARRIER_AC128: @@ -183,6 +184,7 @@ bool hasACState(const decode_type_t protocol) { case DAIKIN216: case DAIKIN312: case ELECTRA_AC: + case EUROM: case FUJITSU_AC: case GREE: case HAIER_AC: @@ -527,912 +529,922 @@ float celsiusToFahrenheit(const float deg) { return (deg * 9.0) / 5.0 + 32.0; } float fahrenheitToCelsius(const float deg) { return (deg - 32.0) * 5.0 / 9.0; } namespace irutils { - /// Create a String with a colon separated "label: value" pair suitable for - /// Humans. - /// @param[in] value The value to come after the label. - /// @param[in] label The label to precede the value. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addLabeledString(const String value, const String label, - const bool precomma) { - String result = ""; - // ", " + ": " = 4 chars - result.reserve(4 + value.length() + label.length()); - if (precomma) result += kCommaSpaceStr; - result += label; - result += kColonSpaceStr; - return result + value; - } +/// Create a String with a colon separated "label: value" pair suitable for +/// Humans. +/// @param[in] value The value to come after the label. +/// @param[in] label The label to precede the value. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addLabeledString(const String value, const String label, + const bool precomma) { + String result = ""; + // ", " + ": " = 4 chars + result.reserve(4 + value.length() + label.length()); + if (precomma) result += kCommaSpaceStr; + result += label; + result += kColonSpaceStr; + return result + value; +} - /// Create a String with a colon separated flag suitable for Humans. - /// e.g. "Power: On" - /// @param[in] value The value to come after the label. - /// @param[in] label The label to precede the value. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addBoolToString(const bool value, const String label, +/// Create a String with a colon separated flag suitable for Humans. +/// e.g. "Power: On" +/// @param[in] value The value to come after the label. +/// @param[in] label The label to precede the value. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addBoolToString(const bool value, const String label, + const bool precomma) { + return addLabeledString(value ? kOnStr : kOffStr, label, precomma); +} + +/// Create a String with a colon separated toggle flag suitable for Humans. +/// e.g. "Light: Toggle", "Light: -" +/// @param[in] toggle The value of the toggle to come after the label. +/// @param[in] label The label to precede the value. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addToggleToString(const bool toggle, const String label, const bool precomma) { - return addLabeledString(value ? kOnStr : kOffStr, label, precomma); - } + return addLabeledString(toggle ? kToggleStr : kDashStr, label, precomma); +} - /// Create a String with a colon separated toggle flag suitable for Humans. - /// e.g. "Light: Toggle", "Light: -" - /// @param[in] toggle The value of the toggle to come after the label. - /// @param[in] label The label to precede the value. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addToggleToString(const bool toggle, const String label, - const bool precomma) { - return addLabeledString(toggle ? kToggleStr : kDashStr, label, precomma); - } +/// Create a String with a colon separated labeled Integer suitable for +/// Humans. +/// e.g. "Foo: 23" +/// @param[in] value The value to come after the label. +/// @param[in] label The label to precede the value. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addIntToString(const uint16_t value, const String label, + const bool precomma) { + return addLabeledString(uint64ToString(value), label, precomma); +} - /// Create a String with a colon separated labeled Integer suitable for - /// Humans. - /// e.g. "Foo: 23" - /// @param[in] value The value to come after the label. - /// @param[in] label The label to precede the value. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addIntToString(const uint16_t value, const String label, +/// Create a String with a colon separated labeled Integer suitable for +/// Humans. +/// e.g. "Foo: 23" +/// @param[in] value The value to come after the label. +/// @param[in] label The label to precede the value. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addSignedIntToString(const int16_t value, const String label, + const bool precomma) { + return addLabeledString(int64ToString(value), label, precomma); +} + + +/// Generate the model string for a given Protocol/Model pair. +/// @param[in] protocol The IR protocol. +/// @param[in] model The model number for that protocol. +/// @return The resulting String. +/// @note After adding a new model you should update IRac::strToModel() too. +String modelToStr(const decode_type_t protocol, const int16_t model) { + switch (protocol) { + case decode_type_t::FUJITSU_AC: + switch (model) { + case fujitsu_ac_remote_model_t::ARRAH2E: return kArrah2eStr; + case fujitsu_ac_remote_model_t::ARDB1: return kArdb1Str; + case fujitsu_ac_remote_model_t::ARREB1E: return kArreb1eStr; + case fujitsu_ac_remote_model_t::ARJW2: return kArjw2Str; + case fujitsu_ac_remote_model_t::ARRY4: return kArry4Str; + case fujitsu_ac_remote_model_t::ARREW4E: return kArrew4eStr; + default: return kUnknownStr; + } + break; + case decode_type_t::GREE: + switch (model) { + case gree_ac_remote_model_t::YAW1F: return kYaw1fStr; + case gree_ac_remote_model_t::YBOFB: return kYbofbStr; + case gree_ac_remote_model_t::YX1FSF: return kYx1fsfStr; + default: return kUnknownStr; + } + break; + case decode_type_t::HAIER_AC176: + switch (model) { + case haier_ac176_remote_model_t::V9014557_A: + return kV9014557AStr; + case haier_ac176_remote_model_t::V9014557_B: + return kV9014557BStr; + default: + return kUnknownStr; + } + break; + case decode_type_t::HITACHI_AC1: + switch (model) { + case hitachi_ac1_remote_model_t::R_LT0541_HTA_A: + return kRlt0541htaaStr; + case hitachi_ac1_remote_model_t::R_LT0541_HTA_B: + return kRlt0541htabStr; + default: + return kUnknownStr; + } + break; + case decode_type_t::LG: + case decode_type_t::LG2: + switch (model) { + case lg_ac_remote_model_t::GE6711AR2853M: return kGe6711ar2853mStr; + case lg_ac_remote_model_t::AKB75215403: return kAkb75215403Str; + case lg_ac_remote_model_t::AKB74955603: return kAkb74955603Str; + case lg_ac_remote_model_t::AKB73757604: return kAkb73757604Str; + case lg_ac_remote_model_t::LG6711A20083V: return kLg6711a20083vStr; + default: return kUnknownStr; + } + break; + case decode_type_t::MIRAGE: + switch (model) { + case mirage_ac_remote_model_t::KKG9AC1: return kKkg9ac1Str; + case mirage_ac_remote_model_t::KKG29AC1: return kKkg29ac1Str; + default: return kUnknownStr; + } + break; + case decode_type_t::PANASONIC_AC: + switch (model) { + case panasonic_ac_remote_model_t::kPanasonicLke: return kLkeStr; + case panasonic_ac_remote_model_t::kPanasonicNke: return kNkeStr; + case panasonic_ac_remote_model_t::kPanasonicDke: return kDkeStr; + case panasonic_ac_remote_model_t::kPanasonicJke: return kJkeStr; + case panasonic_ac_remote_model_t::kPanasonicCkp: return kCkpStr; + case panasonic_ac_remote_model_t::kPanasonicRkr: return kRkrStr; + default: return kUnknownStr; + } + break; + case decode_type_t::SHARP_AC: + switch (model) { + case sharp_ac_remote_model_t::A907: return kA907Str; + case sharp_ac_remote_model_t::A705: return kA705Str; + case sharp_ac_remote_model_t::A903: return kA903Str; + default: return kUnknownStr; + } + break; + case decode_type_t::TCL112AC: + switch (model) { + case tcl_ac_remote_model_t::TAC09CHSD: return kTac09chsdStr; + case tcl_ac_remote_model_t::GZ055BE1: return kGz055be1Str; + default: return kUnknownStr; + } + break; + case decode_type_t::VOLTAS: + switch (model) { + case voltas_ac_remote_model_t::kVoltas122LZF: return k122lzfStr; + default: return kUnknownStr; + } + break; + case decode_type_t::WHIRLPOOL_AC: + switch (model) { + case whirlpool_ac_remote_model_t::DG11J13A: return kDg11j13aStr; + case whirlpool_ac_remote_model_t::DG11J191: return kDg11j191Str; + default: return kUnknownStr; + } + break; + case decode_type_t::ARGO: + switch (model) { + case argo_ac_remote_model_t::SAC_WREM2: return kArgoWrem2Str; + case argo_ac_remote_model_t::SAC_WREM3: return kArgoWrem3Str; + default: return kUnknownStr; + } + break; + case decode_type_t::TOSHIBA_AC: + switch (model) { + case toshiba_ac_remote_model_t::kToshibaGenericRemote_A: + return kToshibaGenericRemoteAStr; + case toshiba_ac_remote_model_t::kToshibaGenericRemote_B: + return kToshibaGenericRemoteBStr; + default: + return kUnknownStr; + } + default: return kUnknownStr; + } +} + +/// Create a String of human output for a given protocol model number. +/// e.g. "Model: JKE" +/// @param[in] protocol The IR protocol. +/// @param[in] model The model number for that protocol. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addModelToString(const decode_type_t protocol, const int16_t model, const bool precomma) { - return addLabeledString(uint64ToString(value), label, precomma); - } + String result = ""; + // ", Model: NNN (BlahBlahEtc)" = ~40 chars for longest model name. + result.reserve(40); + result += addIntToString(model, kModelStr, precomma); + result += kSpaceLBraceStr; + result += modelToStr(protocol, model); + return result + ')'; +} - /// Create a String with a colon separated labeled Integer suitable for - /// Humans. - /// e.g. "Foo: 23" - /// @param[in] value The value to come after the label. - /// @param[in] label The label to precede the value. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addSignedIntToString(const int16_t value, const String label, - const bool precomma) { - return addLabeledString(int64ToString(value), label, precomma); - } +/// Create a String of human output for a given temperature. +/// e.g. "Temp: 25C" +/// @param[in] degrees The temperature in degrees. +/// @param[in] celsius Is the temp Celsius or Fahrenheit. +/// true is C, false is F +/// @param[in] precomma Should the output string start with ", " or not? +/// @param[in] isSensorTemp Is the value a room (ambient) temp. or target? +/// @return The resulting String. +String addTempToString(const uint16_t degrees, const bool celsius, + const bool precomma, const bool isSensorTemp) { + String result = addIntToString(degrees, (isSensorTemp)? + kSensorTempStr : kTempStr, precomma); + result += celsius ? 'C' : 'F'; + return result; +} +/// Create a String of human output for a given temperature. +/// e.g. "Temp: 25.5C" +/// @param[in] degrees The temperature in degrees. +/// @param[in] celsius Is the temp Celsius or Fahrenheit. +/// true is C, false is F +/// @param[in] precomma Should the output string start with ", " or not? +/// @param[in] isSensorTemp Is the value a room (ambient) temp. or target? +/// @return The resulting String. +String addTempFloatToString(const float degrees, const bool celsius, + const bool precomma, const bool isSensorTemp) { + String result = ""; + result.reserve(21); // Assuming ", Sensor Temp: XXX.5F" is the largest. + result += addIntToString(degrees, (isSensorTemp)? + kSensorTempStr : kTempStr, precomma); + // Is it a half degree? + if (static_cast(2 * degrees) & 1) + result += F(".5"); + result += celsius ? 'C' : 'F'; + return result; +} - /// Generate the model string for a given Protocol/Model pair. - /// @param[in] protocol The IR protocol. - /// @param[in] model The model number for that protocol. - /// @return The resulting String. - /// @note After adding a new model you should update IRac::strToModel() too. - String modelToStr(const decode_type_t protocol, const int16_t model) { - switch (protocol) { - case decode_type_t::FUJITSU_AC: - switch (model) { - case fujitsu_ac_remote_model_t::ARRAH2E: return kArrah2eStr; - case fujitsu_ac_remote_model_t::ARDB1: return kArdb1Str; - case fujitsu_ac_remote_model_t::ARREB1E: return kArreb1eStr; - case fujitsu_ac_remote_model_t::ARJW2: return kArjw2Str; - case fujitsu_ac_remote_model_t::ARRY4: return kArry4Str; - case fujitsu_ac_remote_model_t::ARREW4E: return kArrew4eStr; - default: return kUnknownStr; - } - break; - case decode_type_t::GREE: - switch (model) { - case gree_ac_remote_model_t::YAW1F: return kYaw1fStr; - case gree_ac_remote_model_t::YBOFB: return kYbofbStr; - case gree_ac_remote_model_t::YX1FSF: return kYx1fsfStr; - default: return kUnknownStr; - } - break; - case decode_type_t::HAIER_AC176: - switch (model) { - case haier_ac176_remote_model_t::V9014557_A: - return kV9014557AStr; - case haier_ac176_remote_model_t::V9014557_B: - return kV9014557BStr; - default: - return kUnknownStr; - } - break; - case decode_type_t::HITACHI_AC1: - switch (model) { - case hitachi_ac1_remote_model_t::R_LT0541_HTA_A: - return kRlt0541htaaStr; - case hitachi_ac1_remote_model_t::R_LT0541_HTA_B: - return kRlt0541htabStr; - default: - return kUnknownStr; - } - break; - case decode_type_t::LG: - case decode_type_t::LG2: - switch (model) { - case lg_ac_remote_model_t::GE6711AR2853M: return kGe6711ar2853mStr; - case lg_ac_remote_model_t::AKB75215403: return kAkb75215403Str; - case lg_ac_remote_model_t::AKB74955603: return kAkb74955603Str; - case lg_ac_remote_model_t::AKB73757604: return kAkb73757604Str; - case lg_ac_remote_model_t::LG6711A20083V: return kLg6711a20083vStr; - default: return kUnknownStr; - } - break; - case decode_type_t::MIRAGE: - switch (model) { - case mirage_ac_remote_model_t::KKG9AC1: return kKkg9ac1Str; - case mirage_ac_remote_model_t::KKG29AC1: return kKkg29ac1Str; - default: return kUnknownStr; - } - break; - case decode_type_t::PANASONIC_AC: - switch (model) { - case panasonic_ac_remote_model_t::kPanasonicLke: return kLkeStr; - case panasonic_ac_remote_model_t::kPanasonicNke: return kNkeStr; - case panasonic_ac_remote_model_t::kPanasonicDke: return kDkeStr; - case panasonic_ac_remote_model_t::kPanasonicJke: return kJkeStr; - case panasonic_ac_remote_model_t::kPanasonicCkp: return kCkpStr; - case panasonic_ac_remote_model_t::kPanasonicRkr: return kRkrStr; - default: return kUnknownStr; - } - break; - case decode_type_t::SHARP_AC: - switch (model) { - case sharp_ac_remote_model_t::A907: return kA907Str; - case sharp_ac_remote_model_t::A705: return kA705Str; - case sharp_ac_remote_model_t::A903: return kA903Str; - default: return kUnknownStr; - } - break; - case decode_type_t::TCL112AC: - switch (model) { - case tcl_ac_remote_model_t::TAC09CHSD: return kTac09chsdStr; - case tcl_ac_remote_model_t::GZ055BE1: return kGz055be1Str; - default: return kUnknownStr; - } - break; - case decode_type_t::VOLTAS: - switch (model) { - case voltas_ac_remote_model_t::kVoltas122LZF: return k122lzfStr; - default: return kUnknownStr; - } - break; - case decode_type_t::WHIRLPOOL_AC: - switch (model) { - case whirlpool_ac_remote_model_t::DG11J13A: return kDg11j13aStr; - case whirlpool_ac_remote_model_t::DG11J191: return kDg11j191Str; - default: return kUnknownStr; - } - break; - case decode_type_t::ARGO: - switch (model) { - case argo_ac_remote_model_t::SAC_WREM2: return kArgoWrem2Str; - case argo_ac_remote_model_t::SAC_WREM3: return kArgoWrem3Str; - default: return kUnknownStr; - } - break; - default: return kUnknownStr; - } - } +/// Create a String of human output for the given operating mode. +/// e.g. "Mode: 1 (Cool)" +/// @param[in] mode The operating mode to display. +/// @param[in] automatic The numeric value for Auto mode. +/// @param[in] cool The numeric value for Cool mode. +/// @param[in] heat The numeric value for Heat mode. +/// @param[in] dry The numeric value for Dry mode. +/// @param[in] fan The numeric value for Fan mode. +/// @return The resulting String. +String addModeToString(const uint8_t mode, const uint8_t automatic, + const uint8_t cool, const uint8_t heat, + const uint8_t dry, const uint8_t fan) { + String result = ""; + result.reserve(22); // ", Mode: NNN (UNKNOWN)" + result += addIntToString(mode, kModeStr); + result += kSpaceLBraceStr; + if (mode == automatic) result += kAutoStr; + else if (mode == cool) result += kCoolStr; + else if (mode == heat) result += kHeatStr; + else if (mode == dry) result += kDryStr; + else if (mode == fan) result += kFanStr; + else + result += kUnknownStr; + return result + ')'; +} - /// Create a String of human output for a given protocol model number. - /// e.g. "Model: JKE" - /// @param[in] protocol The IR protocol. - /// @param[in] model The model number for that protocol. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addModelToString(const decode_type_t protocol, const int16_t model, - const bool precomma) { - String result = ""; - // ", Model: NNN (BlahBlahEtc)" = ~40 chars for longest model name. - result.reserve(40); - result += addIntToString(model, kModelStr, precomma); - result += kSpaceLBraceStr; - result += modelToStr(protocol, model); - return result + ')'; - } +/// Create a String of the 3-letter day of the week from a numerical day of +/// the week. e.g. "Day: 1 (Mon)" +/// @param[in] day_of_week A numerical version of the sequential day of the +/// week. e.g. Saturday = 7 etc. +/// @param[in] offset Days to offset by. +/// e.g. For different day starting the week. +/// @param[in] precomma Should the output string start with ", " or not? +/// @return The resulting String. +String addDayToString(const uint8_t day_of_week, const int8_t offset, + const bool precomma) { + String result = ""; + result.reserve(19); // ", Day: N (UNKNOWN)" + result += addIntToString(day_of_week, kDayStr, precomma); + result += kSpaceLBraceStr; + result += dayToString(day_of_week, offset); + return result + ')'; +} - /// Create a String of human output for a given temperature. - /// e.g. "Temp: 25C" - /// @param[in] degrees The temperature in degrees. - /// @param[in] celsius Is the temp Celsius or Fahrenheit. - /// true is C, false is F - /// @param[in] precomma Should the output string start with ", " or not? - /// @param[in] isSensorTemp Is the value a room (ambient) temp. or target? - /// @return The resulting String. - String addTempToString(const uint16_t degrees, const bool celsius, - const bool precomma, const bool isSensorTemp) { - String result = addIntToString(degrees, (isSensorTemp)? - kSensorTempStr : kTempStr, precomma); - result += celsius ? 'C' : 'F'; - return result; - } - - /// Create a String of human output for a given temperature. - /// e.g. "Temp: 25.5C" - /// @param[in] degrees The temperature in degrees. - /// @param[in] celsius Is the temp Celsius or Fahrenheit. - /// true is C, false is F - /// @param[in] precomma Should the output string start with ", " or not? - /// @param[in] isSensorTemp Is the value a room (ambient) temp. or target? - /// @return The resulting String. - String addTempFloatToString(const float degrees, const bool celsius, - const bool precomma, const bool isSensorTemp) { - String result = ""; - result.reserve(21); // Assuming ", Sensor Temp: XXX.5F" is the largest. - result += addIntToString(degrees, (isSensorTemp)? - kSensorTempStr : kTempStr, precomma); - // Is it a half degree? - if (((uint16_t)(2 * degrees)) & 1) result += F(".5"); - result += celsius ? 'C' : 'F'; - return result; - } - - /// Create a String of human output for the given operating mode. - /// e.g. "Mode: 1 (Cool)" - /// @param[in] mode The operating mode to display. - /// @param[in] automatic The numeric value for Auto mode. - /// @param[in] cool The numeric value for Cool mode. - /// @param[in] heat The numeric value for Heat mode. - /// @param[in] dry The numeric value for Dry mode. - /// @param[in] fan The numeric value for Fan mode. - /// @return The resulting String. - String addModeToString(const uint8_t mode, const uint8_t automatic, - const uint8_t cool, const uint8_t heat, - const uint8_t dry, const uint8_t fan) { - String result = ""; - result.reserve(22); // ", Mode: NNN (UNKNOWN)" - result += addIntToString(mode, kModeStr); - result += kSpaceLBraceStr; - if (mode == automatic) result += kAutoStr; - else if (mode == cool) result += kCoolStr; - else if (mode == heat) result += kHeatStr; - else if (mode == dry) result += kDryStr; - else if (mode == fan) result += kFanStr; - else - result += kUnknownStr; - return result + ')'; - } - - /// Create a String of the 3-letter day of the week from a numerical day of - /// the week. e.g. "Day: 1 (Mon)" - /// @param[in] day_of_week A numerical version of the sequential day of the - /// week. e.g. Saturday = 7 etc. - /// @param[in] offset Days to offset by. - /// e.g. For different day starting the week. - /// @param[in] precomma Should the output string start with ", " or not? - /// @return The resulting String. - String addDayToString(const uint8_t day_of_week, const int8_t offset, - const bool precomma) { - String result = ""; - result.reserve(19); // ", Day: N (UNKNOWN)" - result += addIntToString(day_of_week, kDayStr, precomma); - result += kSpaceLBraceStr; - result += dayToString(day_of_week, offset); - return result + ')'; - } - - /// Create a String of the 3-letter day of the week from a numerical day of - /// the week. e.g. "Mon" - /// @param[in] day_of_week A numerical version of the sequential day of the - /// week. e.g. Sunday = 1, Monday = 2, ..., Saturday = 7 - /// @param[in] offset Days to offset by. - /// e.g. For different day starting the week. - /// @return The resulting String. - String dayToString(const uint8_t day_of_week, const int8_t offset) { - if ((uint8_t)(day_of_week + offset) < 7) +/// Create a String of the 3-letter day of the week from a numerical day of +/// the week. e.g. "Mon" +/// @param[in] day_of_week A numerical version of the sequential day of the +/// week. e.g. Sunday = 1, Monday = 2, ..., Saturday = 7 +/// @param[in] offset Days to offset by. +/// e.g. For different day starting the week. +/// @return The resulting String. +String dayToString(const uint8_t day_of_week, const int8_t offset) { + if ((uint8_t)(day_of_week + offset) < 7) #if UNIT_TEST - return String(kThreeLetterDayOfWeekStr).substr( - (day_of_week + offset) * 3, 3); + return String(kThreeLetterDayOfWeekStr).substr( + (day_of_week + offset) * 3, 3); #else // UNIT_TEST - return String(kThreeLetterDayOfWeekStr).substring( - (day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3); + return String(kThreeLetterDayOfWeekStr).substring( + (day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3); #endif // UNIT_TEST - else - return kUnknownStr; + else + return kUnknownStr; +} + +/// Create a String of human output for the given fan speed. +/// e.g. "Fan: 0 (Auto)" +/// @param[in] speed The numeric speed of the fan to display. +/// @param[in] high The numeric value for High speed. (second highest) +/// @param[in] low The numeric value for Low speed. +/// @param[in] automatic The numeric value for Auto speed. +/// @param[in] quiet The numeric value for Quiet speed. +/// @param[in] medium The numeric value for Medium speed. +/// @param[in] maximum The numeric value for Highest speed. (if > high) +/// @param[in] medium_high The numeric value for third-highest speed. +/// (if > medium) +/// @return The resulting String. +String addFanToString(const uint8_t speed, const uint8_t high, + const uint8_t low, const uint8_t automatic, + const uint8_t quiet, const uint8_t medium, + const uint8_t maximum, const uint8_t medium_high) { + String result = ""; + result.reserve(21); // ", Fan: NNN (UNKNOWN)" + result += addIntToString(speed, kFanStr); + result += kSpaceLBraceStr; + if (speed == high) result += kHighStr; + else if (speed == low) result += kLowStr; + else if (speed == automatic) result += kAutoStr; + else if (speed == quiet) result += kQuietStr; + else if (speed == medium) result += kMediumStr; + else if (speed == maximum) result += kMaximumStr; + else if (speed == medium_high) result += kMedHighStr; + else + result += kUnknownStr; + return result + ')'; +} + +/// Create a String of human output for the given horizontal swing setting. +/// e.g. "Swing(H): 0 (Auto)" +/// @param[in] position The numeric position of the swing to display. +/// @param[in] automatic The numeric value for Auto position. +/// @param[in] maxleft The numeric value for most left position. +/// @param[in] left The numeric value for Left position. +/// @param[in] middle The numeric value for Middle position. +/// @param[in] right The numeric value for Right position. +/// @param[in] maxright The numeric value for most right position. +/// @param[in] off The numeric value for Off position. +/// @param[in] leftright The numeric value for "left right" position. +/// @param[in] rightleft The numeric value for "right left" position. +/// @param[in] threed The numeric value for 3D setting. +/// @param[in] wide The numeric value for Wide position. +/// @return The resulting String. +String addSwingHToString(const uint8_t position, const uint8_t automatic, + const uint8_t maxleft, const uint8_t left, + const uint8_t middle, + const uint8_t right, const uint8_t maxright, + const uint8_t off, + const uint8_t leftright, const uint8_t rightleft, + const uint8_t threed, const uint8_t wide) { + String result = ""; + result.reserve(30); // ", Swing(H): NNN (Left Right)" + result += addIntToString(position, kSwingHStr); + result += kSpaceLBraceStr; + if (position == automatic) { + result += kAutoStr; + } else if (position == left) { + result += kLeftStr; + } else if (position == middle) { + result += kMiddleStr; + } else if (position == right) { + result += kRightStr; + } else if (position == maxleft) { + result += kMaxLeftStr; + } else if (position == maxright) { + result += kMaxRightStr; + } else if (position == off) { + result += kOffStr; + } else if (position == leftright) { + result += kLeftStr; + result += ' '; + result += kRightStr; + } else if (position == rightleft) { + result += kRightStr; + result += ' '; + result += kLeftStr; + } else if (position == threed) { + result += k3DStr; + } else if (position == wide) { + result += kWideStr; + } else { + result += kUnknownStr; } + return result + ')'; +} - /// Create a String of human output for the given fan speed. - /// e.g. "Fan: 0 (Auto)" - /// @param[in] speed The numeric speed of the fan to display. - /// @param[in] high The numeric value for High speed. (second highest) - /// @param[in] low The numeric value for Low speed. - /// @param[in] automatic The numeric value for Auto speed. - /// @param[in] quiet The numeric value for Quiet speed. - /// @param[in] medium The numeric value for Medium speed. - /// @param[in] maximum The numeric value for Highest speed. (if > high) - /// @param[in] medium_high The numeric value for third-highest speed. - /// (if > medium) - /// @return The resulting String. - String addFanToString(const uint8_t speed, const uint8_t high, - const uint8_t low, const uint8_t automatic, - const uint8_t quiet, const uint8_t medium, - const uint8_t maximum, const uint8_t medium_high) { - String result = ""; - result.reserve(21); // ", Fan: NNN (UNKNOWN)" - result += addIntToString(speed, kFanStr); - result += kSpaceLBraceStr; - if (speed == high) result += kHighStr; - else if (speed == low) result += kLowStr; - else if (speed == automatic) result += kAutoStr; - else if (speed == quiet) result += kQuietStr; - else if (speed == medium) result += kMediumStr; - else if (speed == maximum) result += kMaximumStr; - else if (speed == medium_high) result += kMedHighStr; - else - result += kUnknownStr; - return result + ')'; +/// Create a String of human output for the given vertical swing setting. +/// e.g. "Swing(V): 0 (Auto)" +/// @param[in] position The numeric position of the swing to display. +/// @param[in] automatic The numeric value for Auto position. +/// @param[in] highest The numeric value for Highest position. +/// @param[in] high The numeric value for High position. +/// @param[in] uppermiddle The numeric value for Upper Middle position. +/// @param[in] middle The numeric value for Middle position. +/// @param[in] lowermiddle The numeric value for Lower Middle position. +/// @param[in] low The numeric value for Low position. +/// @param[in] lowest The numeric value for Low position. +/// @param[in] off The numeric value for Off position. +/// @param[in] swing The numeric value for Swing setting. +/// @param[in] breeze The numeric value for Breeze setting. +/// @param[in] circulate The numeric value for Circulate setting. +/// @return The resulting String. +String addSwingVToString(const uint8_t position, const uint8_t automatic, + const uint8_t highest, const uint8_t high, + const uint8_t uppermiddle, + const uint8_t middle, + const uint8_t lowermiddle, + const uint8_t low, const uint8_t lowest, + const uint8_t off, const uint8_t swing, + const uint8_t breeze, const uint8_t circulate) { + String result = ""; + result.reserve(31); // ", Swing(V): NNN (Upper Middle)" + result += addIntToString(position, kSwingVStr); + result += kSpaceLBraceStr; + if (position == automatic) { + result += kAutoStr; + } else if (position == highest) { + result += kHighestStr; + } else if (position == high) { + result += kHighStr; + } else if (position == middle) { + result += kMiddleStr; + } else if (position == low) { + result += kLowStr; + } else if (position == lowest) { + result += kLowestStr; + } else if (position == off) { + result += kOffStr; + } else if (position == uppermiddle) { + result += kUpperStr; + result += ' '; + result += kMiddleStr; + } else if (position == lowermiddle) { + result += kLowerStr; + result += ' '; + result += kMiddleStr; + } else if (position == swing) { + result += kSwingStr; + } else if (position == breeze) { + result += kBreezeStr; + } else if (position == circulate) { + result += kCirculateStr; + } else { + result += kUnknownStr; } + return result + ')'; +} - /// Create a String of human output for the given horizontal swing setting. - /// e.g. "Swing(H): 0 (Auto)" - /// @param[in] position The numeric position of the swing to display. - /// @param[in] automatic The numeric value for Auto position. - /// @param[in] maxleft The numeric value for most left position. - /// @param[in] left The numeric value for Left position. - /// @param[in] middle The numeric value for Middle position. - /// @param[in] right The numeric value for Right position. - /// @param[in] maxright The numeric value for most right position. - /// @param[in] off The numeric value for Off position. - /// @param[in] leftright The numeric value for "left right" position. - /// @param[in] rightleft The numeric value for "right left" position. - /// @param[in] threed The numeric value for 3D setting. - /// @param[in] wide The numeric value for Wide position. - /// @return The resulting String. - String addSwingHToString(const uint8_t position, const uint8_t automatic, - const uint8_t maxleft, const uint8_t left, - const uint8_t middle, - const uint8_t right, const uint8_t maxright, - const uint8_t off, - const uint8_t leftright, const uint8_t rightleft, - const uint8_t threed, const uint8_t wide) { - String result = ""; - result.reserve(30); // ", Swing(H): NNN (Left Right)" - result += addIntToString(position, kSwingHStr); - result += kSpaceLBraceStr; - if (position == automatic) { - result += kAutoStr; - } else if (position == left) { - result += kLeftStr; - } else if (position == middle) { - result += kMiddleStr; - } else if (position == right) { - result += kRightStr; - } else if (position == maxleft) { - result += kMaxLeftStr; - } else if (position == maxright) { - result += kMaxRightStr; - } else if (position == off) { - result += kOffStr; - } else if (position == leftright) { - result += kLeftStr; - result += ' '; - result += kRightStr; - } else if (position == rightleft) { - result += kRightStr; - result += ' '; - result += kLeftStr; - } else if (position == threed) { - result += k3DStr; - } else if (position == wide) { - result += kWideStr; - } else { - result += kUnknownStr; - } - return result + ')'; +/// @brief Create a String of human output for the given timer setting. +/// e.g. "Timer Mode: 2 (Schedule 1)" +/// @param[in] timerMode The numeric value of the timer mode to display. +/// @param[in] noTimer The numeric value for no timer (off) +/// @param[in] delayTimer The numeric value for delay (sleep) timer +/// @param[in] schedule1 The numeric value for schedule timer #1 +/// @param[in] schedule2 The numeric value for schedule timer #2 +/// @param[in] schedule3 The numeric value for schedule timer #3 +/// @param[in] precomma Should the output string start with ", " or not? +/// @return String representation +String addTimerModeToString(const uint8_t timerMode, const uint8_t noTimer, + const uint8_t delayTimer, const uint8_t schedule1, + const uint8_t schedule2, const uint8_t schedule3, + const bool precomma) { + String result = ""; + result.reserve(28); // ", Timer Mode: 2 (Schedule 1)" + result += addIntToString(timerMode, kTimerModeStr, precomma); + result += kSpaceLBraceStr; + if (timerMode == noTimer) { + result += kOffStr; + } else if (timerMode == delayTimer) { + result += kSleepTimerStr; + } else if (timerMode == schedule1) { + result += kScheduleStr; + result += '1'; + } else if (timerMode == schedule2) { + result += kScheduleStr; + result += '2'; + } else if (timerMode == schedule3) { + result += kScheduleStr; + result += '3'; + } else { + result += kUnknownStr; } + return result + ')'; +} - /// Create a String of human output for the given vertical swing setting. - /// e.g. "Swing(V): 0 (Auto)" - /// @param[in] position The numeric position of the swing to display. - /// @param[in] automatic The numeric value for Auto position. - /// @param[in] highest The numeric value for Highest position. - /// @param[in] high The numeric value for High position. - /// @param[in] uppermiddle The numeric value for Upper Middle position. - /// @param[in] middle The numeric value for Middle position. - /// @param[in] lowermiddle The numeric value for Lower Middle position. - /// @param[in] low The numeric value for Low position. - /// @param[in] lowest The numeric value for Low position. - /// @param[in] off The numeric value for Off position. - /// @param[in] swing The numeric value for Swing setting. - /// @param[in] breeze The numeric value for Breeze setting. - /// @param[in] circulate The numeric value for Circulate setting. - /// @return The resulting String. - String addSwingVToString(const uint8_t position, const uint8_t automatic, - const uint8_t highest, const uint8_t high, - const uint8_t uppermiddle, - const uint8_t middle, - const uint8_t lowermiddle, - const uint8_t low, const uint8_t lowest, - const uint8_t off, const uint8_t swing, - const uint8_t breeze, const uint8_t circulate) { - String result = ""; - result.reserve(31); // ", Swing(V): NNN (Upper Middle)" - result += addIntToString(position, kSwingVStr); - result += kSpaceLBraceStr; - if (position == automatic) { - result += kAutoStr; - } else if (position == highest) { - result += kHighestStr; - } else if (position == high) { - result += kHighStr; - } else if (position == middle) { - result += kMiddleStr; - } else if (position == low) { - result += kLowStr; - } else if (position == lowest) { - result += kLowestStr; - } else if (position == off) { - result += kOffStr; - } else if (position == uppermiddle) { - result += kUpperStr; - result += ' '; - result += kMiddleStr; - } else if (position == lowermiddle) { - result += kLowerStr; - result += ' '; - result += kMiddleStr; - } else if (position == swing) { - result += kSwingStr; - } else if (position == breeze) { - result += kBreezeStr; - } else if (position == circulate) { - result += kCirculateStr; - } else { - result += kUnknownStr; - } - return result + ')'; +/// @brief Create a String of human output for the given channel +/// e.g. "[CH#0]" +/// @param channel The numeric value of the channel to display. +/// @return String representation +String channelToString(const uint8_t channel) { + String result = ""; + result.reserve(6); // "[CH#4]" + result += "["; + result += kChStr; + result += uint64ToString(channel); + result += "]"; + return result; +} + +/// @brief Create a String of human output for the given command type +/// e.g. "IFeel Report" +/// @param irCommandType The numeric value of the command type to display. +/// @param acControlCmd The numeric value of the "control" (default) command +/// @param iFeelReportCmd The numeric value of the sensor temperature command +/// @param timerCmd The numeric value of the timer config IR command +/// @param configCmd The numeric value of the config param set IR command +/// @return String representation +String irCommandTypeToString(uint8_t irCommandType, uint8_t acControlCmd, + uint8_t iFeelReportCmd, uint8_t timerCmd, + uint8_t configCmd) { + String result = ""; + result.reserve(12); // "IFeel Report" + if (irCommandType == acControlCmd) { + result += kCommandStr; + } else if (irCommandType == iFeelReportCmd) { + result += kIFeelReportStr; + } else if (irCommandType == timerCmd) { + result += kTimerStr; + } else if (irCommandType == configCmd) { + result += kConfigCommandStr; + } else { + result += kUnknownStr; } + return result; +} - /// @brief Create a String of human output for the given timer setting. - /// e.g. "Timer Mode: 2 (Schedule 1)" - /// @param[in] timerMode The numeric value of the timer mode to display. - /// @param[in] noTimer The numeric value for no timer (off) - /// @param[in] delayTimer The numeric value for delay (sleep) timer - /// @param[in] schedule1 The numeric value for schedule timer #1 - /// @param[in] schedule2 The numeric value for schedule timer #2 - /// @param[in] schedule3 The numeric value for schedule timer #3 - /// @param[in] precomma Should the output string start with ", " or not? - /// @return String representation - String addTimerModeToString(const uint8_t timerMode, const uint8_t noTimer, - const uint8_t delayTimer, const uint8_t schedule1, - const uint8_t schedule2, const uint8_t schedule3, - const bool precomma) { - String result = ""; - result.reserve(28); // ", Timer Mode: 2 (Schedule 1)" - result += addIntToString(timerMode, kTimerModeStr, precomma); - result += kSpaceLBraceStr; - if (timerMode == noTimer) { - result += kOffStr; - } else if (timerMode == delayTimer) { - result += kSleepTimerStr; - } else if (timerMode == schedule1) { - result += kScheduleStr; - result += '1'; - } else if (timerMode == schedule2) { - result += kScheduleStr; - result += '2'; - } else if (timerMode == schedule3) { - result += kScheduleStr; - result += '3'; - } else { - result += kUnknownStr; - } - return result + ')'; - } +/// @brief Create a String of the 3-letter day of the week bitmap +// e.g. 0b0000101 is "Sun | Tue" +/// @param[in] daysBitmap The bitmap representing days of week to represent +/// e.g bit[0]=Sunday, bit[1]=Monday, ... +/// @param[in] offset Days to offset by. +/// e.g. For different day starting the week. +/// @return String representation. +String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset) { + String result = ""; + result.reserve(27); // Sun|Mon|Tue|Wed|Thu|Fri|Sat - /// @brief Create a String of human output for the given channel - /// e.g. "[CH#0]" - /// @param channel The numeric value of the channel to display. - /// @return String representation - String channelToString(const uint8_t channel) { - String result = ""; - result.reserve(6); // "[CH#4]" - result += "["; - result += kChStr; - result += uint64ToString(channel); - result += "]"; - return result; - } - - /// @brief Create a String of human output for the given command type - /// e.g. "IFeel Report" - /// @param irCommandType The numeric value of the command type to display. - /// @param acControlCmd The numeric value of the "control" (default) command - /// @param iFeelReportCmd The numeric value of the sensor temperature command - /// @param timerCmd The numeric value of the timer config IR command - /// @param configCmd The numeric value of the config param set IR command - /// @return String representation - String irCommandTypeToString(uint8_t irCommandType, uint8_t acControlCmd, - uint8_t iFeelReportCmd, uint8_t timerCmd, - uint8_t configCmd) { - String result = ""; - result.reserve(12); // "IFeel Report" - if (irCommandType == acControlCmd) { - result += kCommandStr; - } else if (irCommandType == iFeelReportCmd) { - result += kIFeelReportStr; - } else if (irCommandType == timerCmd) { - result += kTimerStr; - } else if (irCommandType == configCmd) { - result += kConfigCommandStr; - } else { - result += kUnknownStr; - } - return result; - } - - /// @brief Create a String of the 3-letter day of the week bitmap - // e.g. 0b0000101 is "Sun | Tue" - /// @param[in] daysBitmap The bitmap representing days of week to represent - /// e.g bit[0]=Sunday, bit[1]=Monday, ... - /// @param[in] offset Days to offset by. - /// e.g. For different day starting the week. - /// @return String representation. - String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset) { - String result = ""; - result.reserve(27); // Sun|Mon|Tue|Wed|Thu|Fri|Sat - - for (uint8_t i = 0; i < 7; ++i) { - if (((daysBitmap >> i) & 0b1) == 0b1) { - if (result.length() > 0) { - result += "|"; - } - result += irutils::dayToString(i, offset); + for (uint8_t i = 0; i < 7; ++i) { + if (((daysBitmap >> i) & 0b1) == 0b1) { + if (result.length() > 0) { + result += "|"; } + result += irutils::dayToString(i, offset); } - return result; } + return result; +} - /// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS. - /// @param[in] unescaped A String containing text to make HTML safe. - /// @return A string that is HTML safe. - String htmlEscape(const String unescaped) { - String result = ""; - 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; - } +/// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS. +/// @param[in] unescaped A String containing text to make HTML safe. +/// @return A string that is HTML safe. +String htmlEscape(const String unescaped) { + String result = ""; + 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; } + return result; +} - /// Convert a nr. of milliSeconds into a Human-readable string. - /// e.g. "1 Day 6 Hours 34 Minutes 17 Seconds" - /// @param[in] msecs Nr. of milliSeconds (ms). - /// @return A human readable string. - String msToString(uint32_t const msecs) { - uint32_t totalseconds = msecs / 1000; - if (totalseconds == 0) return kNowStr; +/// Convert a nr. of milliSeconds into a Human-readable string. +/// e.g. "1 Day 6 Hours 34 Minutes 17 Seconds" +/// @param[in] msecs Nr. of milliSeconds (ms). +/// @return A human readable string. +String msToString(uint32_t const msecs) { + uint32_t totalseconds = msecs / 1000; + if (totalseconds == 0) return kNowStr; - // Note: uint32_t can only hold 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; + // Note: uint32_t can only hold 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 = ""; - result.reserve(42); // "99 Days, 23 Hours, 59 Minutes, 59 Seconds" - if (days) - result += uint64ToString(days) + ' ' + String((days > 1) ? kDaysStr - : kDayStr); - if (hours) { - if (result.length()) result += ' '; - result += uint64ToString(hours) + ' ' + String((hours > 1) ? kHoursStr - : kHourStr); - } - if (minutes) { - if (result.length()) result += ' '; - result += uint64ToString(minutes) + ' ' + String( - (minutes > 1) ? kMinutesStr : kMinuteStr); - } - if (seconds) { - if (result.length()) result += ' '; - result += uint64ToString(seconds) + ' ' + String( - (seconds > 1) ? kSecondsStr : kSecondStr); - } - return result; + String result = ""; + result.reserve(42); // "99 Days, 23 Hours, 59 Minutes, 59 Seconds" + if (days) + result += uint64ToString(days) + ' ' + String((days > 1) ? kDaysStr + : kDayStr); + if (hours) { + if (result.length()) result += ' '; + result += uint64ToString(hours) + ' ' + String((hours > 1) ? kHoursStr + : kHourStr); } - - /// Convert a nr. of minutes into a 24h clock format Human-readable string. - /// e.g. "23:59" - /// @param[in] mins Nr. of Minutes. - /// @return A human readable string. - String minsToString(const uint16_t mins) { - String result = ""; - result.reserve(5); // 23:59 is the typical worst case. - if (mins / 60 < 10) result += '0'; // Zero pad the hours - result += uint64ToString(mins / 60) + kTimeSep; - if (mins % 60 < 10) result += '0'; // Zero pad the minutes. - result += uint64ToString(mins % 60); - return result; + if (minutes) { + if (result.length()) result += ' '; + result += uint64ToString(minutes) + ' ' + String( + (minutes > 1) ? kMinutesStr : kMinuteStr); } - - /// Sum all the nibbles together in a series of bytes. - /// @param[in] start A ptr to the start of the byte array to calculate over. - /// @param[in] length How many bytes to use in the calculation. - /// @param[in] init Starting value of the calculation to use. (Default is 0) - /// @return The 8-bit calculated result of all the bytes and init value. - uint8_t sumNibbles(const uint8_t * const start, const uint16_t length, - const uint8_t init) { - uint8_t sum = init; - const uint8_t *ptr; - for (ptr = start; ptr - start < length; ptr++) - sum += (*ptr >> 4) + (*ptr & 0xF); - return sum; + if (seconds) { + if (result.length()) result += ' '; + result += uint64ToString(seconds) + ' ' + String( + (seconds > 1) ? kSecondsStr : kSecondStr); } + return result; +} - /// Sum all the nibbles together in an integer. - /// @param[in] data The integer to be summed. - /// @param[in] count The number of nibbles to sum. Starts from LSB. Max of 16. - /// @param[in] init Starting value of the calculation to use. (Default is 0) - /// @param[in] nibbleonly true, the result is 4 bits. false, it's 8 bits. - /// @return The 4/8-bit calculated result of all the nibbles and init value. - uint8_t sumNibbles(const uint64_t data, const uint8_t count, - const uint8_t init, const bool nibbleonly) { - uint8_t sum = init; - uint64_t copy = data; - const uint8_t nrofnibbles = (count < 16) ? count : (64 / 4); - for (uint8_t i = 0; i < nrofnibbles; i++, copy >>= 4) sum += copy & 0xF; - return nibbleonly ? sum & 0xF : sum; +/// Convert a nr. of minutes into a 24h clock format Human-readable string. +/// e.g. "23:59" +/// @param[in] mins Nr. of Minutes. +/// @return A human readable string. +String minsToString(const uint16_t mins) { + String result = ""; + result.reserve(5); // 23:59 is the typical worst case. + if (mins / 60 < 10) result += '0'; // Zero pad the hours + result += uint64ToString(mins / 60) + kTimeSep; + if (mins % 60 < 10) result += '0'; // Zero pad the minutes. + result += uint64ToString(mins % 60); + return result; +} + +/// Sum all the nibbles together in a series of bytes. +/// @param[in] start A ptr to the start of the byte array to calculate over. +/// @param[in] length How many bytes to use in the calculation. +/// @param[in] init Starting value of the calculation to use. (Default is 0) +/// @return The 8-bit calculated result of all the bytes and init value. +uint8_t sumNibbles(const uint8_t * const start, const uint16_t length, + const uint8_t init) { + uint8_t sum = init; + const uint8_t *ptr; + for (ptr = start; ptr - start < length; ptr++) + sum += (*ptr >> 4) + (*ptr & 0xF); + return sum; +} + +/// Sum all the nibbles together in an integer. +/// @param[in] data The integer to be summed. +/// @param[in] count The number of nibbles to sum. Starts from LSB. Max of 16. +/// @param[in] init Starting value of the calculation to use. (Default is 0) +/// @param[in] nibbleonly true, the result is 4 bits. false, it's 8 bits. +/// @return The 4/8-bit calculated result of all the nibbles and init value. +uint8_t sumNibbles(const uint64_t data, const uint8_t count, + const uint8_t init, const bool nibbleonly) { + uint8_t sum = init; + uint64_t copy = data; + const uint8_t nrofnibbles = (count < 16) ? count : (64 / 4); + for (uint8_t i = 0; i < nrofnibbles; i++, copy >>= 4) sum += copy & 0xF; + return nibbleonly ? sum & 0xF : sum; +} + +/// Sum all the bytes together in an integer. +/// @param[in] data The integer to be summed. +/// @param[in] count The number of bytes to sum. Starts from LSB. Max of 8. +/// @param[in] init Starting value of the calculation to use. (Default is 0) +/// @param[in] byteonly true, the result is 8 bits. false, it's 16 bits. +/// @return The 8/16-bit calculated result of all the bytes and init value. +uint16_t sumBytes(const uint64_t data, const uint8_t count, + const uint8_t init, const bool byteonly) { + uint16_t sum = init; + uint64_t copy = data; + const uint8_t nrofbytes = (count < 8) ? count : (64 / 8); + for (uint8_t i = 0; i < nrofbytes; i++, copy >>= 8) sum += (copy & 0xFF); + return byteonly ? sum & 0xFF : sum; +} + +/// Convert a byte of Binary Coded Decimal(BCD) into an Integer. +/// @param[in] bcd The BCD value. +/// @return A normal Integer value. +uint8_t bcdToUint8(const uint8_t bcd) { + if (bcd > 0x99) return 255; // Too big. + return (bcd >> 4) * 10 + (bcd & 0xF); +} + +/// Convert an Integer into a byte of Binary Coded Decimal(BCD). +/// @param[in] integer The number to convert. +/// @return An 8-bit BCD value. +uint8_t uint8ToBcd(const uint8_t integer) { + if (integer > 99) return 255; // Too big. + return ((integer / 10) << 4) + (integer % 10); +} + +/// Return the value of `position`th bit of an Integer. +/// @param[in] data Value to be examined. +/// @param[in] position Nr. of the Nth bit to be examined. `0` is the LSB. +/// @param[in] size Nr. of bits in data. +/// @return The bit's value. +bool getBit(const uint64_t data, const uint8_t position, const uint8_t size) { + if (position >= size) return false; // Outside of range. + return data & (1ULL << position); +} + +/// Return the value of `position`th bit of an Integer. +/// @param[in] data Value to be examined. +/// @param[in] position Nr. of the Nth bit to be examined. `0` is the LSB. +/// @return The bit's value. +bool getBit(const uint8_t data, const uint8_t position) { + if (position >= 8) return false; // Outside of range. + return data & (1 << position); +} + +/// Return the value of an Integer with the `position`th bit changed. +/// @param[in] data Value to be changed. +/// @param[in] position Nr. of the bit to be changed. `0` is the LSB. +/// @param[in] on Value to set the position'th bit to. +/// @param[in] size Nr. of bits in data. +/// @return A suitably modified integer. +uint64_t setBit(const uint64_t data, const uint8_t position, const bool on, + const uint8_t size) { + if (position >= size) return data; // Outside of range. + uint64_t mask = 1ULL << position; + if (on) + return data | mask; + else + return data & ~mask; +} + +/// Return the value of an Integer with the `position`th bit changed. +/// @param[in] data Value to be changed. +/// @param[in] position Nr. of the bit to be changed. `0` is the LSB. +/// @param[in] on Value to set the position'th bit to. +/// @return A suitably modified integer. +uint8_t setBit(const uint8_t data, const uint8_t position, const bool on) { + if (position >= 8) return data; // Outside of range. + uint8_t mask = 1 << position; + if (on) + return data | mask; + else + return data & ~mask; +} + +/// Alter the value of an Integer with the `position`th bit changed. +/// @param[in,out] data A pointer to the 8-bit integer to be changed. +/// @param[in] position Nr. of the bit to be changed. `0` is the LSB. +/// @param[in] on Value to set the position'th bit to. +void setBit(uint8_t * const data, const uint8_t position, const bool on) { + uint8_t mask = 1 << position; + if (on) + *data |= mask; + else + *data &= ~mask; +} + +/// Alter the value of an Integer with the `position`th bit changed. +/// @param[in,out] data A pointer to the 32-bit integer to be changed. +/// @param[in] position Nr. of the bit to be changed. `0` is the LSB. +/// @param[in] on Value to set the position'th bit to. +void setBit(uint32_t * const data, const uint8_t position, const bool on) { + uint32_t mask = static_cast(1) << position; + if (on) + *data |= mask; + else + *data &= ~mask; +} + +/// Alter the value of an Integer with the `position`th bit changed. +/// @param[in,out] data A pointer to the 64-bit integer to be changed. +/// @param[in] position Nr. of the bit to be changed. `0` is the LSB. +/// @param[in] on Value to set the position'th bit to. +void setBit(uint64_t * const data, const uint8_t position, const bool on) { + uint64_t mask = static_cast(1) << position; + if (on) + *data |= mask; + else + *data &= ~mask; +} + +/// Alter an uint8_t value by overwriting an arbitrary given number of bits. +/// @param[in,out] dst A pointer to the value to be changed. +/// @param[in] offset Nr. of bits from the Least Significant Bit to be ignored +/// @param[in] nbits Nr of bits of data to be placed into the destination. +/// @param[in] data The value to be placed. +void setBits(uint8_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint8_t data) { + if (offset >= 8 || !nbits) return; // Short circuit as it won't change. + // Calculate the mask for the supplied value. + uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); + // Calculate the mask & clear the space for the data. + // Clear the destination bits. + *dst &= ~(uint8_t)(mask << offset); + // Merge in the data. + *dst |= ((data & mask) << offset); +} + +/// Alter an uint32_t value by overwriting an arbitrary given number of bits. +/// @param[in,out] dst A pointer to the value to be changed. +/// @param[in] offset Nr. of bits from the Least Significant Bit to be ignored +/// @param[in] nbits Nr of bits of data to be placed into the destination. +/// @param[in] data The value to be placed. +void setBits(uint32_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint32_t data) { + if (offset >= 32 || !nbits) return; // Short circuit as it won't change. + // Calculate the mask for the supplied value. + uint32_t mask = UINT32_MAX >> (32 - ((nbits > 32) ? 32 : nbits)); + // Calculate the mask & clear the space for the data. + // Clear the destination bits. + *dst &= ~(mask << offset); + // Merge in the data. + *dst |= ((data & mask) << offset); +} + +/// Alter an uint64_t value by overwriting an arbitrary given number of bits. +/// @param[in,out] dst A pointer to the value to be changed. +/// @param[in] offset Nr. of bits from the Least Significant Bit to be ignored +/// @param[in] nbits Nr of bits of data to be placed into the destination. +/// @param[in] data The value to be placed. +void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint64_t data) { + if (offset >= 64 || !nbits) return; // Short circuit as it won't change. + // Calculate the mask for the supplied value. + uint64_t mask = UINT64_MAX >> (64 - ((nbits > 64) ? 64 : nbits)); + // Calculate the mask & clear the space for the data. + // Clear the destination bits. + *dst &= ~(mask << offset); + // Merge in the data. + *dst |= ((data & mask) << offset); +} + +/// Create byte pairs where the second byte of the pair is a bit +/// inverted/flipped copy of the first/previous byte of the pair. +/// @param[in,out] ptr A pointer to the start of array to modify. +/// @param[in] length The byte size of the array. +/// @note A length of `<= 1` will do nothing. +/// @return A ptr to the modified array. +uint8_t * invertBytePairs(uint8_t *ptr, const uint16_t length) { + for (uint16_t i = 1; i < length; i += 2) { + // Code done this way to avoid a compiler warning bug. + uint8_t inv = ~*(ptr + i - 1); + *(ptr + i) = inv; } + return ptr; +} - /// Sum all the bytes together in an integer. - /// @param[in] data The integer to be summed. - /// @param[in] count The number of bytes to sum. Starts from LSB. Max of 8. - /// @param[in] init Starting value of the calculation to use. (Default is 0) - /// @param[in] byteonly true, the result is 8 bits. false, it's 16 bits. - /// @return The 8/16-bit calculated result of all the bytes and init value. - uint16_t sumBytes(const uint64_t data, const uint8_t count, - const uint8_t init, const bool byteonly) { - uint16_t sum = init; - uint64_t copy = data; - const uint8_t nrofbytes = (count < 8) ? count : (64 / 8); - for (uint8_t i = 0; i < nrofbytes; i++, copy >>= 8) sum += (copy & 0xFF); - return byteonly ? sum & 0xFF : sum; +/// Check an array to see if every second byte of a pair is a bit +/// inverted/flipped copy of the first/previous byte of the pair. +/// @param[in] ptr A pointer to the start of array to check. +/// @param[in] length The byte size of the array. +/// @note A length of `<= 1` will always return true. +/// @return true, if every second byte is inverted. Otherwise false. +bool checkInvertedBytePairs(const uint8_t * const ptr, + const uint16_t length) { + for (uint16_t i = 1; i < length; i += 2) { + // Code done this way to avoid a compiler warning bug. + uint8_t inv = ~*(ptr + i - 1); + if (*(ptr + i) != inv) return false; } + return true; +} - /// Convert a byte of Binary Coded Decimal(BCD) into an Integer. - /// @param[in] bcd The BCD value. - /// @return A normal Integer value. - uint8_t bcdToUint8(const uint8_t bcd) { - if (bcd > 0x99) return 255; // Too big. - return (bcd >> 4) * 10 + (bcd & 0xF); - } - - /// Convert an Integer into a byte of Binary Coded Decimal(BCD). - /// @param[in] integer The number to convert. - /// @return An 8-bit BCD value. - uint8_t uint8ToBcd(const uint8_t integer) { - if (integer > 99) return 255; // Too big. - return ((integer / 10) << 4) + (integer % 10); - } - - /// Return the value of `position`th bit of an Integer. - /// @param[in] data Value to be examined. - /// @param[in] position Nr. of the Nth bit to be examined. `0` is the LSB. - /// @param[in] size Nr. of bits in data. - /// @return The bit's value. - bool getBit(const uint64_t data, const uint8_t position, const uint8_t size) { - if (position >= size) return false; // Outside of range. - return data & (1ULL << position); - } - - /// Return the value of `position`th bit of an Integer. - /// @param[in] data Value to be examined. - /// @param[in] position Nr. of the Nth bit to be examined. `0` is the LSB. - /// @return The bit's value. - bool getBit(const uint8_t data, const uint8_t position) { - if (position >= 8) return false; // Outside of range. - return data & (1 << position); - } - - /// Return the value of an Integer with the `position`th bit changed. - /// @param[in] data Value to be changed. - /// @param[in] position Nr. of the bit to be changed. `0` is the LSB. - /// @param[in] on Value to set the position'th bit to. - /// @param[in] size Nr. of bits in data. - /// @return A suitably modified integer. - uint64_t setBit(const uint64_t data, const uint8_t position, const bool on, - const uint8_t size) { - if (position >= size) return data; // Outside of range. - uint64_t mask = 1ULL << position; - if (on) - return data | mask; - else - return data & ~mask; - } - - /// Return the value of an Integer with the `position`th bit changed. - /// @param[in] data Value to be changed. - /// @param[in] position Nr. of the bit to be changed. `0` is the LSB. - /// @param[in] on Value to set the position'th bit to. - /// @return A suitably modified integer. - uint8_t setBit(const uint8_t data, const uint8_t position, const bool on) { - if (position >= 8) return data; // Outside of range. - uint8_t mask = 1 << position; - if (on) - return data | mask; - else - return data & ~mask; - } - - /// Alter the value of an Integer with the `position`th bit changed. - /// @param[in,out] data A pointer to the 8-bit integer to be changed. - /// @param[in] position Nr. of the bit to be changed. `0` is the LSB. - /// @param[in] on Value to set the position'th bit to. - void setBit(uint8_t * const data, const uint8_t position, const bool on) { - uint8_t mask = 1 << position; - if (on) - *data |= mask; - else - *data &= ~mask; - } - - /// Alter the value of an Integer with the `position`th bit changed. - /// @param[in,out] data A pointer to the 32-bit integer to be changed. - /// @param[in] position Nr. of the bit to be changed. `0` is the LSB. - /// @param[in] on Value to set the position'th bit to. - void setBit(uint32_t * const data, const uint8_t position, const bool on) { - uint32_t mask = (uint32_t)1 << position; - if (on) - *data |= mask; - else - *data &= ~mask; - } - - /// Alter the value of an Integer with the `position`th bit changed. - /// @param[in,out] data A pointer to the 64-bit integer to be changed. - /// @param[in] position Nr. of the bit to be changed. `0` is the LSB. - /// @param[in] on Value to set the position'th bit to. - void setBit(uint64_t * const data, const uint8_t position, const bool on) { - uint64_t mask = (uint64_t)1 << position; - if (on) - *data |= mask; - else - *data &= ~mask; - } - - /// Alter an uint8_t value by overwriting an arbitrary given number of bits. - /// @param[in,out] dst A pointer to the value to be changed. - /// @param[in] offset Nr. of bits from the Least Significant Bit to be ignored - /// @param[in] nbits Nr of bits of data to be placed into the destination. - /// @param[in] data The value to be placed. - void setBits(uint8_t * const dst, const uint8_t offset, const uint8_t nbits, - const uint8_t data) { - if (offset >= 8 || !nbits) return; // Short circuit as it won't change. - // Calculate the mask for the supplied value. - uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); - // Calculate the mask & clear the space for the data. - // Clear the destination bits. - *dst &= ~(uint8_t)(mask << offset); - // Merge in the data. - *dst |= ((data & mask) << offset); - } - - /// Alter an uint32_t value by overwriting an arbitrary given number of bits. - /// @param[in,out] dst A pointer to the value to be changed. - /// @param[in] offset Nr. of bits from the Least Significant Bit to be ignored - /// @param[in] nbits Nr of bits of data to be placed into the destination. - /// @param[in] data The value to be placed. - void setBits(uint32_t * const dst, const uint8_t offset, const uint8_t nbits, - const uint32_t data) { - if (offset >= 32 || !nbits) return; // Short circuit as it won't change. - // Calculate the mask for the supplied value. - uint32_t mask = UINT32_MAX >> (32 - ((nbits > 32) ? 32 : nbits)); - // Calculate the mask & clear the space for the data. - // Clear the destination bits. - *dst &= ~(mask << offset); - // Merge in the data. - *dst |= ((data & mask) << offset); - } - - /// Alter an uint64_t value by overwriting an arbitrary given number of bits. - /// @param[in,out] dst A pointer to the value to be changed. - /// @param[in] offset Nr. of bits from the Least Significant Bit to be ignored - /// @param[in] nbits Nr of bits of data to be placed into the destination. - /// @param[in] data The value to be placed. - void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, - const uint64_t data) { - if (offset >= 64 || !nbits) return; // Short circuit as it won't change. - // Calculate the mask for the supplied value. - uint64_t mask = UINT64_MAX >> (64 - ((nbits > 64) ? 64 : nbits)); - // Calculate the mask & clear the space for the data. - // Clear the destination bits. - *dst &= ~(mask << offset); - // Merge in the data. - *dst |= ((data & mask) << offset); - } - - /// Create byte pairs where the second byte of the pair is a bit - /// inverted/flipped copy of the first/previous byte of the pair. - /// @param[in,out] ptr A pointer to the start of array to modify. - /// @param[in] length The byte size of the array. - /// @note A length of `<= 1` will do nothing. - /// @return A ptr to the modified array. - uint8_t * invertBytePairs(uint8_t *ptr, const uint16_t length) { - for (uint16_t i = 1; i < length; i += 2) { - // Code done this way to avoid a compiler warning bug. - uint8_t inv = ~*(ptr + i - 1); - *(ptr + i) = inv; - } - return ptr; - } - - /// Check an array to see if every second byte of a pair is a bit - /// inverted/flipped copy of the first/previous byte of the pair. - /// @param[in] ptr A pointer to the start of array to check. - /// @param[in] length The byte size of the array. - /// @note A length of `<= 1` will always return true. - /// @return true, if every second byte is inverted. Otherwise false. - bool checkInvertedBytePairs(const uint8_t * const ptr, - const uint16_t length) { - for (uint16_t i = 1; i < length; i += 2) { - // Code done this way to avoid a compiler warning bug. - uint8_t inv = ~*(ptr + i - 1); - if (*(ptr + i) != inv) return false; - } - return true; - } - - /// Perform a low level bit manipulation sanity check for the given cpu - /// architecture and the compiler operation. Calls to this should return - /// 0 if everything is as expected, anything else means the library won't work - /// as expected. - /// @return A bit mask value of potential issues. - /// 0: (e.g. 0b00000000) Everything appears okay. - /// 0th bit set: (0b1) Unexpected bit field/packing encountered. - /// Try a different compiler. - /// 1st bit set: (0b10) Unexpected Endianness. Try a different compiler flag - /// or use a CPU different architecture. - /// e.g. A result of 3 (0b11) would mean both a bit field and an Endianness - /// issue has been found. - uint8_t lowLevelSanityCheck(void) { - const uint64_t kExpectedBitFieldResult = 0x8000012340000039ULL; - volatile uint32_t EndianTest = 0x12345678; - const uint8_t kBitFieldError = 0b01; - const uint8_t kEndiannessError = 0b10; - uint8_t result = 0; - union bitpackdata { - struct { - uint64_t lowestbit:1; // 0th bit - uint64_t next7bits:7; // 1-7th bits - uint64_t _unused_1:20; // 8-27th bits - // Cross the 32 bit boundary. - uint64_t crossbits:16; // 28-43rd bits - uint64_t _usused_2:18; // 44-61st bits - uint64_t highest2bits:2; // 62-63rd bits - }; - uint64_t all; +/// Perform a low level bit manipulation sanity check for the given cpu +/// architecture and the compiler operation. Calls to this should return +/// 0 if everything is as expected, anything else means the library won't work +/// as expected. +/// @return A bit mask value of potential issues. +/// 0: (e.g. 0b00000000) Everything appears okay. +/// 0th bit set: (0b1) Unexpected bit field/packing encountered. +/// Try a different compiler. +/// 1st bit set: (0b10) Unexpected Endianness. Try a different compiler flag +/// or use a CPU different architecture. +/// e.g. A result of 3 (0b11) would mean both a bit field and an Endianness +/// issue has been found. +uint8_t lowLevelSanityCheck(void) { + const uint64_t kExpectedBitFieldResult = 0x8000012340000039ULL; + volatile uint32_t EndianTest = 0x12345678; + const uint8_t kBitFieldError = 0b01; + const uint8_t kEndiannessError = 0b10; + uint8_t result = 0; + union bitpackdata { + struct { + uint64_t lowestbit:1; // 0th bit + uint64_t next7bits:7; // 1-7th bits + uint64_t _unused_1:20; // 8-27th bits + // Cross the 32 bit boundary. + uint64_t crossbits:16; // 28-43rd bits + uint64_t _usused_2:18; // 44-61st bits + uint64_t highest2bits:2; // 62-63rd bits }; + uint64_t all; + }; - bitpackdata data; - data.lowestbit = true; - data.next7bits = 0b0011100; // 0x1C - data._unused_1 = 0; - data.crossbits = 0x1234; - data._usused_2 = 0; - data.highest2bits = 0b10; // 2 + bitpackdata data; + data.lowestbit = true; + data.next7bits = 0b0011100; // 0x1C + data._unused_1 = 0; + data.crossbits = 0x1234; + data._usused_2 = 0; + data.highest2bits = 0b10; // 2 - if (data.all != kExpectedBitFieldResult) result |= kBitFieldError; - // Check that we are using Little Endian for integers + if (data.all != kExpectedBitFieldResult) result |= kBitFieldError; + // Check that we are using Little Endian for integers #if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) - if (BYTE_ORDER != LITTLE_ENDIAN) result |= kEndiannessError; + if (BYTE_ORDER != LITTLE_ENDIAN) result |= kEndiannessError; #endif #if defined(__IEEE_BIG_ENDIAN) || defined(__IEEE_BYTES_BIG_ENDIAN) - result |= kEndiannessError; + result |= kEndiannessError; #endif - // Brute force check for little endian. - if (*((uint8_t*)(&EndianTest)) != 0x78) // NOLINT(readability/casting) - result |= kEndiannessError; - return result; - } + // Brute force check for little endian. + if (*((uint8_t*)(&EndianTest)) != 0x78) // NOLINT(readability/casting) + result |= kEndiannessError; + return result; +} } // namespace irutils diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h index 8c94df228..65a9b4dea 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h @@ -46,110 +46,111 @@ float fahrenheitToCelsius(const float deg); /// Namespace for covering common functions & procedures for advancd protocol /// handlers namespace irutils { - String addBoolToString(const bool value, const String label, +String addBoolToString(const bool value, const String label, + const bool precomma = true); +String addToggleToString(const bool toggle, const String label, const bool precomma = true); - String addToggleToString(const bool toggle, const String label, - const bool precomma = true); - String addIntToString(const uint16_t value, const String label, +String addIntToString(const uint16_t value, const String label, + const bool precomma = true); +String addSignedIntToString(const int16_t value, const String label, + const bool precomma = true); +String modelToStr(const decode_type_t protocol, const int16_t model); +String addModelToString(const decode_type_t protocol, const int16_t model, const bool precomma = true); - String addSignedIntToString(const int16_t value, const String label, - const bool precomma = true); - String modelToStr(const decode_type_t protocol, const int16_t model); - String addModelToString(const decode_type_t protocol, const int16_t model, - const bool precomma = true); - String addLabeledString(const String value, const String label, - const bool precomma = true); - String addTempToString(const uint16_t degrees, const bool celsius = true, - const bool precomma = true, - const bool isSensorTemp = false); - String addTempFloatToString(const float degrees, const bool celsius = true, - const bool precomma = true, - const bool isSensorTemp = false); - String addModeToString(const uint8_t mode, const uint8_t automatic, - const uint8_t cool, const uint8_t heat, - const uint8_t dry, const uint8_t fan); - String addFanToString(const uint8_t speed, const uint8_t high, - const uint8_t low, const uint8_t automatic, - const uint8_t quiet, const uint8_t medium, - const uint8_t maximum = 0xFF, - const uint8_t medium_high = 0xFF); - String addSwingHToString(const uint8_t position, const uint8_t automatic, - const uint8_t maxleft, const uint8_t left, - const uint8_t middle, - const uint8_t right, const uint8_t maxright, - const uint8_t off, - const uint8_t leftright, const uint8_t rightleft, - const uint8_t threed, const uint8_t wide); - String addSwingVToString(const uint8_t position, const uint8_t automatic, - const uint8_t highest, const uint8_t high, - const uint8_t uppermiddle, - const uint8_t middle, - const uint8_t lowermiddle, - const uint8_t low, const uint8_t lowest, - const uint8_t off, const uint8_t swing, - const uint8_t breeze, const uint8_t circulate); - String addDayToString(const uint8_t day_of_week, const int8_t offset = 0, +String addLabeledString(const String value, const String label, const bool precomma = true); - String addTimerModeToString(const uint8_t timerType, const uint8_t noTimer, - const uint8_t delayTimer, - const uint8_t schedule1 = 0xFF, - const uint8_t schedule2 = 0xFF, - const uint8_t schedule3 = 0xFF, - const bool precomma = true); - String irCommandTypeToString(uint8_t commandType, uint8_t acControlCmd, - uint8_t iFeelReportCmd = 0xFF, - uint8_t timerCmd = 0xFF, - uint8_t configCmd = 0xFF); - String dayToString(const uint8_t day_of_week, const int8_t offset = 0); - String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset = 0); - String channelToString(const uint8_t channel); - String htmlEscape(const String unescaped); - String msToString(uint32_t const msecs); - String minsToString(const uint16_t mins); - uint8_t sumNibbles(const uint8_t * const start, const uint16_t length, - const uint8_t init = 0); - uint8_t sumNibbles(const uint64_t data, const uint8_t count = 16, - const uint8_t init = 0, const bool nibbleonly = true); - uint16_t sumBytes(const uint64_t data, const uint8_t count = 8, - const uint8_t init = 0, const bool byteonly = true); - uint8_t bcdToUint8(const uint8_t bcd); - uint8_t uint8ToBcd(const uint8_t integer); - bool getBit(const uint64_t data, const uint8_t position, - const uint8_t size = 64); - bool getBit(const uint8_t data, const uint8_t position); -#define GETBIT8(a, b) ((a) & ((uint8_t)1 << (b))) -#define GETBIT16(a, b) ((a) & ((uint16_t)1 << (b))) -#define GETBIT32(a, b) ((a) & ((uint32_t)1 << (b))) -#define GETBIT64(a, b) ((a) & ((uint64_t)1 << (b))) +String addTempToString(const uint16_t degrees, const bool celsius = true, + const bool precomma = true, + const bool isSensorTemp = false); +String addTempFloatToString(const float degrees, const bool celsius = true, + const bool precomma = true, + const bool isSensorTemp = false); +String addModeToString(const uint8_t mode, const uint8_t automatic, + const uint8_t cool, const uint8_t heat, + const uint8_t dry, const uint8_t fan); +String addFanToString(const uint8_t speed, const uint8_t high, + const uint8_t low, const uint8_t automatic, + const uint8_t quiet, const uint8_t medium, + const uint8_t maximum = 0xFF, + const uint8_t medium_high = 0xFF); +String addSwingHToString(const uint8_t position, const uint8_t automatic, + const uint8_t maxleft, const uint8_t left, + const uint8_t middle, + const uint8_t right, const uint8_t maxright, + const uint8_t off, + const uint8_t leftright, const uint8_t rightleft, + const uint8_t threed, const uint8_t wide); +String addSwingVToString(const uint8_t position, const uint8_t automatic, + const uint8_t highest, const uint8_t high, + const uint8_t uppermiddle, + const uint8_t middle, + const uint8_t lowermiddle, + const uint8_t low, const uint8_t lowest, + const uint8_t off, const uint8_t swing, + const uint8_t breeze, const uint8_t circulate); +String addDayToString(const uint8_t day_of_week, const int8_t offset = 0, + const bool precomma = true); +String addTimerModeToString(const uint8_t timerType, const uint8_t noTimer, + const uint8_t delayTimer, + const uint8_t schedule1 = 0xFF, + const uint8_t schedule2 = 0xFF, + const uint8_t schedule3 = 0xFF, + const bool precomma = true); +String irCommandTypeToString(uint8_t commandType, uint8_t acControlCmd, + uint8_t iFeelReportCmd = 0xFF, + uint8_t timerCmd = 0xFF, + uint8_t configCmd = 0xFF); +String dayToString(const uint8_t day_of_week, const int8_t offset = 0); +String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset = 0); +String channelToString(const uint8_t channel); +String htmlEscape(const String unescaped); +String msToString(uint32_t const msecs); +String minsToString(const uint16_t mins); +uint8_t sumNibbles(const uint8_t * const start, const uint16_t length, + const uint8_t init = 0); +uint8_t sumNibbles(const uint64_t data, const uint8_t count = 16, + const uint8_t init = 0, const bool nibbleonly = true); +uint16_t sumBytes(const uint64_t data, const uint8_t count = 8, + const uint8_t init = 0, const bool byteonly = true); +uint8_t bcdToUint8(const uint8_t bcd); +uint8_t uint8ToBcd(const uint8_t integer); +bool getBit(const uint64_t data, const uint8_t position, + const uint8_t size = 64); +bool getBit(const uint8_t data, const uint8_t position); +#define GETBIT8(a, b) ((a) & (static_cast(1) << (b))) +#define GETBIT16(a, b) ((a) & (static_cast(1) << (b))) +#define GETBIT32(a, b) ((a) & (static_cast(1) << (b))) +#define GETBIT64(a, b) ((a) & (static_cast(1) << (b))) #define GETBITS8(data, offset, size) \ - (((data) & (((uint8_t)UINT8_MAX >> (8 - (size))) << (offset))) >> (offset)) + (((data) & ((static_cast(UINT8_MAX) >> (8 - (size))) << \ + (offset))) >> (offset)) #define GETBITS16(data, offset, size) \ - (((data) & (((uint16_t)UINT16_MAX >> (16 - (size))) << (offset))) >> \ - (offset)) + (((data) & ((static_cast(UINT16_MAX) >> (16 - (size))) << \ + (offset))) >> (offset)) #define GETBITS32(data, offset, size) \ - (((data) & (((uint32_t)UINT32_MAX >> (32 - (size))) << (offset))) >> \ - (offset)) + (((data) & ((static_cast(UINT32_MAX) >> (32 - (size))) << \ + (offset))) >> (offset)) #define GETBITS64(data, offset, size) \ - (((data) & (((uint64_t)UINT64_MAX >> (64 - (size))) << (offset))) >> \ - (offset)) - uint64_t setBit(const uint64_t data, const uint8_t position, - const bool on = true, const uint8_t size = 64); - uint8_t setBit(const uint8_t data, const uint8_t position, - const bool on = true); - void setBit(uint8_t * const data, const uint8_t position, - const bool on = true); - void setBit(uint32_t * const data, const uint8_t position, - const bool on = true); - void setBit(uint64_t * const data, const uint8_t position, - const bool on = true); - void setBits(uint8_t * const dst, const uint8_t offset, const uint8_t nbits, - const uint8_t data); - void setBits(uint32_t * const dst, const uint8_t offset, const uint8_t nbits, - const uint32_t data); - void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, - const uint64_t data); - uint8_t * invertBytePairs(uint8_t *ptr, const uint16_t length); - bool checkInvertedBytePairs(const uint8_t * const ptr, const uint16_t length); - uint8_t lowLevelSanityCheck(void); + (((data) & ((static_cast(UINT64_MAX) >> (64 - (size))) << \ + (offset))) >> (offset)) +uint64_t setBit(const uint64_t data, const uint8_t position, + const bool on = true, const uint8_t size = 64); +uint8_t setBit(const uint8_t data, const uint8_t position, + const bool on = true); +void setBit(uint8_t * const data, const uint8_t position, + const bool on = true); +void setBit(uint32_t * const data, const uint8_t position, + const bool on = true); +void setBit(uint64_t * const data, const uint8_t position, + const bool on = true); +void setBits(uint8_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint8_t data); +void setBits(uint32_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint32_t data); +void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint64_t data); +uint8_t * invertBytePairs(uint8_t *ptr, const uint16_t length); +bool checkInvertedBytePairs(const uint8_t * const ptr, const uint16_t length); +uint8_t lowLevelSanityCheck(void); } // namespace irutils #endif // IRUTILS_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h index 9b5e89f3f..d902fcaac 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h @@ -68,7 +68,7 @@ const uint8_t kAirtonFanHigh = 0b100; // 4 const uint8_t kAirtonFanMax = 0b101; // 5 const uint8_t kAirtonMinTemp = 16; // 16C -const uint8_t kAirtonMaxTemp = 25; // 25C +const uint8_t kAirtonMaxTemp = 31; // 31C /// Class for handling detailed Airton 56-bit A/C messages. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp index 2f5ce4ea6..ba72764a9 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #ifndef UNIT_TEST #include #endif // UNIT_TEST @@ -1311,14 +1313,14 @@ stdAc::state_t IRArgoAC_WREM3::toCommon(void) const { namespace { - /// @brief Short-hand for casting enum to its underlying storage type - /// @tparam E The type of enum - /// @param e Enum value - /// @return Type of underlying value - template - constexpr typename std::underlying_type::type to_underlying(E e) noexcept { - return static_cast::type>(e); - } +/// @brief Short-hand for casting enum to its underlying storage type +/// @tparam E The type of enum +/// @param e Enum value +/// @return Type of underlying value +template +constexpr typename std::underlying_type::type to_underlying(E e) noexcept { + return static_cast::type>(e); +} } /// Convert the current internal state into a human readable string (WREM2). @@ -1556,16 +1558,16 @@ argo_ac_remote_model_t IRArgoAC_WREM3::getModel() const { } namespace { - String commandTypeToString(argoIrMessageType_t type, uint8_t channel) { - String result = irutils::irCommandTypeToString(to_underlying(type), - to_underlying(argoIrMessageType_t::AC_CONTROL), - to_underlying(argoIrMessageType_t::IFEEL_TEMP_REPORT), - to_underlying(argoIrMessageType_t::TIMER_COMMAND), - to_underlying(argoIrMessageType_t::CONFIG_PARAM_SET)); - result += irutils::channelToString(channel); - result += kColonSpaceStr; - return result; - } +String commandTypeToString(argoIrMessageType_t type, uint8_t channel) { + String result = irutils::irCommandTypeToString(to_underlying(type), + to_underlying(argoIrMessageType_t::AC_CONTROL), + to_underlying(argoIrMessageType_t::IFEEL_TEMP_REPORT), + to_underlying(argoIrMessageType_t::TIMER_COMMAND), + to_underlying(argoIrMessageType_t::CONFIG_PARAM_SET)); + result += irutils::channelToString(channel); + result += kColonSpaceStr; + return result; +} } // namespace /// Convert the current internal state into a human readable string (WREM3). @@ -1791,16 +1793,20 @@ bool IRArgoAC_WREM3::isValidWrem3Message(const uint8_t state[], switch (messageType) { case argoIrMessageType_t::AC_CONTROL : - if (stateLengthBytes != kArgo3AcControlStateLength) { return false; } + if (stateLengthBytes != kArgo3AcControlStateLength) + return false; break; - case argoIrMessageType_t::CONFIG_PARAM_SET: - if (stateLengthBytes != kArgo3ConfigStateLength) { return false; } + case argoIrMessageType_t::CONFIG_PARAM_SET: + if (stateLengthBytes != kArgo3ConfigStateLength) + return false; break; - case argoIrMessageType_t::TIMER_COMMAND: - if (stateLengthBytes != kArgo3TimerStateLength) { return false; } + case argoIrMessageType_t::TIMER_COMMAND: + if (stateLengthBytes != kArgo3TimerStateLength) + return false; break; case argoIrMessageType_t::IFEEL_TEMP_REPORT: - if (stateLengthBytes != kArgo3iFeelReportStateLength) { return false; } + if (stateLengthBytes != kArgo3iFeelReportStateLength) + return false; break; default: return false; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_BluestarHeavy.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_BluestarHeavy.cpp new file mode 100644 index 000000000..5d6452767 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_BluestarHeavy.cpp @@ -0,0 +1,72 @@ +// Copyright 2024 Harsh Bhosale (harshbhosale01) +/// @file +/// @brief Support for BluestarHeavy protocol + +// Supports: +// Brand: Bluestar, Model: D716LXM0535A2400313 (Remote) + +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +const uint16_t kBluestarHeavyHdrMark = 4912; +const uint16_t kBluestarHeavyBitMark = 465; +const uint16_t kBluestarHeavyHdrSpace = 5058; +const uint16_t kBluestarHeavyOneSpace = 572; +const uint16_t kBluestarHeavyZeroSpace = 1548; +const uint16_t kBluestarHeavyFreq = 38000; +const uint16_t kBluestarHeavyOverhead = 3; + +#if SEND_BLUESTARHEAVY +/// Send a BluestarHeavy formatted message. +/// Status: BETA / Tested. +/// @param[in] data An array of bytes containing the IR command. +/// It is assumed to be in MSB order for this code. +/// e.g. +/// @code +/// uint8_t data[kBluestarHeavyStateLength] = +/// {0x2A,0x00,0x20,0xD0,0x05,0xA0,0x05,0xA0,0x00,0x80,0xBA,0x02,0x23}; +/// @endcode +/// @param[in] nbytes Nr. of bytes of data in the array. +/// @param[in] repeat Nr. of times the message is to be repeated. +void IRsend::sendBluestarHeavy(const uint8_t data[], const uint16_t nbytes, + const uint16_t repeat) { + sendGeneric(kBluestarHeavyHdrMark, kBluestarHeavyHdrSpace, + kBluestarHeavyBitMark, kBluestarHeavyOneSpace, + kBluestarHeavyBitMark, kBluestarHeavyZeroSpace, + kBluestarHeavyHdrMark, kDefaultMessageGap, + data, nbytes, // Bytes + kBluestarHeavyFreq, true, repeat, kDutyDefault); +} +#endif // SEND_BLUESTARHEAVY + +#if DECODE_BLUESTARHEAVY +/// Decode the supplied BluestarHeavy message. +/// Status: BETA / Tested. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +/// @return A boolean. True if it can decode it, false if it can't. +bool IRrecv::decodeBluestarHeavy(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict && nbits != kBluestarHeavyBits) + return false; + + uint16_t used = 0; + + used = matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + kBluestarHeavyHdrMark, kBluestarHeavyHdrSpace, + kBluestarHeavyBitMark, kBluestarHeavyOneSpace, + kBluestarHeavyBitMark, kBluestarHeavyZeroSpace, + kBluestarHeavyHdrMark, kDefaultMessageGap, true); + if (used == 0) return false; // We failed to find any data. + + // Success + results->decode_type = decode_type_t::BLUESTARHEAVY; + results->bits = nbits; + return true; +} +#endif // DECODE_BLUESTARHEAVY diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp index 56e9d2b99..c18dddf38 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp @@ -5,6 +5,7 @@ /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1787 #include "ir_Bosch.h" +#include #if SEND_BOSCH144 /// Send a Bosch 144-bit / 18-byte message (96-bit message are also possible) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp index 6769ebb79..bbc3dbbc2 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp @@ -99,6 +99,8 @@ void IRCoolixAC::stateReset(void) { cleanFlag = false; sleepFlag = false; swingFlag = false; + tempLowF = false; + tempHighF = false; } /// Set up hardware to be able to send a message. @@ -112,8 +114,34 @@ void IRCoolixAC::send(const uint16_t repeat) { // Typically repeat is `kCoolixDefaultRepeat` which is `1`, so this allows // it to be 0 normally for this command, and allows additional repeats if // requested rather always 0 for that command. - _irsend.sendCOOLIX(getRaw(), kCoolixBits, repeat - (getSwingVStep() && - repeat > 0) ? 1 : 0); + const uint16_t repeat_override = + repeat - (getSwingVStep() && repeat > 0) ? 1 : 0; + + if (tempHighF || tempLowF) { + uint64_t coolix24_raw = getRaw(); + // We need to sneak our temperature range into a parity bit. + uint64_t coolix48_raw = 0; + + // First create our parity. + uint64_t parity = getRaw() ^ UINT32_MAX; + + // Interleave raw data and parity into output, in order. + coolix48_raw |= ((coolix24_raw >> 16) & 0xFF) << 40; + coolix48_raw |= ((parity >> 16) & 0xFF) << 32; + coolix48_raw |= ((coolix24_raw >> 8) & 0xFF) << 24; + coolix48_raw |= ((parity >> 8) & 0xFF) << 16; + coolix48_raw |= (coolix24_raw & 0xFF) << 8; + coolix48_raw |= parity & 0xFF; + + // Mangle parity as necessary to represent Fahrenheit range. + coolix48_raw |= static_cast(tempLowF ? 1 : 3) << (36); + + // Send as Coolix48. + _irsend.sendCoolix48(coolix48_raw, kCoolix48Bits, repeat_override); + } else { + _irsend.sendCOOLIX(getRaw(), kCoolixBits, repeat_override); + } + // make sure to remove special state from the internal state // after command has being transmitted. recoverSavedState(); @@ -140,6 +168,27 @@ void IRCoolixAC::setRaw(const uint32_t new_code) { _.raw = new_code; } +// Set internal state from a COOLIX48 read, handling F data hidden in parity. +void IRCoolixAC::setRawFromCoolix48(const uint64_t data) { + // Assume parity bits as in coolix24, let's strip them. + CoolixProtocol coolix24; + coolix24.raw = 0; + coolix24.raw |= ((data >> 8) & 0xff); + coolix24.raw |= ((data >> 24) & 0xff) << 8; + coolix24.raw |= ((data >> 40) & 0xff) << 16; + + // Delegate to coolix24 code. + setRaw(coolix24.raw); + + // Handle Fahrenheit range. + uint8_t fRange = (data >> 36) & 3; + if (fRange == 1) { + setTempFRange(false); + } else if (fRange == 3) { + setTempFRange(true); + } +} + /// Is the current state is a special state? /// @return true, if it is. false if it isn't. bool IRCoolixAC::isSpecialState(void) const { @@ -217,19 +266,53 @@ void IRCoolixAC::setTempRaw(const uint8_t code) { _.Temp = code; } /// @return The native temperature value. uint8_t IRCoolixAC::getTempRaw(void) const { return _.Temp; } +/// Set the fahrenheit temperature range. +/// @param[in] high True if setting high F range, false if low F range. +void IRCoolixAC::setTempFRange(const bool high) { + tempLowF = !high; + tempHighF = high; +} + +// Clear the fahrenheit temperature range bits. +void IRCoolixAC::clearTempFRange() { + tempLowF = false; + tempHighF = false; +} + /// Set the temperature. /// @param[in] desired The temperature in degrees celsius. void IRCoolixAC::setTemp(const uint8_t desired) { // Range check. + if (desired >= kCoolixTempLowFMin && + desired <= kCoolixTempLowFMax) { + setTempRaw(kCoolixTempMapLowF[desired - kCoolixTempLowFMin]); + setTempFRange(false); + return; + } + if (desired >= kCoolixTempHighFMin && + desired <= kCoolixTempHighFMax) { + setTempRaw(kCoolixTempMapHighF[desired - kCoolixTempHighFMin]); + setTempFRange(true); + return; + } uint8_t temp = std::min(desired, kCoolixTempMax); temp = std::max(temp, kCoolixTempMin); setTempRaw(kCoolixTempMap[temp - kCoolixTempMin]); + clearTempFRange(); } /// Get the current temperature setting. /// @return The current setting for temp. in degrees celsius. uint8_t IRCoolixAC::getTemp(void) const { const uint8_t code = getTempRaw(); + if (tempLowF) { + for (uint8_t i = 0; i < kCoolixTempLowFRange; i++) + if (kCoolixTempMapLowF[i] == code) return kCoolixTempLowFMin + i; + } + if (tempHighF) { + for (uint8_t i = 0; i < kCoolixTempHighFRange; i++) + if (kCoolixTempMapHighF[i] == code) return kCoolixTempHighFMin + i; + } for (uint8_t i = 0; i < kCoolixTempRange; i++) if (kCoolixTempMap[i] == code) return kCoolixTempMin + i; return kCoolixTempMax; // Not a temp we expected. @@ -613,7 +696,9 @@ String IRCoolixAC::toString(void) const { } result += ')'; // Fan mode doesn't have a temperature. - if (getMode() != kCoolixFan) result += addTempToString(getTemp()); + bool celcius = true; + if (tempHighF || tempLowF) celcius = false; + if (getMode() != kCoolixFan) result += addTempToString(getTemp(), celcius); result += addBoolToString(getZoneFollow(), kZoneFollowStr); result += addLabeledString( (getSensorTemp() == kCoolixSensorTempIgnoreCode) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h index d711367b2..402a5feb2 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h @@ -15,6 +15,7 @@ // Brand: Midea, Model: RG52D/BGE Remote // Brand: Midea, Model: MS12FU-10HRDN1-QRD0GW(B) A/C // Brand: Midea, Model: MSABAU-07HRFN1-QRD0GW A/C (circa 2016) +// Brand: Comfee (Midea), Model: Breezy Cool Pro 2.6 // Brand: Tokio, Model: AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote // Brand: Airwell, Model: RC08B remote // Brand: Kastron, Model: RG57A7/BGEF Inverter remote @@ -25,6 +26,7 @@ // Brand: Toshiba, Model: WH-E1YE remote // Brand: Bosch, Model: RG36B4/BGE remote // Brand: Bosch, Model: B1ZAI2441W/B1ZAO2441W A/C +// Brand: Fisher, Model: R51L1/BGE remote #ifndef IR_COOLIX_H_ #define IR_COOLIX_H_ @@ -78,6 +80,42 @@ const uint8_t kCoolixTempMap[kCoolixTempRange] = { 0b1010, // 29C 0b1011 // 30C }; +const uint8_t kCoolixTempLowFMin = 63; +const uint8_t kCoolixTempLowFMax = 75; +const uint8_t kCoolixTempLowFRange = + kCoolixTempLowFMax - kCoolixTempLowFMin + 1; +const uint8_t kCoolixTempHighFMin = kCoolixTempLowFMax + 1; +const uint8_t kCoolixTempHighFMax = 86; +const uint8_t kCoolixTempHighFRange = + kCoolixTempHighFMax - kCoolixTempHighFMin + 1; +const uint8_t kCoolixTempMapLowF[kCoolixTempLowFRange] = { + 0b1100, // 63F + 0b0010, // 64F + 0b1010, // 65F + 0b0110, // 66F + 0b1110, // 67F + 0b0001, // 68F + 0b1001, // 69F + 0b0101, // 70F + 0b1101, // 71F + 0b0011, // 72F + 0b1011, // 73F + 0b0111, // 74F + 0b1111 // 75F +}; +const uint8_t kCoolixTempMapHighF[kCoolixTempHighFRange] = { + 0b0000, // 76F + 0b1000, // 77F + 0b0100, // 78F + 0b1100, // 79F + 0b0010, // 80F + 0b1010, // 81F + 0b0110, // 82F + 0b1110, // 83F + 0b0001, // 84F + 0b1001, // 85F + 0b0101 // 86F +}; const uint8_t kCoolixSensorTempMax = 30; // Celsius const uint8_t kCoolixSensorTempIgnoreCode = 0b11111; // 0x1F / 31 (DEC) // kCoolixSensorTempMask = 0b000000000000111100000000; // 0xF00 @@ -135,6 +173,8 @@ class IRCoolixAC { void off(void); void setPower(const bool on); bool getPower(void) const; + void setTempFRange(const bool high = false); + void clearTempFRange(); void setTemp(const uint8_t temp); uint8_t getTemp(void) const; void setSensorTemp(const uint8_t temp); @@ -159,6 +199,8 @@ class IRCoolixAC { bool getZoneFollow(void) const; uint32_t getRaw(void) const; void setRaw(const uint32_t new_code); + // Convert from Coolix48 with Fahrenheit handling. + void setRawFromCoolix48(const uint64_t new_code); static uint8_t convertMode(const stdAc::opmode_t mode); static uint8_t convertFan(const stdAc::fanspeed_t speed); static stdAc::opmode_t toCommonMode(const uint8_t mode); @@ -185,6 +227,8 @@ class IRCoolixAC { bool cleanFlag; bool sleepFlag; bool swingFlag; + bool tempLowF; // Indicates low-range F temperatures. + bool tempHighF; // Indicates high-range F temperatures. uint8_t savedFan; void setTempRaw(const uint8_t code); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp index f44cd8f13..fc93ef52a 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp @@ -46,6 +46,7 @@ using irutils::addModeToString; using irutils::addSwingHToString; using irutils::addSwingVToString; using irutils::addTempToString; +using irutils::addTempFloatToString; using irutils::addFanToString; using irutils::bcdToUint8; using irutils::minsToString; @@ -73,7 +74,8 @@ void IRsend::sendDaikin(const unsigned char data[], const uint16_t nbytes, sendGeneric(0, 0, // No header for the header kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, - (uint64_t)0b00000, kDaikinHeaderLength, 38, false, 0, 50); + static_cast(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 @@ -221,15 +223,15 @@ bool IRDaikinESP::getPower(void) const { /// Set the temperature. /// @param[in] temp The temperature in degrees celsius. -void IRDaikinESP::setTemp(const uint8_t temp) { - uint8_t degrees = std::max(temp, kDaikinMinTemp); - degrees = std::min(degrees, kDaikinMaxTemp); - _.Temp = degrees; +void IRDaikinESP::setTemp(const float temp) { + float degrees = std::max(temp, static_cast(kDaikinMinTemp)); + degrees = std::min(degrees, static_cast(kDaikinMaxTemp)); + _.Temp = degrees * 2.0f; } /// Get the current temperature setting. /// @return The current setting for temp. in degrees celsius. -uint8_t IRDaikinESP::getTemp(void) const { return _.Temp; } +float IRDaikinESP::getTemp(void) const { return _.Temp / 2.0f; } /// Set the speed of the fan. /// @param[in] fan The desired setting. @@ -536,7 +538,7 @@ stdAc::state_t IRDaikinESP::toCommon(void) const { result.power = _.Power; result.mode = toCommonMode(_.Mode); result.celsius = true; - result.degrees = _.Temp; + result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(getFan()); result.swingv = _.SwingV ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; @@ -563,7 +565,7 @@ String IRDaikinESP::toString(void) const { result += addBoolToString(_.Power, kPowerStr, false); result += addModeToString(_.Mode, kDaikinAuto, kDaikinCool, kDaikinHeat, kDaikinDry, kDaikinFan); - result += addTempToString(_.Temp); + result += addTempFloatToString(getTemp()); result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin, kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed); result += addBoolToString(_.Powerful, kPowerfulStr); @@ -674,7 +676,7 @@ void IRsend::sendDaikin2(const unsigned char data[], const uint16_t nbytes, 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, 0, 0, 0, 0, 0, static_cast(0), // No data payload. 0, kDaikin2Freq, false, 0, 50); // Section #1 sendGeneric(kDaikin2HdrMark, kDaikin2HdrSpace, kDaikin2BitMark, @@ -2936,7 +2938,8 @@ bool IRrecv::decodeDaikin128(decode_results *results, uint16_t offset, kDaikinTolerance, kDaikinMarkExcess)) return false; } const uint16_t ksectionSize[kDaikin128Sections] = { - kDaikin128SectionLength, (uint16_t)(nbits / 8 - kDaikin128SectionLength)}; + kDaikin128SectionLength, + static_cast(nbits / 8 - kDaikin128SectionLength)}; // Data Sections uint16_t pos = 0; for (uint8_t section = 0; section < kDaikin128Sections; section++) { @@ -2986,7 +2989,7 @@ void IRsend::sendDaikin152(const unsigned char data[], const uint16_t nbytes, sendGeneric(0, 0, kDaikin152BitMark, kDaikin152OneSpace, kDaikin152BitMark, kDaikin152ZeroSpace, kDaikin152BitMark, kDaikin152Gap, - (uint64_t)0, kDaikin152LeaderBits, + static_cast(0), kDaikin152LeaderBits, kDaikin152Freq, false, 0, kDutyDefault); // Header + Data + Footer sendGeneric(kDaikin152HdrMark, kDaikin152HdrSpace, kDaikin152BitMark, @@ -3838,7 +3841,7 @@ void IRsend::sendDaikin312(const unsigned char data[], const uint16_t nbytes, kDaikin312BitMark, kDaikin312OneSpace, kDaikin312BitMark, kDaikin312ZeroSpace, kDaikin312BitMark, kDaikin312HdrGap, - (uint64_t)0b00000, kDaikinHeaderLength, + static_cast(0b00000), kDaikinHeaderLength, kDaikin2Freq, false, 0, kDutyDefault); // Section #1 sendGeneric(kDaikin312HdrMark, kDaikin312HdrSpace, kDaikin312BitMark, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h index 3a98f07e7..a26497000 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h @@ -53,6 +53,7 @@ // Brand: Daikin, Model: BRC4M150W16 remote (DAIKIN200) // Brand: Daikin, Model: FTXM20R5V1B A/C (DAIKIN312) // Brand: Daikin, Model: ARC466A67 remote (DAIKIN312) +// Brand: Daikin, Model: ARC443A5 remote (DAIKIN) #ifndef IR_DAIKIN_H_ #define IR_DAIKIN_H_ @@ -99,8 +100,7 @@ union DaikinESPProtocol{ uint64_t Mode :3; uint64_t :1; // Byte 22 - uint64_t :1; - uint64_t Temp :7; // Temp should be between 10 - 32 + uint64_t Temp :8; // Temp should be between 20 - 64 (10 C - 32 C) // Byte 23 uint64_t :8; @@ -738,8 +738,8 @@ class IRDaikinESP { void off(void); void setPower(const bool on); bool getPower(void) const; - void setTemp(const uint8_t temp); - uint8_t getTemp(void) const; + void setTemp(const float temp); + float getTemp(void) const; void setFan(const uint8_t fan); uint8_t getFan(void) const; void setMode(const uint8_t mode); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Ecoclim.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Ecoclim.cpp index e24559b5f..4aa320a4f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Ecoclim.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Ecoclim.cpp @@ -282,7 +282,7 @@ uint16_t IREcoclimAc::getClock(void) const { return _.Clock; } /// Set the clock time on the A/C unit. /// @param[in] nr_of_mins Nr. of minutes past midnight. void IREcoclimAc::setClock(const uint16_t nr_of_mins) { - _.Clock = std::min(nr_of_mins, (uint16_t)(24 * 60 - 1)); + _.Clock = std::min(nr_of_mins, static_cast(24 * 60 - 1)); } /// Get the Unit type/DIP switch settings of the remote. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp index f8edf9729..40e208a52 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp @@ -310,6 +310,18 @@ bool IRElectraAc::getTurbo(void) const { return _.Turbo; } +/// Set the Quiet/Silent'mode of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRElectraAc::setQuiet(const bool on) { + _.Quiet = on; +} + +/// Get the Quiet/Silent mode of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRElectraAc::getQuiet(void) const { + return _.Quiet; +} + /// Get the IFeel mode of the A/C. /// @return true, the setting is on. false, the setting is off. bool IRElectraAc::getIFeel(void) const { return _.IFeel; } @@ -373,11 +385,11 @@ stdAc::state_t IRElectraAc::toCommon(void) const { : stdAc::swingh_t::kOff; result.light = getLightToggle(); result.turbo = _.Turbo; + result.quiet = _.Quiet; result.clean = _.Clean; result.iFeel = getIFeel(); // Not supported. result.model = -1; // No models used. - result.quiet = false; result.econo = false; result.filter = false; result.beep = false; @@ -404,6 +416,7 @@ String IRElectraAc::toString(void) const { result += addToggleToString(getLightToggle(), kLightStr); result += addBoolToString(_.Clean, kCleanStr); result += addBoolToString(_.Turbo, kTurboStr); + result += addBoolToString(_.Quiet, kQuietStr); result += addBoolToString(_.IFeel, kIFeelStr); } if (_.IFeel || _.SensorUpdate) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h index 602406d8d..ebc330068 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h @@ -15,6 +15,7 @@ // Brand: Centek, Model: YKR-P/002E remote // Brand: AEG, Model: Chillflex Pro AXP26U338CW A/C // Brand: Electrolux, Model: YKR-H/531E A/C +// Brand: Delonghi, Modell: PAC EM90 #ifndef IR_ELECTRA_H_ #define IR_ELECTRA_H_ @@ -52,7 +53,7 @@ union ElectraProtocol { // Byte 5 uint8_t :6; uint8_t Turbo :1; - uint8_t :1; + uint8_t Quiet :1; // Byte 6 uint8_t :3; uint8_t IFeel :1; @@ -145,6 +146,8 @@ class IRElectraAc { bool getLightToggle(void) const; void setTurbo(const bool on); bool getTurbo(void) const; + void setQuiet(const bool on); + bool getQuiet(void) const; void setIFeel(const bool on); bool getIFeel(void) const; void setSensorUpdate(const bool on); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.cpp new file mode 100644 index 000000000..c9b42dd90 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.cpp @@ -0,0 +1,489 @@ +// Copyright 2025 GottemHams +/// @file +/// @brief Support for Eurom A/C protocols. +/// @see https://eurom.nl/wp-content/uploads/2022/04/Polar-12C-16CH-v1.0.pdf + +#include "ir_Eurom.h" +#include +#include +#include +#include "IRrecv.h" +#include "IRsend.h" +#include "IRtext.h" +#include "IRutils.h" + +#if __cplusplus >= 201103L && defined(_GLIBCXX_USE_C99_MATH_TR1) + using std::roundf; +#else + using ::roundf; +#endif + +using irutils::uint8ToBcd; +using irutils::bcdToUint8; +using irutils::addBoolToString; +using irutils::addFanToString; +using irutils::addLabeledString; +using irutils::addModeToString; +using irutils::addTempToString; +using irutils::minsToString; + +#if SEND_EUROM +/// Send a Eurom formatted message. +/// Status: STABLE / Confirmed Working. +/// @param[in] data An array of bytes containing the IR command. +/// It is assumed to be in MSB order for this code. +/// e.g. +/// @code +/// unsigned char data[kEuromStateLength] = +/// {0x18,0x27,0x31,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x10,0x1D}; +/// @endcode +/// @param[in] nbytes The number of bytes of data in the array. +/// @param[in] repeat The number of times the command is to be repeated. +void IRsend::sendEurom(const uint8_t data[], const uint16_t nbytes, + const uint16_t repeat) { + // Check if we have enough bytes to send a proper message + if (nbytes < kEuromStateLength) + return; + + sendGeneric(kEuromHdrMark, kEuromHdrSpace, + kEuromBitMark, kEuromOneSpace, + kEuromBitMark, kEuromZeroSpace, + kEuromBitMark, kEuromSpaceGap, + data, nbytes, kEuromFreq, true, repeat, kDutyDefault); +} +#endif // SEND_EUROM + +#if DECODE_EUROM +/// Decode the supplied Eurom message. +/// Status: STABLE / Confirmed Working. +/// @param[in,out] results PTR to the data to decode & where to store the result +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +/// @return True if it can decode it, false if it can't. +bool IRrecv::decodeEurom(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < nbits) + return false; // Too short a message to match + + if (strict && nbits != kEuromBits) + return false; + + if (!matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + kEuromHdrMark, kEuromHdrSpace, + kEuromBitMark, kEuromOneSpace, + kEuromBitMark, kEuromZeroSpace, + kEuromBitMark, kEuromSpaceGap, true)) return false; + + // Success + results->bits = nbits; + results->decode_type = EUROM; + return true; +} +#endif // DECODE_EUROM + +/// Class constructor. +/// @param[in] pin GPIO to be used when sending. +/// @param[in] inverted Is the output signal to be inverted? +/// @param[in] use_modulation Is frequency modulation to be used? +IREuromAc::IREuromAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { + stateReset(); +} + +/// Combine a mode flag and temperature into a single byte for the AC. +/// Note that validity is not checked again. +/// @param[in] mode A valid mode flag. +/// @param[in] celsius A valid temperature, i.e. within the proper range. +uint8_t IREuromAc::getModeCelsiusByte(const uint8_t mode, + const uint8_t celsius) const { + if (celsius >= kEuromMaxTempC) + return mode | kEuromMaxTempFlag; + return mode | ((celsius - kEuromMinTempC) << 4); +} + +/// Combine sleep mode and a timer duration into a single byte for the AC. +/// Note that validity is not checked again. +/// @param[in] sleep Whether sleep mode should be enabled. +/// @param[in] hours A valid duration, i.e. within the proper range. +uint8_t IREuromAc::getSleepOnTimerByte(const bool sleep, + const uint8_t hours) const { + uint8_t base = sleep ? kEuromSleepEnabled : kEuromSleepOnTimerDisabled; + return base + uint8ToBcd(hours); +} + +/// Reset the internals of the object to a known good state. +void IREuromAc::stateReset(void) { + _.Sum1 = 0x18; + _.Sum2 = 0x27; + // No need to call setMode() separately, is handled by setTemp() + setTemp(state_celsius_); // 23 C + _.Power_Swing = kEuromPowerSwingDisabled; + setSleep(state_sleep_); // false + // No need to call setOnTimer() separately, is handled by setSleep() + _.Sum3 = 0x00; + setOffTimer(0); + _.Sum4 = 0x80; + setFan(kEuromFanLow); +} + +#if SEND_EUROM +/// Send the current internal state as an IR message. +/// @param[in] repeat Number of times the message will be repeated. Note that +/// the original remote sends the same signal twice, but the +/// actual A/C works just fine if you send it once. +void IREuromAc::send(const uint16_t repeat) { + _irsend.sendEurom(getRaw(), kEuromStateLength, repeat); +} +#endif // SEND_EUROM + +/// Set up hardware to be able to send a message. +void IREuromAc::begin(void) { + _irsend.begin(); +} + +/// Calculate the checksum for the supplied state. +/// @param[in] state The source state to generate the checksum from. +/// @param[in] length Length of the supplied state to checksum. +/// @return The checksum value. +uint8_t IREuromAc::calcChecksum(const uint8_t state[], const uint16_t length) { + uint8_t checksum = irutils::sumNibbles(state + 1, length - 2); + checksum -= irutils::sumNibbles(state, 1); + return checksum; +} + +/// Verify if the checksum is valid for a given state. +/// @param[in] state The source state to verify the checksum of. +/// @param[in] length The size of the supplied state. +/// @return A boolean indicating if its checksum is valid. +bool IREuromAc::validChecksum(const uint8_t state[], const uint16_t length) { + return state[length - 1] == IREuromAc::calcChecksum(state, length); +} + +/// Update the checksum value for the current internal state. +void IREuromAc::checksum(void) { + _.Checksum = IREuromAc::calcChecksum(_.raw, kEuromStateLength); +} + +/// Set the raw state of the remote. +/// @param[in] state The raw state from the native IR message. +void IREuromAc::setRaw(const uint8_t state[]) { + std::memcpy(_.raw, state, kEuromStateLength); +} + +/// Get the raw state of the remote, suitable to be sent with the appropriate +/// IRsend object method. +/// @return A PTR to the internal state. +uint8_t *IREuromAc::getRaw(void) { + checksum(); // Let's ensure this is updated before returning + return _.raw; +} + +/// Set the internal state to powered on. +void IREuromAc::on(void) { + setPower(true); +} + +/// Set the internal state to powered off. +void IREuromAc::off(void) { + setPower(false); +} + +/// Set the internal state to use the desired power setting. +/// @param[in] state The desired power setting. +void IREuromAc::setPower(const bool state) { + // We'll also have to preserve the swing state + if (state) + _.Power_Swing |= kEuromPowerOn; + else + _.Power_Swing &= kEuromSwingOn; +} + +/// Get the current power setting from the internal state. +/// @return A boolean indicating the current power setting. +bool IREuromAc::getPower(void) const { + return (_.Power_Swing & kEuromPowerOn) == kEuromPowerOn; +} + +/// Set the internal state to use the desired operation mode. +/// @param[in] mode The desired operation mode. +void IREuromAc::setMode(const uint8_t mode) { + switch (mode) { + case kEuromCool: + case kEuromHeat: + state_mode_ = mode; + _.Mode_Celsius = getModeCelsiusByte(mode, state_celsius_); + break; + case kEuromDehumidify: + case kEuromVentilate: + state_mode_ = mode; + _.Mode_Celsius = mode; + break; + default: + break; + } +} + +/// Get the current operation mode setting from the internal state. +/// @return The current operation mode. +uint8_t IREuromAc::getMode(void) const { + return state_mode_; +} + +/// Set the internal state to use the desired temperature. +/// @param[in] degrees The desired temperature in degrees, normally Celsius. +/// @param[in] fahrenheit If the given temperature is in Fahrenheit instead. +void IREuromAc::setTemp(const uint8_t degrees, const bool fahrenheit) { + if (state_mode_ != kEuromCool && state_mode_ != kEuromHeat) + return; + + uint8_t temp_c, temp_f; + if (fahrenheit) { + temp_f = std::max(kEuromMinTempF, degrees); + temp_f = std::min(kEuromMaxTempF, temp_f); + temp_c = static_cast(roundf(fahrenheitToCelsius(temp_f))); + _.Fahrenheit = kEuromFahrenheitEnabled + temp_f; + } else { + temp_c = degrees; + _.Fahrenheit = kEuromFahrenheitDisabled; + } + + temp_c = std::max(kEuromMinTempC, temp_c); + temp_c = std::min(kEuromMaxTempC, temp_c); + state_celsius_ = temp_c; + _.Mode_Celsius = getModeCelsiusByte(state_mode_, temp_c); +} + +/// Get the current temperature from the internal state. +/// @return The current temperature, which can be either Celsius or Fahrenheit, +/// depending on what was used with setTemp(). See also: getTempIsFahrenheit(). +uint8_t IREuromAc::getTemp(void) const { + if (state_mode_ != kEuromCool && state_mode_ != kEuromHeat) + return 0; // Not supported in other modes + if (getTempIsFahrenheit()) + return _.Fahrenheit - kEuromFahrenheitEnabled; + return state_celsius_; +} + +/// Check if Fahrenheit is currently being used by the internal state. +/// @return A boolean indicating if the current temperature is in Fahrenheit. +bool IREuromAc::getTempIsFahrenheit(void) const { + return _.Fahrenheit != kEuromFahrenheitDisabled; +} + +/// Set the internal state to use the desired fan speed. +/// @param[in] speed The desired fan speed. +void IREuromAc::setFan(const uint8_t speed) { + switch (speed) { + case kEuromFanLow: + case kEuromFanMed: + case kEuromFanHigh: + _.Fan = speed; + break; + default: + break; + } +} + +/// Get the current fan speed from the internal state. +/// @return The current fan speed. +uint8_t IREuromAc::getFan(void) const { + return _.Fan; +} + +/// Set the internal state to use the desired swing setting. +/// @param[in] state The desired swing setting. +void IREuromAc::setSwing(const bool state) { + if (state) + _.Power_Swing |= kEuromSwingOn; + else + _.Power_Swing &= kEuromPowerOn; +} + +/// Get the current swing setting from the internal state. +/// @return A boolean indicating the current swing setting. +bool IREuromAc::getSwing(void) const { + return (_.Power_Swing & kEuromSwingOn) == kEuromSwingOn; +} + +/// Set the internal state to use the desired sleep setting. +/// @param[in] state The desired sleep setting. +void IREuromAc::setSleep(const bool state) { + state_sleep_ = state; + _.Sleep_OnTimer = getSleepOnTimerByte(state, state_on_timer_); +} + +/// Get the current sleep setting from the internal state. +/// @return A boolean indicating the current sleep setting. +bool IREuromAc::getSleep(void) const { + return state_sleep_; +} + +/// Set the internal state to use the desired "off timer" duration. +/// @param[in] duration The desired duration, in hours. +void IREuromAc::setOffTimer(const uint8_t duration) { + uint8_t hours = std::max(kEuromTimerMin, duration); + hours = std::min(kEuromTimerMax, hours); + _.OffTimer = kEuromOffTimer + uint8ToBcd(hours); + _.OffTimerEnabled = hours ? kEuromOffTimer : kEuromOffTimerDisabled; +} + +/// Get the current "off timer" duration from the internal state. +/// @return The current duration, in hours. +uint8_t IREuromAc::getOffTimer(void) const { + return bcdToUint8(_.OffTimer - kEuromOffTimer); +} + +/// Set the internal state to use the desired "on timer" duration. +/// @param[in] duration The desired duration, in hours. +void IREuromAc::setOnTimer(const uint8_t duration) { + uint8_t hours = std::max(kEuromTimerMin, duration); + hours = std::min(kEuromTimerMax, hours); + state_on_timer_ = hours; + _.Sleep_OnTimer = getSleepOnTimerByte(state_sleep_, hours); +} + +/// Get the current "on timer" duration from the internal state. +/// @return The current duration, in hours. +uint8_t IREuromAc::getOnTimer(void) const { + return state_on_timer_; +} + +/// Convert a stdAc::opmode_t enum into its native operation mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IREuromAc::convertMode(const stdAc::opmode_t mode) { + // This particular A/C doesn't actually have an 'Auto' mode, so we'll just use + // the normal fan mode instead + switch (mode) { + case stdAc::opmode_t::kCool: + return kEuromCool; + case stdAc::opmode_t::kHeat: + return kEuromHeat; + case stdAc::opmode_t::kDry: + return kEuromDehumidify; + default: + return kEuromVentilate; + } +} + +/// Convert a stdAc::fanspeed_t enum into its native speed. +/// @param[in] speed The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IREuromAc::convertFan(const stdAc::fanspeed_t speed) { + // This particular A/C doesn't actually have an 'Auto' mode, so we'll just use + // the lowest fan speed instead + switch (speed) { + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: + return kEuromFanHigh; + case stdAc::fanspeed_t::kMedium: + return kEuromFanMed; + default: + return kEuromFanLow; + } +} + +/// Convert a stdAc::swingv_t enum into its native swing. +/// @param[in] swing The enum to be converted. +/// @return The native equivalent of the enum. +bool IREuromAc::convertSwing(const stdAc::swingv_t swing) { + // The only choice is on or off, so let's just treat the former as auto mode + switch (swing) { + case stdAc::swingv_t::kAuto: + return true; + default: + return false; + } +} + +/// Convert a native operation mode into its stdAc enum equivalent. +/// @param[in] mode The native operation mode setting to be converted. +/// @return The stdAc enum equivalent of the native setting. +stdAc::opmode_t IREuromAc::toCommonMode(const uint8_t mode) { + // This particular A/C doesn't actually have an 'Auto' mode, so we'll just use + // the normal fan mode instead. To make this more clear, 'kEuromVentilate' is + // explicitly included in the switch (instead of being omitted and implicitly + // handled via the default case). + switch (mode) { + case kEuromCool: + return stdAc::opmode_t::kCool; + case kEuromHeat: + return stdAc::opmode_t::kHeat; + case kEuromDehumidify: + return stdAc::opmode_t::kDry; + case kEuromVentilate: + default: + return stdAc::opmode_t::kFan; + } +} + +/// Convert a native fan speed into its stdAc enum equivalent. +/// @param[in] speed The native speed setting to be converted. +/// @return The stdAc enum equivalent of the native setting. +stdAc::fanspeed_t IREuromAc::toCommonFanSpeed(const uint8_t speed) { + // This particular A/C doesn't actually have an 'Auto' mode, so we'll just use + // the lowest speed instead. To make this more clear, 'kEuromFanLow' is + // explicitly included in the switch (instead of being omitted and implicitly + // handled via the default case). + switch (speed) { + case kEuromFanHigh: + return stdAc::fanspeed_t::kMax; + case kEuromFanMed: + return stdAc::fanspeed_t::kMedium; + case kEuromFanLow: + default: + return stdAc::fanspeed_t::kMin; + } +} + +/// Convert a native swing setting into its stdAc enum equivalent. +/// @param[in] swing The native swing setting to be converted. +/// @return The stdAc enum equivalent of the native setting. +stdAc::swingv_t IREuromAc::toCommonSwing(const bool swing) { + // The only choice is on or off, so let's just treat the former as auto mode + return swing ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; +} + +/// Convert the current internal state into its stdAc::state_t equivalent. +/// @return The stdAc struct equivalent of the native settings. +stdAc::state_t IREuromAc::toCommon(void) const { + stdAc::state_t result{}; + result.protocol = EUROM; + result.power = getPower(); + result.mode = toCommonMode(getMode()); + result.degrees = getTemp(); + result.celsius = !getTempIsFahrenheit(); + result.fanspeed = toCommonFanSpeed(getFan()); + result.swingv = toCommonSwing(getSwing()); + result.sleep = getSleep(); + return result; +} + +/// Convert the current internal state into a human-readable string. +/// @return A human-readable string. +String IREuromAc::toString(void) const { + String result = ""; + result.reserve(70); // Reserve some heap for the string to reduce fragging + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), 0xFF, kEuromCool, + kEuromHeat, kEuromDehumidify, kEuromVentilate); + result += addTempToString(getTemp(), !getTempIsFahrenheit()); + result += addFanToString(getFan(), kEuromFanHigh, kEuromFanLow, + 0xFF, 0xFF, + kEuromFanMed); + + result += addBoolToString(getSwing(), kSwingVStr); + result += addBoolToString(getSleep(), kSleepStr); + + uint8_t off_timer_min = getOffTimer() * 60; + uint8_t on_timer_min = getOnTimer() * 60; + String off_timer_str = off_timer_min ? minsToString(off_timer_min) : kOffStr; + String on_timer_str = on_timer_min ? minsToString(on_timer_min) : kOffStr; + result += addLabeledString(off_timer_str, kOffTimerStr); + result += addLabeledString(on_timer_str, kOnTimerStr); + return result; +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.h new file mode 100644 index 000000000..01cd5e5b2 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Eurom.h @@ -0,0 +1,244 @@ +// Copyright 2025 GottemHams +/// @file +/// @brief Support for Eurom A/C protocols. +/// @see https://eurom.nl/wp-content/uploads/2022/04/Polar-12C-16CH-v1.0.pdf + +// Supports: +// Brand: Eurom, Model: Polar 16CH + +#ifndef IR_EUROM_H_ +#define IR_EUROM_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +/// Native representation of a Eurom message. +union EuromProtocol { + uint8_t raw[kEuromStateLength]; // The state of the IR remote + struct { + // Byte 0 is used as a negative offset for the checksum and is always 0x18 + uint8_t Sum1 :8; + + // Byte 1 is used as part of the checksum only and is always 0x27 + uint8_t Sum2 :8; + + // Byte 2 combines 2 functions and has some considerations: + // 1. Cooling mode almost always has the lower nibble set to 0x1, + // e.g. 0x01 = 16 C, 0x11 = 17 C, 0xF1 = 31 C. + // Exception: 0x09 means 32 C (max temperature). + // 2. Dehumidification doesn't support temperatures, so this is always 0x72. + // 3. Same goes for fan mode, which is always 0x73. + // 4. Heating mode almost always has the lower nibble set to 0x4, + // e.g. 0x04 = 16 C, 0x14 = 17 C, 0xF4 = 31 C. + // Exception: 0x0C means 32 C (max temperature). + uint8_t Mode_Celsius :8; + + // Byte 3 also combines 2 functions, with the values being OR'ed together: + // 1. 0x00 means power off, swing off + // 2. 0x40 means power off, swing on + // 3. 0x80 means power on, swing off + // 3. 0xC0 means power on, swing on + uint8_t Power_Swing :8; + + // Byte 4 is to track Fahrenheit separately, but note that it will always + // reset to 0x00 if Celsius is used. On the other hand, Celsius moves along + // with this, i.e. a change of +1/-1 C for roughly every 3 F. The base value + // is 0x41 which corresponds to 61 F and increases by 0x01 for every degree. + // This gives it a range of 0x41 - 0x5E (inclusive). + uint8_t Fahrenheit :8; + + // Byte 5 yet again combines functions: + // 1. 0x00 for sleep mode disabled, 0x40 for enabled + // 2. The timer duration is simply encoded as BCD and added to this, with a + // maximum of 24 hours + uint8_t Sleep_OnTimer :8; + + // Byte 6 seems to be truly unused, since it's always 0x00. We'll still + // always use it in checksums though. + uint8_t Sum3 :8; + + // Byte 7 is always at least 0x80, with the hours also being added as BCD, + // e.g. 0x80 = 0 hours, 0x81 = 1 h, 0xA4 = 24 h. + uint8_t OffTimer :8; + + // Byte 8 doesn't really seem to matter, but it should be 0x00 or 0x80 for + // off and on respectively. Apparently setting the **duration** alone is + // already enough to set the timer? + uint8_t OffTimerEnabled :8; + + // Byte 9 is used as part of the checksum only and is slways 0x80 + uint8_t Sum4 :8; + + // Byte 10 is simple: 0x10, 0x20, 0x40 for low, medium and high respectively + uint8_t Fan :8; + + // Byte 11 holds a funny checksum. =] + // Add all nibbles beyond the first byte (excluding the checksum of course), + // then subtract the first byte. The second byte should always be larger, so + // this never results in sudden signedness (i.e. underflowing). It might be + // pure coincidence that the first byte is always 0x18 and they could have + // hardcoded that value elsewhere/otherwise. + uint8_t Checksum :8; + }; +}; + +// Constants + +// IR signal information +const uint16_t kEuromHdrMark = 3257; +const uint16_t kEuromBitMark = 454; +const uint16_t kEuromHdrSpace = 3187; +const uint16_t kEuromOneSpace = 1162; +const uint16_t kEuromZeroSpace = 355; +const uint16_t kEuromSpaceGap = 50058; +const uint16_t kEuromFreq = 38000; + +// Modes +const uint8_t kEuromCool = 0x01; // Lowest possible value, 16 C +const uint8_t kEuromDehumidify = 0x72; +const uint8_t kEuromVentilate = 0x73; +const uint8_t kEuromHeat = 0x04; // Also 16 C + +// Reaching the highest temperature breaks the formula that is used otherwise, +// because we should basically just OR this flag to the above mode byte. It +// seems more like it indicates "max temp" instead of "32 C". +const uint8_t kEuromMaxTempFlag = 0x08; + +// Temperatures +const uint8_t kEuromMinTempC = 16; +const uint8_t kEuromMaxTempC = 32; + +const uint8_t kEuromMinTempF = 61; +const uint8_t kEuromMaxTempF = 90; + +// The enabled flag will simply be added to chosen temperature +const uint8_t kEuromFahrenheitDisabled = 0x00; +const uint8_t kEuromFahrenheitEnabled = 0x04; + +// Power and swing +const uint8_t kEuromPowerSwingDisabled = 0x00; +const uint8_t kEuromPowerOn = 0x80; +const uint8_t kEuromSwingOn = 0x40; + +// Sleep mode and the "on timer" +const uint8_t kEuromSleepOnTimerDisabled = 0x00; +const uint8_t kEuromSleepEnabled = 0x40; + +// The "off timer" +const uint8_t kEuromOffTimerDisabled = 0x00; +const uint8_t kEuromOffTimerEnabled = 0x80; +const uint8_t kEuromOffTimer = kEuromOffTimerEnabled; // Corresponds to 0 hours + +// Stuff for all timers +const uint8_t kEuromTimerMin = 0; +const uint8_t kEuromTimerMax = 24; + +// Fan speeds +const uint8_t kEuromFanLow = 0x10; +const uint8_t kEuromFanMed = 0x20; +const uint8_t kEuromFanHigh = 0x40; + +// Classes + +/// Class for handling detailed Eurom A/C messages. +class IREuromAc { + public: + explicit IREuromAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + + void stateReset(); +#if SEND_EUROM + void send(const uint16_t repeat = kNoRepeat); + /// Run the calibration to calculate uSec timing offsets for this platform. + /// @return The uSec timing offset needed per modulation of the IR Led. + /// @note This will produce a 65 ms IR signal pulse at 38 kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { + return _irsend.calibrate(); + } +#endif // SEND_EUROM + + void begin(void); + static uint8_t calcChecksum(const uint8_t state[], + const uint16_t length = kEuromStateLength); + static bool validChecksum(const uint8_t state[], + const uint16_t length = kEuromStateLength); + + void setRaw(const uint8_t state[]); + uint8_t *getRaw(void); + + void on(void); + void off(void); + + void setPower(const bool state); + bool getPower(void) const; + + void setMode(const uint8_t mode); + uint8_t getMode(void) const; + + void setTemp(const uint8_t degrees, const bool fahrenheit = false); + uint8_t getTemp(void) const; + bool getTempIsFahrenheit(void) const; + + void setFan(const uint8_t speed); + uint8_t getFan(void) const; + + void setSwing(const bool state); + bool getSwing(void) const; + + void setSleep(const bool state); + bool getSleep(void) const; + + void setOffTimer(const uint8_t duration); + uint8_t getOffTimer(void) const; + + void setOnTimer(const uint8_t duration); + uint8_t getOnTimer(void) const; + + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint8_t convertFan(const stdAc::fanspeed_t speed); + static bool convertSwing(const stdAc::swingv_t swing); + + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + static stdAc::swingv_t toCommonSwing(const bool swing); + + stdAc::state_t toCommon(void) const; + String toString(void) const; +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + /// @cond IGNORE + IRsendTest _irsend; + /// @endcond +#endif + EuromProtocol _; + + // Due to some bytes combining multiple functions, we'll need to keep track of + // some of the original values ourselves. Otherwise we wouldn't really be able + // to e.g. return the current mode or temperature, or changing the sleep mode + // without also messing with the timer hours. + uint8_t state_mode_ = kEuromCool; + uint8_t state_celsius_ = 23; + bool state_sleep_ = false; + uint8_t state_on_timer_ = kEuromTimerMin; + + // Some helper functions for reusing the above state variables depending on + // context and returning the byte expected by the AC. + uint8_t getModeCelsiusByte(const uint8_t mode, const uint8_t celsius) const; + uint8_t getSleepOnTimerByte(const bool sleep, const uint8_t hours) const; + + void checksum(void); +}; + +#endif // IR_EUROM_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h index 6e2583a0c..ed4979dac 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h @@ -41,6 +41,7 @@ // Brand: Fujitsu, Model: AR-REG1U remote (ARRAH2E) // Brand: OGeneral, Model: AR-RCL1E remote (ARRAH2E) // Brand: Fujitsu General, Model: AR-JW17 remote (ARDB1) +// Brand: Fujitsu General, Model: AR-JW19 remote (ARDB1) #ifndef IR_FUJITSU_H_ #define IR_FUJITSU_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_GlobalCache.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_GlobalCache.cpp index e8ebac4af..4fbc34050 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_GlobalCache.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_GlobalCache.cpp @@ -37,7 +37,8 @@ void IRsend::sendGC(uint16_t buf[], uint16_t len) { enableIROut(hz); uint32_t periodic_time = calcUSecPeriod(hz, false); uint8_t emits = - std::min(buf[kGlobalCacheRptIndex], (uint16_t)kGlobalCacheMaxRepeat); + std::min(buf[kGlobalCacheRptIndex], + static_cast(kGlobalCacheMaxRepeat)); // Repeat for (uint8_t repeat = 0; repeat < emits; repeat++) { // First time through, start at the beginning (kGlobalCacheStartIndex), diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp index c3d9d62c8..3eb07c859 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp @@ -471,7 +471,7 @@ bool IRrecv::decodeGoodweather(decode_results* results, uint16_t offset, DPRINT("DEBUG: inverted = "); DPRINTLN((uint16_t)inverted); if (data != (inverted ^ 0xFF)) return false; // Data integrity failed. - dataSoFar |= (uint64_t)data << dataBitsSoFar; + dataSoFar |= static_cast(data) << dataBitsSoFar; } // Footer. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp index 2c44cfe52..3d2da38f7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp @@ -375,6 +375,7 @@ void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) { uint8_t new_position = position; if (!automatic) { switch (position) { + case kGreeSwingLastPos: case kGreeSwingUp: case kGreeSwingMiddleUp: case kGreeSwingMiddle: @@ -503,6 +504,7 @@ uint8_t IRGreeAC::convertFan(const stdAc::fanspeed_t speed) { /// @return The native equivalent of the enum. uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) { switch (swingv) { + case stdAc::swingv_t::kOff: return kGreeSwingLastPos; case stdAc::swingv_t::kHighest: return kGreeSwingUp; case stdAc::swingv_t::kHigh: return kGreeSwingMiddleUp; case stdAc::swingv_t::kMiddle: return kGreeSwingMiddle; @@ -562,7 +564,7 @@ stdAc::swingv_t IRGreeAC::toCommonSwingV(const uint8_t pos) { case kGreeSwingMiddle: return stdAc::swingv_t::kMiddle; case kGreeSwingMiddleDown: return stdAc::swingv_t::kLow; case kGreeSwingDown: return stdAc::swingv_t::kLowest; - default: return stdAc::swingv_t::kAuto; + default: return stdAc::swingv_t::kOff; } } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp index a60828282..c18846942 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp @@ -723,8 +723,10 @@ void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) { temp = kHaierAcYrw02MinTempF; else if (temp > kHaierAcYrw02MaxTempF) temp = kHaierAcYrw02MaxTempF; - if (degree >= 77) { temp++; } - if (degree >= 79) { temp++; } + if (degree >= 77) + temp++; + if (degree >= 79) + temp++; // See at IRHaierAC176::getTemp() comments for clarification _.ExtraDegreeF = temp % 2; _.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1; @@ -741,7 +743,8 @@ void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) { /// The unit of temperature is specified by UseFahrenheit value. /// @return The current setting for temperature. uint8_t IRHaierAC176::getTemp(void) const { - if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; } + if (!_.UseFahrenheit) + return _.Temp + kHaierAcYrw02MinTempC; uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF; // The way of coding the temperature in degree Fahrenheit is // kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example @@ -778,8 +781,10 @@ uint8_t IRHaierAC176::getTemp(void) const { // | 84F | 0b1101 | 0b0 | // | 86F | 0b1110 | 0b0 | // | 85F | 0b1101 | 0b1 | - if (degree >= 77) { degree--; } - if (degree >= 79) { degree--; } + if (degree >= 77) + degree--; + if (degree >= 79) + degree--; return degree; } @@ -958,7 +963,7 @@ uint8_t IRHaierAC176::getTimerMode(void) const { return _.TimerMode; } /// Set the number of minutes of the On Timer setting. /// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer. void IRHaierAC176::setOnTimer(const uint16_t mins) { - const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins); + const uint16_t nr_mins = std::min(static_cast(23 * 60 + 59), mins); _.OnTimerHrs = nr_mins / 60; _.OnTimerMins = nr_mins % 60; @@ -988,7 +993,7 @@ uint16_t IRHaierAC176::getOnTimer(void) const { /// Set the number of minutes of the Off Timer setting. /// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer. void IRHaierAC176::setOffTimer(const uint16_t mins) { - const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins); + const uint16_t nr_mins = std::min(static_cast(23 * 60 + 59), mins); _.OffTimerHrs = nr_mins / 60; _.OffTimerMins = nr_mins % 60; @@ -1617,8 +1622,10 @@ void IRHaierAC160::setTemp(const uint8_t degree, const bool fahrenheit) { temp = kHaierAcYrw02MinTempF; else if (temp > kHaierAcYrw02MaxTempF) temp = kHaierAcYrw02MaxTempF; - if (degree >= 77) { temp++; } - if (degree >= 79) { temp++; } + if (degree >= 77) + temp++; + if (degree >= 79) + temp++; // See at IRHaierAC160::getTemp() comments for clarification _.ExtraDegreeF = temp % 2; _.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1; @@ -1635,7 +1642,8 @@ void IRHaierAC160::setTemp(const uint8_t degree, const bool fahrenheit) { /// The unit of temperature is specified by UseFahrenheit value. /// @return The current setting for temperature. uint8_t IRHaierAC160::getTemp(void) const { - if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; } + if (!_.UseFahrenheit) + return _.Temp + kHaierAcYrw02MinTempC; uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF; // The way of coding the temperature in degree Fahrenheit is // kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example @@ -1672,8 +1680,10 @@ uint8_t IRHaierAC160::getTemp(void) const { // | 84F | 0b1101 | 0b0 | // | 86F | 0b1110 | 0b0 | // | 85F | 0b1101 | 0b1 | - if (degree >= 77) { degree--; } - if (degree >= 79) { degree--; } + if (degree >= 77) + degree--; + if (degree >= 79) + degree--; return degree; } @@ -1854,7 +1864,7 @@ uint8_t IRHaierAC160::getTimerMode(void) const { return _.TimerMode; } /// Set the number of minutes of the On Timer setting. /// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer. void IRHaierAC160::setOnTimer(const uint16_t mins) { - const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins); + const uint16_t nr_mins = std::min(static_cast(23 * 60 + 59), mins); _.OnTimerHrs = nr_mins / 60; _.OnTimerMins = nr_mins % 60; @@ -1884,7 +1894,7 @@ uint16_t IRHaierAC160::getOnTimer(void) const { /// Set the number of minutes of the Off Timer setting. /// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer. void IRHaierAC160::setOffTimer(const uint16_t mins) { - const uint16_t nr_mins = std::min((uint16_t)(23 * 60 + 59), mins); + const uint16_t nr_mins = std::min(static_cast(23 * 60 + 59), mins); _.OffTimerHrs = nr_mins / 60; _.OffTimerMins = nr_mins % 60; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Kelon.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Kelon.cpp index bb8f16093..c891b738f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Kelon.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Kelon.cpp @@ -318,8 +318,9 @@ void IRKelonAc::setTimer(uint16_t mins) { /// @return The timer set minutes uint16_t IRKelonAc::getTimer() const { if (_.TimerHours >= 10) - return ((uint16_t) ((_.TimerHours << 1) | _.TimerHalfHour) - 10) * 60; - return (((uint16_t) _.TimerHours) * 60) + (_.TimerHalfHour ? 30 : 0); + return (static_cast((_.TimerHours << 1) | _.TimerHalfHour) - + 10) * 60; + return static_cast(_.TimerHours) * 60 + (_.TimerHalfHour ? 30 : 0); } /// Enable or disable the timer. Note that in order to enable the timer the diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lego.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lego.cpp index 3b7144768..6470bb547 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lego.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lego.cpp @@ -38,7 +38,7 @@ void IRsend::sendLegoPf(const uint64_t data, const uint16_t nbits, // 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++) { + for (uint16_t r = 0; r < std::max(repeat, static_cast(5)); r++) { // Lego has a special repeat mode which repeats a message with varying // start to start times. sendGeneric(kLegoPfBitMark, kLegoPfHdrSpace, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lutron.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lutron.cpp index 5d0424784..11e4c0ae7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lutron.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Lutron.cpp @@ -96,7 +96,7 @@ bool IRrecv::decodeLutron(decode_results *results, uint16_t offset, break; // We've likely reached the end of a message. } // Remove a bit length from the current entry. - entry = std::max(entry, (uint16_t)(kLutronTick / kRawTick)) - + entry = std::max(entry, static_cast(kLutronTick / kRawTick)) - kLutronTick / kRawTick; } if (offset % 2 && !match(entry, kLutronDelta, 0, kLutronDelta)) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.cpp index 80acfcda3..c8cd610a3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.cpp @@ -566,7 +566,7 @@ uint16_t IRMideaAC::getOnTimer(void) const { /// Setting it will disable that mode/settings. void IRMideaAC::setOnTimer(const uint16_t mins) { setEnableSensorTemp(false); - uint8_t halfhours = std::min((uint16_t)(24 * 60), mins) / 30; + uint8_t halfhours = std::min(static_cast(24 * 60), mins) / 30; if (halfhours) _.SensorTemp = ((halfhours - 1) << 1) | 1; else @@ -589,7 +589,7 @@ uint16_t IRMideaAC::getOffTimer(void) const { return _.OffTimer * 30 + 30; } /// of the actual device/protocol. /// @note A value of less than 30 will disable the Timer. void IRMideaAC::setOffTimer(const uint16_t mins) { - uint8_t halfhours = std::min((uint16_t)(24 * 60), mins) / 30; + uint8_t halfhours = std::min(static_cast(24 * 60), mins) / 30; if (halfhours) _.OffTimer = halfhours - 1; else diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp index b7d6ce42d..caa72375a 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp @@ -389,8 +389,9 @@ void IRMirageAc::setClock(const uint32_t nr_of_seconds) { _.Minutes = _.Seconds = 0; // No clock setting. Clear it just in case. break; default: + // Limit to 23:59:59 uint32_t remaining = std::min( - nr_of_seconds, (uint32_t)(24 * 60 * 60 - 1)); // Limit to 23:59:59. + nr_of_seconds, static_cast(24 * 60 * 60 - 1)); _.Seconds = uint8ToBcd(remaining % 60); remaining /= 60; _.Minutes = uint8ToBcd(remaining % 60); @@ -586,7 +587,7 @@ uint16_t IRMirageAc::getOnTimer(void) const { /// Set the number of minutes for the On Timer. /// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer. void IRMirageAc::setOnTimer(const uint16_t nr_of_mins) { - uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60)); + uint16_t mins = std::min(nr_of_mins, static_cast(24 * 60)); switch (_model) { case mirage_ac_remote_model_t::KKG29AC1: _.OnTimerEnable = (mins > 0); @@ -612,7 +613,7 @@ uint16_t IRMirageAc::getOffTimer(void) const { /// Set the number of minutes for the Off Timer. /// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer. void IRMirageAc::setOffTimer(const uint16_t nr_of_mins) { - uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60)); + uint16_t mins = std::min(nr_of_mins, static_cast(24 * 60)); switch (_model) { case mirage_ac_remote_model_t::KKG29AC1: _.OffTimerEnable = (mins > 0); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.cpp index 82acaac71..37241570c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.cpp @@ -88,7 +88,8 @@ void IRsend::sendPanasonic64(const uint64_t data, const uint16_t nbits, /// @note This protocol is a modified version of Kaseikyo. void IRsend::sendPanasonic(const uint16_t address, const uint32_t data, const uint16_t nbits, const uint16_t repeat) { - sendPanasonic64(((uint64_t)address << 32) | (uint64_t)data, nbits, repeat); + sendPanasonic64(static_cast(address) << 32 | + static_cast(data), nbits, repeat); } /// Calculate the raw Panasonic data based on device, subdevice, & function. @@ -105,8 +106,10 @@ uint64_t IRsend::encodePanasonic(const uint16_t manufacturer, const uint8_t subdevice, const uint8_t function) { uint8_t checksum = device ^ subdevice ^ function; - return (((uint64_t)manufacturer << 32) | ((uint64_t)device << 24) | - ((uint64_t)subdevice << 16) | ((uint64_t)function << 8) | checksum); + return ((static_cast(manufacturer) << 32) | + (static_cast(device) << 24) | + (static_cast(subdevice) << 16) | + (static_cast(function) << 8) | checksum); } #endif // (SEND_PANASONIC || SEND_DENON) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.h index 5668e4a57..50b0783ac 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Panasonic.h @@ -20,9 +20,11 @@ // Brand: Panasonic, Model: CS-Z9RKR A/C (PANASONIC_AC RKR/6) // Brand: Panasonic, Model: CS-Z24RKR A/C (PANASONIC_AC RKR/6) // Brand: Panasonic, Model: CS-YW9MKD A/C (PANASONIC_AC JKE/4) +// Brand: Panasonic, Model: CS-E12QKEW A/C (PANASONIC_AC DKE/3) // Brand: Panasonic, Model: A75C2311 remote (PANASONIC_AC CKP/5) // Brand: Panasonic, Model: A75C2616-1 remote (PANASONIC_AC DKE/3) // Brand: Panasonic, Model: A75C3704 remote (PANASONIC_AC DKE/3) +// Brand: Panasonic, Model: PN1122V remote (PANASONIC_AC DKE/3) // Brand: Panasonic, Model: A75C3747 remote (PANASONIC_AC JKE/4) // Brand: Panasonic, Model: CS-E9CKP series A/C (PANASONIC_AC32) // Brand: Panasonic, Model: A75C2295 remote (PANASONIC_AC32) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pioneer.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pioneer.cpp index 6efe15c0a..98f4420f1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pioneer.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pioneer.cpp @@ -80,7 +80,7 @@ void IRsend::sendPioneer(const uint64_t data, const uint16_t nbits, /// `irsend.sendPioneer(irsend.encodePioneer(0xAA1C, 0xAA1C), 64, 0);` /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1749#issuecomment-1028122645 uint64_t IRsend::encodePioneer(const uint16_t address, const uint16_t command) { - return (((uint64_t)encodeNEC(address >> 8, address & 0xFF)) << 32) | + return static_cast(encodeNEC(address >> 8, address & 0xFF)) << 32 | encodeNEC(command >> 8, command & 0xFF); } #endif // SEND_PIONEER diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pronto.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pronto.cpp index 2d4ffa759..dcd513d10 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pronto.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Pronto.cpp @@ -62,7 +62,8 @@ void IRsend::sendPronto(uint16_t data[], uint16_t len, uint16_t repeat) { // Pronto frequency is in Hz. uint16_t hz = - (uint16_t)(1000000U / (data[kProntoFreqOffset] * kProntoFreqFactor)); + static_cast(1000000U / (data[kProntoFreqOffset] * + kProntoFreqFactor)); enableIROut(hz); // Grab the length of the two sequences. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RC5_RC6.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RC5_RC6.cpp index 1e0c75b3f..c47303aa2 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RC5_RC6.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RC5_RC6.cpp @@ -129,7 +129,7 @@ uint16_t IRsend::encodeRC5X(const uint8_t address, const uint8_t command, // The 2nd start/field bit (MSB of the return value) is the value of the 7th // command bit. bool s2 = (command >> 6) & 1; - return ((uint16_t)s2 << (kRC5XBits - 1)) | + return (static_cast(s2) << (kRC5XBits - 1)) | encodeRC5(address, command, key_released); } @@ -174,7 +174,8 @@ uint64_t IRsend::encodeRC6(const uint32_t address, const uint8_t command, case kRC6Mode0Bits: return ((address & 0xFFF) << 8) | (command & 0xFF); case kRC6_36Bits: - return ((uint64_t)(address & 0xFFFFFFF) << 8) | (command & 0xFF); + return (static_cast(address & 0xFFFFFFF) << 8) | + (command & 0xFF); default: return 0; } @@ -360,7 +361,7 @@ bool IRrecv::decodeRC5(decode_results *results, uint16_t offset, results->repeat = false; if (is_rc5x) { results->decode_type = RC5X; - results->command |= ((uint32_t)is_rc5x) << 6; + results->command |= (static_cast(is_rc5x)) << 6; } else { results->decode_type = RC5; actual_bits--; // RC5 doesn't count the field bit as data. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RCMM.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RCMM.cpp index 97a3c79b5..36cbbd51a 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RCMM.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_RCMM.cpp @@ -35,7 +35,6 @@ const uint16_t kRcmmMinGapTicks = 120; const uint32_t kRcmmMinGap = 3360; // Use a tolerance of +/-10% when matching some data spaces. const uint8_t kRcmmTolerance = 10; -const uint16_t kRcmmExcess = 50; #if SEND_RCMM /// Send a Philips RC-MM packet. @@ -102,13 +101,15 @@ bool IRrecv::decodeRCMM(decode_results *results, uint16_t offset, // Calc the maximum size in bits, the message can be, or that we can accept. int16_t maxBitSize = - std::min((uint16_t)results->rawlen - 5, (uint16_t)sizeof(data) * 8); + std::min(static_cast(results->rawlen) - 5, + static_cast(sizeof(data)) * 8); // Compliance if (strict) { // Technically the spec says bit sizes should be 12 xor 24. however // 32 bits has been seen from a device. We are going to assume // 12 <= bits <= 32 is the 'required' bit length for the spec. - if (maxBitSize < 12 || maxBitSize > 32) return false; + if (maxBitSize < 12 || maxBitSize > 32) + return false; if (maxBitSize < nbits) return false; // Short cut, we can never reach the expected nr. of bits. } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp index 958f2665b..fc5cbfcc7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp @@ -775,7 +775,7 @@ uint16_t IRSamsungAc::getSleepTimer(void) const { } #define TIMER_RESOLUTION(mins) \ - (((std::min((mins), (uint16_t)(24 * 60))) / 10) * 10) + (((std::min((mins), static_cast(24 * 60))) / 10) * 10) /// Set the On Timer value of the A/C. /// @param[in] nr_of_mins The number of minutes the timer should be. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp index 4b99d0492..6c939e18d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp @@ -892,7 +892,8 @@ uint16_t IRSanyoAc88::getClock(void) const { /// Set the current clock time. /// @param[in] mins_since_midnight The time as nr. of minutes past midnight. void IRSanyoAc88::setClock(const uint16_t mins_since_midnight) { - uint16_t mins = std::min(mins_since_midnight, (uint16_t)(23 * 60 + 59)); + uint16_t mins = std::min(mins_since_midnight, + static_cast(23 * 60 + 59)); _.ClockMins = mins % 60; _.ClockHrs = mins / 60; _.ClockSecs = 0; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp index d184c9301..984551ee0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp @@ -35,9 +35,11 @@ const uint16_t kSharpGapTicks = 1677; const uint16_t kSharpGap = kSharpGapTicks * kSharpTick; // Address(5) + Command(8) + Expansion(1) + Check(1) const uint64_t kSharpToggleMask = - ((uint64_t)1 << (kSharpBits - kSharpAddressBits)) - 1; -const uint64_t kSharpAddressMask = ((uint64_t)1 << kSharpAddressBits) - 1; -const uint64_t kSharpCommandMask = ((uint64_t)1 << kSharpCommandBits) - 1; + (static_cast(1) << (kSharpBits - kSharpAddressBits)) - 1; +const uint64_t kSharpAddressMask = (static_cast(1) << + kSharpAddressBits) - 1; +const uint64_t kSharpCommandMask = (static_cast(1) << + kSharpCommandBits) - 1; using irutils::addBoolToString; using irutils::addFanToString; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sherwood.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sherwood.cpp index 76ffc35ff..e3a7eb506 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sherwood.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sherwood.cpp @@ -19,6 +19,7 @@ /// @note Sherwood remote codes appear to be NEC codes with a mandatory repeat /// code. i.e. repeat should be >= kSherwoodMinRepeat (1). void IRsend::sendSherwood(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendNEC(data, nbits, std::max((uint16_t)kSherwoodMinRepeat, repeat)); + sendNEC(data, nbits, + std::max(static_cast(kSherwoodMinRepeat), repeat)); } #endif // SEND_SHERWOOD diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h index 805270aa2..da80efbac 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h @@ -11,6 +11,7 @@ // Brand: Daewoo, Model: DSB-F0934ELH-V A/C // Brand: Daewoo, Model: GYKQ-52E remote // Brand: TCL, Model: GYKQ-58(XM) remote (TCL96AC) +// Brand: Electrolux, Model: EACM CL/N3 series remote #ifndef IR_TCL_H_ #define IR_TCL_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Teco.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Teco.cpp index 289e15d52..a8845fb05 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Teco.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Teco.cpp @@ -231,7 +231,8 @@ uint16_t IRTecoAc::getTimer(void) const { /// `0` will clear the timer. Max is 24 hrs. /// @note Time is stored internally in increments of 30 mins. void IRTecoAc::setTimer(const uint16_t nr_mins) { - uint16_t mins = std::min(nr_mins, (uint16_t)(24 * 60)); // Limit to 24 hrs. + // Limit to 24 hrs + uint16_t mins = std::min(nr_mins, static_cast(24 * 60)); uint8_t hours = mins / 60; _.TimerOn = mins > 0; // Set the timer flag. _.HalfHour = (mins % 60) >= 30; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp index c9672bcab..53eff99d1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp @@ -40,6 +40,7 @@ using irutils::addModeToString; using irutils::addTempToString; using irutils::checkInvertedBytePairs; using irutils::invertBytePairs; +using irutils::addModelToString; #if SEND_TOSHIBA_AC /// Send a Toshiba A/C message. @@ -104,8 +105,9 @@ void IRToshibaAC::send(const uint16_t repeat) { uint16_t IRToshibaAC::getInternalStateLength(const uint8_t state[], const uint16_t size) { if (size < kToshibaAcLengthByte) return 0; - return std::min((uint16_t)(state[kToshibaAcLengthByte] + kToshibaAcMinLength), - kToshibaACStateLengthLong); + // Fix: Extract the last 4 bits instead + return std::min(static_cast((state[kToshibaAcLengthByte] & 0xF) + + kToshibaAcMinLength), kToshibaACStateLengthLong); } /// Get the length of the current internal state per the protocol structure. @@ -462,7 +464,8 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const { String IRToshibaAC::toString(void) const { String result = ""; result.reserve(95); - result += addTempToString(getTemp(), true, false); + result += addModelToString(decode_type_t::TOSHIBA_AC, getModel(), false); + result += addTempToString(getTemp(), true); switch (getStateLength()) { case kToshibaACStateLengthShort: result += addIntToString(getSwing(true), kSwingVStr); @@ -493,6 +496,30 @@ String IRToshibaAC::toString(void) const { return result; } +/// Get the model information currently known. +/// @return The known model number. +toshiba_ac_remote_model_t IRToshibaAC::getModel(void) const { + switch (_.Model) { + case kToshibaAcRemoteB: + return toshiba_ac_remote_model_t::kToshibaGenericRemote_B; + default: + return toshiba_ac_remote_model_t::kToshibaGenericRemote_A; + } +} + +/// Set the current model for the remote. +/// @param[in] model The model number. +void IRToshibaAC::setModel(const toshiba_ac_remote_model_t model) { + switch (model) { + case toshiba_ac_remote_model_t::kToshibaGenericRemote_B: + _.Model = kToshibaAcRemoteB; + break; + default: + _.Model = kToshibaAcRemoteA; + break; + } +} + #if DECODE_TOSHIBA_AC /// Decode the supplied Toshiba A/C message. /// Status: STABLE / Working. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h index 1314cf54d..163847ad1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h @@ -53,7 +53,11 @@ union ToshibaProtocol{ ///< 1 (56 bit message) ///< 3 (72 bit message) ///< 4 (80 bit message) - uint8_t Length :8; + uint8_t Length :4; + // Toshiba remote type + // 0 - Remote control A + // 1 - Remote control B + uint8_t Model :4; // Byte[3] - The bit-inverted value of the "length" byte. uint8_t :8; // Byte[4] @@ -111,6 +115,9 @@ const uint8_t kToshibaAcFanMax = 5; // 0b101 const uint8_t kToshibaAcTurboOn = 1; // 0b01 const uint8_t kToshibaAcEconoOn = 3; // 0b11 +const uint8_t kToshibaAcRemoteA = 0; // 0b0000 +const uint8_t kToshibaAcRemoteB = 1; // 0b0001 + // Legacy defines. (Deprecated) #define TOSHIBA_AC_AUTO kToshibaAcAuto #define TOSHIBA_AC_COOL kToshibaAcCool @@ -140,6 +147,8 @@ class IRToshibaAC { void begin(void); void on(void); void off(void); + void setModel(const toshiba_ac_remote_model_t model); + toshiba_ac_remote_model_t getModel() const; void setPower(const bool on); bool getPower(void) const; void setTemp(const uint8_t degrees); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.cpp index 9837e0605..71eceb6c7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.cpp @@ -422,7 +422,7 @@ uint16_t IRVoltas::getOnTime(void) const { /// 0 disables the timer. Max is 23 hrs & 59 mins (1439 mins) void IRVoltas::setOnTime(const uint16_t nr_of_mins) { // Cap the total number of mins. - uint16_t mins = std::min(nr_of_mins, (uint16_t)(23 * 60 + 59)); + uint16_t mins = std::min(nr_of_mins, static_cast(23 * 60 + 59)); uint16_t hrs = (mins / 60) + 1; _.OnTimerMins = mins % 60; _.OnTimer12Hr = hrs / 12; @@ -442,7 +442,7 @@ uint16_t IRVoltas::getOffTime(void) const { /// 0 disables the timer. Max is 23 hrs & 59 mins (1439 mins) void IRVoltas::setOffTime(const uint16_t nr_of_mins) { // Cap the total number of mins. - uint16_t mins = std::min(nr_of_mins, (uint16_t)(23 * 60 + 59)); + uint16_t mins = std::min(nr_of_mins, static_cast(23 * 60 + 59)); uint16_t hrs = (mins / 60) + 1; _.OffTimerMins = mins % 60; _.OffTimer12Hr = hrs / 12; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Xmp.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Xmp.cpp index 5d9da4c52..a60bcdbbb 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Xmp.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Xmp.cpp @@ -30,81 +30,81 @@ const uint8_t kXmpRepeatCodeAlt = 0b1001; using irutils::setBits; namespace IRXmpUtils { - /// Get the current checksum value from an XMP data section. - /// @param[in] data The value of the data section. - /// @param[in] nbits The number of data bits in the section. - /// @return The value of the stored checksum. - /// @warning Returns 0 if we can't obtain a valid checksum. - uint8_t getSectionChecksum(const uint32_t data, const uint16_t nbits) { - // The checksum is the 2nd most significant nibble of a section. - return (nbits < 2 * kNibbleSize) ? 0 : GETBITS32(data, - nbits - (2 * kNibbleSize), - kNibbleSize); - } +/// Get the current checksum value from an XMP data section. +/// @param[in] data The value of the data section. +/// @param[in] nbits The number of data bits in the section. +/// @return The value of the stored checksum. +/// @warning Returns 0 if we can't obtain a valid checksum. +uint8_t getSectionChecksum(const uint32_t data, const uint16_t nbits) { + // The checksum is the 2nd most significant nibble of a section. + return (nbits < 2 * kNibbleSize) ? 0 : GETBITS32(data, + nbits - (2 * kNibbleSize), + kNibbleSize); +} - /// Calculate the correct checksum value for an XMP data section. - /// @param[in] data The value of the data section. - /// @param[in] nbits The number of data bits in the section. - /// @return The value of the correct checksum. - uint8_t calcSectionChecksum(const uint32_t data, const uint16_t nbits) { - return (0xF & ~(irutils::sumNibbles(data, nbits / kNibbleSize, 0xF, false) - - getSectionChecksum(data, nbits))); - } +/// Calculate the correct checksum value for an XMP data section. +/// @param[in] data The value of the data section. +/// @param[in] nbits The number of data bits in the section. +/// @return The value of the correct checksum. +uint8_t calcSectionChecksum(const uint32_t data, const uint16_t nbits) { + return (0xF & ~(irutils::sumNibbles(data, nbits / kNibbleSize, 0xF, false) - + getSectionChecksum(data, nbits))); +} - /// Recalculate a XMP message code ensuring it has the checksums valid. - /// @param[in] data The value of the XMP message code. - /// @param[in] nbits The number of data bits in the entire message code. - /// @return The corrected XMP message with valid checksum sections. - uint64_t updateChecksums(const uint64_t data, const uint16_t nbits) { - const uint16_t sectionbits = nbits / kXmpSections; - uint64_t result = data; - for (uint16_t sectionOffset = 0; sectionOffset < nbits; - sectionOffset += sectionbits) { - const uint16_t checksumOffset = sectionOffset + sectionbits - - (2 * kNibbleSize); - setBits(&result, checksumOffset, kNibbleSize, - calcSectionChecksum(GETBITS64(data, sectionOffset, sectionbits), - sectionbits)); - } - return result; +/// Recalculate a XMP message code ensuring it has the checksums valid. +/// @param[in] data The value of the XMP message code. +/// @param[in] nbits The number of data bits in the entire message code. +/// @return The corrected XMP message with valid checksum sections. +uint64_t updateChecksums(const uint64_t data, const uint16_t nbits) { + const uint16_t sectionbits = nbits / kXmpSections; + uint64_t result = data; + for (uint16_t sectionOffset = 0; sectionOffset < nbits; + sectionOffset += sectionbits) { + const uint16_t checksumOffset = sectionOffset + sectionbits - + (2 * kNibbleSize); + setBits(&result, checksumOffset, kNibbleSize, + calcSectionChecksum(GETBITS64(data, sectionOffset, sectionbits), + sectionbits)); } + return result; +} - /// Calculate the bit offset the repeat nibble in an XMP code. - /// @param[in] nbits The number of data bits in the entire message code. - /// @return The offset to the start of the XMP repeat nibble. - uint16_t calcRepeatOffset(const uint16_t nbits) { - return (nbits < 3 * kNibbleSize) ? 0 - : (nbits / kXmpSections) - - (3 * kNibbleSize); - } +/// Calculate the bit offset the repeat nibble in an XMP code. +/// @param[in] nbits The number of data bits in the entire message code. +/// @return The offset to the start of the XMP repeat nibble. +uint16_t calcRepeatOffset(const uint16_t nbits) { + return (nbits < 3 * kNibbleSize) ? 0 + : (nbits / kXmpSections) - + (3 * kNibbleSize); +} - /// Test if an XMP message code is a repeat or not. - /// @param[in] data The value of the XMP message code. - /// @param[in] nbits The number of data bits in the entire message code. - /// @return true, if it looks like a repeat, false if not. - bool isRepeat(const uint64_t data, const uint16_t nbits) { - switch (GETBITS64(data, calcRepeatOffset(nbits), kNibbleSize)) { - case kXmpRepeatCode: - case kXmpRepeatCodeAlt: - return true; - default: - return false; - } +/// Test if an XMP message code is a repeat or not. +/// @param[in] data The value of the XMP message code. +/// @param[in] nbits The number of data bits in the entire message code. +/// @return true, if it looks like a repeat, false if not. +bool isRepeat(const uint64_t data, const uint16_t nbits) { + switch (GETBITS64(data, calcRepeatOffset(nbits), kNibbleSize)) { + case kXmpRepeatCode: + case kXmpRepeatCodeAlt: + return true; + default: + return false; } +} - /// Adjust an XMP message code to make it a valid repeat or non-repeat code. - /// @param[in] data The value of the XMP message code. - /// @param[in] nbits The number of data bits in the entire message code. - /// @param[in] repeat_code The value of the XMP repeat nibble to use. - /// A value of `8` is the normal value for a repeat. `9` has also been seen. - /// A value of `0` will convert the code to a non-repeat code. - /// @return The valud of the modified XMP code. - uint64_t adjustRepeat(const uint64_t data, const uint16_t nbits, - const uint8_t repeat_code) { - uint64_t result = data; - setBits(&result, calcRepeatOffset(nbits), kNibbleSize, repeat_code); - return updateChecksums(result, nbits); - } +/// Adjust an XMP message code to make it a valid repeat or non-repeat code. +/// @param[in] data The value of the XMP message code. +/// @param[in] nbits The number of data bits in the entire message code. +/// @param[in] repeat_code The value of the XMP repeat nibble to use. +/// A value of `8` is the normal value for a repeat. `9` has also been seen. +/// A value of `0` will convert the code to a non-repeat code. +/// @return The valud of the modified XMP code. +uint64_t adjustRepeat(const uint64_t data, const uint16_t nbits, + const uint8_t repeat_code) { + uint64_t result = data; + setBits(&result, calcRepeatOffset(nbits), kNibbleSize, repeat_code); + return updateChecksums(result, nbits); +} } // namespace IRXmpUtils using IRXmpUtils::calcSectionChecksum; @@ -126,7 +126,8 @@ void IRsend::sendXmp(const uint64_t data, const uint16_t nbits, uint64_t send_data = data; for (uint16_t r = 0; r <= repeat; r++) { uint16_t bits_so_far = kXmpWordSize; - for (uint64_t mask = ((uint64_t)kXmpMaxWordValue) << (nbits - kXmpWordSize); + for (uint64_t mask = static_cast(kXmpMaxWordValue) << + (nbits - kXmpWordSize); mask; mask >>= kXmpWordSize) { uint8_t word = (send_data & mask) >> (nbits - bits_so_far); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h index 438cc5da3..68b1a7c74 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h @@ -751,6 +751,9 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_ARRIS #define D_STR_ARRIS "ARRIS" #endif // D_STR_ARRIS +#ifndef D_STR_BLUESTARHEACY +#define D_STR_BLUESTARHEAVY "BLUESTARHEAVY" +#endif // D_STR_TESTEXAMPLE #ifndef D_STR_BOSCH #define D_STR_BOSCH "BOSCH" #endif // D_STR_BOSCH @@ -841,6 +844,9 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_EPSON #define D_STR_EPSON "EPSON" #endif // D_STR_EPSON +#ifndef D_STR_EUROM +#define D_STR_EUROM "EUROM" +#endif // D_STR_EUROM #ifndef D_STR_FUJITSU_AC #define D_STR_FUJITSU_AC "FUJITSU_AC" #endif // D_STR_FUJITSU_AC @@ -1120,6 +1126,12 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_ZEPEAL #define D_STR_ZEPEAL "ZEPEAL" #endif // D_STR_ZEPEAL +#ifndef D_STR_TOSHIBAGENERICREMOTEA +#define D_STR_TOSHIBAGENERICREMOTEA "TOSHIBA REMOTE A" +#endif // D_STR_TOSHIBAGENERICREMOTEA +#ifndef D_STR_TOSHIBAGENERICREMOTEB +#define D_STR_TOSHIBAGENERICREMOTEB "TOSHIBA REMOTE B" +#endif // D_STR_TOSHIBAGENERICREMOTEB // IRrecvDumpV2+ #ifndef D_STR_TIMESTAMP diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h index 02a892403..2059420b9 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h @@ -143,7 +143,7 @@ #define D_STR_MESGDESC "ОĐŋĐ¸ŅĐ°ĐŊиĐĩ ĐĄĐžĐžĐąŅ‰ĐĩĐŊĐ¸Ņ." #define D_STR_TOLERANCE "ДоĐŋ҃ҁĐē" #define D_STR_IRRECVDUMP_STARTUP \ - "IRrecvDump СаĐŋŅƒŅ‰ĐĩĐŊ и ĐžĐļдаĐĩŅ‚ ИК ĐēĐžĐŧаĐŊĐ´Ņ‹ ĐŊа Đ’Ņ…ĐžĐ´Đĩ %d" + "IRrecvDump СаĐŋŅƒŅ‰ĐĩĐŊ и ĐžĐļидаĐĩŅ‚ ИК ĐēĐžĐŧаĐŊĐ´Ņ‹ ĐŊа Đ’Ņ…ĐžĐ´Đĩ %d" #define D_WARN_BUFFERFULL \ "ĐŸĐ Đ•Đ”ĐŖĐŸĐ Đ•Đ–Đ”Đ•ĐĐ˜Đ•: ИК ĐēОд ҁĐģĐ¸ŅˆĐēĐžĐŧ вĐĩĐģиĐē Đ´ĐģŅ ĐąŅƒŅ„ĐĩŅ€Đ° (>= %d). " \ "Đ­Ņ‚ĐžĐŧ҃ Ņ€ĐĩĐˇŅƒĐģŅŒŅ‚Đ°Ņ‚Ņƒ ĐŊĐĩ ҁĐģĐĩĐ´ŅƒĐĩŅ‚ дОвĐĩŅ€ŅŅ‚ŅŒ, ĐŋĐžĐēа ŅŅ‚Đž ĐŊĐĩ ĐąŅƒĐ´ĐĩŅ‚ Đ¸ŅĐŋŅ€Đ°Đ˛ĐģĐĩĐŊĐž. " \ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sk-SK.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sk-SK.h new file mode 100644 index 000000000..88532c685 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sk-SK.h @@ -0,0 +1,190 @@ +// Copyright 2024 - @misa1515 +// Locale/language file for Slovakia. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_SK_SK_H_ +#define LOCALE_SK_SK_H_ + +#define D_STR_UNKNOWN "NEZNÁME" +#define D_STR_PROTOCOL "Protokol" +#define D_STR_POWER "VÃŊkon" +#define D_STR_PREVIOUS "PredchÃĄdzajÃēce" +#define D_STR_ON "Zap" +#define D_STR_OFF "Vyp" +#define D_STR_MODE "ReÅžim" +#define D_STR_TOGGLE "PrepnÃēÅĨ" +#define D_STR_SLEEP "SpaÅĨ" +#define D_STR_LIGHT "Svetlo" +#define D_STR_POWERFUL "VÃŊkonnÃŊ" +#define D_STR_QUIET "TichÃŊ" +#define D_STR_ECONO "Econo" +#define D_STR_SWING "KÃŊvanie" +#define D_STR_SWINGH D_STR_SWING"(H)" // Set `D_STR_SWING` prvÊ! +#define D_STR_SWINGV D_STR_SWING"(V)" // Set `D_STR_SWING` prvÊ! +#define D_STR_BEEP "Pípnutie" +#define D_STR_MOULD "Pleseň" +#define D_STR_CLEAN "ČistiÅĨ" +#define D_STR_PURIFY "Čistota" +#define D_STR_TIMER "Časovač" +#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER // Set `D_STR_ON` prvÊ! +#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER // Set `D_STR_OFF` prvÊ! +#define D_STR_TIMERMODE D_STR_TIMER " " D_STR_MODE // Set `D_STR_MODE` prvÊ! +#define D_STR_CLOCK "Hodiny" +#define D_STR_COMMAND "Príkaz" +#define D_STR_XFAN "XVentilÃĄtor" +#define D_STR_HEALTH "Zdravie" +#define D_STR_TEMP "Teplota" +#define D_STR_IFEEL "IPocitovo" +#define D_STR_ISEE "IVidieÅĨ" +#define D_STR_HUMID "VlhkosÅĨ" +#define D_STR_SAVE "UloÅžiÅĨ" +#define D_STR_EYE "Oči" +#define D_STR_FOLLOW "NasledovaÅĨ" +#define D_STR_FRESH "ČerstvÊ" +#define D_STR_HOLD "PodrÅžaÅĨ" +#define D_STR_8C_HEAT "8C " D_STR_HEAT // Set `D_STR_HEAT` prvÊ! +#define D_STR_10C_HEAT "10C " D_STR_HEAT // Set `D_STR_HEAT` prvÊ! +#define D_STR_BUTTON "Tlačidlo" +#define D_STR_NIGHT "Noc" +#define D_STR_SILENT "TichÊ" +#define D_STR_CELSIUS "Celzia" +#define D_STR_FAHRENHEIT "Fahrenheit" +#define D_STR_CELSIUS_FAHRENHEIT D_STR_CELSIUS "/" D_STR_FAHRENHEIT +#define D_STR_UP "Hore" +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP // Set `D_STR_TEMP` prvÊ! +#define D_STR_DOWN "Dole" +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN // Set `D_STR_TEMP` prvÊ! +#define D_STR_CHANGE "ZmeniÅĨ" +#define D_STR_START "Å tart" +#define D_STR_MOVE "Posun" +#define D_STR_SET "NastaviÅĨ" +#define D_STR_CANCEL "ZruÅĄiÅĨ" +#define D_STR_COMFORT "Komfort" +#define D_STR_SENSOR "Snímač" +#define D_STR_ABSENSEDETECT "Detekcia neprítomnosti" +#define D_STR_DIRECT "Priamo" +#define D_STR_INDIRECT "Nepriamo" +#define D_STR_DIRECTINDIRECTMODE D_STR_DIRECT " / " \ +D_STR_INDIRECT " " D_STR_MODE +#define D_STR_DISPLAY "Displej" +#define D_STR_WEEKLY "TÃŊÅždenne" +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER // Needs `D_STR_WEEKLY`! +#define D_STR_LAST "PoslednÊ" +#define D_STR_FAST "RÃŊchlo" +#define D_STR_SLOW "Pomaly" +#define D_STR_AIRFLOW "PrÃēd vzduchu" +#define D_STR_STEP "Krok" +#define D_STR_INSIDE "VnÃētri" +#define D_STR_OUTSIDE "Vonku" +#define D_STR_LOUD "Hlasno" +#define D_STR_UPPER "HornÃĄ" +#define D_STR_LOWER "DolnÃĄ" +#define D_STR_BREEZE "VÃĄnok" +#define D_STR_CIRCULATE "CirkulÃĄcia" +#define D_STR_CEILING "Strop" +#define D_STR_WALL "Stena" +#define D_STR_ROOM "Izba" +#define D_STR_6THSENSE "6ty zmysel" +#define D_STR_ZONEFOLLOW "Sledovanie zÃŗny" +#define D_STR_FIXED "FixovanÊ" +#define D_STR_TYPE "Typ" +#define D_STR_SPECIAL "Å peciÃĄlne" +#define D_STR_RECYCLE "RecyklovaÅĨ" +#define D_STR_LOCK "ZamknutÊ" +#define D_STR_AUTOMATIC "AutomatickÊ" +#define D_STR_MANUAL "ManuÃĄlne" +#define D_STR_COOL "ChladiÅĨ" +#define D_STR_COOLING "Chladenie" +#define D_STR_HEAT "Ohrev" +#define D_STR_HEATING "KÃērenie" +#define D_STR_FAN "VentilÃĄtor" +#define D_STR_FANONLY "len ventilÃĄtor" +#define D_STR_FAN_ONLY "len_ventilÃĄtor" +#define D_STR_ONLY "Len" +#define D_STR_FANSPACEONLY D_STR_FAN " " D_STR_ONLY +#define D_STR_FANONLYNOSPACE D_STR_FAN D_STR_ONLY +#define D_STR_DRY "SuÅĄiÅĨ" +#define D_STR_DRYING "SuÅĄenie" +#define D_STR_DEHUMIDIFY "OdvlhčiÅĨ" +#define D_STR_MAX "Max" +#define D_STR_MIN "Min" +#define D_STR_MED "Str" +#define D_STR_MEDIUM "StrednÊ" +#define D_STR_MED_HIGH D_STR_MED "-" D_STR_HIGH +#define D_STR_HIGHEST "NajvyÅĄÅĄie" +#define D_STR_HIGH "VysokÊ" +#define D_STR_HI "Vys" +#define D_STR_MID "Str" +#define D_STR_MIDDLE "StrednÊ" +#define D_STR_LOW "NÃŗzke" +#define D_STR_LO "Níz" +#define D_STR_LOWEST "NajniÅžÅĄie" +#define D_STR_RIGHT "PravÊ" +#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT // Set `D_STR_MAX` prvÊ! +#define D_STR_MAXRIGHT_NOSPACE D_STR_MAX D_STR_RIGHT // Set `D_STR_MAX` prvÊ! +#define D_STR_RIGHTMAX D_STR_RIGHT " " D_STR_MAX // Set `D_STR_MAX` prvÊ! +#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` prvÊ! +#define D_STR_LEFT "VÄžavo" +#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT // Set `D_STR_MAX` prvÊ! +#define D_STR_MAXLEFT_NOSPACE D_STR_MAX D_STR_LEFT // Set `D_STR_MAX` prvÊ! +#define D_STR_LEFTMAX D_STR_LEFT " " D_STR_MAX // Set `D_STR_MAX` prvÊ! +#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` prvÊ! +#define D_STR_WIDE "Å irokÊ" +#define D_STR_CENTRE "StrednÊ" +#define D_STR_TOP "HornÊ" +#define D_STR_BOTTOM "DolnÊ" +#define D_STR_UPPER_MIDDLE D_STR_UPPER "-" D_STR_MIDDLE +#define D_STR_CONFIG "KonfigurÃĄcia" +#define D_STR_CONTROL "Riadenie" +#define D_STR_SET_TIMER D_STR_SET " " D_STR_TIMER +#define D_STR_SCHEDULE "Rozvrh" +#define D_STR_CH "CH#" +#define D_STR_TIMER_ACTIVE_DAYS "TimerActiveDays" +#define D_STR_KEY "KÄžÃēč" +#define D_STR_VALUE "Hodnota" + +// Compound words/phrases/descriptions from pre-defined words. +// Note: Obviously these need to be defined *after* their component words. +#define D_STR_ECONOTOGGLE D_STR_ECONO " " D_STR_TOGGLE +#define D_STR_EYEAUTO D_STR_EYE " " D_STR_AUTO +#define D_STR_LIGHTTOGGLE D_STR_LIGHT " " D_STR_TOGGLE +#define D_STR_OUTSIDEQUIET D_STR_OUTSIDE " " D_STR_QUIET +#define D_STR_POWERTOGGLE D_STR_POWER " " D_STR_TOGGLE +#define D_STR_POWERBUTTON D_STR_POWER " " D_STR_BUTTON +#define D_STR_PREVIOUSPOWER D_STR_PREVIOUS " " D_STR_POWER +#define D_STR_DISPLAYTEMP D_STR_DISPLAY " " D_STR_TEMP +#define D_STR_IFEELREPORT D_STR_IFEEL " " D_STR_REPORT +#define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP +#define D_STR_SLEEP_TIMER D_STR_SLEEP " " D_STR_TIMER +#define D_STR_SWINGVMODE D_STR_SWINGV " " D_STR_MODE +#define D_STR_SWINGVTOGGLE D_STR_SWINGV " " D_STR_TOGGLE +#define D_STR_TURBOTOGGLE D_STR_TURBO " " D_STR_TOGGLE + +// Separators +#define D_STR_DAY "Deň" +#define D_STR_DAYS D_STR_DAY "s" +#define D_STR_HOUR "Hodina" +#define D_STR_HOURS D_STR_HOUR "s" +#define D_STR_MINUTE "MinÃēta" +#define D_STR_MINUTES D_STR_MINUTE "s" +#define D_STR_SECOND "Sekunda" +#define D_STR_SECONDS D_STR_SECOND "s" +#define D_STR_NOW "Teraz" +#define D_STR_YES "Áno" +#define D_STR_NO "Nie" +#define D_STR_REPEAT "OpakovaÅĨ" +#define D_STR_CODE "KÃŗd" +#define D_STR_BITS "Bity" + +// IRrecvDumpV2+ +#define D_STR_TIMESTAMP "ČasovÃĄ pečiatka" +#define D_STR_LIBRARY "KniÅžnica" +#define D_STR_MESGDESC "Mesg Desc." +#define D_STR_TOLERANCE "Tolerancia" +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDump teraz beŞí a čakÃĄ na IR vstup na pine %d" +#define D_WARN_BUFFERFULL \ + "UPOZORNENIE: IR kÃŗd je príliÅĄ veÄžkÃŊ pre vyrovnÃĄvaciu pamäÅĨ (>= %d). " \ + "Tomuto vÃŊsledku by sa nemalo dôverovaÅĨ, kÃŊm sa to nevyrieÅĄi. " \ + "UpraviÅĨ a zvÃ¤ÄÅĄiÅĨ `kCaptureBufferSize`." + +#endif // LOCALE_SK_SK_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp index 8d6274c65..428eab3c2 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp @@ -247,6 +247,36 @@ TEST(TestIRac, Coolix) { ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command); } +TEST(TestIRac, Coolix_Issue2103) { + IRCoolixAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + char expected[] = + "Power: On, Mode: 4 (Fan), Fan: 5 (Auto), Zone Follow: Off, " + "Sensor Temp: Off"; + + ac.begin(); + irac.coolix(&ac, + true, // Power + stdAc::opmode_t::kFan, // Mode + 21, // Celsius + kNoTempValue, // Sensor Temp + stdAc::fanspeed_t::kAuto, // Fan speed + stdAc::swingv_t::kOff, // Vertical swing + stdAc::swingh_t::kOff, // Horizontal swing + false, // iFeel + 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); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + TEST(TestIRac, Corona) { IRCoronaAc ac(kGpioUnused); IRac irac(kGpioUnused); @@ -613,7 +643,7 @@ TEST(TestIRac, Electra) { char expected[] = "Power: On, Mode: 6 (Fan), Temp: 26C, Fan: 1 (High), " "Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On, " - "IFeel: Off"; + "Quiet: On, IFeel: Off"; ac.begin(); irac.electra(&ac, @@ -625,6 +655,7 @@ TEST(TestIRac, Electra) { stdAc::swingv_t::kAuto, // Vertical swing stdAc::swingh_t::kLeft, // Horizontal swing false, // iFeel + true, // Quiet true, // Turbo true, // Light (toggle) true); // Clean @@ -2157,8 +2188,8 @@ TEST(TestIRac, Toshiba) { IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); char expected[] = - "Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), " - "Turbo: Off, Econo: On, Filter: Off"; + "Model: 0 (TOSHIBA REMOTE A), Temp: 29C, Power: On, Mode: 2 (Dry), " + "Fan: 2 (UNKNOWN), Turbo: Off, Econo: On, Filter: Off"; ac.begin(); irac.toshiba(&ac, @@ -3144,8 +3175,8 @@ TEST(TestIRac, Issue1250) { // Now send the state so we can actually decode/capture what we sent. char expected_on[] = - "Temp: 19C, Power: On, Mode: 4 (Fan), Fan: 0 (Auto), " - "Turbo: Off, Econo: Off, Filter: Off"; + "Model: 0 (TOSHIBA REMOTE A), Temp: 19C, Power: On, Mode: 4 (Fan), " + "Fan: 0 (Auto), Turbo: Off, Econo: Off, Filter: Off"; ac._irsend.reset(); irac.toshiba(&ac, irac.next.power, // Power @@ -3171,8 +3202,8 @@ TEST(TestIRac, Issue1250) { irac.sendAc(); // Now send the state so we can actually decode/capture what we sent. char expected_off[] = - "Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, " - "Filter: Off"; + "Model: 0 (TOSHIBA REMOTE A), Temp: 19C, Power: Off, Fan: 0 (Auto), " + "Turbo: Off, Econo: Off, Filter: Off"; ac._irsend.reset(); irac.toshiba(&ac, irac.next.power, // Power diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.cpp index 51fae7499..e1cb78f4e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.cpp @@ -674,16 +674,16 @@ TEST(TestSend, GenericSimpleSendMethodFailure) { for (int i = 0; i <= kLastDecodeType; i++) { if (hasACState((decode_type_t)i) && i != GREE) { // Gree is an exception. // Check it fails. - ASSERT_FALSE(irsend.send((decode_type_t)i, (uint64_t)0, 0)); + ASSERT_FALSE(irsend.send((decode_type_t)i, static_cast(0), 0)); } } // Test some other special cases. - ASSERT_FALSE(irsend.send(UNKNOWN, (uint64_t)0, 0)); - ASSERT_FALSE(irsend.send(UNUSED, (uint64_t)0, 0)); - ASSERT_FALSE(irsend.send(RAW, (uint64_t)0, 0)); - ASSERT_FALSE(irsend.send(PRONTO, (uint64_t)0, 0)); - ASSERT_FALSE(irsend.send(GLOBALCACHE, (uint64_t)0, 0)); + ASSERT_FALSE(irsend.send(UNKNOWN, static_cast(0), 0)); + ASSERT_FALSE(irsend.send(UNUSED, static_cast(0), 0)); + ASSERT_FALSE(irsend.send(RAW, static_cast(0), 0)); + ASSERT_FALSE(irsend.send(PRONTO, static_cast(0), 0)); + ASSERT_FALSE(irsend.send(GLOBALCACHE, static_cast(0), 0)); } // Test expected to work/produce a message for complex irsend:send() diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.h index f43409433..60787988e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRsend_test.h @@ -72,7 +72,7 @@ class IRsendTest : public IRsend { capture.decode_type = UNKNOWN; capture.bits = 0; capture.rawlen = last + 2 - offset; - capture.overflow = (last - offset >= (int16_t)RAW_BUF); + capture.overflow = (last - offset >= static_cast(RAW_BUF)); capture.repeat = false; capture.address = 0; capture.command = 0; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRutils_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRutils_test.cpp index c5a6d1339..d0d15c896 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRutils_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRutils_test.cpp @@ -582,12 +582,12 @@ TEST(TestUtils, getBit) { EXPECT_FALSE(GETBIT8((uint8_t)0b01111111, 7)); EXPECT_TRUE(GETBIT8((uint8_t)0b10000000, 7)); // uint64_t method. - EXPECT_FALSE(irutils::getBit((uint64_t)0, 0)); - EXPECT_TRUE(irutils::getBit((uint64_t)1, 0)); - EXPECT_FALSE(irutils::getBit((uint64_t)0b01, 1)); - EXPECT_TRUE(irutils::getBit((uint64_t)0b10, 1)); - EXPECT_FALSE(irutils::getBit((uint64_t)0b01111111, 7)); - EXPECT_TRUE(irutils::getBit((uint64_t)0b10000000, 7)); + EXPECT_FALSE(irutils::getBit(static_cast(0), 0)); + EXPECT_TRUE(irutils::getBit(static_cast(1), 0)); + EXPECT_FALSE(irutils::getBit(static_cast(0b01), 1)); + EXPECT_TRUE(irutils::getBit(static_cast(0b10), 1)); + EXPECT_FALSE(irutils::getBit(static_cast(0b01111111), 7)); + EXPECT_TRUE(irutils::getBit(static_cast(0b10000000), 7)); } TEST(TestUtils, setBit) { @@ -603,16 +603,17 @@ TEST(TestUtils, setBit) { EXPECT_EQ(0b11111111, irutils::setBit((uint8_t)0b01111111, 7, true)); EXPECT_EQ(0, irutils::setBit((uint8_t)0b10000000, 7, false)); // uint64_t method. - EXPECT_EQ(0, irutils::setBit((uint64_t)0, 0, false)); - EXPECT_EQ(0, irutils::setBit((uint64_t)1, 0, false)); - EXPECT_EQ(1, irutils::setBit((uint64_t)0, 0, true)); - EXPECT_EQ(1, irutils::setBit((uint64_t)1, 0, true)); - EXPECT_EQ(0b101, irutils::setBit((uint64_t)0b101, 1, false)); - EXPECT_EQ(0b100, irutils::setBit((uint64_t)0b110, 1, false)); - EXPECT_EQ(0b111, irutils::setBit((uint64_t)0b101, 1, true)); - EXPECT_EQ(0b110, irutils::setBit((uint64_t)0b110, 1, true)); - EXPECT_EQ(0b11111111, irutils::setBit((uint64_t)0b01111111, 7, true)); - EXPECT_EQ(0, irutils::setBit((uint64_t)0b10000000, 7, false)); + EXPECT_EQ(0, irutils::setBit(static_cast(0), 0, false)); + EXPECT_EQ(0, irutils::setBit(static_cast(1), 0, false)); + EXPECT_EQ(1, irutils::setBit(static_cast(0), 0, true)); + EXPECT_EQ(1, irutils::setBit(static_cast(1), 0, true)); + EXPECT_EQ(0b101, irutils::setBit(static_cast(0b101), 1, false)); + EXPECT_EQ(0b100, irutils::setBit(static_cast(0b110), 1, false)); + EXPECT_EQ(0b111, irutils::setBit(static_cast(0b101), 1, true)); + EXPECT_EQ(0b110, irutils::setBit(static_cast(0b110), 1, true)); + EXPECT_EQ(0b11111111, + irutils::setBit(static_cast(0b01111111), 7, true)); + EXPECT_EQ(0, irutils::setBit(static_cast(0b10000000), 7, false)); // uint8_t Pointer method. uint8_t data = 0; irutils::setBit(&data, 0, false); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Argo_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Argo_test.cpp index 817272a17..0a83ef50e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Argo_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Argo_test.cpp @@ -2,7 +2,13 @@ // Copyright 2022 Mateusz Bronk (mbronk) #include #include +#include #include +#include +#include +#include +#include +#include #include "ir_Argo.h" #include "IRac.h" #include "IRrecv.h" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp index 101fab654..fbc2a1db0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp @@ -393,6 +393,7 @@ TEST(TestCoolixACClass, SetAndGetRaw) { TEST(TestCoolixACClass, SetAndGetTemp) { IRCoolixAC ac(kGpioUnused); + // Celcius ac.setTemp(25); EXPECT_EQ(25, ac.getTemp()); ac.setTemp(kCoolixTempMin); @@ -403,6 +404,26 @@ TEST(TestCoolixACClass, SetAndGetTemp) { EXPECT_EQ(kCoolixTempMin, ac.getTemp()); ac.setTemp(kCoolixTempMax + 1); EXPECT_EQ(kCoolixTempMax, ac.getTemp()); + + // Fahrenheit low + ac.setTemp(70); + EXPECT_EQ(70, ac.getTemp()); + ac.setTemp(kCoolixTempLowFMin); + EXPECT_EQ(kCoolixTempLowFMin, ac.getTemp()); + ac.setTemp(kCoolixTempLowFMax); + EXPECT_EQ(kCoolixTempLowFMax, ac.getTemp()); + ac.setTemp(kCoolixTempLowFMin - 1); + EXPECT_EQ(kCoolixTempMax, ac.getTemp()); + + // Fahrenheit high + ac.setTemp(80); + EXPECT_EQ(80, ac.getTemp()); + ac.setTemp(kCoolixTempHighFMin); + EXPECT_EQ(kCoolixTempHighFMin, ac.getTemp()); + ac.setTemp(kCoolixTempHighFMax); + EXPECT_EQ(kCoolixTempHighFMax, ac.getTemp()); + ac.setTemp(kCoolixTempHighFMax + 1); + EXPECT_EQ(kCoolixTempMax, ac.getTemp()); } TEST(TestCoolixACClass, SetAndGetMode) { @@ -1104,3 +1125,55 @@ TEST(TestCoolixACClass, Issue2012) { ac.toString()); EXPECT_EQ(kNoTempValue, ac.toCommon().sensorTemperature); } + +// Test decoding Fahrenheit from Coolix48. +TEST(TestCoolixACClass, SetRawFahrenheit) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + IRCoolixAC ac(kGpioUnused); + + ac.stateReset(); + ac.setRawFromCoolix48(0xB25DFF00C03F); + EXPECT_EQ( + "Power: On, Mode: 0 (Cool), Fan: 7 (Fixed), Temp: 63F, " + "Zone Follow: Off, Sensor Temp: Off", + ac.toString()); +} + +// Test sending and decoding of Fahrenheit values. +TEST(TestCoolixACClass, SendFahrenheit) { + IRrecv irrecv(kGpioUnused); + IRCoolixAC ac(kGpioUnused); + + const uint32_t on_cool_63f_fan_fixed_noparity = 0xB2FFC0; + ac.begin(); + ac.on(); + ac.setPower(true); + ac.setMode(kCoolixCool); + ac.setFan(kCoolixFanFixed); + ac.setTemp(63); + EXPECT_EQ(on_cool_63f_fan_fixed_noparity, ac.getRaw()); + + ac.send(); + ac._irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(COOLIX48, ac._irsend.capture.decode_type); + EXPECT_EQ(kCoolix48Bits, ac._irsend.capture.bits); + EXPECT_EQ(0xB25DFF00C03F, ac._irsend.capture.value); + EXPECT_EQ(0x0, ac._irsend.capture.address); + EXPECT_EQ(0x0, ac._irsend.capture.command); + + const uint32_t on_cool_80f_fan_fixed_noparity = 0xB2FF20; + ac.setTemp(80); + EXPECT_EQ(on_cool_80f_fan_fixed_noparity, ac.getRaw()); + + ac._irsend.reset(); + ac.send(); + ac._irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(COOLIX48, ac._irsend.capture.decode_type); + EXPECT_EQ(kCoolix48Bits, ac._irsend.capture.bits); + EXPECT_EQ(0xB27DFF0020DF, ac._irsend.capture.value); + EXPECT_EQ(0x0, ac._irsend.capture.address); + EXPECT_EQ(0x0, ac._irsend.capture.command); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp index 9c1dedd09..6eefc8b1d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp @@ -102,7 +102,7 @@ TEST(TestDecodeElectraAC, RealExampleDecode) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -237,7 +237,7 @@ TEST(TestIRElectraAcClass, HumanReadable) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 32C, Fan: 5 (Auto), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); uint8_t on_cool_16C_auto_voff[13] = { 0xC3, 0x47, 0xE0, 0x00, 0xA0, 0x00, 0x20, @@ -246,7 +246,7 @@ TEST(TestIRElectraAcClass, HumanReadable) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 5 (Auto), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); uint8_t on_cool_16C_low_voff[13] = { 0xC3, 0x47, 0xE0, 0x00, 0x60, 0x00, 0x20, @@ -255,7 +255,7 @@ TEST(TestIRElectraAcClass, HumanReadable) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); } @@ -280,7 +280,7 @@ TEST(TestIRElectraAcClass, Clean) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); } @@ -307,7 +307,7 @@ TEST(TestIRElectraAcClass, Turbo) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); } @@ -332,7 +332,7 @@ TEST(TestIRElectraAcClass, LightToggle) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); } @@ -360,7 +360,7 @@ TEST(TestIRElectraAcClass, ConstructKnownState) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, " - "IFeel: Off", + "Quiet: Off, IFeel: Off", ac.toString()); EXPECT_STATE_EQ(on_cool_24C_fan1_swing_off_turbo_off_clean_on, ac.getRaw(), kElectraAcBits); @@ -379,7 +379,7 @@ TEST(TestIRElectraAcClass, IFeelAndSensor) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 5 (Auto), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " - "IFeel: On, Sensor Temp: 26C", + "Quiet: Off, IFeel: On, Sensor Temp: 26C", ac.toString()); ac.stateReset(); @@ -429,6 +429,6 @@ TEST(TestIRElectraAcClass, IFeelAndSensor) { EXPECT_EQ( "Power: On, Mode: 4 (Heat), Temp: 27C, Fan: 5 (Auto), " "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " - "IFeel: On, Sensor Temp: 28C", + "Quiet: Off, IFeel: On, Sensor Temp: 28C", ac.toString()); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Eurom_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Eurom_test.cpp new file mode 100644 index 000000000..2d3fdd653 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Eurom_test.cpp @@ -0,0 +1,377 @@ +// Copyright 2025 GottemHams + +#include "ir_Eurom.h" +#include "gtest/gtest.h" +#include "IRac.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" + +TEST(TestEurom, Housekeeping) { + ASSERT_EQ("EUROM", typeToString(decode_type_t::EUROM)); + ASSERT_EQ(decode_type_t::EUROM, strToDecodeType("EUROM")); + ASSERT_TRUE(hasACState(decode_type_t::EUROM)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::EUROM)); + ASSERT_EQ(kEuromBits, IRsend::defaultBits(decode_type_t::EUROM)); +} + +/// Tests for sendEurom(). + +/// Test sending typical data only. +TEST(TestSendEurom, SendDataOnly) { + IRsendTest irsend(kGpioUnused); + + const uint8_t state[kEuromStateLength] = { + 0x18, 0x27, + 0x71, // Cooling mode, 23 C + 0x80, // Power on, swing off + 0x00, // No Fahrenheit + 0x00, // Sleep disabled, no "on timer" + 0x00, + 0x80, // No "off timer" + 0x00, // "Off timer" disabled + 0x80, + 0x10, // Low fan + 0x21, // Checksum + }; + + irsend.begin(); + irsend.reset(); + irsend.sendEurom(state); + EXPECT_EQ( + "f38000d50" + "m3257s3187" + "m454s355m454s355m454s355m454s1162m454s1162m454s355m454s355m454s355m454s355" + "m454s355m454s1162m454s355m454s355m454s1162m454s1162m454s1162m454s355m454" + "s1162m454s1162m454s1162m454s355m454s355m454s355m454s1162m454s1162m454s355" + "m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s355m454s355m454s1162m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s1162m454s355m454s355m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s355m454s355m454s1162m454s355m454s355m454s355m454s355m454s355" + "m454s355m454s1162m454s355m454s355m454s355m454s355m454s1162m454" + "s50058", + irsend.outputStr()); + + irsend.reset(); +} + +/// Tests for decodeEurom(). + +/// Decode a normal Eurom message. +TEST(TestDecodeEurom, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + + // This is the same state as used in SendDataOnly + const uint8_t state[kEuromStateLength] = { + 0x18, 0x27, + 0x71, // Cooling mode, 23 C + 0x80, // Power on, swing off + 0x00, // No Fahrenheit + 0x00, // Sleep disabled, no "on timer" + 0x00, + 0x80, // No "off timer" + 0x00, // "Off timer" disabled + 0x80, + 0x10, // Low fan + 0x21, // Checksum + }; + + irsend.begin(); + irsend.reset(); + irsend.sendEurom(state); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::EUROM, irsend.capture.decode_type); + EXPECT_EQ(kEuromBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + + EXPECT_STATE_EQ(state, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 16 (Low), Swing(V): Off" + ", Sleep: Off, Off Timer: Off, On Timer: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); + + irsend.reset(); +} + +/// Decode a real example. +TEST(TestDecodeEurom, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + + // UNKNOWN 1C60B17 + const uint16_t raw_data[391] = { + 3318, 3136, + 490, 318, 490, 322, 486, 324, 488, 1126, 490, 1118, 490, 322, 490, 318, 490, + 326, 490, 318, 488, 322, 486, 1124, 490, 328, 488, 318, 490, 1124, 490, + 1122, 486, 1130, 484, 324, 490, 1122, 486, 1122, 490, 1128, 490, 322, 486, + 322, 490, 322, 486, 1132, 484, 1124, 488, 1124, 486, 322, 490, 328, 488, + 318, 490, 322, 486, 322, 490, 328, 486, 322, 490, 322, 486, 322, 486, 330, + 486, 322, 486, 322, 490, 322, 486, 332, 486, 322, 486, 322, 490, 322, 484, + 328, 490, 322, 486, 322, 486, 322, 490, 326, 484, 324, 488, 324, 484, 324, + 484, 332, 486, 322, 486, 326, 486, 322, 486, 330, 486, 1122, 490, 324, 486, + 322, 484, 332, 486, 322, 486, 328, 484, 322, 486, 332, 484, 322, 490, 324, + 484, 322, 486, 332, 486, 326, 486, 322, 486, 322, 484, 336, 486, 1124, 486, + 348, 458, 328, 486, 330, 486, 350, 458, 326, 486, 324, 484, 332, 484, 326, + 486, 322, 486, 322, 486, 1136, 486, 322, 484, 348, 438, 348, 484, 332, 484, + 348, 460, 326, 486, 1122, 486, 336, 486, 344, 464, 1148, 438, 348, 486, + 1130, 486, + 50010, + 3308, 3140, + 490, 322, 486, 322, 486, 322, 486, 1132, 490, 1122, 486, 324, 484, 328, 484, + 328, 490, 322, 486, 322, 486, 1126, 486, 328, 488, 324, 484, 1124, 490, + 1122, 486, 1132, 486, 322, 490, 1122, 486, 1128, 484, 1132, 486, 322, 486, + 322, 490, 322, 486, 1132, 486, 1122, 490, 1122, 486, 322, 490, 326, 486, + 328, 484, 324, 486, 322, 484, 332, 486, 322, 486, 328, 484, 322, 486, 330, + 486, 324, 484, 322, 486, 326, 486, 328, 484, 328, 486, 324, 484, 322, 486, + 330, 486, 322, 486, 326, 486, 322, 486, 332, 486, 322, 484, 348, 460, 328, + 486, 330, 482, 326, 486, 322, 486, 322, 486, 330, 486, 1128, 484, 324, 484, + 322, 486, 332, 484, 348, 460, 328, 484, 324, 484, 358, 460, 326, 486, 322, + 486, 348, 460, 336, 480, 328, 484, 348, 460, 328, 480, 336, 486, 1148, 460, + 328, 484, 324, 484, 358, 460, 326, 482, 326, 486, 348, 458, 336, 480, 348, + 464, 348, 460, 328, 480, 1136, 484, 348, 460, 328, 480, 328, 484, 358, 460, + 326, 482, 348, 460, 1152, 460, 356, 460, 354, 458, 1148, 460, 328, 484, + 1162, 460, + }; + + // Note that this is a different state than before + const uint8_t expected_state[kEuromStateLength] = { + 0x18, 0x27, 0x71, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x10, 0x25, + }; + + irsend.begin(); + irsend.reset(); + irsend.sendRaw(raw_data, 391, kEuromFreq); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::EUROM, irsend.capture.decode_type); + EXPECT_EQ(kEuromBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + + EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 16 (Low), Swing(V): On" + ", Sleep: Off, Off Timer: Off, On Timer: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); + + irsend.reset(); +} + +/// Decode a real example without repeat. +TEST(TestDecodeEurom, RealExampleNoRepeat) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + + // UNKNOWN 14601C1D + const uint16_t raw_data[195] = { + 3260, 3186, + 468, 344, 438, 374, 438, 370, 438, 1178, 438, 1174, 438, 374, 438, 370, 438, + 378, 438, 370, 438, 374, 438, 1174, 438, 378, 438, 370, 438, 1174, 438, + 1170, 438, 1184, 438, 370, 438, 1174, 438, 370, 438, 1182, 434, 374, 438, + 374, 434, 374, 438, 1178, 438, 374, 438, 370, 438, 374, 434, 382, 434, 374, + 438, 374, 434, 374, 438, 378, 438, 370, 438, 374, 434, 374, 438, 378, 438, + 370, 438, 374, 434, 374, 438, 378, 438, 370, 438, 374, 438, 370, 438, 378, + 438, 374, 434, 374, 438, 370, 438, 378, 438, 374, 434, 374, 438, 374, 434, + 378, 438, 374, 438, 370, 438, 374, 434, 382, 434, 1174, 438, 374, 438, 370, + 438, 378, 438, 370, 438, 374, 438, 370, 438, 382, 434, 374, 438, 370, 438, + 374, 438, 378, 438, 374, 434, 374, 438, 370, 438, 382, 434, 1174, 464, 348, + 434, 374, 438, 382, 434, 374, 438, 370, 438, 374, 438, 378, 438, 374, 434, + 374, 438, 370, 438, 1182, 438, 374, 434, 374, 438, 370, 438, 382, 434, 374, + 438, 374, 434, 374, 438, 1182, 434, 374, 438, 1174, 434, 1174, 438, 1182, + 434, + }; + + // This is also another state than all the earlier tests + const uint8_t expected_state[kEuromStateLength] = { + 0x18, 0x27, 0x51, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x10, 0x17, + }; + + irsend.begin(); + irsend.reset(); + irsend.sendRaw(raw_data, 195, kEuromFreq); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::EUROM, irsend.capture.decode_type); + EXPECT_EQ(kEuromBits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + + EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: Off, Mode: 1 (Cool), Temp: 23C, Fan: 16 (Low), Swing(V): Off" + ", Sleep: Off, Off Timer: Off, On Timer: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); + + irsend.reset(); +} + +/// Tests for the IREuromAc class. + +/// Test power setting and getting. +TEST(TestEuromAc, SetAndGetPower) { + IREuromAc ac(kGpioUnused); + + // The initial state is powered off + ASSERT_FALSE(ac.getPower()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); +} + +/// Test operation mode setting and getting. +TEST(TestEuromAc, SetAndGetMode) { + IREuromAc ac(kGpioUnused); + + // The initial state is cooling mode + ASSERT_EQ(kEuromCool, ac.getMode()); + + // Temperature is not used in dehumidification/ventilation modes + ac.setMode(kEuromDehumidify); + EXPECT_EQ(kEuromDehumidify, ac.getMode()); + + ac.setMode(kEuromVentilate); + EXPECT_EQ(kEuromVentilate, ac.getMode()); + + ac.setMode(kEuromHeat); + EXPECT_EQ(kEuromHeat, ac.getMode()); +} + +/// Test temperature setting and getting. +TEST(TestEuromAc, SetAndGetTemperature) { + IREuromAc ac(kGpioUnused); + + // The initial state is 23 C + ASSERT_FALSE(ac.getTempIsFahrenheit()); + ASSERT_EQ(23, ac.getTemp()); + + ac.setTemp(22); + ASSERT_FALSE(ac.getTempIsFahrenheit()); + EXPECT_EQ(22, ac.getTemp()); +} + +/// Test temperature setting and getting with Fahrenheit. +TEST(TestEuromAc, SetAndGetTemperatureFahrenheit) { + IREuromAc ac(kGpioUnused); + + // The initial state is not using Fahrenheit + ASSERT_FALSE(ac.getTempIsFahrenheit()); + + // This corresponds to 16 C + ac.setTemp(70, true); + ASSERT_TRUE(ac.getTempIsFahrenheit()); + EXPECT_EQ(70, ac.getTemp()); +} + +/// Test fan speed setting and getting. +TEST(TestEuromAc, SetAndGetFan) { + IREuromAc ac(kGpioUnused); + + // The initial state is low fan + ASSERT_EQ(kEuromFanLow, ac.getFan()); + + ac.setFan(kEuromFanHigh); + EXPECT_EQ(kEuromFanHigh, ac.getFan()); +} + +/// Test swing setting and getting. +TEST(TestEuromAc, SetAndGetSwing) { + IREuromAc ac(kGpioUnused); + + // The initial state is swing disabled + ASSERT_FALSE(ac.getSwing()); + + ac.setSwing(true); + EXPECT_TRUE(ac.getSwing()); +} + +/// Test sleep mode setting and getting. +TEST(TestEuromAc, SetAndGetSleep) { + IREuromAc ac(kGpioUnused); + + // The initial state is sleep disabled + ASSERT_FALSE(ac.getSleep()); + + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); +} + +/// Test "off timer" setting and getting. +TEST(TestEuromAc, SetAndGetOffTimer) { + IREuromAc ac(kGpioUnused); + + // The initial state is no timer + ASSERT_EQ(kEuromTimerMin, ac.getOffTimer()); + + ac.setOffTimer(kEuromTimerMax); + EXPECT_EQ(kEuromTimerMax, ac.getOffTimer()); +} + +/// Test "on timer" setting and getting. +TEST(TestEuromAc, SetAndGetOnTimer) { + IREuromAc ac(kGpioUnused); + + // The initial state is no timer + ASSERT_EQ(kEuromTimerMin, ac.getOnTimer()); + + ac.setOnTimer(kEuromTimerMax); + EXPECT_EQ(kEuromTimerMax, ac.getOnTimer()); +} + +/// Test checksumming for the initial state. +TEST(TestEuromAc, ChecksumInitial) { + IREuromAc ac(kGpioUnused); + + // The initial state is powered off, cooling mode, 23 C, low fan, swing and + // sleep disabled, no timers + const uint8_t *raw_state = ac.getRaw(); + ASSERT_EQ(0x19, raw_state[kEuromStateLength - 1]); +} + +/// Test checksumming with every "feature" set to the "highest" value, which +/// also includes the special case of using the max temperature. +TEST(TestEuromAc, ChecksumHigh) { + IREuromAc ac(kGpioUnused); + + // The initial state is powered off, cooling mode, 23 C, low fan, swing and + // sleep disabled, no timers + ac.setPower(true); + ac.setMode(kEuromHeat); + ac.setTemp(kEuromMaxTempF, true); + ac.setFan(kEuromFanHigh); + ac.setSwing(true); + ac.setSleep(true); + ac.setOffTimer(kEuromTimerMax); + ac.setOnTimer(kEuromTimerMax); + + const uint8_t expected_state[kEuromStateLength] = { + 0x18, 0x27, + 0x0C, // Heating mode, 32 C (changing Fahrenheit updates this too) + 0xC0, // Power on, swing on + 0x5E, // 90 F + 0x64, // Sleep enabled, "on timer" set to 24 hours + 0x00, + 0xA4, // "Off timer" set to 24 hours + 0x80, // "Off timer" enabled + 0x80, + 0x40, // High fan + 0x57, // Checksum + }; + + EXPECT_STATE_EQ(expected_state, ac.getRaw(), kEuromBits); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gorenje_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gorenje_test.cpp index 245b29b98..dc803ffdd 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gorenje_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gorenje_test.cpp @@ -1,5 +1,7 @@ // Copyright 2022 Mateusz Bronk (mbronk) +#include +#include #include "IRac.h" #include "IRsend.h" #include "IRsend_test.h" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp index e0160577e..a5e77c529 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp @@ -202,7 +202,7 @@ TEST(TestSendGree, CompareUint64ToCharResults) { irsend_chars.reset(); irsend_uint64.reset(); irsend_chars.sendGree(gree_zero_code); - irsend_uint64.sendGree((uint64_t)0x0); + irsend_uint64.sendGree(static_cast(0x0)); ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr()); } @@ -701,6 +701,11 @@ TEST(TestGreeClass, toCommon) { ASSERT_FALSE(ac.toCommon().filter); ASSERT_FALSE(ac.toCommon().beep); ASSERT_EQ(-1, ac.toCommon().clock); + + // Test kGreeSwingLastPos following the pattern in IRac::gree(). + ASSERT_EQ(kGreeSwingLastPos, ac.convertSwingV(stdAc::swingv_t::kOff)); + ac.setSwingVertical(false, kGreeSwingLastPos); + ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv); } TEST(TestGreeClass, Issue814Power) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp index 4a63780d5..37ab2db2c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp @@ -311,22 +311,25 @@ TEST(TestToshibaACClass, HumanReadableOutput) { 0x00, 0xC1, 0x00, 0xC0}; ac.setRaw(initial_state); - EXPECT_EQ("Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), " - "Turbo: Off, Econo: Off, Filter: Off", + EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, " + "Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, Econo: Off, " + "Filter: Off", ac.toString()); ac.setRaw(modified_state); - EXPECT_EQ("Temp: 17C, Power: On, Mode: 1 (Cool), Fan: 5 (High), " - "Turbo: Off, Econo: Off, Filter: Off", + EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, " + "Mode: 1 (Cool), Fan: 5 (High), Turbo: Off, Econo: Off, " + "Filter: Off", ac.toString()); ac.setTemp(25); ac.setFan(3); ac.setMode(kToshibaAcDry); - EXPECT_EQ("Temp: 25C, Power: On, Mode: 2 (Dry), Fan: 3 (Medium), " - "Turbo: Off, Econo: Off, Filter: Off", + EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 25C, Power: On, " + "Mode: 2 (Dry), Fan: 3 (Medium), Turbo: Off, Econo: Off, " + "Filter: Off", ac.toString()); ac.off(); - EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off, " - "Filter: Off", + EXPECT_EQ("Model: 0 (TOSHIBA REMOTE A), Temp: 25C, Power: Off, " + "Fan: 3 (Medium), Turbo: Off, Econo: Off, Filter: Off", ac.toString()); } @@ -379,8 +382,8 @@ TEST(TestDecodeToshibaAC, SyntheticExample) { ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, " - "Econo: Off, Filter: Off", + "Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Power: On, Mode: 0 (Auto), " + "Fan: 0 (Auto), Turbo: Off, Econo: Off, Filter: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -627,8 +630,8 @@ TEST(TestDecodeToshibaAC, RealLongExample) { EXPECT_EQ(kToshibaACBitsLong, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Temp: 22C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: On, " - "Econo: Off, Filter: Off", + "Model: 0 (TOSHIBA REMOTE A), Temp: 22C, Power: On, Mode: 0 (Auto), " + "Fan: 0 (Auto), Turbo: On, Econo: Off, Filter: Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -718,7 +721,7 @@ TEST(TestDecodeToshibaAC, RealShortExample) { EXPECT_EQ(kToshibaACBitsShort, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Temp: 17C, Swing(V): 0 (Step)", + "Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 0 (Step)", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -732,8 +735,8 @@ TEST(TestToshibaACClass, ConstructLongState) { ac.setTurbo(false); ac.setEcono(true); EXPECT_EQ( - "Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), " - "Turbo: Off, Econo: On, Filter: Off", + "Model: 0 (TOSHIBA REMOTE A), Temp: 29C, Power: On, Mode: 2 (Dry), " + "Fan: 2 (UNKNOWN), Turbo: Off, Econo: On, Filter: Off", ac.toString()); EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength()); const uint8_t expectedState[kToshibaACStateLengthLong] = { @@ -783,8 +786,8 @@ TEST(TestDecodeToshibaAC, RealExample_WHUB03NJ) { EXPECT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, " - "Filter: Off", + "Model: 0 (TOSHIBA REMOTE A), Temp: 20C, Power: Off, Fan: 0 (Auto), " + "Turbo: Off, Econo: Off, Filter: Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -805,7 +808,7 @@ TEST(TestToshibaACClass, SwingCodes) { ac.setSwing(kToshibaAcSwingOn); EXPECT_EQ( - "Temp: 17C, Swing(V): 1 (On)", + "Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 1 (On)", ac.toString()); EXPECT_EQ(kToshibaACStateLengthShort, ac.getStateLength()); const uint8_t swingOnState[kToshibaACStateLengthShort] = { @@ -815,7 +818,7 @@ TEST(TestToshibaACClass, SwingCodes) { ac.setSwing(kToshibaAcSwingOff); EXPECT_EQ( - "Temp: 17C, Swing(V): 2 (Off)", + "Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 2 (Off)", ac.toString()); EXPECT_EQ(kToshibaACStateLengthShort, ac.getStateLength()); const uint8_t swingOffState[kToshibaACStateLengthShort] = { @@ -828,7 +831,7 @@ TEST(TestToshibaACClass, SwingCodes) { ac.setRaw(swingToggleState, kToshibaACStateLengthShort); EXPECT_EQ(kToshibaAcSwingToggle, ac.getSwing()); EXPECT_EQ( - "Temp: 17C, Swing(V): 4 (Toggle)", + "Model: 0 (TOSHIBA REMOTE A), Temp: 17C, Swing(V): 4 (Toggle)", ac.toString()); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py index 69149215d..0d5ebabc9 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py @@ -105,7 +105,7 @@ class RawIRMessage(): code.append(f" // Data Section #{self.section_count}") code.append(f" // e.g. data = 0x{int(bin_str, 2):X}, nbits = {nbits}") code.append(f" sendData(k{name}BitMark, k{name}OneSpace, k{name}BitMark," - f" k{name}ZeroSpace, send_data, {nbits}, true);") + f" k{name}ZeroSpace, send_data, {nbits}, k{name}MsbFirst);") code.append(f" send_data >>= {nbits};") if footer: code.append(" // Footer") @@ -122,7 +122,8 @@ class RawIRMessage(): f" // e.g. data_result.data = 0x{int(bin_str, 2):X}, nbits = {nbits}", f" data_result = matchData(&(results->rawbuf[offset]), {nbits},", f" k{name}BitMark, k{name}OneSpace,", - f" k{name}BitMark, k{name}ZeroSpace);", + f" k{name}BitMark, k{name}ZeroSpace,", + f" kUseDefTol, kMarkExcess, k{name}MsbFirst);", " offset += data_result.used;", " if (data_result.success == false) return false; // Fail", f" data <<= {nbits}; // Make room for the new bits of data.", @@ -163,7 +164,8 @@ class RawIRMessage(): f" k{name}BitMark, k{name}ZeroSpace,", f" {lastmark}, {lastspace},", f" data + pos, {int(nbytes)}, // Bytes", - f" k{name}Freq, true, kNoRepeat, kDutyDefault);", + f" k{name}Freq, k{name}MsbFirst, kNoRepeat," + " kDutyDefault);", f" pos += {int(nbytes)};" f" // Adjust by how many bytes of data we sent"]) return code @@ -198,7 +200,7 @@ class RawIRMessage(): f" {firstmark}, {firstspace},", f" k{name}BitMark, k{name}OneSpace,", f" k{name}BitMark, k{name}ZeroSpace,", - f" {lastmark}, {lastspace}, true);", + f" {lastmark}, {lastspace}, k{name}MsbFirst);", " if (used == 0) return false; // We failed to find any data.", " offset += used; // Adjust for how much of the message we read.", f" pos += {int(nbytes)};" @@ -351,6 +353,7 @@ def dump_constants(message, defines, name="", output=sys.stdout): defines.append(f"const uint16_t k{name}SpaceGap{count} = {gap};") defines.append(f"const uint16_t k{name}Freq = 38000; " "// Hz. (Guessing the most common frequency.)") + defines.append(f"const bool k{name}MsbFirst = true; // default assumption") def parse_and_report(rawdata_str, margin, gen_code=False, name="", diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data_test.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data_test.py index 1b080c5a8..724fbfe2e 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data_test.py +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data_test.py @@ -76,7 +76,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'const uint16_t kBAROneSpace = 1485;', 'const uint16_t kBARZeroSpace = 520;', 'const uint16_t kBARFreq = 38000; // Hz. (Guessing the most common ' - 'frequency.)' + 'frequency.)', + 'const bool kBARMsbFirst = true; // default assumption' ]) self.assertEqual( output.getvalue(), 'Guessing key value:\n' @@ -113,7 +114,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'const uint16_t kTESTZeroSpace = 554;', 'const uint16_t kTESTSpaceGap = 19990;', 'const uint16_t kTESTFreq = 38000; // Hz. (Guessing the most common ' - 'frequency.)' + 'frequency.)', + 'const bool kTESTMsbFirst = true; // default assumption' ]) self.assertEqual( output.getvalue(), 'Guessing key value:\n' @@ -302,6 +304,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'const uint16_t kFOOZeroSpace = 520;\n' 'const uint16_t kFOOFreq = 38000; // Hz. (Guessing the most common' ' frequency.)\n' + 'const bool kFOOMsbFirst = true; // default assumption\n' 'const uint16_t kFOOBits = 16; // Move to IRremoteESP8266.h\n' 'const uint16_t kFOOOverhead = 5;\n' '\n' @@ -323,7 +326,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #1\n' ' // e.g. data = 0xEB, nbits = 8\n' ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' - ' send_data, 8, true);\n' + ' send_data, 8, kFOOMsbFirst);\n' ' send_data >>= 8;\n' ' // Footer\n' ' mark(kFOOBitMark);\n' @@ -331,7 +334,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #2\n' ' // e.g. data = 0x1, nbits = 8\n' ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' - ' send_data, 8, true);\n' + ' send_data, 8, kFOOMsbFirst);\n' ' send_data >>= 8;\n' ' // Footer\n' ' mark(kFOOBitMark);\n' @@ -374,7 +377,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // e.g. data_result.data = 0xEB, nbits = 8\n' ' data_result = matchData(&(results->rawbuf[offset]), 8,\n' ' kFOOBitMark, kFOOOneSpace,\n' - ' kFOOBitMark, kFOOZeroSpace);\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 8; // Make room for the new bits of data.\n' @@ -390,7 +394,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // e.g. data_result.data = 0x1, nbits = 8\n' ' data_result = matchData(&(results->rawbuf[offset]), 8,\n' ' kFOOBitMark, kFOOOneSpace,\n' - ' kFOOBitMark, kFOOZeroSpace);\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 8; // Make room for the new bits of data.\n' @@ -585,6 +590,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'const uint16_t kHitachiSpaceGap = 49290;\n' 'const uint16_t kHitachiFreq = 38000; // Hz. (Guessing the most' ' common frequency.)\n' + 'const bool kHitachiMsbFirst = true; // default assumption\n' 'const uint16_t kHitachiBits = 424; // Move to IRremoteESP8266.h\n' 'const uint16_t kHitachiStateLength = 53; // Move to IRremoteESP8266.h' '\n' @@ -616,7 +622,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'FFCA358F7000FF00FF01FEC03F807F11EE00FF00FFFF00FF00FF00FF00,' ' nbits = 424\n' ' sendData(kHitachiBitMark, kHitachiOneSpace, kHitachiBitMark,' - ' kHitachiZeroSpace, send_data, 424, true);\n' + ' kHitachiZeroSpace, send_data, 424, kHitachiMsbFirst);\n' ' send_data >>= 424;\n' ' // Footer\n' ' mark(kHitachiBitMark);\n' @@ -663,7 +669,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kHitachiBitMark, kHitachiZeroSpace,\n' ' kHitachiBitMark, kHitachiSpaceGap,\n' ' data + pos, 53, // Bytes\n' - ' kHitachiFreq, true, kNoRepeat, kDutyDefault);\n' + ' kHitachiFreq, kHitachiMsbFirst, kNoRepeat,' + ' kDutyDefault);\n' ' pos += 53; // Adjust by how many bytes of data we sent\n' ' }\n' '}\n' @@ -714,7 +721,9 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' nbits = 424\n' ' data_result = matchData(&(results->rawbuf[offset]), 424,\n' ' kHitachiBitMark, kHitachiOneSpace,\n' - ' kHitachiBitMark, kHitachiZeroSpace);\n' + ' kHitachiBitMark, kHitachiZeroSpace,\n' + ' kUseDefTol, kMarkExcess,' + ' kHitachiMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 424; // Make room for the new bits of data.\n' @@ -772,7 +781,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kHitachiHdrMark, kHitachiHdrSpace,\n' ' kHitachiBitMark, kHitachiOneSpace,\n' ' kHitachiBitMark, kHitachiZeroSpace,\n' - ' kHitachiBitMark, kHitachiSpaceGap, true);\n' + ' kHitachiBitMark, kHitachiSpaceGap,' + ' kHitachiMsbFirst);\n' ' if (used == 0) return false; // We failed to find any data.\n' ' offset += used; // Adjust for how much of the message we read.\n' ' pos += 53; // Adjust by how many bytes of data we read\n' @@ -898,6 +908,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'const uint16_t kFOOSpaceGap = 13996;\n' 'const uint16_t kFOOFreq = 38000; // Hz. (Guessing the most common' ' frequency.)\n' + 'const bool kFOOMsbFirst = true; // default assumption\n' 'const uint16_t kFOOBits = 128; // Move to IRremoteESP8266.h\n' 'const uint16_t kFOOStateLength = 16; // Move to IRremoteESP8266.h\n' 'const uint16_t kFOOOverhead = 16;\n' @@ -922,7 +933,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #1\n' ' // e.g. data = 0x5F5F4040, nbits = 32\n' ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' - ' send_data, 32, true);\n' + ' send_data, 32, kFOOMsbFirst);\n' ' send_data >>= 32;\n' ' // Header\n' ' mark(kFOOHdrMark);\n' @@ -930,7 +941,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #2\n' ' // e.g. data = 0x5F5F4040, nbits = 32\n' ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' - ' send_data, 32, true);\n' + ' send_data, 32, kFOOMsbFirst);\n' ' send_data >>= 32;\n' ' // Header\n' ' mark(kFOOHdrMark);\n' @@ -944,7 +955,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #3\n' ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' - ' send_data, 32, true);\n' + ' send_data, 32, kFOOMsbFirst);\n' ' send_data >>= 32;\n' ' // Header\n' ' mark(kFOOHdrMark);\n' @@ -952,7 +963,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #4\n' ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' - ' send_data, 32, true);\n' + ' send_data, 32, kFOOMsbFirst);\n' ' send_data >>= 32;\n' ' // Header\n' ' mark(kFOOHdrMark);\n' @@ -994,7 +1005,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOBitMark, kFOOZeroSpace,\n' ' kFOOHdrMark, kFOOHdrSpace,\n' ' data + pos, 4, // Bytes\n' - ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n' ' pos += 4; // Adjust by how many bytes of data we sent\n' ' // Data Section #2\n' ' // e.g.\n' @@ -1005,7 +1016,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOBitMark, kFOOZeroSpace,\n' ' kFOOHdrMark, kFOOHdrSpace,\n' ' data + pos, 4, // Bytes\n' - ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n' ' pos += 4; // Adjust by how many bytes of data we sent\n' ' // Data Section #3\n' ' // e.g.\n' @@ -1016,7 +1027,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOBitMark, kFOOZeroSpace,\n' ' kFOOHdrMark, kFOOHdrSpace,\n' ' data + pos, 4, // Bytes\n' - ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n' ' pos += 4; // Adjust by how many bytes of data we sent\n' ' // Data Section #4\n' ' // e.g.\n' @@ -1027,7 +1038,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOBitMark, kFOOZeroSpace,\n' ' kFOOHdrMark, kFOOHdrSpace,\n' ' data + pos, 4, // Bytes\n' - ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' kFOOFreq, kFOOMsbFirst, kNoRepeat, kDutyDefault);\n' ' pos += 4; // Adjust by how many bytes of data we sent\n' ' }\n' '}\n' @@ -1068,7 +1079,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // e.g. data_result.data = 0x5F5F4040, nbits = 32\n' ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' ' kFOOBitMark, kFOOOneSpace,\n' - ' kFOOBitMark, kFOOZeroSpace);\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 32; // Make room for the new bits of data.\n' @@ -1084,7 +1096,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // e.g. data_result.data = 0x5F5F4040, nbits = 32\n' ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' ' kFOOBitMark, kFOOOneSpace,\n' - ' kFOOBitMark, kFOOZeroSpace);\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 32; // Make room for the new bits of data.\n' @@ -1112,7 +1125,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // e.g. data_result.data = 0x2F2F6C6C, nbits = 32\n' ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' ' kFOOBitMark, kFOOOneSpace,\n' - ' kFOOBitMark, kFOOZeroSpace);\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 32; // Make room for the new bits of data.\n' @@ -1128,7 +1142,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // e.g. data_result.data = 0x2F2F6C6C, nbits = 32\n' ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' ' kFOOBitMark, kFOOOneSpace,\n' - ' kFOOBitMark, kFOOZeroSpace);\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kFOOMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 32; // Make room for the new bits of data.\n' @@ -1189,7 +1204,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOHdrMark, kFOOHdrSpace,\n' ' kFOOBitMark, kFOOOneSpace,\n' ' kFOOBitMark, kFOOZeroSpace,\n' - ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n' ' if (used == 0) return false; // We failed to find any data.\n' ' offset += used; // Adjust for how much of the message we read.\n' ' pos += 4; // Adjust by how many bytes of data we read\n' @@ -1204,7 +1219,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOHdrMark, kFOOHdrSpace,\n' ' kFOOBitMark, kFOOOneSpace,\n' ' kFOOBitMark, kFOOZeroSpace,\n' - ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n' ' if (used == 0) return false; // We failed to find any data.\n' ' offset += used; // Adjust for how much of the message we read.\n' ' pos += 4; // Adjust by how many bytes of data we read\n' @@ -1219,7 +1234,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOHdrMark, kFOOHdrSpace,\n' ' kFOOBitMark, kFOOOneSpace,\n' ' kFOOBitMark, kFOOZeroSpace,\n' - ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n' ' if (used == 0) return false; // We failed to find any data.\n' ' offset += used; // Adjust for how much of the message we read.\n' ' pos += 4; // Adjust by how many bytes of data we read\n' @@ -1234,7 +1249,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kFOOHdrMark, kFOOHdrSpace,\n' ' kFOOBitMark, kFOOOneSpace,\n' ' kFOOBitMark, kFOOZeroSpace,\n' - ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' kFOOHdrMark, kFOOHdrSpace, kFOOMsbFirst);\n' ' if (used == 0) return false; // We failed to find any data.\n' ' offset += used; // Adjust for how much of the message we read.\n' ' pos += 4; // Adjust by how many bytes of data we read\n' @@ -1333,6 +1348,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): 'const uint16_t kZeroSpace = 547;\n' 'const uint16_t kFreq = 38000; // Hz. (Guessing the most common' ' frequency.)\n' + 'const bool kMsbFirst = true; // default assumption\n' 'const uint16_t kBits = 128; // Move to IRremoteESP8266.h\n' 'const uint16_t kStateLength = 16; // Move to IRremoteESP8266.h\n' 'const uint16_t kOverhead = 1;\n' @@ -1354,7 +1370,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' // Data Section #1\n' ' // e.g. data = 0xA55A0000400000000000000000000080, nbits = 128\n' ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, send_data,' - ' 128, true);\n' + ' 128, kMsbFirst);\n' ' send_data >>= 128;\n' ' // Footer\n' ' mark(kBitMark);\n' @@ -1393,7 +1409,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' kBitMark, kZeroSpace,\n' ' kBitMark, kDefaultMessageGap,\n' ' data + pos, 16, // Bytes\n' - ' kFreq, true, kNoRepeat, kDutyDefault);\n' + ' kFreq, kMsbFirst, kNoRepeat, kDutyDefault);\n' ' pos += 16; // Adjust by how many bytes of data we sent\n' ' }\n' '}\n' @@ -1429,7 +1445,8 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' = 128\n' ' data_result = matchData(&(results->rawbuf[offset]), 128,\n' ' kBitMark, kOneSpace,\n' - ' kBitMark, kZeroSpace);\n' + ' kBitMark, kZeroSpace,\n' + ' kUseDefTol, kMarkExcess, kMsbFirst);\n' ' offset += data_result.used;\n' ' if (data_result.success == false) return false; // Fail\n' ' data <<= 128; // Make room for the new bits of data.\n' @@ -1483,7 +1500,7 @@ class TestAutoAnalyseRawData(unittest.TestCase): ' 0, 0,\n' ' kBitMark, kOneSpace,\n' ' kBitMark, kZeroSpace,\n' - ' kBitMark, kDefaultMessageGap, true);\n' + ' kBitMark, kDefaultMessageGap, kMsbFirst);\n' ' if (used == 0) return false; // We failed to find any data.\n' ' offset += used; // Adjust for how much of the message we read.\n' ' pos += 16; // Adjust by how many bytes of data we read\n' diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp index 7358f16da..49838d634 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "IRac.h" #include "IRsend.h" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/gc_decode.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/gc_decode.cpp index f1c374bbe..d1a543867 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/gc_decode.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/gc_decode.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include "IRac.h" #include "IRsend.h" @@ -21,7 +23,7 @@ void str_to_uint16(char *str, uint16_t *res, uint8_t base) { if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || *end != '\0') return; - *res = (uint16_t)val; + *res = static_cast(val); } void usage_error(char *name) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mode2_decode.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mode2_decode.cpp index 63dfa6221..e81df390b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mode2_decode.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mode2_decode.cpp @@ -21,6 +21,7 @@ space 500000 #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ void str_to_uint16(char *str, uint16_t *res, uint8_t base) { if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || *end != '\0') return; - *res = (uint16_t)val; + *res = static_cast(val); } void usage_error(char *name) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py index 8d8fc815c..436cfa6bf 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py @@ -8,7 +8,7 @@ from auto_analyse_raw_data import convert_rawdata, add_rawdata_args, get_rawdata # pylint: disable=too-many-arguments -def parse_and_report(rawdata_str, hertz=38000, end_usecs=100000, +def parse_and_report(rawdata_str, hertz=38000, *, end_usecs=100000, use_initial=False, generate_code=False, verbose=False, output=sys.stdout): """Analyse the rawdata c++ definition of a IR message.""" @@ -94,9 +94,11 @@ def main(): default=False) add_rawdata_args(arg_parser) arg_options = arg_parser.parse_args() - parse_and_report(get_rawdata(arg_options), arg_options.hertz, - arg_options.usecs, arg_options.use_initial, - arg_options.generate_code, arg_options.verbose) + parse_and_report(get_rawdata(arg_options), hertz=arg_options.hertz, + end_usecs=arg_options.usecs, + use_initial=arg_options.use_initial, + generate_code=arg_options.generate_code, + verbose=arg_options.verbose) if __name__ == '__main__': diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code_test.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code_test.py index b7b029b66..ca23eee37 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code_test.py +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code_test.py @@ -14,8 +14,9 @@ class TestRawToPronto(unittest.TestCase): input_str = """ uint16_t rawData[7] = { 20100, 20472, 15092, 30704, 20102, 20472, 15086};""" - pronto.parse_and_report(input_str, 38000, 100000, True, False, False, - output) + pronto.parse_and_report(input_str, hertz=38000, end_usecs=100000, + use_initial=True, generate_code=False, + verbose=False, output=output) self.assertEqual( output.getvalue(), "Pronto code = " @@ -28,8 +29,9 @@ class TestRawToPronto(unittest.TestCase): input_str = """ uint16_t rawData[7] = { 20100, 20472, 15092, 30704, 20102, 20472, 15086};""" - pronto.parse_and_report(input_str, 36000, 100000, True, False, False, - output) + pronto.parse_and_report(input_str, hertz=36000, end_usecs=100000, + use_initial=True, generate_code=False, + verbose=False, output=output) self.assertEqual( output.getvalue(), "Pronto code = " @@ -42,8 +44,9 @@ class TestRawToPronto(unittest.TestCase): input_str = """ uint16_t rawData[7] = { 20100, 20472, 15092, 30704, 20102, 20472, 15086};""" - pronto.parse_and_report(input_str, 57600, 100000, True, False, False, - output) + pronto.parse_and_report(input_str, hertz=57600, end_usecs=100000, + use_initial=True, generate_code=False, + verbose=False, output=output) self.assertEqual( output.getvalue(), "Pronto code = " @@ -56,8 +59,9 @@ class TestRawToPronto(unittest.TestCase): input_str = """ uint16_t rawData[7] = { 20100, 20472, 15092, 30704, 20102, 20472, 15086};""" - pronto.parse_and_report(input_str, 38000, 30000, False, False, False, - output) + pronto.parse_and_report(input_str, hertz=38000, end_usecs=30000, + use_initial=False, generate_code=False, + verbose=False, output=output) self.assertEqual( output.getvalue(), "Pronto code = " @@ -70,7 +74,9 @@ class TestRawToPronto(unittest.TestCase): input_str = """ uint16_t rawData[7] = { 20100, 20472, 15092, 30704, 20102, 20472, 15086};""" - pronto.parse_and_report(input_str, 38000, 30000, True, True, False, output) + pronto.parse_and_report(input_str, 38000, end_usecs=30000, + use_initial=True, generate_code=True, + verbose=False, output=output) self.assertEqual( output.getvalue(), "uint16_t pronto[12] = {0x0000, 0x006D, 0x0004, 0x0000, 0x02fb, "