diff --git a/CHANGELOG.md b/CHANGELOG.md index d32d63e39..ec6d81b6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. ### Changed - ESP32 Increase number of button GPIOs from 8 to 28 (#16518) +- IRremoteESP8266 library from v2.8.2 to v2.8.3 ### Fixed diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md index e9d16eddd..da3243d2d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md @@ -10,8 +10,8 @@ This library enables you to **send _and_ receive** infra-red signals on an [ESP8266](https://github.com/esp8266/Arduino) or an [ESP32](https://github.com/espressif/arduino-esp32) using the [Arduino framework](https://www.arduino.cc/) using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* demodulators etc. -## v2.8.2 Now Available -Version 2.8.2 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. +## v2.8.3 Now Available +Version 2.8.3 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. #### Upgrading from pre-v2.0 Usage of the library has been slightly changed in v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md index 50dbab2cb..87045c49e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md @@ -11,8 +11,8 @@ Diese Programmbibliothek ermöglicht das **Senden _und_ Empfangen** von Infrarotsignalen mit [ESP8266](https://github.com/esp8266/Arduino)- und [ESP32](https://github.com/espressif/arduino-esp32)-Mikrocontrollern mithilfe des [Arduino-Frameworks](https://www.arduino.cc/) und handelsüblichen 940nm Infrarot-LEDs undIR-Empfängermodulen, wie zum Beispiel TSOP{17,22,24,36,38,44,48}*-Demodulatoren. -## v2.8.2 jetzt verfügbar -Version 2.8.2 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen. +## v2.8.3 jetzt verfügbar +Version 2.8.3 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen. #### Hinweis für Nutzer von Versionen vor v2.0 Die Benutzung der Bibliothek hat sich mit Version 2.0 leicht geändert. Einige Anpassungen im aufrufenden Code werden nötig sein, um mit Version ab 2.0 korrekt zu funktionieren. Mehr zu den Anpassungen finden sich auf unserer [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0)-Seite. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md index 71f4d4abc..ccbaad95a 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md @@ -10,8 +10,8 @@ Cette librairie vous permetra de **recevoir et d'envoyer des signaux** infrarouge sur le protocole [ESP8266](https://github.com/esp8266/Arduino) ou sur le protocole [ESP32](https://github.com/espressif/arduino-esp32) en utilisant le [Arduino framework](https://www.arduino.cc/) qui utilise la norme 940nm IR LEDs et le module basique de reception d'onde IR. Exemple : TSOP{17,22,24,36,38,44,48}* modules etc. -## v2.8.2 disponible -Version 2.8.2 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants. +## v2.8.3 disponible +Version 2.8.3 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants. #### mise à jour depuis pre-v2.0 L'utilisation de la librairie à un peu changer depuis la version in v2.0. Si vous voulez l'utiliser vous devrez changer votre utilisation aussi. Vous pouvez vous renseigner sur les précondition d'utilisation ici : [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md index 5fd04c726..070be5993 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md @@ -1,5 +1,48 @@ # Release Notes +## _v2.8.3 (20220915)_ + +**[Bug Fixes]** +- Fix `#if` for DECODE_COOLIX48 (#1796) +- Add missing `prev`s to `decodeToState()` (#1783) + +**[Features]** +- Add `pause()` function to ESP32 when receiving. (#1871) +- ARGO: Argo add `sendSensorTemp()` (#1858 #1859) +- HAIER_AC160: Experimental detail support. (#1852 #1804) +- BOSCH144: Add IRac class support (#1841) +- Mitsubishi_AC: update left vane in `IRac` class (#1837) +- Basic support for Daikin 312bit/39byte A/C protocol. (#1836 #1829) +- Experimental basic support for Sanyo AC 152 bit protocol. (#1828 #1826) +- GREE: Add model support for `YX1FSF`/Soleus Air Windown A/C (#1823 #1821) +- Experimental basic support for Bosch 144bit protocol. (#1822 #1787) +- Experimental basic support for TCL AC 96 bit protocol. (#1820 #1810) +- Add basic support for clima-butler (52bit) RCS-SD43UWI (#1815 #1812) +- TOTO: An experimental _(s)wipe_ at support for Toto Toilets. (#1811 #1806) +- CARRIER_AC128: Experimental Basic support for Carrier AC 128bit protocol. (#1798 #1797) +- HAIER_AC160: Add basic support for Haier 160bit protocol. (#1805 #1804) +- DAIKIN: Add basic support for 200-bit Daikin protocol. (#1803 #1802) +- FUJITSU: Improve handling of 10C Heat mode. (#1788 #1780) +- FUJITSU: Improve handling of short (command only) messages. (#1784 #1780) + +**[Misc]** +- Improve the `_IRREMOTEESP8266_VERSION_VAL` macro (#1875 #1870) +- SONY: Update supported devices. (#1872) +- SAMSUNG: Update supported devices (#1873) +- NEC: Update supported devices (#1874) +- Give IRmacros.h smaller scope to avoid impacting projects using IRremoteESP8266 (#1857 #1853 #1851) +- Inhibit protocol names for not-included protocols (#1853 #1851) +- Test out codeql static analysis (#1842) +- Remove pylint disable=no-self-use (#1817) +- Fujitsu General: update supported devices (#1813) +- DAIKIN: Update supported devices (#1808 #1807) +- Fujitsu: Update supported remote info. (#1801 #1794) +- DAIKIN128: Update supported devices (#1754) +- Voltas: Add link to manual for 122LZF A/C. (#1800 #1799 #1238) +- Daikin128: Additional unit test. (#1795 #1754) +- MIDEA: Update supported devices (#1791 #1790) + + ## _v2.8.2 (20220314)_ **[Bug Fixes]** diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md index 509e7cd50..422a5bf2d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md @@ -1,6 +1,6 @@ + Last generated: Thu 15 Sep 2022 12:54:42 +0000 ---> # IR Protocols supported by this library | Protocol | Brand | Model | A/C Model | Detailed A/C Support | @@ -11,8 +11,11 @@ | [Amcor](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Amcor.cpp) | **[Amcor](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Amcor.h)** | ADR-853H A/C
TAC-444 remote
TAC-495 remote | | Yes | | [Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.cpp) | **[Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.h)** | Ulisse 13 DCI Mobile Split A/C | | Yes | | [Arris](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Arris.cpp) | **Arris** | 120A V1.0 A18 remote
VIP1113M Set-top box | | - | +| [Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bosch.cpp) | **[Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bosch.h)** | CL3000i-Set 26 E A/C
RG10A(G2S)BGEF remote | | Yes | | [Bose](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bose.cpp) | **Bose** | Bose TV Speaker | | - | +| [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 40GKX0E2006 remote (CARRIER_AC128) | | Yes | | [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier/Surrey](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 42QG5A55970 remote
53NGK009/012 Inverter
619EGX0090E0 A/C
619EGX0120E0 A/C
619EGX0180E0 A/C
619EGX0220E0 A/C | | Yes | +| [ClimaButler](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_ClimaButler.cpp) | **Clima-Butler** | AR-715 remote
RCS-SD43UWI A/C | | - | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | RC08B remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Beko](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | BINR 070/071 split-type A/C
RG57K7(B)/BGEF Remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | B1ZAI2441W/B1ZAO2441W A/C
RG36B4/BGE remote | | Yes | @@ -22,7 +25,7 @@ | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Tokio](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | AATOEMF17-12CHR1SW split-type RG51\|50/BGE Remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | RAS-4M27YAV-E A/C
RAS-M10YKV-E A/C
RAS-M13YKV-E A/C
WH-E1YE remote | | Yes | | [Corona](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Corona.cpp) | **[Corona](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Corona.h)** | AR-01 remote
CSH-N2211 A/C
CSH-N2511 A/C
CSH-N2811 A/C
CSH-N4011 A/C | | Yes | -| [Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | 17 Series FTXB09AXVJU A/C (DAIKIN128)
17 Series FTXB12AXVJU A/C (DAIKIN128)
17 Series FTXB24AXVJU A/C (NOT SUPPORTED)
ARC423A5 remote (DAIKIN160)
ARC433** remote (DAIKIN)
ARC433B69 remote (DAIKIN216)
ARC466A33 remote (DAIKIN)
ARC477A1 remote (DAIKIN2)
ARC480A5 remote (DAIKIN152)
ARC484A4 remote (DAIKIN216)
BRC4C151 remote (DAIKIN176)
BRC4C153 remote (DAIKIN176)
BRC52B63 remote (DAIKIN128)
DGS01 remote (DAIKIN64)
FFN-C/FCN-F Series A/C (DAIKIN64)
FFQ35B8V1B A/C (DAIKIN176)
FTE12HV2S A/C
FTQ60TV16U2 A/C (DAIKIN216)
FTWX35AXV1 A/C (DAIKIN64)
FTXM-M A/C (DAIKIN)
FTXZ25NV1B A/C (DAIKIN2)
FTXZ35NV1B A/C (DAIKIN2)
FTXZ50NV1B A/C (DAIKIN2)
M Series A/C (DAIKIN) | | Yes | +| [Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | 17 Series FTXB09AXVJU A/C (DAIKIN128)
17 Series FTXB12AXVJU A/C (DAIKIN128)
17 Series FTXB24AXVJU A/C (DAIKIN128)
ARC423A5 remote (DAIKIN160)
ARC433** remote (DAIKIN)
ARC433B69 remote (DAIKIN216)
ARC466A12 remote (DAIKIN)
ARC466A33 remote (DAIKIN)
ARC466A67 remote (DAIKIN312)
ARC477A1 remote (DAIKIN2)
ARC480A5 remote (DAIKIN152)
ARC484A4 remote (DAIKIN216)
BRC4C151 remote (DAIKIN176)
BRC4C153 remote (DAIKIN176)
BRC4M150W16 remote (DAIKIN200)
BRC52B63 remote (DAIKIN128)
DGS01 remote (DAIKIN64)
FFN-C/FCN-F Series A/C (DAIKIN64)
FFQ35B8V1B A/C (DAIKIN176)
FTE12HV2S A/C
FTQ60TV16U2 A/C (DAIKIN216)
FTWX35AXV1 A/C (DAIKIN64)
FTXM-M A/C (DAIKIN)
FTXM20R5V1B A/C (DAIKIN312)
FTXZ25NV1B A/C (DAIKIN2)
FTXZ35NV1B A/C (DAIKIN2)
FTXZ50NV1B A/C (DAIKIN2)
M Series A/C (DAIKIN) | | Yes | | [Delonghi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Delonghi.cpp) | **[Delonghi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Delonghi.h)** | PAC A95 | | Yes | | [Denon](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Denon.cpp) | **Denon** | AVR-3801 A/V Receiver (probably) | | - | | [Dish](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Dish.cpp) | **DISH NETWORK** | echostar 301 | | - | @@ -37,21 +40,23 @@ | [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Elite Screens** | CineTension2 / CineTension3 series
Home2 / Home3 series
Spectrum series
VMAX Plus4 series
VMAX2 / VMAX2 Plus series
ZSP-IR-B / ZSP-IR-W remote | | - | | [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Lumene Screens** | Embassy | | - | | [Epson](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Epson.cpp) | **Epson** | EN-TW9100W Projector
EX3220 Projector
EX5220 Projector
EX5230 Projector
EX6220 Projector
EX7220 Projector
VS230 Projector
VS330 Projector | | - | -| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C (ARRAH2E)
AR-DB1 remote (ARDB1)
AR-DL10 remote (ARDB1)
AR-RAC1E remote (ARRAH2E)
AR-RAE1E remote (ARRAH2E)
AR-RAH1U remote (ARREB1E)
AR-RAH2E remote (ARRAH2E)
AR-REB1E remote (ARREB1E)
AR-REB4E remote (ARREB1E)
AR-REW1E remote (ARREW4E)
AR-REW4E remote (ARREW4E)
AR-RY4 remote (ARRY4)
AST9RSGCW A/C (ARDB1)
ASTB09LBC A/C (ARRY4)
ASTG09K A/C (ARREW4E)
ASTG18K A/C (ARREW4E)
ASU12RLF A/C (ARREB1E)
ASU30C1 A/C (ARDB1)
ASYG09KETA-B A/C (ARREW4E)
ASYG30LFCA A/C (ARRAH2E)
ASYG7LMCA A/C (ARREB1E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | -| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AOHG09LLC A/C (ARRAH2E)
AR-JW2 remote (ARJW2)
AR-RCE1E remote (ARRAH2E)
ASHG09LLCA A/C (ARRAH2E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | +| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C (ARRAH2E)
AR-DB1 remote (ARDB1)
AR-DL10 remote (ARDB1)
AR-RAC1E remote (ARRAH2E)
AR-RAE1E remote (ARRAH2E)
AR-RAH1U remote (ARREB1E)
AR-RAH2E remote (ARRAH2E)
AR-RAH2U remote (ARRAH2E)
AR-REB1E remote (ARREB1E)
AR-REB4E remote (ARREB1E)
AR-REG1U remote (ARRAH2E)
AR-REW1E remote (ARREW4E)
AR-REW4E remote (ARREW4E)
AR-RY4 remote (ARRY4)
AST9RSGCW A/C (ARDB1)
ASTB09LBC A/C (ARRY4)
ASTG09K A/C (ARREW4E)
ASTG18K A/C (ARREW4E)
ASU12RLF A/C (ARREB1E)
ASU30C1 A/C (ARDB1)
ASYG09KETA-B A/C (ARREW4E)
ASYG30LFCA A/C (ARRAH2E)
ASYG7LMCA A/C (ARREB1E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | +| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AOHG09LLC A/C (ARRAH2E)
AR-JW17 remote (ARDB1)
AR-JW2 remote (ARJW2)
AR-RCE1E remote (ARRAH2E)
ASHG09LLCA A/C (ARRAH2E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | +| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[OGeneral](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AR-RCL1E remote (ARRAH2E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | | [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **G.I. Cable** | XRC-200 remote | | - | | [GlobalCache](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Global Cache** | Control Tower IR DB | | - | | [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Amana](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | PBC093G00CC A/C
YX1FF remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Cooper & Hunter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | CH-S09FTXG A/C
YB1F2 remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VIR09HP115V1AH A/C
VIR12HP230V1AH A/C
YAA1FBF remote
YAN1F1 remote
YB1F2F remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Vailland](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VAI5-035WNI A/C
YACIFB remote | YAW1F
YBOFB | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Amana](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | PBC093G00CC A/C
YX1FF remote | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Cooper & Hunter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | CH-S09FTXG A/C
YB1F2 remote | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VIR09HP115V1AH A/C
VIR12HP230V1AH A/C
YAA1FBF remote
YAN1F1 remote
YB1F2F remote
YX1F2F remote (YX1FSF) | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Soleus Air](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | window A/C (YX1FSF) | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F
YBOFB
YX1FSF | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Vailland](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VAI5-035WNI A/C
YACIFB remote | YAW1F
YBOFB
YX1FSF | Yes | | [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Daichi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | D-H A/C (HAIER_AC176) | | Yes | -| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C (HAIER_AC_YRW02)
HSU07-HEA03 remote (HAIER_AC)
V9014557 M47 8D remote (HAIER_AC176)
YR-W02 remote (HAIER_AC_YRW02) | | Yes | +| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C (HAIER_AC_YRW02)
HSU07-HEA03 remote (HAIER_AC)
KFR-26GW/83@UI-Ge A/C (HAIER_AC160)
V9014557 M47 8D remote (HAIER_AC176)
YR-W02 remote (HAIER_AC_YRW02) | | Yes | | [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Mabe](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | MMI18HDBWCA6MI8 A/C (HAIER_AC176)
V12843 HJ200223 remote (HAIER_AC176) | | Yes | | [Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp) | **[Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.h)** | KAZE-312KSDP A/C (HITACHI_AC1)
LT0541-HTA remote (HITACHI_AC1)
PC-LH3B (HITACHI_AC3)
R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1)
RAK-25NH5 A/C (HITACHI_AC264)
RAR-2P2 remote (HITACHI_AC264)
RAR-3U3 remote (HITACHI_AC296)
RAR-8P2 remote (HITACHI_AC424)
RAS-22NK A/C (HITACHI_AC344)
RAS-35THA6 remote
RAS-70YHA3 A/C (HITACHI_AC296)
RAS-AJ25H A/C (HITACHI_AC424)
RF11T1 remote (HITACHI_AC344)
Series VI A/C (Circa 2007) (HITACHI_AC1) | | Yes | | [Inax](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Inax.cpp) | **Lixil** | Inax DT-BA283 Toilet | | - | @@ -78,7 +83,7 @@ | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | FS40-7AR Stand Fan (MIDEA24) | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[MrCool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57A6/BGEFU1 remote (MIDEA) | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG66B6(B)/BGEFU1 remote (MIDEA)
RUBO18GMFILCAD A/C (18K BTU) (MIDEA)
RYBO12GMFILCAD A/C (12K BTU) (MIDEA)
UB018GMFILCFHD A/C (12K BTU) (MIDEA)
WS012GMFI22HLD A/C (12K BTU) (MIDEA)
WS018GMFI22HLD A/C (12K BTU) (MIDEA) | | Yes | -| [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H(B)/BGE remote (MIDEA)
TROTEC PAC 3900 X (MIDEA) | | Yes | +| [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H(B)/BGE remote (MIDEA)
RG57H3(B)/BGCEF-M remote (MIDEA)
TROTEC PAC 2100 X (MIDEA)
TROTEC PAC 3900 X (MIDEA) | | Yes | | [MilesTag2](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MilesTag2.cpp) | **Milestag2** | Various | | - | | [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Maxell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | KKG9A-C1 remote
MX-CH18CF A/C | KKG29AC1
KKG9AC1 | Yes | | [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | VLU series A/C | KKG29AC1
KKG9AC1 | Yes | @@ -88,8 +93,10 @@ | [MitsubishiHeavy](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.cpp) | **[Mitsubishi Heavy Industries](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.h)** | RKX502A001C remote (88 bit)
RLA502A700B remote (152 bit)
SRKxxZJ-S A/C (88 bit)
SRKxxZM-S A/C (152 bit)
SRKxxZMXA-S A/C (152 bit) | | Yes | | [Multibrackets](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Multibrackets.cpp) | **Multibrackets** | Motorized Swing mount large - 4500 | | - | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Aloka](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SleepyLights LED Lamp | | - | +| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[BBK](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SP550S 5.1 sound system | | - | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Duux](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | Blizzard Smart 10K / DXMA04 A/C
YJ-A081 TR Remote | | - | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Silan Microelectronics](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SC6121-001 IC | | - | +| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Tanix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | TX3 mini Android TV Box | | - | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | 42TL838 LCD TV | | - | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Yamaha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | RAV561 remote
RXV585B A/V Receiver | | - | | [Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.cpp) | **[Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.h)** | NS-09AHTI A/C
ZH/TY-01 remote | | Yes | @@ -101,11 +108,11 @@ | [RC5_RC6](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Philips** | RC-5X (RC5X)
Standard RC-5 (RC5)
Standard RC-6 (RC6) | | - | | [RCMM](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RCMM.cpp) | **Microsoft** | XBOX 360 | | - | | [Rhoss](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Rhoss.cpp) | **[Rhoss](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Rhoss.h)** | Idrowall MPCV 20-30-35-40 | | Yes | -| [Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AH59-02692E Soundbar remote (SAMSUNG36)
AK59-00167A Bluray remote (SAMSUNG36)
AR09FSSDAWKNFA A/C (SAMSUNG_AC)
AR09HSFSBWKN A/C (SAMSUNG_AC)
AR12HSSDBWKNEU A/C (SAMSUNG_AC)
AR12KSFPEWQNET A/C (SAMSUNG_AC)
AR12NXCXAWKXEU A/C (SAMSUNG_AC)
AR12TXEAAWKNEU A/C (SAMSUNG_AC)
BN59-01178B TV remote (SAMSUNG)
DB63-03556X003 remote
DB93-14195A remote (SAMSUNG_AC)
DB93-16761C remote
DB96-24901C remote (SAMSUNG_AC)
HW-J551 Soundbar (SAMSUNG36)
IEC-R03 remote
UA55H6300 TV (SAMSUNG) | | Yes | -| [Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.cpp) | **[Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.h)** | LC7461 transmitter IC (SANYO_LC7461)
RCS-2HS4E remote (SANYO_AC)
RCS-2S4E remote (SANYO_AC)
SA 8650B - disabled
SAP-K121AHA A/C (SANYO_AC)
SAP-K242AH A/C (SANYO_AC) | | Yes | +| [Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AH59-02692E Soundbar remote (SAMSUNG36)
AK59-00167A Bluray remote (SAMSUNG36)
AR09FSSDAWKNFA A/C (SAMSUNG_AC)
AR09HSFSBWKN A/C (SAMSUNG_AC)
AR12HSSDBWKNEU A/C (SAMSUNG_AC)
AR12KSFPEWQNET A/C (SAMSUNG_AC)
AR12NXCXAWKXEU A/C (SAMSUNG_AC)
AR12TXEAAWKNEU A/C (SAMSUNG_AC)
BN59-01178B TV remote (SAMSUNG)
DB63-03556X003 remote
DB93-14195A remote (SAMSUNG_AC)
DB93-16761C remote
DB96-24901C remote (SAMSUNG_AC)
HW-J551 Soundbar (SAMSUNG36)
IEC-R03 remote
UA55H6300 TV (SAMSUNG)
UE40K5510AUXRU TV (SAMSUNG) | | Yes | +| [Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.cpp) | **[Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.h)** | LC7461 transmitter IC (SANYO_LC7461)
RCS-2HS4E remote (SANYO_AC)
RCS-2S4E remote (SANYO_AC)
RCS-4MHVPIS4EE remote (SANYO_AC152)
SA 8650B - disabled
SAP-K121AHA A/C (SANYO_AC)
SAP-K242AH A/C (SANYO_AC)
SAP-KMRV124EHE A/C (SANYO_AC152) | | Yes | | [Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AH-A12REVP-1 A/C (A903)
AH-AxSAY A/C (A907)
AH-PR13-GL A/C (A903)
AH-XP10NRY A/C (A903)
AY-ZP40KR A/C (A907)
CRMC-820 JBEZ remote (A903)
CRMC-A705 JBEZ remote (A705)
CRMC-A863 JBEZ remote (A903)
CRMC-A903JBEZ remote (A903)
CRMC-A907 JBEZ remote (A907)
CRMC-A950 JBEZ (A907)
LC-52D62U TV | A705
A903
A907 | Yes | | [Sherwood](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sherwood.cpp) | **Sherwood** | RC-138 remote
RD6505(B) Receiver | | - | -| [Sony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Sony** | HT-CT380 Soundbar (Uses 38kHz & 3 repeats) | | - | +| [Sony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Sony** | HT-CT380 Soundbar (Uses 38kHz & 3 repeats)
HT-SF150 Soundbar (Uses 38kHz & 3 repeats) | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Blyss** | Owen-SW-5 3 Fan
WP-YK8 090218 remote | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **SamHop** | SM3015 Fan Remote Control
SM5021 Encoder chip
SM5032 Decoder chip | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Satellite Electronic** | ID6 Remote
JY199I Fan driver
JY199I-L Fan driver | | - | @@ -114,13 +121,14 @@ | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Westinghouse** | 78095 Remote
Ceiling fan | | - | | [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Daewoo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | DSB-F0934ELH-V A/C
GYKQ-52E remote | GZ055BE1
TAC09CHSD | Yes | | [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Leberg](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | LBS-TOR07 A/C (TAC09CHSD) | GZ055BE1
TAC09CHSD | Yes | -| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[TCL](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | TAC-09CHSD/XA31I A/C (TAC09CHSD) | GZ055BE1
TAC09CHSD | Yes | +| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[TCL](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | GYKQ-58(XM) remote (TCL96AC)
TAC-09CHSD/XA31I A/C (TAC09CHSD) | GZ055BE1
TAC09CHSD | Yes | | [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Teknopoint](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | Allegro SSA-09H A/C (GZ055BE1)
GZ-055B-E1 remote (GZ055BE1) | GZ055BE1
TAC09CHSD | Yes | | [Technibel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Technibel.cpp) | **[Technibel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Technibel.h)** | IRO PLUS | | Yes | | [Teco](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.cpp) | **[Alaska](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.h)** | SAC9010QC A/C
SAC9010QC remote | | Yes | | [Teknopoint](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teknopoint.cpp) | **Teknopoint** | Allegro SSA-09H A/C
GZ-055B-E1 remote
GZ01-BEJ0-000 remote | | - | | [Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.cpp) | **[Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.h)** | 42NQV025M2 / 38NYV025M2 A/C
42NQV035M2 / 38NYV035M2 A/C
42NQV050M2 / 38NYV050M2 A/C
42NQV060M2 / 38NYV060M2 A/C | | Yes | | [Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.h)** | Akita EVO II
RAS 18SKP-ES
RAS-2558V A/C
RAS-25SKVP2-ND A/C
RAS-B13N3KV2
RAS-B13N3KVP-E
WC-L03SE
WH-TA01JE remote
WH-TA04NE
WH-UB03NJ remote | | Yes | +| [Toto](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toto.cpp) | **Toto** | Washlet Toilet NJ | | - | | [Transcold](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Transcold.cpp) | **[Transcold](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Transcold.h)** | M1-F-NO-6 A/C | | Yes | | [Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.cpp) | **[Duux](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.h)** | Blizzard Smart 10K / DXMA04 A/C (TROTEC) | | Yes | | [Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.cpp) | **[Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.h)** | PAC 3200 A/C (TROTEC)
PAC 3550 Pro A/C (TROTEC_3550) | | Yes | @@ -150,10 +158,13 @@ - AMCOR - ARGO - ARRIS +- BOSCH144 - BOSE - CARRIER_AC +- CARRIER_AC128 - CARRIER_AC40 - CARRIER_AC64 +- CLIMABUTLER - COOLIX - COOLIX48 - CORONA_AC @@ -163,7 +174,9 @@ - DAIKIN160 - DAIKIN176 - DAIKIN2 +- DAIKIN200 - DAIKIN216 +- DAIKIN312 - DAIKIN64 - DELONGHI_AC - DENON @@ -178,6 +191,7 @@ - GOODWEATHER - GREE - HAIER_AC +- HAIER_AC160 - HAIER_AC176 - HAIER_AC_YRW02 - HITACHI_AC @@ -231,6 +245,7 @@ - SAMSUNG_AC - SANYO - SANYO_AC +- SANYO_AC152 - SANYO_AC88 - SANYO_LC7461 - SHARP @@ -238,10 +253,12 @@ - SONY - SYMPHONY - TCL112AC +- TCL96AC - TECHNIBEL_AC - TECO - TEKNOPOINT - TOSHIBA_AC +- TOTO - TRANSCOLD - TROTEC - TROTEC_3550 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt index bab1f5d5e..a562d2451 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt @@ -25,6 +25,7 @@ IRAirtonAc KEYWORD1 IRAirwellAc KEYWORD1 IRAmcorAc KEYWORD1 IRArgoAC KEYWORD1 +IRBosch144AC KEYWORD1 IRCarrierAc64 KEYWORD1 IRCoolixAC KEYWORD1 IRCoronaAc KEYWORD1 @@ -43,6 +44,7 @@ IRFujitsuAC KEYWORD1 IRGoodweatherAc KEYWORD1 IRGreeAC KEYWORD1 IRHaierAC KEYWORD1 +IRHaierAC160 KEYWORD1 IRHaierAC176 KEYWORD1 IRHaierACYRW02 KEYWORD1 IRHitachiAc KEYWORD1 @@ -159,6 +161,7 @@ argo KEYWORD2 bcdToUint8 KEYWORD2 begin KEYWORD2 boolToString KEYWORD2 +bosch144 KEYWORD2 buildFromState KEYWORD2 calcBlockChecksum KEYWORD2 calcChecksum KEYWORD2 @@ -213,11 +216,14 @@ decodeAiwaRCT501 KEYWORD2 decodeAmcor KEYWORD2 decodeArgo KEYWORD2 decodeArris KEYWORD2 +decodeBosch144 KEYWORD2 decodeBose KEYWORD2 decodeCOOLIX KEYWORD2 decodeCarrierAC KEYWORD2 +decodeCarrierAC128 KEYWORD2 decodeCarrierAC40 KEYWORD2 decodeCarrierAC64 KEYWORD2 +decodeClimaButler KEYWORD2 decodeCoolix48 KEYWORD2 decodeCoronaAc KEYWORD2 decodeDISH KEYWORD2 @@ -227,7 +233,9 @@ decodeDaikin152 KEYWORD2 decodeDaikin160 KEYWORD2 decodeDaikin176 KEYWORD2 decodeDaikin2 KEYWORD2 +decodeDaikin200 KEYWORD2 decodeDaikin216 KEYWORD2 +decodeDaikin312 KEYWORD2 decodeDaikin64 KEYWORD2 decodeDelonghiAc KEYWORD2 decodeDenon KEYWORD2 @@ -241,6 +249,7 @@ decodeGICable KEYWORD2 decodeGoodweather KEYWORD2 decodeGree KEYWORD2 decodeHaierAC KEYWORD2 +decodeHaierAC160 KEYWORD2 decodeHaierAC176 KEYWORD2 decodeHaierACYRW02 KEYWORD2 decodeHash KEYWORD2 @@ -287,17 +296,20 @@ decodeSamsung36 KEYWORD2 decodeSamsungAC KEYWORD2 decodeSanyo KEYWORD2 decodeSanyoAc KEYWORD2 +decodeSanyoAc152 KEYWORD2 decodeSanyoAc88 KEYWORD2 decodeSanyoLC7461 KEYWORD2 decodeSharp KEYWORD2 decodeSharpAc KEYWORD2 decodeSony KEYWORD2 decodeSymphony KEYWORD2 +decodeTcl96Ac KEYWORD2 decodeTechnibelAc KEYWORD2 decodeTeco KEYWORD2 decodeTeknopoint KEYWORD2 decodeToState KEYWORD2 decodeToshibaAC KEYWORD2 +decodeToto KEYWORD2 decodeTranscold KEYWORD2 decodeTrotec KEYWORD2 decodeTrotec3550 KEYWORD2 @@ -351,6 +363,7 @@ get3D KEYWORD2 get8CHeat KEYWORD2 get8CHeatToggle KEYWORD2 getAbsenseDetect KEYWORD2 +getAuxHeating KEYWORD2 getBeep KEYWORD2 getBit KEYWORD2 getBoost KEYWORD2 @@ -490,6 +503,7 @@ getiFeel KEYWORD2 goodweather KEYWORD2 gree KEYWORD2 haier KEYWORD2 +haier160 KEYWORD2 haier176 KEYWORD2 haierYrwo2 KEYWORD2 handleSpecialState KEYWORD2 @@ -511,6 +525,7 @@ is8CHeatToggle KEYWORD2 isCleanToggle KEYWORD2 isEconoToggle KEYWORD2 isLightToggle KEYWORD2 +isLongCode KEYWORD2 isOffCommand KEYWORD2 isOffTimerActive KEYWORD2 isOffTimerEnabled KEYWORD2 @@ -569,6 +584,7 @@ on KEYWORD2 opmodeToString KEYWORD2 panasonic KEYWORD2 panasonic32 KEYWORD2 +pause KEYWORD2 recoverSavedState KEYWORD2 reset KEYWORD2 resultAcToString KEYWORD2 @@ -591,11 +607,14 @@ sendAiwaRCT501 KEYWORD2 sendAmcor KEYWORD2 sendArgo KEYWORD2 sendArris KEYWORD2 +sendBosch144 KEYWORD2 sendBose KEYWORD2 sendCOOLIX KEYWORD2 sendCarrierAC KEYWORD2 +sendCarrierAC128 KEYWORD2 sendCarrierAC40 KEYWORD2 sendCarrierAC64 KEYWORD2 +sendClimaButler KEYWORD2 sendCoolix48 KEYWORD2 sendCoronaAc KEYWORD2 sendDISH KEYWORD2 @@ -605,7 +624,9 @@ sendDaikin152 KEYWORD2 sendDaikin160 KEYWORD2 sendDaikin176 KEYWORD2 sendDaikin2 KEYWORD2 +sendDaikin200 KEYWORD2 sendDaikin216 KEYWORD2 +sendDaikin312 KEYWORD2 sendDaikin64 KEYWORD2 sendData KEYWORD2 sendDelonghiAc KEYWORD2 @@ -623,6 +644,7 @@ sendGeneric KEYWORD2 sendGoodweather KEYWORD2 sendGree KEYWORD2 sendHaierAC KEYWORD2 +sendHaierAC160 KEYWORD2 sendHaierAC176 KEYWORD2 sendHaierACYRW02 KEYWORD2 sendHitachiAC KEYWORD2 @@ -680,8 +702,10 @@ sendSAMSUNG KEYWORD2 sendSamsung36 KEYWORD2 sendSamsungAC KEYWORD2 sendSanyoAc KEYWORD2 +sendSanyoAc152 KEYWORD2 sendSanyoAc88 KEYWORD2 sendSanyoLC7461 KEYWORD2 +sendSensorTemp KEYWORD2 sendSharp KEYWORD2 sendSharpAc KEYWORD2 sendSharpRaw KEYWORD2 @@ -690,10 +714,12 @@ sendSony KEYWORD2 sendSony38 KEYWORD2 sendSymphony KEYWORD2 sendTcl112Ac KEYWORD2 +sendTcl96Ac KEYWORD2 sendTechnibelAc KEYWORD2 sendTeco KEYWORD2 sendTeknopoint KEYWORD2 sendToshibaAC KEYWORD2 +sendToto KEYWORD2 sendTranscold KEYWORD2 sendTrotec KEYWORD2 sendTrotec3550 KEYWORD2 @@ -711,6 +737,7 @@ set8CHeat KEYWORD2 set8CHeatToggle KEYWORD2 setAbsenseDetect KEYWORD2 setAuto KEYWORD2 +setAuxHeating KEYWORD2 setBeep KEYWORD2 setBit KEYWORD2 setBits KEYWORD2 @@ -718,6 +745,7 @@ setBoost KEYWORD2 setBreeze KEYWORD2 setButton KEYWORD2 setCelsius KEYWORD2 +setCheckSumS3 KEYWORD2 setClean KEYWORD2 setCleanToggle KEYWORD2 setClock KEYWORD2 @@ -753,6 +781,7 @@ setIFeel KEYWORD2 setISave10C KEYWORD2 setISee KEYWORD2 setId KEYWORD2 +setInvertBytes KEYWORD2 setInvertedStates KEYWORD2 setIon KEYWORD2 setIonFilter KEYWORD2 @@ -927,11 +956,14 @@ ARREB1E LITERAL1 ARREW4E LITERAL1 ARRIS LITERAL1 ARRY4 LITERAL1 +BOSCH144 LITERAL1 BOSE LITERAL1 CARRIER_AC LITERAL1 +CARRIER_AC128 LITERAL1 CARRIER_AC40 LITERAL1 CARRIER_AC64 LITERAL1 CARRIER_AC_BITS LITERAL1 +CLIMABUTLER LITERAL1 COOLIX LITERAL1 COOLIX48 LITERAL1 COOLIX_BITS LITERAL1 @@ -942,7 +974,9 @@ DAIKIN152 LITERAL1 DAIKIN160 LITERAL1 DAIKIN176 LITERAL1 DAIKIN2 LITERAL1 +DAIKIN200 LITERAL1 DAIKIN216 LITERAL1 +DAIKIN312 LITERAL1 DAIKIN64 LITERAL1 DAIKIN_AUTO LITERAL1 DAIKIN_COMMAND_LENGTH LITERAL1 @@ -963,10 +997,13 @@ DECODE_AIWA_RC_T501 LITERAL1 DECODE_AMCOR LITERAL1 DECODE_ARGO LITERAL1 DECODE_ARRIS LITERAL1 +DECODE_BOSCH144 LITERAL1 DECODE_BOSE LITERAL1 DECODE_CARRIER_AC LITERAL1 +DECODE_CARRIER_AC128 LITERAL1 DECODE_CARRIER_AC40 LITERAL1 DECODE_CARRIER_AC64 LITERAL1 +DECODE_CLIMABUTLER LITERAL1 DECODE_COOLIX LITERAL1 DECODE_COOLIX48 LITERAL1 DECODE_CORONA_AC LITERAL1 @@ -976,7 +1013,9 @@ DECODE_DAIKIN152 LITERAL1 DECODE_DAIKIN160 LITERAL1 DECODE_DAIKIN176 LITERAL1 DECODE_DAIKIN2 LITERAL1 +DECODE_DAIKIN200 LITERAL1 DECODE_DAIKIN216 LITERAL1 +DECODE_DAIKIN312 LITERAL1 DECODE_DAIKIN64 LITERAL1 DECODE_DELONGHI_AC LITERAL1 DECODE_DENON LITERAL1 @@ -992,6 +1031,7 @@ DECODE_GLOBALCACHE LITERAL1 DECODE_GOODWEATHER LITERAL1 DECODE_GREE LITERAL1 DECODE_HAIER_AC LITERAL1 +DECODE_HAIER_AC160 LITERAL1 DECODE_HAIER_AC176 LITERAL1 DECODE_HAIER_AC_YRW02 LITERAL1 DECODE_HASH LITERAL1 @@ -1043,6 +1083,7 @@ DECODE_SAMSUNG36 LITERAL1 DECODE_SAMSUNG_AC LITERAL1 DECODE_SANYO LITERAL1 DECODE_SANYO_AC LITERAL1 +DECODE_SANYO_AC152 LITERAL1 DECODE_SANYO_AC88 LITERAL1 DECODE_SHARP LITERAL1 DECODE_SHARP_AC LITERAL1 @@ -1050,10 +1091,12 @@ DECODE_SHERWOOD LITERAL1 DECODE_SONY LITERAL1 DECODE_SYMPHONY LITERAL1 DECODE_TCL112AC LITERAL1 +DECODE_TCL96AC LITERAL1 DECODE_TECHNIBEL_AC LITERAL1 DECODE_TECO LITERAL1 DECODE_TEKNOPOINT LITERAL1 DECODE_TOSHIBA_AC LITERAL1 +DECODE_TOTO LITERAL1 DECODE_TRANSCOLD LITERAL1 DECODE_TROTEC LITERAL1 DECODE_TROTEC_3550 LITERAL1 @@ -1133,6 +1176,7 @@ GREE_SWING_UP LITERAL1 GREE_SWING_UP_AUTO LITERAL1 GZ055BE1 LITERAL1 HAIER_AC LITERAL1 +HAIER_AC160 LITERAL1 HAIER_AC176 LITERAL1 HAIER_AC_AUTO LITERAL1 HAIER_AC_CMD_FAN LITERAL1 @@ -1289,6 +1333,7 @@ NEC_LIKE LITERAL1 NEOCLIMA LITERAL1 NIKAI LITERAL1 NIKAI_BITS LITERAL1 +NOTHING LITERAL1 ONCE LITERAL1 PANASONIC LITERAL1 PANASONIC_AC LITERAL1 @@ -1317,6 +1362,7 @@ SAMSUNG_AC LITERAL1 SAMSUNG_BITS LITERAL1 SANYO LITERAL1 SANYO_AC LITERAL1 +SANYO_AC152 LITERAL1 SANYO_AC88 LITERAL1 SANYO_LC7461 LITERAL1 SANYO_LC7461_BITS LITERAL1 @@ -1327,10 +1373,13 @@ SEND_AIWA_RC_T501 LITERAL1 SEND_AMCOR LITERAL1 SEND_ARGO LITERAL1 SEND_ARRIS LITERAL1 +SEND_BOSCH144 LITERAL1 SEND_BOSE LITERAL1 SEND_CARRIER_AC LITERAL1 +SEND_CARRIER_AC128 LITERAL1 SEND_CARRIER_AC40 LITERAL1 SEND_CARRIER_AC64 LITERAL1 +SEND_CLIMABUTLER LITERAL1 SEND_COOLIX LITERAL1 SEND_COOLIX48 LITERAL1 SEND_CORONA_AC LITERAL1 @@ -1340,7 +1389,9 @@ SEND_DAIKIN152 LITERAL1 SEND_DAIKIN160 LITERAL1 SEND_DAIKIN176 LITERAL1 SEND_DAIKIN2 LITERAL1 +SEND_DAIKIN200 LITERAL1 SEND_DAIKIN216 LITERAL1 +SEND_DAIKIN312 LITERAL1 SEND_DAIKIN64 LITERAL1 SEND_DELONGHI_AC LITERAL1 SEND_DENON LITERAL1 @@ -1356,6 +1407,7 @@ SEND_GLOBALCACHE LITERAL1 SEND_GOODWEATHER LITERAL1 SEND_GREE LITERAL1 SEND_HAIER_AC LITERAL1 +SEND_HAIER_AC160 LITERAL1 SEND_HAIER_AC176 LITERAL1 SEND_HAIER_AC_YRW02 LITERAL1 SEND_HITACHI_AC LITERAL1 @@ -1407,6 +1459,7 @@ SEND_SAMSUNG36 LITERAL1 SEND_SAMSUNG_AC LITERAL1 SEND_SANYO LITERAL1 SEND_SANYO_AC LITERAL1 +SEND_SANYO_AC152 LITERAL1 SEND_SANYO_AC88 LITERAL1 SEND_SHARP LITERAL1 SEND_SHARP_AC LITERAL1 @@ -1414,10 +1467,12 @@ SEND_SHERWOOD LITERAL1 SEND_SONY LITERAL1 SEND_SYMPHONY LITERAL1 SEND_TCL112AC LITERAL1 +SEND_TCL96AC LITERAL1 SEND_TECHNIBEL_AC LITERAL1 SEND_TECO LITERAL1 SEND_TEKNOPOINT LITERAL1 SEND_TOSHIBA_AC LITERAL1 +SEND_TOTO LITERAL1 SEND_TRANSCOLD LITERAL1 SEND_TROTEC LITERAL1 SEND_TROTEC_3550 LITERAL1 @@ -1441,6 +1496,7 @@ SONY_38K LITERAL1 SYMPHONY LITERAL1 TAC09CHSD LITERAL1 TCL112AC LITERAL1 +TCL96AC LITERAL1 TECHNIBEL_AC LITERAL1 TECO LITERAL1 TEKNOPOINT LITERAL1 @@ -1456,6 +1512,7 @@ TOSHIBA_AC_MAX_TEMP LITERAL1 TOSHIBA_AC_MIN_TEMP LITERAL1 TOSHIBA_AC_POWER LITERAL1 TOSHIBA_AC_STATE_LENGTH LITERAL1 +TOTO LITERAL1 TRANSCOLD LITERAL1 TROTEC LITERAL1 TROTEC_3550 LITERAL1 @@ -1484,6 +1541,7 @@ WHYNTER_BITS LITERAL1 XMP LITERAL1 YAW1F LITERAL1 YBOFB LITERAL1 +YX1FSF LITERAL1 ZEPEAL LITERAL1 k0Str LITERAL1 k10CHeatStr LITERAL1 @@ -1644,6 +1702,35 @@ kAutoStr LITERAL1 kAutomaticStr LITERAL1 kBeepStr LITERAL1 kBitsStr LITERAL1 +kBosch144Auto LITERAL1 +kBosch144Bits LITERAL1 +kBosch144BytesPerSection LITERAL1 +kBosch144Cool LITERAL1 +kBosch144DefaultState LITERAL1 +kBosch144Dry LITERAL1 +kBosch144Fan LITERAL1 +kBosch144Fan100 LITERAL1 +kBosch144Fan20 LITERAL1 +kBosch144Fan40 LITERAL1 +kBosch144Fan60 LITERAL1 +kBosch144Fan80 LITERAL1 +kBosch144FanAuto LITERAL1 +kBosch144FanAuto0 LITERAL1 +kBosch144Heat LITERAL1 +kBosch144NrOfSections LITERAL1 +kBosch144Off LITERAL1 +kBosch144StateLength LITERAL1 +kBosch144TempMap LITERAL1 +kBosch144TempMax LITERAL1 +kBosch144TempMin LITERAL1 +kBosch144TempRange LITERAL1 +kBoschBitMark LITERAL1 +kBoschFooterSpace LITERAL1 +kBoschFreq LITERAL1 +kBoschHdrMark LITERAL1 +kBoschHdrSpace LITERAL1 +kBoschOneSpace LITERAL1 +kBoschZeroSpace LITERAL1 kBoseBitMark LITERAL1 kBoseBits LITERAL1 kBoseFreq LITERAL1 @@ -1656,6 +1743,19 @@ kBottomStr LITERAL1 kBreezeStr LITERAL1 kButtonStr LITERAL1 kCancelStr LITERAL1 +kCarrierAc128BitMark LITERAL1 +kCarrierAc128Bits LITERAL1 +kCarrierAc128Hdr2Mark LITERAL1 +kCarrierAc128Hdr2Space LITERAL1 +kCarrierAc128HdrMark LITERAL1 +kCarrierAc128HdrSpace LITERAL1 +kCarrierAc128InterSpace LITERAL1 +kCarrierAc128MinRepeat LITERAL1 +kCarrierAc128OneSpace LITERAL1 +kCarrierAc128SectionBits LITERAL1 +kCarrierAc128SectionGap LITERAL1 +kCarrierAc128StateLength LITERAL1 +kCarrierAc128ZeroSpace LITERAL1 kCarrierAc40BitMark LITERAL1 kCarrierAc40Bits LITERAL1 kCarrierAc40Gap LITERAL1 @@ -1702,6 +1802,14 @@ kChangeStr LITERAL1 kCirculateStr LITERAL1 kCkpStr LITERAL1 kCleanStr LITERAL1 +kClimaButlerBitMark LITERAL1 +kClimaButlerBits LITERAL1 +kClimaButlerFreq LITERAL1 +kClimaButlerGap LITERAL1 +kClimaButlerHdrMark LITERAL1 +kClimaButlerHdrSpace LITERAL1 +kClimaButlerOneSpace LITERAL1 +kClimaButlerZeroSpace LITERAL1 kClockStr LITERAL1 kCodeStr LITERAL1 kColonSpaceStr LITERAL1 @@ -1880,6 +1988,19 @@ kDaikin176StateLength LITERAL1 kDaikin176SwingHAuto LITERAL1 kDaikin176SwingHOff LITERAL1 kDaikin176ZeroSpace LITERAL1 +kDaikin200BitMark LITERAL1 +kDaikin200Bits LITERAL1 +kDaikin200DefaultRepeat LITERAL1 +kDaikin200Freq LITERAL1 +kDaikin200Gap LITERAL1 +kDaikin200HdrMark LITERAL1 +kDaikin200HdrSpace LITERAL1 +kDaikin200OneSpace LITERAL1 +kDaikin200Section1Length LITERAL1 +kDaikin200Section2Length LITERAL1 +kDaikin200Sections LITERAL1 +kDaikin200StateLength LITERAL1 +kDaikin200ZeroSpace LITERAL1 kDaikin216BitMark LITERAL1 kDaikin216Bits LITERAL1 kDaikin216DefaultRepeat LITERAL1 @@ -1940,6 +2061,19 @@ kDaikin2SwingVSwing LITERAL1 kDaikin2SwingVUpperMiddle LITERAL1 kDaikin2Tolerance LITERAL1 kDaikin2ZeroSpace LITERAL1 +kDaikin312BitMark LITERAL1 +kDaikin312Bits LITERAL1 +kDaikin312DefaultRepeat LITERAL1 +kDaikin312HdrGap LITERAL1 +kDaikin312HdrMark LITERAL1 +kDaikin312HdrSpace LITERAL1 +kDaikin312OneSpace LITERAL1 +kDaikin312Section1Length LITERAL1 +kDaikin312Section2Length LITERAL1 +kDaikin312SectionGap LITERAL1 +kDaikin312Sections LITERAL1 +kDaikin312StateLength LITERAL1 +kDaikin312ZeroSpace LITERAL1 kDaikin64BitMark LITERAL1 kDaikin64Bits LITERAL1 kDaikin64ChecksumOffset LITERAL1 @@ -2202,6 +2336,8 @@ kFujitsuAcMaxTemp LITERAL1 kFujitsuAcMaxTempF LITERAL1 kFujitsuAcMinBits LITERAL1 kFujitsuAcMinGap LITERAL1 +kFujitsuAcMinHeat LITERAL1 +kFujitsuAcMinHeatF LITERAL1 kFujitsuAcMinRepeat LITERAL1 kFujitsuAcMinTemp LITERAL1 kFujitsuAcMinTempF LITERAL1 @@ -2290,6 +2426,7 @@ kGreeDisplayTempOff LITERAL1 kGreeDisplayTempOutside LITERAL1 kGreeDisplayTempSet LITERAL1 kGreeDry LITERAL1 +kGreeEcono LITERAL1 kGreeFan LITERAL1 kGreeFanAuto LITERAL1 kGreeFanMax LITERAL1 @@ -2325,12 +2462,27 @@ kGreeSwingUpAuto LITERAL1 kGreeTimerMax LITERAL1 kGreeZeroSpace LITERAL1 kGz055be1Str LITERAL1 +kHaierAC160Bits LITERAL1 +kHaierAC160StateLength LITERAL1 kHaierAC176Bits LITERAL1 kHaierAC176StateLength LITERAL1 kHaierACBits LITERAL1 kHaierACStateLength LITERAL1 kHaierACYRW02Bits LITERAL1 kHaierACYRW02StateLength LITERAL1 +kHaierAc160ButtonAuxHeating LITERAL1 +kHaierAc160ButtonClean LITERAL1 +kHaierAc160ButtonLight LITERAL1 +kHaierAc160DefaultRepeat LITERAL1 +kHaierAc160Prefix LITERAL1 +kHaierAc160SwingVAuto LITERAL1 +kHaierAc160SwingVHigh LITERAL1 +kHaierAc160SwingVHighest LITERAL1 +kHaierAc160SwingVLow LITERAL1 +kHaierAc160SwingVLowest LITERAL1 +kHaierAc160SwingVMiddle LITERAL1 +kHaierAc160SwingVOff LITERAL1 +kHaierAc160SwingVTop LITERAL1 kHaierAc176DefaultRepeat LITERAL1 kHaierAc176Prefix LITERAL1 kHaierAcAuto LITERAL1 @@ -3538,6 +3690,16 @@ kSamsungRptSpaceTicks LITERAL1 kSamsungTick LITERAL1 kSamsungZeroSpace LITERAL1 kSamsungZeroSpaceTicks LITERAL1 +kSanyoAc152BitMark LITERAL1 +kSanyoAc152Bits LITERAL1 +kSanyoAc152ExtraTolerance LITERAL1 +kSanyoAc152Freq LITERAL1 +kSanyoAc152HdrMark LITERAL1 +kSanyoAc152HdrSpace LITERAL1 +kSanyoAc152MinRepeat LITERAL1 +kSanyoAc152OneSpace LITERAL1 +kSanyoAc152StateLength LITERAL1 +kSanyoAc152ZeroSpace LITERAL1 kSanyoAc88Auto LITERAL1 kSanyoAc88BitMark LITERAL1 kSanyoAc88Bits LITERAL1 @@ -3770,6 +3932,15 @@ kTcl112AcTimerMax LITERAL1 kTcl112AcTimerResolution LITERAL1 kTcl112AcTolerance LITERAL1 kTcl112AcZeroSpace LITERAL1 +kTcl96AcBitMark LITERAL1 +kTcl96AcBitSpaces LITERAL1 +kTcl96AcBits LITERAL1 +kTcl96AcDefaultRepeat LITERAL1 +kTcl96AcGap LITERAL1 +kTcl96AcHdrMark LITERAL1 +kTcl96AcHdrSpace LITERAL1 +kTcl96AcSpaceCount LITERAL1 +kTcl96AcStateLength LITERAL1 kTechnibelAcBitMark LITERAL1 kTechnibelAcBits LITERAL1 kTechnibelAcCool LITERAL1 @@ -3871,6 +4042,19 @@ kToshibaAcSwingToggle LITERAL1 kToshibaAcTurboOn LITERAL1 kToshibaAcUsualGap LITERAL1 kToshibaAcZeroSpace LITERAL1 +kTotoBitMark LITERAL1 +kTotoBits LITERAL1 +kTotoDefaultRepeat LITERAL1 +kTotoGap LITERAL1 +kTotoHdrMark LITERAL1 +kTotoHdrSpace LITERAL1 +kTotoLongBits LITERAL1 +kTotoOneSpace LITERAL1 +kTotoPrefix LITERAL1 +kTotoPrefixBits LITERAL1 +kTotoShortBits LITERAL1 +kTotoSpecialGap LITERAL1 +kTotoZeroSpace LITERAL1 kTranscoldAuto LITERAL1 kTranscoldBitMark LITERAL1 kTranscoldBits LITERAL1 @@ -4090,6 +4274,7 @@ kXmpWordSize LITERAL1 kYaw1fStr LITERAL1 kYbofbStr LITERAL1 kYesStr LITERAL1 +kYx1fsfStr LITERAL1 kZepealBits LITERAL1 kZepealCommandOffOn LITERAL1 kZepealCommandOffTimer LITERAL1 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json index 948ae48fa..2e19b34bb 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json @@ -1,6 +1,6 @@ { "name": "IRremoteESP8266", - "version": "2.8.2", + "version": "2.8.3", "keywords": "infrared, ir, remote, esp8266, esp32", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "repository": diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties index d776853f2..8d68c8275 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties @@ -1,5 +1,5 @@ name=IRremoteESP8266 -version=2.8.2 +version=2.8.3 author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff maintainer=David Conran, Mark Szabo, Sebastien Warin, Roi Dayan, Massimiliano Pinto, Christian Nilsson sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp index de07bf964..af6beb30b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp @@ -20,6 +20,7 @@ #include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" +#include "ir_Bosch.h" #include "ir_Carrier.h" #include "ir_Coolix.h" #include "ir_Corona.h" @@ -161,6 +162,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_ARGO case decode_type_t::ARGO: #endif +#if SEND_BOSCH144 + case decode_type_t::BOSCH144: +#endif #if SEND_CARRIER_AC64 case decode_type_t::CARRIER_AC64: #endif // SEND_CARRIER_AC64 @@ -215,6 +219,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_HAIER_AC case decode_type_t::HAIER_AC: #endif +#if SEND_HAIER_AC160 + case decode_type_t::HAIER_AC160: +#endif // SEND_HAIER_AC160 #if SEND_HAIER_AC176 case decode_type_t::HAIER_AC176: #endif // SEND_HAIER_AC176 @@ -459,6 +466,47 @@ void IRac::argo(IRArgoAC *ac, } #endif // SEND_ARGO +#if SEND_BOSCH144 +/// Send a Bosch144 A/C message with the supplied settings. +/// @note May result in multiple messages being sent. +/// @param[in, out] ac A Ptr to an IRBosch144AC object to use. +/// @param[in] on The power setting. +/// @param[in] mode The operation mode setting. +/// @param[in] degrees The temperature setting in degrees. +/// @param[in] fan The speed setting for the fan. +/// @param[in] quiet Run the device in quiet/silent mode. +/// @note -1 is Off, >= 0 is on. +void IRac::bosch144(IRBosch144AC *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const bool quiet) { + ac->begin(); + ac->setPower(on); + if (!on) { + // after turn off AC no more commands should + // be accepted + ac->send(); + return; + } + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setMode(ac->convertMode(mode)); + ac->setQuiet(quiet); + ac->send(); // Send the state, which will also power on the unit. + // The following are all options/settings that create their own special + // messages. Often they only make sense to be sent after the unit is turned + // on. For instance, assuming a person wants to have the a/c on and in turbo + // mode. If we send the turbo message, it is ignored if the unit is off. + // Hence we send the special mode/setting messages after a normal message + // which will turn on the device. + // No Filter setting available. + // No Beep setting available. + // No Clock setting available. + // No Econo setting available. + // No Sleep setting available. +} +#endif // SEND_BOSCH144 + #if SEND_CARRIER_AC64 /// Send a Carrier 64-bit A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRCarrierAc64 object to use. @@ -1155,6 +1203,52 @@ void IRac::haier(IRHaierAC *ac, } #endif // SEND_HAIER_AC +#if SEND_HAIER_AC160 +/// Send a Haier 160 bit A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IRHaierAC160 object to use. +/// @param[in] on The power setting. +/// @param[in] mode The operation mode setting. +/// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit. +/// @param[in] degrees The temperature setting in degrees. +/// @param[in] fan The speed setting for the fan. +/// @param[in] swingv The vertical swing setting. +/// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] quiet Run the device in quiet mode. +/// @param[in] filter Turn on the (ion/pollen/etc) filter mode. +/// @param[in] clean Turn on the clean mode. +/// @param[in] light Turn on the LED/Display mode. +/// @param[in] prevlight Previous LED/Display mode. +/// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. +void IRac::haier160(IRHaierAC160 *ac, + const bool on, const stdAc::opmode_t mode, + const bool celsius, const float degrees, + const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const bool turbo, const bool quiet, const bool filter, + const bool clean, const bool light, const bool prevlight, + const int16_t sleep) { + ac->begin(); + // No Model setting available. + ac->setMode(ac->convertMode(mode)); + ac->setUseFahrenheit(!celsius); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setSwingV(ac->convertSwingV(swingv)); + // No Horizontal Swing setting available. + ac->setQuiet(quiet); + ac->setTurbo(turbo); + ac->setHealth(filter); + ac->setClean(clean); + // No Clean setting available. + // No Beep setting available. + ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off. + ac->setPower(on); + // Light needs to be sent last as the "button" value seems to control it. + ac->setLightToggle(light ^ prevlight); + ac->send(); +} +#endif // SEND_HAIER_AC160 + #if SEND_HAIER_AC176 /// Send a Haier 176 bit A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRHaierAC176 object to use. @@ -1642,6 +1736,7 @@ void IRac::mitsubishi(IRMitsubishiAC *ac, ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); ac->setVane(ac->convertSwingV(swingv)); + ac->setVaneLeft(ac->convertSwingV(swingv)); ac->setWideVane(ac->convertSwingH(swingh)); if (quiet) ac->setFan(kMitsubishiAcFanSilent); ac->setISave10C(false); @@ -2718,6 +2813,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { const stdAc::swingv_t prev_swingv = (prev != NULL) ? prev->swingv : stdAc::swingv_t::kOff; #endif // (SEND_LG || SEND_SHARP_AC) +#if (SEND_HAIER_AC160) + const bool prev_light = (prev != NULL) ? prev->light : !send.light; +#endif // (SEND_HAIER_AC160) #if SEND_MIDEA const bool prev_quiet = (prev != NULL) ? prev->quiet : !send.quiet; #endif // SEND_MIDEA @@ -2758,6 +2856,14 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { break; } #endif // SEND_ARGO +#if SEND_BOSCH144 + case BOSCH144: + { + IRBosch144AC ac(_pin, _inverted, _modulation); + bosch144(&ac, send.power, send.mode, degC, send.fanspeed, send.quiet); + break; + } +#endif // SEND_BOSCH144 #if SEND_CARRIER_AC64 case CARRIER_AC64: { @@ -2924,6 +3030,16 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { break; } #endif // SEND_HAIER_AC +#if SEND_HAIER_AC160 + case HAIER_AC160: + { + 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); + break; + } +#endif // SEND_HAIER_AC160 #if SEND_HAIER_AC176 case HAIER_AC176: { @@ -3472,6 +3588,8 @@ int16_t IRac::strToModel(const char *str, const int16_t def) { return gree_ac_remote_model_t::YAW1F; } else if (!STRCASECMP(str, kYbofbStr)) { return gree_ac_remote_model_t::YBOFB; + } else if (!STRCASECMP(str, kYx1fsfStr)) { + return gree_ac_remote_model_t::YX1FSF; // Haier models } else if (!STRCASECMP(str, kV9014557AStr)) { return haier_ac176_remote_model_t::V9014557_A; @@ -3683,6 +3801,13 @@ namespace IRAcUtils { 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); @@ -3813,6 +3938,13 @@ namespace IRAcUtils { 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); @@ -4132,6 +4264,14 @@ namespace IRAcUtils { break; } #endif // DECODE_ARGO +#if DECODE_BOSCH144 + 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); @@ -4168,7 +4308,7 @@ namespace IRAcUtils { case decode_type_t::DAIKIN128: { IRDaikin128 ac(kGpioUnused); ac.setRaw(decode->state); - *result = ac.toCommon(); + *result = ac.toCommon(prev); break; } #endif // DECODE_DAIKIN128 @@ -4252,7 +4392,7 @@ namespace IRAcUtils { case decode_type_t::FUJITSU_AC: { IRFujitsuAC ac(kGpioUnused); ac.setRaw(decode->state, decode->bits / 8); - *result = ac.toCommon(); + *result = ac.toCommon(prev); break; } #endif // DECODE_FUJITSU_AC @@ -4280,6 +4420,14 @@ namespace IRAcUtils { 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; + } +#endif // DECODE_HAIER_AC160 #if DECODE_HAIER_AC176 case decode_type_t::HAIER_AC176: { IRHaierAC176 ac(kGpioUnused); @@ -4348,7 +4496,7 @@ namespace IRAcUtils { case decode_type_t::KELON: { IRKelonAc ac(kGpioUnused); ac.setRaw(decode->value); - *result = ac.toCommon(); + *result = ac.toCommon(prev); break; } #endif // DECODE_KELON diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h index 8e3ef7582..9193a531d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h @@ -11,6 +11,7 @@ #include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" +#include "ir_Bosch.h" #include "ir_Carrier.h" #include "ir_Coolix.h" #include "ir_Corona.h" @@ -134,6 +135,12 @@ class IRac { const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const int16_t sleep = -1); #endif // SEND_ARGO +#if SEND_BOSCH144 + void bosch144(IRBosch144AC *ac, + const bool on, const stdAc::opmode_t mode, const float degrees, + const stdAc::fanspeed_t fan, + const bool quiet); +#endif // SEND_COOLIX #if SEND_CARRIER_AC64 void carrier64(IRCarrierAc64 *ac, const bool on, const stdAc::opmode_t mode, @@ -268,6 +275,15 @@ void electra(IRElectraAc *ac, const bool filter, const int16_t sleep = -1, const int16_t clock = -1); #endif // SEND_HAIER_AC +#if SEND_HAIER_AC160 + void haier160(IRHaierAC160 *ac, + const bool on, const stdAc::opmode_t mode, const bool celsius, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const bool turbo, const bool quiet, const bool filter, + const bool clean, const bool light, const bool prevlight, + const int16_t sleep = -1); +#endif // SEND_HAIER_AC160 #if SEND_HAIER_AC176 void haier176(IRHaierAC176 *ac, const haier_ac176_remote_model_t model, const bool on, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRmacros.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRmacros.h new file mode 100644 index 000000000..3e074cd11 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRmacros.h @@ -0,0 +1,32 @@ +#ifndef IRMACROS_H_ +#define IRMACROS_H_ +/**************************************************************** + * Copyright 2022 IRremoteESP8266 project and others + */ +/// @file IRmacros.h + +/** + * COND() Set of macros to facilitate single-line conditional compilation + * argument checking. + * Found here: https://www.reddit.com/r/C_Programming/comments/ud3xrv/ + * conditional_preprocessor_macro_anyone/ + * + * Usage: + * COND([||/&&...], , ) + */ +/// @cond TEST +#define NOTHING +#define EXPAND(...) __VA_ARGS__ +#define STUFF_P(a, ...) __VA_OPT__(a) +#define STUFF(...) STUFF_P(__VA_ARGS__) +#define VA_TEST_P(a, ...) __VA_OPT__(NO)##THING +#define VA_TEST(...) VA_TEST_P(__VA_ARGS__) +#define NEGATE(a) VA_TEST(a, a) +#define COND_P(cond, a, b) STUFF(a, cond)STUFF(b, NEGATE(cond)) +#define COND(cond, a, b) EXPAND(COND_P(cond, a, b)) +/// @endcond +/** + * end of COND() set of macros + */ + +#endif // IRMACROS_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp index fc4113d81..95f7c2af9 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp @@ -741,6 +741,11 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Sharp decode"); if (decodeSharp(results, offset)) return true; #endif +#if DECODE_BOSCH144 + DPRINTLN("Attempting Bosch 144-bit decode"); + // Bosch is similar to Coolix, so it must be attempted before decodeCOOLIX. + if (decodeBosch144(results, offset)) return true; +#endif // DECODE_BOSCH144 #if DECODE_COOLIX DPRINTLN("Attempting Coolix 24-bit decode"); if (decodeCOOLIX(results, offset)) return true; @@ -1114,6 +1119,39 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Coolix 48-bit decode"); if (decodeCoolix48(results, offset)) return true; #endif // DECODE_COOLIX48 +#if DECODE_DAIKIN200 + DPRINTLN("Attempting Daikin 200-bit decode"); + if (decodeDaikin200(results, offset)) return true; +#endif // DECODE_DAIKIN200 +#if DECODE_HAIER_AC160 + DPRINTLN("Attempting Haier AC 160 bit decode"); + if (decodeHaierAC160(results, offset)) return true; +#endif // DECODE_HAIER_AC160 +#if DECODE_CARRIER_AC128 + DPRINTLN("Attempting Carrier AC 128-bit decode"); + if (decodeCarrierAC128(results, offset)) return true; +#endif // DECODE_CARRIER_AC128 +#if DECODE_TOTO + DPRINTLN("Attempting Toto 48/24-bit decode"); + if (decodeToto(results, offset, kTotoLongBits) || // Long needs to be first + decodeToto(results, offset, kTotoShortBits)) return true; +#endif // DECODE_TOTO +#if DECODE_CLIMABUTLER + DPRINTLN("Attempting ClimaButler decode"); + if (decodeClimaButler(results)) return true; +#endif // DECODE_CLIMABUTLER +#if DECODE_TCL96AC + DPRINTLN("Attempting TCL AC 96-bit decode"); + if (decodeTcl96Ac(results, offset)) return true; +#endif // DECODE_TCL96AC +#if DECODE_SANYO_AC152 + DPRINTLN("Attempting Sanyo AC 152-bit decode"); + if (decodeSanyoAc152(results, offset)) return true; +#endif // DECODE_SANYO_AC152 +#if DECODE_DAIKIN312 + DPRINTLN("Attempting Daikin 312-bit decode"); + if (decodeDaikin312(results, offset)) return true; +#endif // DECODE_DAIKIN312 // Typically new protocols are added above this line. } #if DECODE_HASH @@ -1128,7 +1166,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, if (!resumed) // Check if we have already resumed. resume(); return false; -} +} // NOLINT(readability/fn_size) /// Convert the tolerance percentage into something valid. /// @param[in] percentage An integer percentage. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h index 9b833f704..ad09f6d35 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h @@ -326,6 +326,12 @@ class IRrecv { const uint16_t nbits = kSanyoAc88Bits, const bool strict = true); #endif // DECODE_SANYO_AC88 +#if DECODE_SANYO_AC152 + bool decodeSanyoAc152(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kSanyoAc152Bits, + const bool strict = true); +#endif // DECODE_SANYO_AC152 #if DECODE_MITSUBISHI bool decodeMitsubishi(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kMitsubishiBits, @@ -508,11 +514,21 @@ class IRrecv { const uint16_t nbits = kDaikin2Bits, const bool strict = true); #endif +#if DECODE_DAIKIN200 + bool decodeDaikin200(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kDaikin200Bits, + const bool strict = true); +#endif // DECODE_DAIKIN200 #if DECODE_DAIKIN216 bool decodeDaikin216(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kDaikin216Bits, const bool strict = true); -#endif +#endif // DECODE_DAIKIN216 +#if DECODE_DAIKIN312 + bool decodeDaikin312(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kDaikin312Bits, + const bool strict = true); +#endif // DECODE_DAIKIN312 #if DECODE_TOSHIBA_AC bool decodeToshibaAC(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kToshibaACBits, @@ -570,6 +586,12 @@ class IRrecv { const uint16_t nbits = kCarrierAc64Bits, const bool strict = true); #endif // DECODE_CARRIER_AC64 +#if DECODE_CARRIER_AC128 + bool decodeCarrierAC128(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kCarrierAc128Bits, + const bool strict = true); +#endif // DECODE_CARRIER_AC128 #if DECODE_GOODWEATHER bool decodeGoodweather(decode_results *results, uint16_t offset = kStartOffset, @@ -581,7 +603,8 @@ class IRrecv { const uint16_t nbits = kGreeBits, const bool strict = true); #endif -#if (DECODE_HAIER_AC | DECODE_HAIER_AC_YRW02) +#if (DECODE_HAIER_AC | DECODE_HAIER_AC_YRW02 || DECODE_HAIER_AC160 || \ + DECODE_HAIER_AC176) bool decodeHaierAC(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kHaierACBits, const bool strict = true); @@ -592,6 +615,12 @@ class IRrecv { const uint16_t nbits = kHaierACYRW02Bits, const bool strict = true); #endif +#if DECODE_HAIER_AC160 + bool decodeHaierAC160(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kHaierAC160Bits, + const bool strict = true); +#endif // DECODE_HAIER_AC160 #if DECODE_HAIER_AC176 bool decodeHaierAC176(decode_results *results, uint16_t offset = kStartOffset, @@ -805,6 +834,29 @@ class IRrecv { const uint16_t nbits = kAirtonBits, const bool strict = true); #endif // DECODE_AIRTON +#if DECODE_TOTO + bool decodeToto(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kTotoBits, + const bool strict = true); +#endif // DECODE_TOTO +#if DECODE_CLIMABUTLER + bool decodeClimaButler(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kClimaButlerBits, + const bool strict = true); +#endif // DECODE_CLIMABUTLER +#if DECODE_TCL96AC + bool decodeTcl96Ac(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kTcl96AcBits, + const bool strict = true); +#endif // DECODE_TCL96AC +#if DECODE_BOSCH144 + bool decodeBosch144(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kBosch144Bits, + const bool strict = true); +#endif // DECODE_BOSCH144 }; #endif // IRRECV_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h index 574b01d3d..5349b72a7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h @@ -58,10 +58,10 @@ // Minor version number (x.X.x) #define _IRREMOTEESP8266_VERSION_MINOR 8 // Patch version number (x.x.X) -#define _IRREMOTEESP8266_VERSION_PATCH 2 +#define _IRREMOTEESP8266_VERSION_PATCH 3 // Macro to convert version info into an integer #define _IRREMOTEESP8266_VERSION_VAL(major, minor, patch) \ - ((major << 16) | (minor << 8) | (patch)) + (((major) << 16) | ((minor) << 8) | (patch)) // Macro to convert literal into a string #define MKSTR_HELPER(x) #x #define MKSTR(x) MKSTR_HELPER(x) @@ -238,6 +238,13 @@ #define SEND_SANYO_AC88 _IR_ENABLE_DEFAULT_ #endif // SEND_SANYO_AC88 +#ifndef DECODE_SANYO_AC152 +#define DECODE_SANYO_AC152 _IR_ENABLE_DEFAULT_ +#endif // DECODE_SANYO_AC152 +#ifndef SEND_SANYO_AC152 +#define SEND_SANYO_AC152 _IR_ENABLE_DEFAULT_ +#endif // SEND_SANYO_AC152 + #ifndef DECODE_MITSUBISHI #define DECODE_MITSUBISHI _IR_ENABLE_DEFAULT_ #endif // DECODE_MITSUBISHI @@ -455,6 +462,13 @@ #define SEND_CARRIER_AC64 _IR_ENABLE_DEFAULT_ #endif // SEND_CARRIER_AC64 +#ifndef DECODE_CARRIER_AC128 +#define DECODE_CARRIER_AC128 _IR_ENABLE_DEFAULT_ +#endif // DECODE_CARRIER_AC128 +#ifndef SEND_CARRIER_AC128 +#define SEND_CARRIER_AC128 _IR_ENABLE_DEFAULT_ +#endif // SEND_CARRIER_AC128 + #ifndef DECODE_HAIER_AC #define DECODE_HAIER_AC _IR_ENABLE_DEFAULT_ #endif // DECODE_HAIER_AC @@ -602,6 +616,13 @@ #define SEND_TECO _IR_ENABLE_DEFAULT_ #endif // SEND_TECO +#ifndef DECODE_TCL96AC +#define DECODE_TCL96AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_TCL96AC +#ifndef SEND_TCL96AC +#define SEND_TCL96AC _IR_ENABLE_DEFAULT_ +#endif // SEND_TCL96AC + #ifndef DECODE_TCL112AC #define DECODE_TCL112AC _IR_ENABLE_DEFAULT_ #endif // DECODE_TCL112AC @@ -861,6 +882,48 @@ #define SEND_KELON168 _IR_ENABLE_DEFAULT_ #endif // SEND_KELON168 +#ifndef DECODE_DAIKIN200 +#define DECODE_DAIKIN200 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN200 +#ifndef SEND_DAIKIN200 +#define SEND_DAIKIN200 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN200 + +#ifndef DECODE_HAIER_AC160 +#define DECODE_HAIER_AC160 _IR_ENABLE_DEFAULT_ +#endif // DECODE_HAIER_AC160 +#ifndef SEND_HAIER_AC160 +#define SEND_HAIER_AC160 _IR_ENABLE_DEFAULT_ +#endif // SEND_HAIER_AC160 + +#ifndef DECODE_TOTO +#define DECODE_TOTO _IR_ENABLE_DEFAULT_ +#endif // DECODE_TOTO +#ifndef SEND_TOTO +#define SEND_TOTO _IR_ENABLE_DEFAULT_ +#endif // SEND_TOTO + +#ifndef DECODE_CLIMABUTLER +#define DECODE_CLIMABUTLER _IR_ENABLE_DEFAULT_ +#endif // DECODE_CLIMABUTLER +#ifndef SEND_CLIMABUTLER +#define SEND_CLIMABUTLER _IR_ENABLE_DEFAULT_ +#endif // SEND_CLIMABUTLER + +#ifndef DECODE_BOSCH144 +#define DECODE_BOSCH144 _IR_ENABLE_DEFAULT_ +#endif // DECODE_BOSCH144 +#ifndef SEND_BOSCH144 +#define SEND_BOSCH144 _IR_ENABLE_DEFAULT_ +#endif // SEND_BOSCH144 + +#ifndef DECODE_DAIKIN312 +#define DECODE_DAIKIN312 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN312 +#ifndef SEND_DAIKIN312 +#define SEND_DAIKIN312 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN312 + #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 || \ @@ -876,7 +939,9 @@ DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176 || \ DECODE_TEKNOPOINT || DECODE_KELON || DECODE_TROTEC_3550 || \ DECODE_SANYO_AC88 || DECODE_RHOSS || DECODE_HITACHI_AC264 || \ - DECODE_KELON168 || DECODE_HITACHI_AC296 || \ + DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \ + DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \ + DECODE_BOSCH144 || DECODE_SANYO_AC152 || DECODE_DAIKIN312 || \ 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 @@ -1030,8 +1095,17 @@ enum decode_type_t { HITACHI_AC264, KELON168, HITACHI_AC296, + DAIKIN200, + HAIER_AC160, // 115 + CARRIER_AC128, + TOTO, + CLIMABUTLER, + TCL96AC, + BOSCH144, // 120 + SANYO_AC152, + DAIKIN312, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = HITACHI_AC296, + kLastDecodeType = DAIKIN312, }; // Message lengths & required repeat values @@ -1052,6 +1126,8 @@ const uint16_t kArgoStateLength = 12; const uint16_t kArgoBits = kArgoStateLength * 8; const uint16_t kArgoDefaultRepeat = kNoRepeat; const uint16_t kArrisBits = 32; +const uint16_t kBosch144StateLength = 18; +const uint16_t kBosch144Bits = kBosch144StateLength * 8; const uint16_t kCoolixBits = 24; const uint16_t kCoolix48Bits = kCoolixBits * 2; const uint16_t kCoolixDefaultRepeat = kSingleRepeat; @@ -1061,6 +1137,9 @@ const uint16_t kCarrierAc40Bits = 40; const uint16_t kCarrierAc40MinRepeat = 2; const uint16_t kCarrierAc64Bits = 64; const uint16_t kCarrierAc64MinRepeat = kNoRepeat; +const uint16_t kCarrierAc128StateLength = 16; +const uint16_t kCarrierAc128Bits = kCarrierAc128StateLength * 8; +const uint16_t kCarrierAc128MinRepeat = kNoRepeat; const uint16_t kCoronaAcStateLengthShort = 7; const uint16_t kCoronaAcStateLength = kCoronaAcStateLengthShort * 3; const uint16_t kCoronaAcBitsShort = kCoronaAcStateLengthShort * 8; @@ -1087,9 +1166,15 @@ const uint16_t kDaikin152DefaultRepeat = kNoRepeat; const uint16_t kDaikin176StateLength = 22; const uint16_t kDaikin176Bits = kDaikin176StateLength * 8; const uint16_t kDaikin176DefaultRepeat = kNoRepeat; +const uint16_t kDaikin200StateLength = 25; +const uint16_t kDaikin200Bits = kDaikin200StateLength * 8; +const uint16_t kDaikin200DefaultRepeat = kNoRepeat; const uint16_t kDaikin216StateLength = 27; const uint16_t kDaikin216Bits = kDaikin216StateLength * 8; const uint16_t kDaikin216DefaultRepeat = kNoRepeat; +const uint16_t kDaikin312StateLength = 39; +const uint16_t kDaikin312Bits = kDaikin312StateLength * 8; +const uint16_t kDaikin312DefaultRepeat = kNoRepeat; const uint16_t kDelonghiAcBits = 64; const uint16_t kDelonghiAcDefaultRepeat = kNoRepeat; const uint16_t kTechnibelAcBits = 56; @@ -1127,6 +1212,9 @@ const uint16_t kHaierAcDefaultRepeat = kNoRepeat; const uint16_t kHaierACYRW02StateLength = 14; const uint16_t kHaierACYRW02Bits = kHaierACYRW02StateLength * 8; const uint16_t kHaierAcYrw02DefaultRepeat = kNoRepeat; +const uint16_t kHaierAC160StateLength = 20; +const uint16_t kHaierAC160Bits = kHaierAC160StateLength * 8; +const uint16_t kHaierAc160DefaultRepeat = kNoRepeat; const uint16_t kHaierAC176StateLength = 22; const uint16_t kHaierAC176Bits = kHaierAC176StateLength * 8; const uint16_t kHaierAc176DefaultRepeat = kNoRepeat; @@ -1230,6 +1318,9 @@ const uint16_t kSanyoAcBits = kSanyoAcStateLength * 8; const uint16_t kSanyoAc88StateLength = 11; const uint16_t kSanyoAc88Bits = kSanyoAc88StateLength * 8; const uint16_t kSanyoAc88MinRepeat = 2; +const uint16_t kSanyoAc152StateLength = 19; +const uint16_t kSanyoAc152Bits = kSanyoAc152StateLength * 8; +const uint16_t kSanyoAc152MinRepeat = kNoRepeat; const uint16_t kSanyoSA8650BBits = 12; const uint16_t kSanyoLC7461AddressBits = 13; const uint16_t kSanyoLC7461CommandBits = 8; @@ -1250,6 +1341,9 @@ const uint16_t kSonyMinBits = 12; const uint16_t kSonyMinRepeat = 2; const uint16_t kSymphonyBits = 12; const uint16_t kSymphonyDefaultRepeat = 3; +const uint16_t kTcl96AcStateLength = 12; +const uint16_t kTcl96AcBits = kTcl96AcStateLength * 8; +const uint16_t kTcl96AcDefaultRepeat = kNoRepeat; const uint16_t kTcl112AcStateLength = 14; const uint16_t kTcl112AcBits = kTcl112AcStateLength * 8; const uint16_t kTcl112AcDefaultRepeat = kNoRepeat; @@ -1264,6 +1358,10 @@ const uint16_t kToshibaACStateLengthShort = kToshibaACStateLength - 2; const uint16_t kToshibaACBitsShort = kToshibaACStateLengthShort * 8; const uint16_t kToshibaACStateLengthLong = kToshibaACStateLength + 1; const uint16_t kToshibaACBitsLong = kToshibaACStateLengthLong * 8; +const uint16_t kTotoBits = 24; +const uint16_t kTotoShortBits = kTotoBits; +const uint16_t kTotoLongBits = kTotoShortBits * 2; +const uint16_t kTotoDefaultRepeat = kSingleRepeat; const uint16_t kTranscoldBits = 24; const uint16_t kTranscoldDefaultRepeat = kNoRepeat; const uint16_t kTrotecStateLength = 9; @@ -1287,6 +1385,7 @@ const uint16_t kBoseBits = 16; const uint16_t kRhossStateLength = 12; const uint16_t kRhossBits = kRhossStateLength * 8; const uint16_t kRhossDefaultRepeat = 0; +const uint16_t kClimaButlerBits = 52; // Legacy defines. (Deprecated) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp index d80b4bbf6..1fb1339c5 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp @@ -571,6 +571,7 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) { case MULTIBRACKETS: case SHERWOOD: case TOSHIBA_AC: + case TOTO: return kSingleRepeat; // Special case AIRWELL: @@ -633,6 +634,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { case MIDEA24: case NIKAI: case RCMM: + case TOTO: case TRANSCOLD: return 24; case LG: @@ -668,6 +670,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { case MIDEA: case PANASONIC: return 48; + case CLIMABUTLER: + return kClimaButlerBits; // 52 case AIRTON: case ECOCLIM: case MAGIQUEST: @@ -682,8 +686,12 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return 64; case ARGO: return kArgoBits; + case BOSCH144: + return kBosch144Bits; case CORONA_AC: return kCoronaAcBits; + case CARRIER_AC128: + return kCarrierAc128Bits; case DAIKIN: return kDaikinBits; case DAIKIN128: @@ -696,8 +704,12 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kDaikin176Bits; case DAIKIN2: return kDaikin2Bits; + case DAIKIN200: + return kDaikin200Bits; case DAIKIN216: return kDaikin216Bits; + case DAIKIN312: + return kDaikin312Bits; case DAIKIN64: return kDaikin64Bits; case ELECTRA_AC: @@ -708,6 +720,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kHaierACBits; case HAIER_AC_YRW02: return kHaierACYRW02Bits; + case HAIER_AC160: + return kHaierAC160Bits; case HAIER_AC176: return kHaierAC176Bits; case HITACHI_AC: @@ -756,8 +770,12 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kSanyoAcBits; case SANYO_AC88: return kSanyoAc88Bits; + case SANYO_AC152: + return kSanyoAc152Bits; case SHARP_AC: return kSharpAcBits; + case TCL96AC: + return kTcl96AcBits; case TCL112AC: return kTcl112AcBits; case TEKNOPOINT: @@ -833,6 +851,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data, sendCarrierAC64(data, nbits, min_repeat); break; #endif // SEND_CARRIER_AC64 +#if SEND_CLIMABUTLER + case CLIMABUTLER: + sendClimaButler(data, nbits, min_repeat); + break; +#endif // SEND_CLIMABUTLER #if SEND_COOLIX case COOLIX: sendCOOLIX(data, nbits, min_repeat); @@ -1066,6 +1089,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data, sendTeco(data, nbits, min_repeat); break; #endif // SEND_TECO +#if SEND_TOTO + case TOTO: + sendToto(data, nbits, min_repeat); + break; +#endif // SEND_TOTO #if SEND_TRANSCOLD case TRANSCOLD: sendTranscold(data, nbits, min_repeat); @@ -1126,6 +1154,16 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendArgo(state, nbytes); break; #endif // SEND_ARGO +#if SEND_BOSCH144 + case BOSCH144: + sendBosch144(state, nbytes); + break; +#endif // SEND_BOSCH144 +#if SEND_CARRIER_AC128 + case CARRIER_AC128: + sendCarrierAC128(state, nbytes); + break; +#endif // SEND_CARRIER_AC128 #if SEND_CORONA_AC case CORONA_AC: sendCoronaAc(state, nbytes); @@ -1161,11 +1199,21 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendDaikin2(state, nbytes); break; #endif // SEND_DAIKIN2 +#if SEND_DAIKIN200 + case DAIKIN200: + sendDaikin200(state, nbytes); + break; +#endif // SEND_DAIKIN200 #if SEND_DAIKIN216 case DAIKIN216: sendDaikin216(state, nbytes); break; #endif // SEND_DAIKIN216 +#if SEND_DAIKIN312 + case DAIKIN312: + sendDaikin312(state, nbytes); + break; +#endif // SEND_DAIKIN312 #if SEND_ELECTRA_AC case ELECTRA_AC: sendElectraAC(state, nbytes); @@ -1191,6 +1239,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendHaierACYRW02(state, nbytes); break; #endif // SEND_HAIER_AC_YRW02 +#if SEND_HAIER_AC160 + case HAIER_AC160: + sendHaierAC160(state, nbytes); + break; +#endif // SEND_HAIER_AC160 #if SEND_HAIER_AC176 case HAIER_AC176: sendHaierAC176(state, nbytes); @@ -1309,11 +1362,21 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendSanyoAc88(state, nbytes); break; #endif // SEND_SANYO_AC88 +#if SEND_SANYO_AC152 + case SANYO_AC152: + sendSanyoAc152(state, nbytes); + break; +#endif // SEND_SANYO_AC152 #if SEND_SHARP_AC case SHARP_AC: sendSharpAc(state, nbytes); break; #endif // SEND_SHARP_AC +#if SEND_TCL96AC + case TCL96AC: + sendTcl96Ac(state, nbytes); + break; +#endif // SEND_TCL96AC #if SEND_TCL112AC case TCL112AC: sendTcl112Ac(state, nbytes); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h index 06d168375..02f2c939e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h @@ -118,7 +118,8 @@ struct state_t { /// Fujitsu A/C model numbers enum fujitsu_ac_remote_model_t { - ARRAH2E = 1, ///< (1) AR-RAH2E, AR-RAC1E, AR-RAE1E, AR-RCE1E (Default) + ARRAH2E = 1, ///< (1) AR-RAH2E, AR-RAC1E, AR-RAE1E, AR-RCE1E, AR-RAH2U, + ///< AR-REG1U (Default) ///< Warning: Use on incorrect models can cause the A/C to lock ///< up, requring the A/C to be physically powered off to fix. ///< e.g. AR-RAH1U may lock up with a Swing command. @@ -133,7 +134,9 @@ enum fujitsu_ac_remote_model_t { /// Gree A/C model numbers enum gree_ac_remote_model_t { YAW1F = 1, // (1) Ultimate, EKOKAI, RusClimate (Default) - YBOFB, // (2) Green, YBOFB2, YAPOF3 + YBOFB, // (2) Green, YBOFB2, YAPOF3 + YX1FSF, // (3) Soleus Air window unit (Similar to YAW1F, but with an + // Operation mode of Energy Saver (Econo)) }; /// HAIER_AC176 A/C model numbers @@ -343,6 +346,11 @@ class IRsend { const uint16_t nbytes = kSanyoAc88StateLength, const uint16_t repeat = kSanyoAc88MinRepeat); #endif // SEND_SANYO_AC88 +#if SEND_SANYO_AC152 + void sendSanyoAc152(const uint8_t *data, + const uint16_t nbytes = kSanyoAc152StateLength, + const uint16_t repeat = kSanyoAc152MinRepeat); +#endif // SEND_SANYO_AC152 #if SEND_DISH // sendDISH() should typically be called with repeat=3 as DISH devices // expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes) @@ -481,11 +489,21 @@ class IRsend { const uint16_t nbytes = kDaikin2StateLength, const uint16_t repeat = kDaikin2DefaultRepeat); #endif +#if SEND_DAIKIN200 + void sendDaikin200(const unsigned char data[], + const uint16_t nbytes = kDaikin200StateLength, + const uint16_t repeat = kDaikin200DefaultRepeat); +#endif // SEND_DAIKIN200 #if SEND_DAIKIN216 void sendDaikin216(const unsigned char data[], const uint16_t nbytes = kDaikin216StateLength, const uint16_t repeat = kDaikin216DefaultRepeat); -#endif +#endif // SEND_DAIKIN216 +#if SEND_DAIKIN312 + void sendDaikin312(const unsigned char data[], + const uint16_t nbytes = kDaikin312StateLength, + const uint16_t repeat = kDaikin312DefaultRepeat); +#endif // SEND_DAIKIN312 #if SEND_AIWA_RC_T501 void sendAiwaRCT501(uint64_t data, uint16_t nbits = kAiwaRcT501Bits, uint16_t repeat = kAiwaRcT501MinRepeats); @@ -557,6 +575,11 @@ class IRsend { void sendCarrierAC64(uint64_t data, uint16_t nbits = kCarrierAc64Bits, uint16_t repeat = kCarrierAc64MinRepeat); #endif +#if SEND_CARRIER_AC128 + void sendCarrierAC128(const uint8_t data[], + uint16_t nbytes = kCarrierAc128StateLength, + uint16_t repeat = kCarrierAc128MinRepeat); +#endif // SEND_CARRIER_AC128 #if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02 || SEND_HAIER_AC176) void sendHaierAC(const unsigned char data[], const uint16_t nbytes = kHaierACStateLength, @@ -567,6 +590,11 @@ class IRsend { const uint16_t nbytes = kHaierACYRW02StateLength, const uint16_t repeat = kHaierAcYrw02DefaultRepeat); #endif // SEND_HAIER_AC_YRW02 +#if SEND_HAIER_AC160 + void sendHaierAC160(const unsigned char data[], + const uint16_t nbytes = kHaierAC160StateLength, + const uint16_t repeat = kHaierAc160DefaultRepeat); +#endif // SEND_HAIER_AC160 #if SEND_HAIER_AC176 void sendHaierAC176(const unsigned char data[], const uint16_t nbytes = kHaierAC176StateLength, @@ -654,11 +682,16 @@ class IRsend { void sendVestelAc(const uint64_t data, const uint16_t nbits = kVestelAcBits, const uint16_t repeat = kNoRepeat); #endif +#if SEND_TCL96AC + void sendTcl96Ac(const unsigned char data[], + const uint16_t nbytes = kTcl96AcStateLength, + const uint16_t repeat = kTcl96AcDefaultRepeat); +#endif // SEND_TCL96AC #if SEND_TCL112AC void sendTcl112Ac(const unsigned char data[], const uint16_t nbytes = kTcl112AcStateLength, const uint16_t repeat = kTcl112AcDefaultRepeat); -#endif +#endif // SEND_TCL112AC #if SEND_TECO void sendTeco(const uint64_t data, const uint16_t nbits = kTecoBits, const uint16_t repeat = kNoRepeat); @@ -790,6 +823,20 @@ class IRsend { void sendAirton(const uint64_t data, const uint16_t nbits = kAirtonBits, const uint16_t repeat = kAirtonDefaultRepeat); #endif // SEND_AIRTON +#if SEND_TOTO + void sendToto(const uint64_t data, const uint16_t nbits = kTotoBits, + const uint16_t repeat = kTotoDefaultRepeat); +#endif // SEND_TOTO +#if SEND_CLIMABUTLER + void sendClimaButler(const uint64_t data, + const uint16_t nbits = kClimaButlerBits, + const uint16_t repeat = kNoRepeat); +#endif // SEND_CLIMABUTLER +#if SEND_BOSCH144 + void sendBosch144(const unsigned char data[], + const uint16_t nbytes = kBosch144StateLength, + const uint16_t repeat = kNoRepeat); +#endif // SEND_BOSCH144 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 9c649f916..5bd25ed95 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp @@ -11,6 +11,8 @@ #include "IRremoteESP8266.h" #include "i18n.h" +#include "IRmacros.h" + #ifndef PROGMEM #define PROGMEM // Pretend we have the PROGMEM macro even if we really don't. #endif @@ -236,6 +238,7 @@ IRTEXT_CONST_STRING(kBitsStr, D_STR_BITS); ///< "Bits" // Model Names IRTEXT_CONST_STRING(kYaw1fStr, D_STR_YAW1F); ///< "YAW1F" IRTEXT_CONST_STRING(kYbofbStr, D_STR_YBOFB); ///< "YBOFB" +IRTEXT_CONST_STRING(kYx1fsfStr, D_STR_YX1FSF); ///< "YX1FSF" IRTEXT_CONST_STRING(kV9014557AStr, D_STR_V9014557_A); ///< "V9014557-A" IRTEXT_CONST_STRING(kV9014557BStr, D_STR_V9014557_B); ///< "V9014557-B" IRTEXT_CONST_STRING(kRlt0541htaaStr, D_STR_RLT0541HTA_A); ///< "R-LT0541-HTA-A" @@ -279,125 +282,258 @@ IRTEXT_CONST_STRING(kDg11j13aStr, D_STR_DG11J13A); ///< "DG11J13A" IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104" IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191" +#define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as + // a question mark, check for length > 1 + // to show only currently included protocols // Protocol Names // Needs to be in decode_type_t order. IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) { D_STR_UNUSED "\x0" - D_STR_RC5 "\x0" - D_STR_RC6 "\x0" - D_STR_NEC "\x0" - D_STR_SONY "\x0" - D_STR_PANASONIC "\x0" - D_STR_JVC "\x0" - D_STR_SAMSUNG "\x0" - D_STR_WHYNTER "\x0" - D_STR_AIWA_RC_T501 "\x0" - D_STR_LG "\x0" - D_STR_SANYO "\x0" - D_STR_MITSUBISHI "\x0" - D_STR_DISH "\x0" - D_STR_SHARP "\x0" - D_STR_COOLIX "\x0" - D_STR_DAIKIN "\x0" - D_STR_DENON "\x0" - D_STR_KELVINATOR "\x0" - D_STR_SHERWOOD "\x0" - D_STR_MITSUBISHI_AC "\x0" - D_STR_RCMM "\x0" - D_STR_SANYO_LC7461 "\x0" - D_STR_RC5X "\x0" - D_STR_GREE "\x0" - D_STR_PRONTO "\x0" - D_STR_NEC_LIKE "\x0" - D_STR_ARGO "\x0" - D_STR_TROTEC "\x0" - D_STR_NIKAI "\x0" - D_STR_RAW "\x0" - D_STR_GLOBALCACHE "\x0" - D_STR_TOSHIBA_AC "\x0" - D_STR_FUJITSU_AC "\x0" - D_STR_MIDEA "\x0" - D_STR_MAGIQUEST "\x0" - D_STR_LASERTAG "\x0" - D_STR_CARRIER_AC "\x0" - D_STR_HAIER_AC "\x0" - D_STR_MITSUBISHI2 "\x0" - D_STR_HITACHI_AC "\x0" - D_STR_HITACHI_AC1 "\x0" - D_STR_HITACHI_AC2 "\x0" - D_STR_GICABLE "\x0" - D_STR_HAIER_AC_YRW02 "\x0" - D_STR_WHIRLPOOL_AC "\x0" - D_STR_SAMSUNG_AC "\x0" - D_STR_LUTRON "\x0" - D_STR_ELECTRA_AC "\x0" - D_STR_PANASONIC_AC "\x0" - D_STR_PIONEER "\x0" - D_STR_LG2 "\x0" - D_STR_MWM "\x0" - D_STR_DAIKIN2 "\x0" - D_STR_VESTEL_AC "\x0" - D_STR_TECO "\x0" - D_STR_SAMSUNG36 "\x0" - D_STR_TCL112AC "\x0" - D_STR_LEGOPF "\x0" - D_STR_MITSUBISHI_HEAVY_88 "\x0" - D_STR_MITSUBISHI_HEAVY_152 "\x0" - D_STR_DAIKIN216 "\x0" - D_STR_SHARP_AC "\x0" - D_STR_GOODWEATHER "\x0" - D_STR_INAX "\x0" - D_STR_DAIKIN160 "\x0" - D_STR_NEOCLIMA "\x0" - D_STR_DAIKIN176 "\x0" - D_STR_DAIKIN128 "\x0" - D_STR_AMCOR "\x0" - D_STR_DAIKIN152 "\x0" - D_STR_MITSUBISHI136 "\x0" - D_STR_MITSUBISHI112 "\x0" - D_STR_HITACHI_AC424 "\x0" - D_STR_SONY_38K "\x0" - D_STR_EPSON "\x0" - D_STR_SYMPHONY "\x0" - D_STR_HITACHI_AC3 "\x0" - D_STR_DAIKIN64 "\x0" - D_STR_AIRWELL "\x0" - D_STR_DELONGHI_AC "\x0" - D_STR_DOSHISHA "\x0" - D_STR_MULTIBRACKETS "\x0" - D_STR_CARRIER_AC40 "\x0" - D_STR_CARRIER_AC64 "\x0" - D_STR_HITACHI_AC344 "\x0" - D_STR_CORONA_AC "\x0" - D_STR_MIDEA24 "\x0" - D_STR_ZEPEAL "\x0" - D_STR_SANYO_AC "\x0" - D_STR_VOLTAS "\x0" - D_STR_METZ "\x0" - D_STR_TRANSCOLD "\x0" - D_STR_TECHNIBEL_AC "\x0" - D_STR_MIRAGE "\x0" - D_STR_ELITESCREENS "\x0" - D_STR_PANASONIC_AC32 "\x0" - D_STR_MILESTAG2 "\x0" - D_STR_ECOCLIM "\x0" - D_STR_XMP "\x0" - D_STR_TRUMA "\x0" - D_STR_HAIER_AC176 "\x0" - D_STR_TEKNOPOINT "\x0" - D_STR_KELON "\x0" - D_STR_TROTEC_3550 "\x0" - D_STR_SANYO_AC88 "\x0" - D_STR_BOSE "\x0" - D_STR_ARRIS "\x0" - D_STR_RHOSS "\x0" - D_STR_AIRTON "\x0" - D_STR_COOLIX48 "\x0" - D_STR_HITACHI_AC264 "\x0" - D_STR_KELON168 "\x0" - D_STR_HITACHI_AC296 "\x0" - ///< New protocol strings should be added just above this line. + COND(DECODE_RC5 || SEND_RC5, + D_STR_RC5, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_RC6 || SEND_RC6, + D_STR_RC6, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_NEC || SEND_NEC, + D_STR_NEC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SONY || SEND_SONY, + D_STR_SONY, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_PANASONIC || SEND_PANASONIC, + D_STR_PANASONIC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_JVC || SEND_JVC, + D_STR_JVC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SAMSUNG || SEND_SAMSUNG, + D_STR_SAMSUNG, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_WHYNTER || SEND_WHYNTER, + D_STR_WHYNTER, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_AIWA_RC_T501 || SEND_AIWA_RC_T501, + D_STR_AIWA_RC_T501, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_LG || SEND_LG, + D_STR_LG, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SANYO || SEND_SANYO, + D_STR_SANYO, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MITSUBISHI || SEND_MITSUBISHI, + D_STR_MITSUBISHI, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DISH || SEND_DISH, + D_STR_DISH, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SHARP || SEND_SHARP, + D_STR_SHARP, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_COOLIX || SEND_COOLIX, + D_STR_COOLIX, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN || SEND_DAIKIN, + D_STR_DAIKIN, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DENON || SEND_DENON, + D_STR_DENON, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_KELVINATOR || SEND_KELVINATOR, + D_STR_KELVINATOR, D_STR_UNSUPPORTED) "\x0" + COND(SEND_SHERWOOD, + D_STR_SHERWOOD, D_STR_UNSUPPORTED) "\x0" // SEND-ONLY + COND(DECODE_MITSUBISHI_AC || SEND_MITSUBISHI_AC, + D_STR_MITSUBISHI_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_RCMM || SEND_RCMM, + D_STR_RCMM, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SANYO || SEND_SANYO, + D_STR_SANYO_LC7461, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_RC5 || SEND_RC5, + D_STR_RC5X, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_GREE || SEND_GREE, + D_STR_GREE, D_STR_UNSUPPORTED) "\x0" + COND(SEND_PRONTO, + D_STR_PRONTO, D_STR_UNSUPPORTED) "\x0" // SEND-ONLY + COND(DECODE_NEC || SEND_NEC, + D_STR_NEC_LIKE, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_ARGO || SEND_ARGO, + D_STR_ARGO, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TROTEC || SEND_TROTEC, + D_STR_TROTEC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_NIKAI || SEND_NIKAI, + D_STR_NIKAI, D_STR_UNSUPPORTED) "\x0" + COND(SEND_RAW, + D_STR_RAW, D_STR_UNSUPPORTED) "\x0" // SEND-ONLY + COND(SEND_GLOBALCACHE, + D_STR_GLOBALCACHE, D_STR_UNSUPPORTED) "\x0" // SEND + COND(DECODE_TOSHIBA_AC || SEND_TOSHIBA_AC, + D_STR_TOSHIBA_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_FUJITSU_AC || SEND_FUJITSU_AC, + D_STR_FUJITSU_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MIDEA || SEND_MIDEA, + D_STR_MIDEA, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MAGIQUEST || SEND_MAGIQUEST, + D_STR_MAGIQUEST, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_LASERTAG || SEND_LASERTAG, + D_STR_LASERTAG, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_CARRIER_AC || SEND_CARRIER_AC, + D_STR_CARRIER_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HAIER_AC || SEND_HAIER_AC, + D_STR_HAIER_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MITSUBISHI2 || SEND_MITSUBISHI2, + D_STR_MITSUBISHI2, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC || SEND_HITACHI_AC, + D_STR_HITACHI_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC1 || SEND_HITACHI_AC1, + D_STR_HITACHI_AC1, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC2 || SEND_HITACHI_AC2, + D_STR_HITACHI_AC2, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_GICABLE || SEND_GICABLE, + D_STR_GICABLE, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HAIER_AC_YRW02 || SEND_HAIER_AC_YRW02, + D_STR_HAIER_AC_YRW02, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_WHIRLPOOL_AC || SEND_WHIRLPOOL_AC, + D_STR_WHIRLPOOL_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SAMSUNG_AC || SEND_SAMSUNG_AC, + D_STR_SAMSUNG_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_LUTRON || SEND_LUTRON, + D_STR_LUTRON, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_ELECTRA_AC || SEND_ELECTRA_AC, + D_STR_ELECTRA_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_PANASONIC_AC || SEND_PANASONIC_AC, + D_STR_PANASONIC_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_PIONEER || SEND_PIONEER, + D_STR_PIONEER, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_LG || SEND_LG, + D_STR_LG2, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MWM || SEND_MWM, + D_STR_MWM, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN2 || SEND_DAIKIN2, + D_STR_DAIKIN2, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_VESTEL_AC || SEND_VESTEL_AC, + D_STR_VESTEL_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TECO || SEND_TECO, + D_STR_TECO, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SAMSUNG36 || SEND_SAMSUNG36, + D_STR_SAMSUNG36, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TCL112AC || SEND_TCL112AC, + D_STR_TCL112AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_LEGOPF || SEND_LEGOPF, + D_STR_LEGOPF, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MITSUBISHIHEAVY || SEND_MITSUBISHIHEAVY, + D_STR_MITSUBISHI_HEAVY_88, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MITSUBISHIHEAVY || SEND_MITSUBISHIHEAVY, + D_STR_MITSUBISHI_HEAVY_152, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN216 || SEND_DAIKIN216, + D_STR_DAIKIN216, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SHARP_AC || SEND_SHARP_AC, + D_STR_SHARP_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_GOODWEATHER || SEND_GOODWEATHER, + D_STR_GOODWEATHER, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_INAX || SEND_INAX, + D_STR_INAX, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN160 || SEND_DAIKIN160, + D_STR_DAIKIN160, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_NEOCLIMA || SEND_NEOCLIMA, + D_STR_NEOCLIMA, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN176 || SEND_DAIKIN176, + D_STR_DAIKIN176, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN128 || SEND_DAIKIN128, + D_STR_DAIKIN128, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_AMCOR || SEND_AMCOR, + D_STR_AMCOR, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN152 || SEND_DAIKIN152, + D_STR_DAIKIN152, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MITSUBISHI136 || SEND_MITSUBISHI136, + D_STR_MITSUBISHI136, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MITSUBISHI112 || SEND_MITSUBISHI112, + D_STR_MITSUBISHI112, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC424 || SEND_HITACHI_AC424, + D_STR_HITACHI_AC424, D_STR_UNSUPPORTED) "\x0" + COND(SEND_SONY, + D_STR_SONY_38K, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_EPSON || SEND_EPSON, + D_STR_EPSON, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SYMPHONY || SEND_SYMPHONY, + D_STR_SYMPHONY, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC3 || SEND_HITACHI_AC3, + D_STR_HITACHI_AC3, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN64 || SEND_DAIKIN64, + D_STR_DAIKIN64, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_AIRWELL || SEND_AIRWELL, + D_STR_AIRWELL, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DELONGHI_AC || SEND_DELONGHI_AC, + D_STR_DELONGHI_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DOSHISHA || SEND_DOSHISHA, + D_STR_DOSHISHA, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MULTIBRACKETS || SEND_MULTIBRACKETS, + D_STR_MULTIBRACKETS, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_CARRIER_AC40 || SEND_CARRIER_AC40, + D_STR_CARRIER_AC40, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_CARRIER_AC64 || SEND_CARRIER_AC64, + D_STR_CARRIER_AC64, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC344 || SEND_HITACHI_AC344, + D_STR_HITACHI_AC344, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_CORONA_AC || SEND_CORONA_AC, + D_STR_CORONA_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MIDEA24 || SEND_MIDEA24, + D_STR_MIDEA24, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_ZEPEAL || SEND_ZEPEAL, + D_STR_ZEPEAL, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SANYO_AC || SEND_SANYO_AC, + D_STR_SANYO_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_VOLTAS || SEND_VOLTAS, + D_STR_VOLTAS, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_METZ || SEND_METZ, + D_STR_METZ, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TRANSCOLD || SEND_TRANSCOLD, + D_STR_TRANSCOLD, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TECHNIBEL_AC || SEND_TECHNIBEL_AC, + D_STR_TECHNIBEL_AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MIRAGE || SEND_MIRAGE, + D_STR_MIRAGE, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_ELITESCREENS || SEND_ELITESCREENS, + D_STR_ELITESCREENS, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_PANASONIC_AC32 || SEND_PANASONIC_AC32, + D_STR_PANASONIC_AC32, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_MILESTAG2 || SEND_MILESTAG2, + D_STR_MILESTAG2, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_ECOCLIM || SEND_ECOCLIM, + D_STR_ECOCLIM, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_XMP || SEND_XMP, + D_STR_XMP, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TRUMA || SEND_TRUMA, + D_STR_TRUMA, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HAIER_AC176 || SEND_HAIER_AC176, + D_STR_HAIER_AC176, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TEKNOPOINT || SEND_TEKNOPOINT, + D_STR_TEKNOPOINT, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_KELON || SEND_KELON, + D_STR_KELON, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TROTEC_3550 || SEND_TROTEC_3550, + D_STR_TROTEC_3550, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SANYO_AC88 || SEND_SANYO_AC88, + D_STR_SANYO_AC88, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_BOSE || SEND_BOSE, + D_STR_BOSE, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_ARRIS || SEND_ARRIS, + D_STR_ARRIS, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_RHOSS || SEND_RHOSS, + D_STR_RHOSS, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_AIRTON || SEND_AIRTON, + D_STR_AIRTON, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_COOLIX48 || SEND_COOLIX48, + D_STR_COOLIX48, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC264 || SEND_HITACHI_AC264, + D_STR_HITACHI_AC264, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_KELON168 || SEND_KELON168, + D_STR_KELON168, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HITACHI_AC296 || SEND_HITACHI_AC296, + D_STR_HITACHI_AC296, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN200 || SEND_DAIKIN200, + D_STR_DAIKIN200, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_HAIER_AC160 || SEND_HAIER_AC160, + D_STR_HAIER_AC160, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_CARRIER_AC128 || SEND_CARRIER_AC128, + D_STR_CARRIER_AC128, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TOTO || SEND_TOTO, + D_STR_TOTO, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_CLIMABUTLER || SEND_CLIMABUTLER, + D_STR_CLIMABUTLER, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_TCL96AC || SEND_TCL96AC, + D_STR_TCL96AC, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_BOSCH144 || SEND_BOSCH144, + D_STR_BOSCH144, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_SANYO_AC152 || SEND_SANYO_AC152, + D_STR_SANYO_AC152, D_STR_UNSUPPORTED) "\x0" + COND(DECODE_DAIKIN312 || SEND_DAIKIN312, + D_STR_DAIKIN312, D_STR_UNSUPPORTED) "\x0" + ///< New protocol (macro) strings should be added just above this line. "\x0" ///< This string requires double null termination. }; - IRTEXT_CONST_BLOB_PTR(kAllProtocolNamesStr); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h index aab671314..7bd4fbed3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h @@ -44,8 +44,8 @@ extern IRTEXT_CONST_PTR(kArrah2eStr); extern IRTEXT_CONST_PTR(kArreb1eStr); extern IRTEXT_CONST_PTR(kArrew4eStr); extern IRTEXT_CONST_PTR(kArry4Str); -extern IRTEXT_CONST_PTR(kAutomaticStr); extern IRTEXT_CONST_PTR(kAutoStr); +extern IRTEXT_CONST_PTR(kAutomaticStr); extern IRTEXT_CONST_PTR(kBeepStr); extern IRTEXT_CONST_PTR(kBitsStr); extern IRTEXT_CONST_PTR(kBottomStr); @@ -64,13 +64,13 @@ extern IRTEXT_CONST_PTR(kClockStr); extern IRTEXT_CONST_PTR(kCodeStr); extern IRTEXT_CONST_PTR(kColonSpaceStr); extern IRTEXT_CONST_PTR(kComfortStr); -extern IRTEXT_CONST_PTR(kCommandStr); extern IRTEXT_CONST_PTR(kCommaSpaceStr); -extern IRTEXT_CONST_PTR(kCoolingStr); +extern IRTEXT_CONST_PTR(kCommandStr); extern IRTEXT_CONST_PTR(kCoolStr); +extern IRTEXT_CONST_PTR(kCoolingStr); extern IRTEXT_CONST_PTR(kDashStr); -extern IRTEXT_CONST_PTR(kDaysStr); extern IRTEXT_CONST_PTR(kDayStr); +extern IRTEXT_CONST_PTR(kDaysStr); extern IRTEXT_CONST_PTR(kDehumidifyStr); extern IRTEXT_CONST_PTR(kDg11j104Str); extern IRTEXT_CONST_PTR(kDg11j13aStr); @@ -80,18 +80,18 @@ extern IRTEXT_CONST_PTR(kDirectStr); extern IRTEXT_CONST_PTR(kDisplayTempStr); extern IRTEXT_CONST_PTR(kDkeStr); extern IRTEXT_CONST_PTR(kDownStr); -extern IRTEXT_CONST_PTR(kDryingStr); extern IRTEXT_CONST_PTR(kDryStr); +extern IRTEXT_CONST_PTR(kDryingStr); extern IRTEXT_CONST_PTR(kEconoStr); extern IRTEXT_CONST_PTR(kEconoToggleStr); extern IRTEXT_CONST_PTR(kEyeAutoStr); extern IRTEXT_CONST_PTR(kEyeStr); extern IRTEXT_CONST_PTR(kFalseStr); extern IRTEXT_CONST_PTR(kFanOnlyNoSpaceStr); -extern IRTEXT_CONST_PTR(kFan_OnlyStr); extern IRTEXT_CONST_PTR(kFanOnlyStr); extern IRTEXT_CONST_PTR(kFanOnlyWithSpaceStr); extern IRTEXT_CONST_PTR(kFanStr); +extern IRTEXT_CONST_PTR(kFan_OnlyStr); extern IRTEXT_CONST_PTR(kFastStr); extern IRTEXT_CONST_PTR(kFilterStr); extern IRTEXT_CONST_PTR(kFixedStr); @@ -100,21 +100,21 @@ extern IRTEXT_CONST_PTR(kFreshStr); extern IRTEXT_CONST_PTR(kGe6711ar2853mStr); extern IRTEXT_CONST_PTR(kGz055be1Str); extern IRTEXT_CONST_PTR(kHealthStr); -extern IRTEXT_CONST_PTR(kHeatingStr); extern IRTEXT_CONST_PTR(kHeatStr); -extern IRTEXT_CONST_PTR(kHighestStr); -extern IRTEXT_CONST_PTR(kHighStr); +extern IRTEXT_CONST_PTR(kHeatingStr); extern IRTEXT_CONST_PTR(kHiStr); +extern IRTEXT_CONST_PTR(kHighStr); +extern IRTEXT_CONST_PTR(kHighestStr); extern IRTEXT_CONST_PTR(kHoldStr); -extern IRTEXT_CONST_PTR(kHoursStr); extern IRTEXT_CONST_PTR(kHourStr); +extern IRTEXT_CONST_PTR(kHoursStr); extern IRTEXT_CONST_PTR(kHumidStr); -extern IRTEXT_CONST_PTR(kIdStr); extern IRTEXT_CONST_PTR(kIFeelStr); +extern IRTEXT_CONST_PTR(kISeeStr); +extern IRTEXT_CONST_PTR(kIdStr); extern IRTEXT_CONST_PTR(kIndirectStr); extern IRTEXT_CONST_PTR(kInsideStr); extern IRTEXT_CONST_PTR(kIonStr); -extern IRTEXT_CONST_PTR(kISeeStr); extern IRTEXT_CONST_PTR(kJkeStr); extern IRTEXT_CONST_PTR(kKkg29ac1Str); extern IRTEXT_CONST_PTR(kKkg9ac1Str); @@ -126,29 +126,29 @@ extern IRTEXT_CONST_PTR(kLg6711a20083vStr); extern IRTEXT_CONST_PTR(kLightStr); extern IRTEXT_CONST_PTR(kLightToggleStr); extern IRTEXT_CONST_PTR(kLkeStr); -extern IRTEXT_CONST_PTR(kLockStr); extern IRTEXT_CONST_PTR(kLoStr); +extern IRTEXT_CONST_PTR(kLockStr); extern IRTEXT_CONST_PTR(kLoudStr); +extern IRTEXT_CONST_PTR(kLowStr); extern IRTEXT_CONST_PTR(kLowerStr); extern IRTEXT_CONST_PTR(kLowestStr); -extern IRTEXT_CONST_PTR(kLowStr); extern IRTEXT_CONST_PTR(kManualStr); -extern IRTEXT_CONST_PTR(kMaximumStr); extern IRTEXT_CONST_PTR(kMaxLeftNoSpaceStr); extern IRTEXT_CONST_PTR(kMaxLeftStr); extern IRTEXT_CONST_PTR(kMaxRightNoSpaceStr); extern IRTEXT_CONST_PTR(kMaxRightStr); extern IRTEXT_CONST_PTR(kMaxStr); -extern IRTEXT_CONST_PTR(kMediumStr); +extern IRTEXT_CONST_PTR(kMaximumStr); extern IRTEXT_CONST_PTR(kMedStr); -extern IRTEXT_CONST_PTR(kMiddleStr); +extern IRTEXT_CONST_PTR(kMediumStr); extern IRTEXT_CONST_PTR(kMidStr); -extern IRTEXT_CONST_PTR(kMinimumStr); +extern IRTEXT_CONST_PTR(kMiddleStr); extern IRTEXT_CONST_PTR(kMinStr); -extern IRTEXT_CONST_PTR(kMinutesStr); +extern IRTEXT_CONST_PTR(kMinimumStr); extern IRTEXT_CONST_PTR(kMinuteStr); -extern IRTEXT_CONST_PTR(kModelStr); +extern IRTEXT_CONST_PTR(kMinutesStr); extern IRTEXT_CONST_PTR(kModeStr); +extern IRTEXT_CONST_PTR(kModelStr); extern IRTEXT_CONST_PTR(kMouldStr); extern IRTEXT_CONST_PTR(kMoveStr); extern IRTEXT_CONST_PTR(kNAStr); @@ -171,9 +171,9 @@ extern IRTEXT_CONST_PTR(kPanasonicPkrStr); extern IRTEXT_CONST_PTR(kPanasonicRkrStr); extern IRTEXT_CONST_PTR(kPkrStr); extern IRTEXT_CONST_PTR(kPowerButtonStr); -extern IRTEXT_CONST_PTR(kPowerfulStr); extern IRTEXT_CONST_PTR(kPowerStr); extern IRTEXT_CONST_PTR(kPowerToggleStr); +extern IRTEXT_CONST_PTR(kPowerfulStr); extern IRTEXT_CONST_PTR(kPreviousPowerStr); extern IRTEXT_CONST_PTR(kProtocolStr); extern IRTEXT_CONST_PTR(kPurifyStr); @@ -188,8 +188,8 @@ extern IRTEXT_CONST_PTR(kRlt0541htaaStr); extern IRTEXT_CONST_PTR(kRlt0541htabStr); extern IRTEXT_CONST_PTR(kRoomStr); extern IRTEXT_CONST_PTR(kSaveStr); -extern IRTEXT_CONST_PTR(kSecondsStr); extern IRTEXT_CONST_PTR(kSecondStr); +extern IRTEXT_CONST_PTR(kSecondsStr); extern IRTEXT_CONST_PTR(kSensorStr); extern IRTEXT_CONST_PTR(kSensorTempStr); extern IRTEXT_CONST_PTR(kSetStr); @@ -222,8 +222,8 @@ extern IRTEXT_CONST_PTR(kTurboStr); extern IRTEXT_CONST_PTR(kTurboToggleStr); extern IRTEXT_CONST_PTR(kTypeStr); extern IRTEXT_CONST_PTR(kUnknownStr); -extern IRTEXT_CONST_PTR(kUpperStr); extern IRTEXT_CONST_PTR(kUpStr); +extern IRTEXT_CONST_PTR(kUpperStr); extern IRTEXT_CONST_PTR(kV9014557AStr); extern IRTEXT_CONST_PTR(kV9014557BStr); extern IRTEXT_CONST_PTR(kVaneStr); @@ -235,6 +235,7 @@ extern IRTEXT_CONST_PTR(kXFanStr); extern IRTEXT_CONST_PTR(kYaw1fStr); extern IRTEXT_CONST_PTR(kYbofbStr); extern IRTEXT_CONST_PTR(kYesStr); +extern IRTEXT_CONST_PTR(kYx1fsfStr); extern IRTEXT_CONST_PTR(kZoneFollowStr); extern IRTEXT_CONST_PTR(kAllProtocolNamesStr); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp index b284a4129..7c59228c0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp @@ -172,6 +172,8 @@ bool hasACState(const decode_type_t protocol) { // This is kept sorted by name case AMCOR: case ARGO: + case BOSCH144: + case CARRIER_AC128: case CORONA_AC: case DAIKIN: case DAIKIN128: @@ -179,12 +181,15 @@ bool hasACState(const decode_type_t protocol) { case DAIKIN160: case DAIKIN176: case DAIKIN2: + case DAIKIN200: case DAIKIN216: + case DAIKIN312: case ELECTRA_AC: case FUJITSU_AC: case GREE: case HAIER_AC: case HAIER_AC_YRW02: + case HAIER_AC160: case HAIER_AC176: case HITACHI_AC: case HITACHI_AC1: @@ -209,7 +214,9 @@ bool hasACState(const decode_type_t protocol) { case SAMSUNG_AC: case SANYO_AC: case SANYO_AC88: + case SANYO_AC152: case SHARP_AC: + case TCL96AC: case TCL112AC: case TEKNOPOINT: case TOSHIBA_AC: @@ -605,9 +612,10 @@ namespace irutils { 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; - default: return kUnknownStr; + 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: diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp index 04cde67ed..680178ceb 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.cpp @@ -63,6 +63,28 @@ void IRArgoAC::begin(void) { _irsend.begin(); } void IRArgoAC::send(const uint16_t repeat) { _irsend.sendArgo(getRaw(), kArgoStateLength, repeat); } + +/// Send current room temperature for the iFeel feature as a silent IR +/// message (no acknowledgement from the device). +/// @param[in] temp The temperature in degrees celsius. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRArgoAC::sendSensorTemp(const uint8_t temp, const uint16_t repeat) { + uint8_t tempc = temp - kArgoTempDelta; + uint8_t check = 52 + tempc; + uint8_t end = 0b011; + + ArgoProtocol data; + data.raw[0] = 0b10101100; + data.raw[1] = 0b11110101; + data.raw[2] = (tempc << 3) | (check >> 5); + data.raw[3] = (check << 3) | end; + for (uint8_t i = 4; i < kArgoStateLength; i++) data.raw[i] = 0x0; + uint8_t sum = IRArgoAC::calcChecksum(data.raw, kArgoStateLength); + data.raw[10] = 0b00000010; + data.Sum = sum; + + _irsend.sendArgo(data.raw, kArgoStateLength, repeat); +} #endif // SEND_ARGO /// Verify the checksum is valid for a given state. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.h index 6ceb58e42..8ef7bb386 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Argo.h @@ -131,6 +131,8 @@ class IRArgoAC { #if SEND_ARGO void send(const uint16_t repeat = kArgoDefaultRepeat); + void sendSensorTemp(const uint8_t temp, + const uint16_t repeat = kArgoDefaultRepeat); /// 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 65ms IR signal pulse at 38kHz. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp new file mode 100644 index 000000000..56e9d2b99 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.cpp @@ -0,0 +1,331 @@ +// Copyright 2022 David Conran +// Copyright 2022 Nico Thien +/// @file +/// @brief Support for the Bosch A/C / heatpump protocol +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1787 + +#include "ir_Bosch.h" + +#if SEND_BOSCH144 +/// Send a Bosch 144-bit / 18-byte message (96-bit message are also possible) +/// Status: BETA / Probably Working. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +void IRsend::sendBosch144(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + // nbytes is required to be a multiple of kBosch144BytesPerSection. + if (nbytes % kBosch144BytesPerSection != 0)return; + // Set IR carrier frequency + enableIROut(kBoschFreq); + + for (uint16_t r = 0; r <= repeat; r++) { + for (uint16_t offset=0; offset < nbytes; offset += kBosch144BytesPerSection) + // Section Header + Data + Footer + sendGeneric(kBoschHdrMark, kBoschHdrSpace, + kBoschBitMark, kBoschOneSpace, + kBoschBitMark, kBoschZeroSpace, + kBoschBitMark, kBoschFooterSpace, + data + offset, kBosch144BytesPerSection, + kBoschFreq, true, 0, kDutyDefault); + space(kDefaultMessageGap); // Complete guess + } +} + +#endif // SEND_BOSCH144 + +/// 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? +IRBosch144AC::IRBosch144AC(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +/// Reset the internal state to a fixed known good state. +void IRBosch144AC::stateReset(void) { + setRaw(kBosch144DefaultState, kBosch144StateLength); + setPower(true); +} + +/// Set up hardware to be able to send a message. +void IRBosch144AC::begin(void) { _irsend.begin(); } + +#if SEND_BOSCH144 +/// Send the current internal state as an IR message. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRBosch144AC::send(const uint16_t repeat) { + if (!powerFlag) { // "Off" is a 96bit message + _irsend.sendBosch144(kBosch144Off, sizeof(kBosch144Off), repeat); + } else { + _irsend.sendBosch144(getRaw(), kBosch144StateLength, repeat); + } // other 96bit messages are not yet supported +} +#endif // SEND_BOSCH144 + +/// Get a copy of the internal state as a valid code for this protocol. +/// @return A valid code for this protocol based on the current internal state. +unsigned char* IRBosch144AC::getRaw(void) { + setInvertBytes(); + setCheckSumS3(); + return _.raw; +} + +/// Set the internal state from a valid code for this protocol. +/// @param[in] new_code A valid code for this protocol. +/// @param[in] length Size of the array being passed in in bytes. +void IRBosch144AC::setRaw(const uint8_t new_code[], const uint16_t length) { + const uint16_t len = min(length, kBosch144StateLength); + const uint16_t lenOff = sizeof(kBosch144Off); +// Is it an off message? + if (memcmp(kBosch144Off, new_code, min(lenOff, len)) == 0) + setPower(false); // It is. + else + setPower(true); + memcpy(_.raw, new_code, len); +} + +void IRBosch144AC::setPower(const bool on) { + powerFlag = on; +} + +bool IRBosch144AC::getPower(void) const { + return powerFlag; +} + +void IRBosch144AC::setTempRaw(const uint8_t code) { + _.TempS1 = _.TempS2 = code >> 1; // save 4 bits in S1 and S2 + _.TempS3 = code & 1; // save 1 bit in Section3 +} + +/// Set the temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRBosch144AC::setTemp(const uint8_t degrees) { + uint8_t temp = max(kBosch144TempMin, degrees); + temp = min(kBosch144TempMax, temp); + setTempRaw(kBosch144TempMap[temp - kBosch144TempMin]); +} + +uint8_t IRBosch144AC::getTemp(void) const { + uint8_t temp = (_.TempS1 << 1) + _.TempS3; + uint8_t retemp = 25; + for (uint8_t i = 0; i < kBosch144TempRange; i++) { + if (temp == kBosch144TempMap[i]) { + retemp = kBosch144TempMin + i; + } + } + return retemp; +} + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +void IRBosch144AC::setFan(const uint16_t speed) { + _.FanS1 = _.FanS2 = speed >> 6; // save 3 bits in S1 and S2 + _.FanS3 = speed & 0b111111; // save 6 bits in Section3 +} + +uint16_t IRBosch144AC::getFan(void) const { + return (_.FanS1 << 6) + _.FanS3; +} + +/// Set the desired operation mode. +/// @param[in] mode The desired operation mode. +void IRBosch144AC::setMode(const uint8_t mode) { + _.ModeS1 = _.ModeS2 = mode >> 1; // save 2 bits in S1 and S2 + _.ModeS3 = mode & 0b1; // save 1 bit in Section3 + if (mode == kBosch144Auto || mode == kBosch144Dry) { + _.FanS1 = _.FanS2 = 0b000; // save 3 bits in S1 and S2 + _.FanS3 = kBosch144FanAuto0; // save 6 bits in Section3 + } +} + +uint8_t IRBosch144AC::getMode(void) const { + return (_.ModeS1 << 1) + _.ModeS3; +} + +/// Set the Quiet mode of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRBosch144AC::setQuiet(const bool on) { + _.Quiet = on; // save 1 bit in Section3 + setFan(kBosch144FanAuto); // set Fan -> Auto +} + +/// Get the Quiet mode of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRBosch144AC::getQuiet(void) const { return _.Quiet; } + +/// Convert a stdAc::opmode_t enum into its native mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRBosch144AC::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: + return kBosch144Cool; + case stdAc::opmode_t::kHeat: + return kBosch144Heat; + case stdAc::opmode_t::kDry: + return kBosch144Dry; + case stdAc::opmode_t::kFan: + return kBosch144Fan; + default: + return kBosch144Auto; + } +} + +/// Convert a stdAc::fanspeed_t enum into it's native speed. +/// @param[in] speed The enum to be converted. +/// @return The native equivalent of the enum. +uint16_t IRBosch144AC::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + return kBosch144Fan20; + case stdAc::fanspeed_t::kLow: + return kBosch144Fan40; + case stdAc::fanspeed_t::kMedium: + return kBosch144Fan60; + case stdAc::fanspeed_t::kHigh: + return kBosch144Fan80; + case stdAc::fanspeed_t::kMax: + return kBosch144Fan100; + default: + return kBosch144FanAuto; + } +} + +/// Convert a native mode into its stdAc equivalent. +/// @param[in] mode The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::opmode_t IRBosch144AC::toCommonMode(const uint8_t mode) { + switch (mode) { + case kBosch144Cool: return stdAc::opmode_t::kCool; + case kBosch144Heat: return stdAc::opmode_t::kHeat; + case kBosch144Dry: return stdAc::opmode_t::kDry; + case kBosch144Fan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +/// Convert a native fan speed into its stdAc equivalent. +/// @param[in] speed The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::fanspeed_t IRBosch144AC::toCommonFanSpeed(const uint16_t speed) { + switch (speed) { + case kBosch144Fan100: return stdAc::fanspeed_t::kMax; + case kBosch144Fan80: return stdAc::fanspeed_t::kHigh; + case kBosch144Fan60: return stdAc::fanspeed_t::kMedium; + case kBosch144Fan40: return stdAc::fanspeed_t::kLow; + case kBosch144Fan20: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; + } +} + +/// Convert the current internal state into its stdAc::state_t equivalent. +/// @return The stdAc equivalent of the native settings. +stdAc::state_t IRBosch144AC::toCommon(void) const { + stdAc::state_t result{}; + result.protocol = decode_type_t::BOSCH144; + result.power = getPower(); + result.mode = toCommonMode(getMode()); + result.celsius = true; + result.degrees = getTemp(); + result.fanspeed = toCommonFanSpeed(getFan()); + result.quiet = getQuiet(); + // Not supported. + result.model = -1; + result.turbo = false; + result.swingv = stdAc::swingv_t::kOff; + result.swingh = stdAc::swingh_t::kOff; + result.light = false; + result.filter = false; + result.econo = false; + result.clean = false; + result.beep = false; + result.clock = -1; + result.sleep = -1; + return result; +} + +/// Convert the current internal state into a human readable string. +/// @return A human readable string. +String IRBosch144AC::toString(void) const { + uint8_t mode = getMode(); + uint8_t fan = static_cast(toCommonFanSpeed(getFan())); + String result = ""; + result.reserve(70); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(mode, kBosch144Auto, kBosch144Cool, + kBosch144Heat, kBosch144Dry, kBosch144Fan); + result += addFanToString(fan, static_cast(stdAc::fanspeed_t::kMax), + static_cast(stdAc::fanspeed_t::kMin), + static_cast(stdAc::fanspeed_t::kAuto), + static_cast(stdAc::fanspeed_t::kAuto), + static_cast(stdAc::fanspeed_t::kMedium)); + result += addTempToString(getTemp()); + result += addBoolToString(_.Quiet, kQuietStr); + return result; +} + +void IRBosch144AC::setInvertBytes() { + for (uint8_t i = 0; i <= 10; i += 2) { + _.raw[i + 1] = ~_.raw[i]; + } +} + +void IRBosch144AC::setCheckSumS3() { + _.ChecksumS3 = sumBytes(&(_.raw[12]), 5); +} + +#if DECODE_BOSCH144 +/// Decode the supplied Bosch 144-bit / 18-byte A/C message. +/// Status: STABLE / Confirmed Working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// 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 A boolean. True if it can decode it, false if it can't. +bool IRrecv::decodeBosch144(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < 2 * nbits + + kBosch144NrOfSections * (kHeader + kFooter) - + 1 + offset) + return false; // Can't possibly be a valid BOSCH144 message. + if (strict && nbits != kBosch144Bits) + return false; // Not strictly a BOSCH144 message. + if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte. + return false; + if (nbits % kBosch144NrOfSections != 0) + return false; // nbits has to be a multiple of kBosch144NrOfSections. + const uint16_t kSectionBits = nbits / kBosch144NrOfSections; + const uint16_t kSectionBytes = kSectionBits / 8; + const uint16_t kNBytes = kSectionBytes * kBosch144NrOfSections; + // Capture each section individually + for (uint16_t pos = 0, section = 0; + pos < kNBytes; + pos += kSectionBytes, section++) { + uint16_t used = 0; + // Section Header + Section Data + Section Footer + used = matchGeneric(results->rawbuf + offset, results->state + pos, + results->rawlen - offset, kSectionBits, + kBoschHdrMark, kBoschHdrSpace, + kBoschBitMark, kBoschOneSpace, + kBoschBitMark, kBoschZeroSpace, + kBoschBitMark, kBoschFooterSpace, + section >= kBosch144NrOfSections - 1, + _tolerance, kMarkExcess, true); + if (!used) return false; // Didn't match. + offset += used; + } + + // Compliance + + // Success + results->decode_type = decode_type_t::BOSCH144; + results->bits = nbits; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_BOSCH144 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.h new file mode 100644 index 000000000..9ebee9854 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Bosch.h @@ -0,0 +1,193 @@ +// Copyright 2022 Nico Thien +/// @file +/// @brief Support for Bosch A/C protocol +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1787 + +// Supports: +// Brand: Bosch, Model: CL3000i-Set 26 E A/C +// Brand: Bosch, Model: RG10A(G2S)BGEF remote + + +#ifndef IR_BOSCH_H_ +#define IR_BOSCH_H_ + +#define __STDC_LIMIT_MACROS +#include +#include +#include +#include "IRremoteESP8266.h" +#include "IRsend.h" +#include "IRrecv.h" +#include "IRtext.h" +#include "IRutils.h" +#ifndef UNIT_TEST +#include +#endif +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +// Constants +const uint16_t kBoschHdrMark = 4366; +const uint16_t kBoschBitMark = 502; +const uint16_t kBoschHdrSpace = 4415; +const uint16_t kBoschOneSpace = 1645; +const uint16_t kBoschZeroSpace = 571; +const uint16_t kBoschFooterSpace = 5235; +const uint16_t kBoschFreq = 38000; // Hz. (Guessing the most common frequency.) +const uint16_t kBosch144NrOfSections = 3; +const uint16_t kBosch144BytesPerSection = 6; + +using irutils::addBoolToString; +using irutils::addModeToString; +using irutils::addFanToString; +using irutils::addTempToString; +using std::min; +using std::max; +using std::memcpy; +using std::memcmp; + +// Modes Bit[0] to Section 3 Bit[1-2] to Section 1 +// ModeS3 ModeS1 +const uint8_t kBosch144Cool = 0b000; +const uint8_t kBosch144Dry = 0b011; +const uint8_t kBosch144Auto = 0b101; +const uint8_t kBosch144Heat = 0b110; +const uint8_t kBosch144Fan = 0b010; + +// Fan Control Bit[0-5] to Section 3 Bit[6-8] to Section 1 +// FanS3 FanS1 +const uint16_t kBosch144Fan20 = 0b111001010; +const uint16_t kBosch144Fan40 = 0b100010100; +const uint16_t kBosch144Fan60 = 0b010011110; +const uint16_t kBosch144Fan80 = 0b001101000; +const uint16_t kBosch144Fan100 = 0b001110010; +const uint16_t kBosch144FanAuto = 0b101110011; +const uint16_t kBosch144FanAuto0 = 0b000110011; + +// Temperature +const uint8_t kBosch144TempMin = 16; // Celsius +const uint8_t kBosch144TempMax = 30; // Celsius +const uint8_t kBosch144TempRange = kBosch144TempMax - kBosch144TempMin + 1; +const uint8_t kBosch144TempMap[kBosch144TempRange] = { + 0b00001, // 16C // Bit[0] to Section 3 Bit[1-4] to Section 1 + 0b00000, // 17C // TempS3 TempS1 + 0b00010, // 18c + 0b00110, // 19C + 0b00100, // 20C + 0b01100, // 21C + 0b01110, // 22C + 0b01010, // 23C + 0b01000, // 24C + 0b11000, // 25C + 0b11010, // 26C + 0b10010, // 27C + 0b10000, // 28C + 0b10100, // 29C + 0b10110 // 30C +}; + +// "OFF" is a 96bit-message the same as Coolix protocol +const uint8_t kBosch144Off[] = {0xB2, 0x4D, 0x7B, 0x84, 0xE0, 0x1F, + 0xB2, 0x4D, 0x7B, 0x84, 0xE0, 0x1F}; + +// On, 25C, Mode: Auto +const uint8_t kBosch144DefaultState[kBosch144StateLength] = { + 0xB2, 0x4D, 0x1F, 0xE0, 0xC8, 0x37, + 0xB2, 0x4D, 0x1F, 0xE0, 0xC8, 0x37, + 0xD5, 0x65, 0x00, 0x00, 0x00, 0x3A}; + +union Bosch144Protocol { + uint8_t raw[kBosch144StateLength]; ///< The state in IR code form. + struct { + uint8_t :8; // Fixed value 0b10110010 / 0xB2. ############ + uint8_t InnvertS1_1:8; // Invert byte 0b01001101 / 0x4D # + uint8_t :5; // not used (without timer use) # + uint8_t FanS1 :3; // Fan speed bits in Section 1 # + uint8_t InnvertS1_2:8; // Invert byte # Section 1 = + uint8_t :2; // not used (without timer use) # Sektion 2 + uint8_t ModeS1 :2; // Operation mode bits S1 # + uint8_t TempS1 :4; // Desired temperature (Celsius) S2 # + uint8_t InnvertS1_3:8; // Invert byte (without timer use) ############ + + uint8_t :8; // Fixed value 0b10110010 / 0xB2. ############ + uint8_t InnvertS2_1:8; // Invert byte 0b01001101 / 0x4D # + uint8_t :5; // not used (without timer use) # + uint8_t FanS2 :3; // Fan speed bits in Section 2 # + uint8_t InnvertS2_2:8; // Invert byte # Section 2 = + uint8_t :2; // not used (without timer use) # Sektion 1 + uint8_t ModeS2 :2; // Operation mode bits S2 # + uint8_t TempS2 :4; // Desired temperature (Celsius) S2 # + uint8_t InnvertS2_3:8; // Invert byte (without timer use) ########### + + uint8_t :8; // Fixed value 0b11010101 / 0xD5 ########### + uint8_t ModeS3 :1; // ModeBit in Section 3 # + uint8_t FanS3 :6; // Fan speed bits in Section 3 # + uint8_t :1; // Unknown # + uint8_t :7; // Unknown # + uint8_t Quiet :1; // Silent-Mode # Section 3 + uint8_t :4; // Unknown # + uint8_t TempS3 :1; // Desired temp. Bit in Section3 # + uint8_t :3; // Unknown # + uint8_t :8; // Unknown # + uint8_t ChecksumS3 :8; // Checksum from byte 13-17 ########### + }; +}; + +// Classes + +/// Class for handling detailed Bosch144 A/C messages. +class IRBosch144AC { + public: + explicit IRBosch144AC(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + void stateReset(void); +#if SEND_BOSCH144 + void send(const uint16_t repeat = 0); + /// 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 65ms IR signal pulse at 38kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_BOSCH144 + void begin(); + void setPower(const bool state); + bool getPower(void) const; + void setTemp(const uint8_t temp); + uint8_t getTemp(void) const; + void setFan(const uint16_t speed); + uint16_t getFan(void) const; + void setMode(const uint8_t mode); + uint8_t getMode(void) const; + void setQuiet(const bool on); + bool getQuiet(void) const; + uint8_t* getRaw(void); + void setRaw(const uint8_t new_code[], + const uint16_t length = kBosch144StateLength); + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint16_t convertFan(const stdAc::fanspeed_t speed); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint16_t speed); + stdAc::state_t toCommon(void) const; + String toString(void) const; +#ifndef UNIT_TEST + + private: + IRsend _irsend; ///< Instance of the IR send class +#else + /// @cond IGNORE + IRsendTest _irsend; ///< Instance of the testing IR send class + /// @endcond +#endif + Bosch144Protocol _; ///< The state of the IR remote in IR code form. + + // Internal State settings + bool powerFlag; + + void setInvertBytes(); + void setCheckSumS3(); + void setTempRaw(const uint8_t code); + uint8_t getTempRaw(void) const; +}; + +#endif // IR_BOSCH_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.cpp index f52628aae..42b45f9ab 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.cpp @@ -1,8 +1,9 @@ -// Copyright 2018, 2020 David Conran +// Copyright 2018-2022 David Conran /// @file /// @brief Carrier protocols. /// @see CarrierAc https://github.com/crankyoldgit/IRremoteESP8266/issues/385 /// @see CarrierAc64 https://github.com/crankyoldgit/IRremoteESP8266/issues/1127 +/// @see CarrierAc128 https://github.com/crankyoldgit/IRremoteESP8266/issues/1797 #include "ir_Carrier.h" #include @@ -45,6 +46,16 @@ const uint16_t kCarrierAc64OneSpace = 1736; const uint16_t kCarrierAc64ZeroSpace = 615; const uint32_t kCarrierAc64Gap = kDefaultMessageGap; // A guess. +const uint16_t kCarrierAc128HdrMark = 4600; +const uint16_t kCarrierAc128HdrSpace = 2600; +const uint16_t kCarrierAc128Hdr2Mark = 9300; +const uint16_t kCarrierAc128Hdr2Space = 5000; +const uint16_t kCarrierAc128BitMark = 340; +const uint16_t kCarrierAc128OneSpace = 1000; +const uint16_t kCarrierAc128ZeroSpace = 400; +const uint16_t kCarrierAc128SectionGap = 20600; +const uint16_t kCarrierAc128InterSpace = 6700; +const uint16_t kCarrierAc128SectionBits = kCarrierAc128Bits / 2; #if SEND_CARRIER_AC /// Send a Carrier HVAC formatted message. @@ -533,3 +544,104 @@ stdAc::state_t IRCarrierAc64::toCommon(void) const { result.clock = -1; return result; } + +#if SEND_CARRIER_AC128 +/// Send a Carrier 128bit HVAC formatted message. +/// Status: BETA / Seems to work with tests. Needs testing agaisnt real devices. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The byte size of the message being sent. +/// @param[in] repeat The number of times the message is to be repeated. +void IRsend::sendCarrierAC128(const uint8_t data[], const uint16_t nbytes, + const uint16_t repeat) { + // Min length check. + if (nbytes <= kCarrierAc128StateLength / 2) return; + + enableIROut(kCarrierAcFreq); + // Handle repeats. + for (uint16_t r = 0; r <= repeat; r++) { + // First part of the message. + // Headers + Data + SectionGap + sendGeneric(kCarrierAc128HdrMark, kCarrierAc128HdrSpace, + kCarrierAc128BitMark, kCarrierAc128OneSpace, + kCarrierAc128BitMark, kCarrierAc128ZeroSpace, + kCarrierAc128BitMark, kCarrierAc128SectionGap, + data, nbytes / 2, kCarrierAcFreq, false, 0, kDutyDefault); + // Inter-message markers + mark(kCarrierAc128HdrMark); + space(kCarrierAc128InterSpace); + // Second part of the message + // Headers + Data + SectionGap + sendGeneric(kCarrierAc128Hdr2Mark, kCarrierAc128Hdr2Space, + kCarrierAc128BitMark, kCarrierAc128OneSpace, + kCarrierAc128BitMark, kCarrierAc128ZeroSpace, + kCarrierAc128BitMark, kCarrierAc128SectionGap, + data + (nbytes / 2), nbytes / 2, kCarrierAcFreq, + false, 0, kDutyDefault); + // Footer + mark(kCarrierAc128HdrMark); + space(kDefaultMessageGap); + } +} +#endif // SEND_CARRIER_AC128 + +#if DECODE_CARRIER_AC128 +/// Decode the supplied Carrier 128-bit HVAC message. +/// Status: STABLE / Expected to work. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// 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 A boolean. True if it can decode it, false if it can't. +bool IRrecv::decodeCarrierAC128(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < 2 * (nbits + 2 * kHeader + kFooter) - 1 + offset) + return false; // Can't possibly be a valid Carrier message. + if (strict && nbits != kCarrierAc128Bits) + return false; // We expect Carrier to be 128 bits of message. + + uint16_t used; + uint16_t pos = 0; + const uint16_t sectionbits = nbits / 2; + // Match the first section. + used = matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, sectionbits, + kCarrierAc128HdrMark, kCarrierAc128HdrSpace, + kCarrierAc128BitMark, kCarrierAc128OneSpace, + kCarrierAc128BitMark, kCarrierAc128ZeroSpace, + kCarrierAc128BitMark, kCarrierAc128SectionGap, true, + kUseDefTol, kMarkExcess, false); + if (used == 0) return false; // No match. + offset += used; + pos += sectionbits / 8; + // Look for the inter-message markers. + if (!matchMark(results->rawbuf[offset++], kCarrierAc128HdrMark)) + return false; + if (!matchSpace(results->rawbuf[offset++], kCarrierAc128InterSpace)) + return false; + // Now look for the second section. + used = matchGeneric(results->rawbuf + offset, results->state + pos, + results->rawlen - offset, sectionbits, + kCarrierAc128Hdr2Mark, kCarrierAc128Hdr2Space, + kCarrierAc128BitMark, kCarrierAc128OneSpace, + kCarrierAc128BitMark, kCarrierAc128ZeroSpace, + kCarrierAc128BitMark, kCarrierAc128SectionGap, true, + kUseDefTol, kMarkExcess, false); + if (used == 0) return false; // No match. + offset += used; + // Now check for the Footer. + if (!matchMark(results->rawbuf[offset++], kCarrierAc128HdrMark)) return false; + if (offset < results->rawlen && + !matchAtLeast(results->rawbuf[offset], kDefaultMessageGap)) return false; + + + // Compliance + // if (strict && !IRCarrierAc128::validChecksum(results->value)) return false; + + // Success + results->bits = nbits; + results->decode_type = CARRIER_AC128; + return true; +} +#endif // DECODE_CARRIER_AC128 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.h index aa9ea8447..c642c51e5 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Carrier.h @@ -1,8 +1,9 @@ -// Copyright 2020 David Conran +// Copyright 2020-2022 David Conran /// @file /// @brief Carrier A/C /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1127 /// @see https://docs.google.com/spreadsheets/d/1EZy78L0cn1KDIX1aKq2biptejFqCjD5HO3tLiRvXf48/edit#gid=0 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1797 // Supports: // Brand: Carrier/Surrey, Model: 42QG5A55970 remote @@ -11,6 +12,7 @@ // Brand: Carrier/Surrey, Model: 619EGX0180E0 A/C // Brand: Carrier/Surrey, Model: 619EGX0220E0 A/C // Brand: Carrier/Surrey, Model: 53NGK009/012 Inverter +// Brand: Carrier, Model: 40GKX0E2006 remote (CARRIER_AC128) #ifndef IR_CARRIER_H_ #define IR_CARRIER_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_ClimaButler.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_ClimaButler.cpp new file mode 100644 index 000000000..d8b4f5a98 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_ClimaButler.cpp @@ -0,0 +1,86 @@ +// Copyright 2022 benjy3gg +// Copyright 2022 David Conran (crankyoldgit) +/// @file +/// @brief Support for Clima-Butler protocol +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1812 + +// Supports: +// Brand: Clima-Butler, Model: AR-715 remote +// Brand: Clima-Butler, Model: RCS-SD43UWI A/C + +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + + +const uint16_t kClimaButlerBitMark = 511; // uSeconds +const uint16_t kClimaButlerHdrMark = kClimaButlerBitMark; +const uint16_t kClimaButlerHdrSpace = 3492; // uSeconds +const uint16_t kClimaButlerOneSpace = 1540; // uSeconds +const uint16_t kClimaButlerZeroSpace = 548; // uSeconds +const uint32_t kClimaButlerGap = kDefaultMessageGap; // uSeconds (A guess.) +const uint16_t kClimaButlerFreq = 38000; // Hz. (Guess.) + +#if SEND_CLIMABUTLER +/// Send a ClimaButler formatted message. +/// Status: STABLE / Confirmed working. +/// @param[in] data containing the IR command. +/// @param[in] nbits Nr. of bits to send. usually kClimaButlerBits +/// @param[in] repeat Nr. of times the message is to be repeated. +void IRsend::sendClimaButler(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + enableIROut(kClimaButlerFreq); + for (uint16_t r = 0; r <= repeat; r++) { + // Header + Data + sendGeneric(kClimaButlerHdrMark, kClimaButlerHdrSpace, + kClimaButlerBitMark, kClimaButlerOneSpace, + kClimaButlerBitMark, kClimaButlerZeroSpace, + kClimaButlerBitMark, kClimaButlerHdrSpace, + data, nbits, kClimaButlerFreq, true, 0, kDutyDefault); + // Footer + mark(kClimaButlerBitMark); + space(kClimaButlerGap); + } +} +#endif // SEND_CLIMABUTLER + +#if DECODE_CLIMABUTLER +/// Decode the supplied ClimaButler message. +/// Status: STABLE / Confirmed working. +/// @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::decodeClimaButler(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < 2 * nbits + kHeader + 2 * kFooter - offset) + return false; // Too short a message to match. + if (strict && nbits != kClimaButlerBits) + return false; + + // Header + Data + uint16_t used = matchGeneric(results->rawbuf + offset, &(results->value), + results->rawlen - offset, nbits, + kClimaButlerHdrMark, kClimaButlerHdrSpace, + kClimaButlerBitMark, kClimaButlerOneSpace, + kClimaButlerBitMark, kClimaButlerZeroSpace, + kClimaButlerBitMark, kClimaButlerHdrSpace); + if (!used) return false; // Didn't matched. + offset += used; + // Footer + if (!matchMark(results->rawbuf[offset++], kClimaButlerBitMark)) + return false; + if (results->rawlen <= offset && !matchAtLeast(results->rawbuf[offset], + kClimaButlerGap)) + return false; + + // Success + results->decode_type = decode_type_t::CLIMABUTLER; + results->bits = nbits; + results->command = 0; + results->address = 0; + return true; +} +#endif // DECODE_CLIMABUTLER diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp index 0358b89a5..755e89190 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp @@ -719,7 +719,7 @@ void IRsend::sendCoolix48(const uint64_t data, const uint16_t nbits, } #endif // SEND_COOLIX48 -#if DECODE_COOLIX +#if DECODE_COOLIX48 /// Decode the supplied Coolix 48-bit A/C message. /// Status: BETA / Probably Working. /// @param[in,out] results Ptr to the data to decode & where to store the decode diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp index cf5f3a694..f44cd8f13 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.cpp @@ -1,6 +1,6 @@ // Copyright 2016 sillyfrog // Copyright 2017 sillyfrog, crankyoldgit -// Copyright 2018-2021 crankyoldgit +// Copyright 2018-2022 crankyoldgit // Copyright 2019 pasna (IRDaikin160 class / Daikin176 class) /// @file @@ -21,6 +21,7 @@ /// @see Daikin216 https://github.com/crankyoldgit/IRremoteESP8266/issues/689 /// @see Daikin216 https://github.com/danny-source/Arduino_DY_IRDaikin /// @see Daikin64 https://github.com/crankyoldgit/IRremoteESP8266/issues/1064 +/// @see Daikin200 https://github.com/crankyoldgit/IRremoteESP8266/issues/1802 #include "ir_Daikin.h" #include @@ -3733,3 +3734,193 @@ stdAc::state_t IRDaikin64::toCommon(const stdAc::state_t *prev) const { result.light = false; return result; } + +#if SEND_DAIKIN200 +/// Send a Daikin200 (200-bit) A/C formatted message. +/// Status: BETA / Untested on a real device. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1802 +void IRsend::sendDaikin200(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kDaikin200Section1Length) + return; // Not enough bytes to send a partial message. + + for (uint16_t r = 0; r <= repeat; r++) { + // Section #1 + sendGeneric(kDaikin200HdrMark, kDaikin200HdrSpace, kDaikin200BitMark, + kDaikin200OneSpace, kDaikin200BitMark, kDaikin200ZeroSpace, + kDaikin200BitMark, kDaikin200Gap, data, + kDaikin200Section1Length, + kDaikin200Freq, false, 0, kDutyDefault); + // Section #2 + sendGeneric(kDaikin200HdrMark, kDaikin200HdrSpace, kDaikin200BitMark, + kDaikin200OneSpace, kDaikin200BitMark, kDaikin200ZeroSpace, + kDaikin200BitMark, kDaikin200Gap, + data + kDaikin200Section1Length, + nbytes - kDaikin200Section1Length, + kDaikin200Freq, false, 0, kDutyDefault); + } +} +#endif // SEND_DAIKIN200 + +#if DECODE_DAIKIN200 +/// Decode the supplied Daikin 200-bit message. (DAIKIN200) +/// Status: STABLE / Known to be working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// 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 A boolean. True if it can decode it, false if it can't. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1802 +bool IRrecv::decodeDaikin200(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < 2 * (nbits + kHeader + kFooter) - 1 + offset) + return false; + + // Compliance + if (strict && nbits != kDaikin200Bits) return false; + + const uint8_t ksectionSize[kDaikin200Sections] = {kDaikin200Section1Length, + kDaikin200Section2Length}; + // Sections + uint16_t pos = 0; + for (uint8_t section = 0; section < kDaikin200Sections; section++) { + uint16_t used; + // Section Header + Section Data + Section Footer + used = matchGeneric(results->rawbuf + offset, results->state + pos, + results->rawlen - offset, ksectionSize[section] * 8, + kDaikin200HdrMark, kDaikin200HdrSpace, + kDaikin200BitMark, kDaikin200OneSpace, + kDaikin200BitMark, kDaikin200ZeroSpace, + kDaikin200BitMark, kDaikin200Gap, + section >= kDaikin200Sections - 1, + kDaikinTolerance, 0, false); + if (used == 0) return false; + offset += used; + pos += ksectionSize[section]; + } + // Compliance + if (strict) { + if (pos * 8 != kDaikin200Bits) return false; + // Validate the checksum. + if (!IRDaikin176::validChecksum(results->state, pos)) return false; + } + + // Success + results->decode_type = decode_type_t::DAIKIN200; + results->bits = nbits; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_DAIKIN200 + +#if SEND_DAIKIN312 +/// Send a Daikin312 (312-bit / 39 byte) A/C formatted message. +/// Status: BETA / Untested on a real device. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1829 +void IRsend::sendDaikin312(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kDaikin312Section1Length) + return; // Not enough bytes to send a partial message. + + for (uint16_t r = 0; r <= repeat; r++) { + // Send the header, 0b00000 + sendGeneric(0, 0, // No header for the header + kDaikin312BitMark, kDaikin312OneSpace, + kDaikin312BitMark, kDaikin312ZeroSpace, + kDaikin312BitMark, kDaikin312HdrGap, + (uint64_t)0b00000, kDaikinHeaderLength, + kDaikin2Freq, false, 0, kDutyDefault); + // Section #1 + sendGeneric(kDaikin312HdrMark, kDaikin312HdrSpace, kDaikin312BitMark, + kDaikin312OneSpace, kDaikin312BitMark, kDaikin312ZeroSpace, + kDaikin312BitMark, kDaikin312SectionGap, data, + kDaikin312Section1Length, + kDaikin2Freq, false, 0, kDutyDefault); + // Section #2 + sendGeneric(kDaikin312HdrMark, kDaikin312HdrSpace, kDaikin312BitMark, + kDaikin312OneSpace, kDaikin312BitMark, kDaikin312ZeroSpace, + kDaikin312BitMark, kDaikin312SectionGap, + data + kDaikin312Section1Length, + nbytes - kDaikin312Section1Length, + kDaikin2Freq, false, 0, kDutyDefault); + } +} +#endif // SEND_DAIKIN312 + +#if DECODE_DAIKIN312 +/// Decode the supplied Daikin 312-bit / 39-byte message. (DAIKIN312) +/// Status: STABLE / Confirmed working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// 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 A boolean. True if it can decode it, false if it can't. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1829 +bool IRrecv::decodeDaikin312(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + // Is there enough data to match successfully? + if (results->rawlen < 2 * (nbits + kDaikinHeaderLength + kHeader + kFooter) + + kFooter - 1 + offset) + return false; + + // Compliance + if (strict && nbits != kDaikin312Bits) return false; + + const uint8_t ksectionSize[kDaikin312Sections] = {kDaikin312Section1Length, + kDaikin312Section2Length}; + // Header/Leader Section + uint64_t leaderdata = 0; + uint16_t used = matchGeneric(results->rawbuf + offset, &leaderdata, + results->rawlen - offset, kDaikinHeaderLength, + 0, 0, // No Header Mark or Space for the "header" + kDaikin312BitMark, kDaikin312OneSpace, + kDaikin312BitMark, kDaikin312ZeroSpace, + kDaikin312BitMark, kDaikin312HdrGap, + false, kDaikinTolerance, 0, false); + if (!used) return false; // Failed to match. + if (leaderdata) return false; // The header bits should all be zero. + + offset += used; + + // Data Sections + uint16_t pos = 0; + for (uint8_t section = 0; section < kDaikin312Sections; section++) { + // Section Header + Section Data + Section Footer + used = matchGeneric(results->rawbuf + offset, results->state + pos, + results->rawlen - offset, ksectionSize[section] * 8, + kDaikin312HdrMark, kDaikin312HdrSpace, + kDaikin312BitMark, kDaikin312OneSpace, + kDaikin312BitMark, kDaikin312ZeroSpace, + kDaikin312BitMark, kDaikin312SectionGap, + section >= kDaikin312Sections - 1, + kDaikinTolerance, 0, false); + if (used == 0) return false; + offset += used; + pos += ksectionSize[section]; + } + // Compliance + if (strict) { + if (pos * 8 != kDaikin312Bits) return false; + } + + // Success + results->decode_type = decode_type_t::DAIKIN312; + results->bits = nbits; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_DAIKIN312 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h index 25540e2c2..3a98f07e7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Daikin.h @@ -1,6 +1,6 @@ // Copyright 2016 sillyfrog // Copyright 2017 sillyfrog, crankyoldgit -// Copyright 2018-2021 crankyoldgit +// Copyright 2018-2022 crankyoldgit // Copyright 2019 pasna (IRDaikin160 class / Daikin176 class) /// @file @@ -21,6 +21,8 @@ /// @see Daikin216 https://github.com/crankyoldgit/IRremoteESP8266/issues/689 /// @see Daikin216 https://github.com/danny-source/Arduino_DY_IRDaikin /// @see Daikin64 https://github.com/crankyoldgit/IRremoteESP8266/issues/1064 +/// @see Daikin200 https://github.com/crankyoldgit/IRremoteESP8266/issues/1802 +/// @see Daikin312 https://github.com/crankyoldgit/IRremoteESP8266/issues/1829 // Supports: // Brand: Daikin, Model: ARC433** remote (DAIKIN) @@ -36,17 +38,21 @@ // Brand: Daikin, Model: BRC4C151 remote (DAIKIN176) // Brand: Daikin, Model: 17 Series FTXB09AXVJU A/C (DAIKIN128) // Brand: Daikin, Model: 17 Series FTXB12AXVJU A/C (DAIKIN128) -// Brand: Daikin, Model: 17 Series FTXB24AXVJU A/C (NOT SUPPORTED) +// Brand: Daikin, Model: 17 Series FTXB24AXVJU A/C (DAIKIN128) // Brand: Daikin, Model: BRC52B63 remote (DAIKIN128) // Brand: Daikin, Model: ARC480A5 remote (DAIKIN152) // Brand: Daikin, Model: FFN-C/FCN-F Series A/C (DAIKIN64) // Brand: Daikin, Model: DGS01 remote (DAIKIN64) // Brand: Daikin, Model: M Series A/C (DAIKIN) // Brand: Daikin, Model: FTXM-M A/C (DAIKIN) +// Brand: Daikin, Model: ARC466A12 remote (DAIKIN) // Brand: Daikin, Model: ARC466A33 remote (DAIKIN) // Brand: Daikin, Model: FTWX35AXV1 A/C (DAIKIN64) // Brand: Daikin, Model: ARC484A4 remote (DAIKIN216) // Brand: Daikin, Model: FTQ60TV16U2 A/C (DAIKIN216) +// Brand: Daikin, Model: BRC4M150W16 remote (DAIKIN200) +// Brand: Daikin, Model: FTXM20R5V1B A/C (DAIKIN312) +// Brand: Daikin, Model: ARC466A67 remote (DAIKIN312) #ifndef IR_DAIKIN_H_ #define IR_DAIKIN_H_ @@ -676,6 +682,30 @@ const uint8_t kDaikin64MaxTemp = 30; // Celsius const uint8_t kDaikin64ChecksumOffset = 60; const uint8_t kDaikin64ChecksumSize = 4; // Mask 0b1111 << 59 +const uint16_t kDaikin200Freq = 38000; // Modulation Frequency in Hz. +const uint16_t kDaikin200HdrMark = 4920; +const uint16_t kDaikin200HdrSpace = 2230; +const uint16_t kDaikin200BitMark = 290; +const uint16_t kDaikin200OneSpace = 1850; +const uint16_t kDaikin200ZeroSpace = 780; +const uint16_t kDaikin200Gap = 29400; +const uint16_t kDaikin200Sections = 2; +const uint16_t kDaikin200Section1Length = 7; +const uint16_t kDaikin200Section2Length = kDaikin200StateLength - + kDaikin200Section1Length; + +const uint16_t kDaikin312HdrMark = 3518; +const uint16_t kDaikin312HdrSpace = 1688; +const uint16_t kDaikin312BitMark = 453; +const uint16_t kDaikin312ZeroSpace = 414; +const uint16_t kDaikin312OneSpace = 1275; +const uint16_t kDaikin312HdrGap = 25100; +const uint16_t kDaikin312SectionGap = 35512; +const uint16_t kDaikin312Sections = 2; +const uint16_t kDaikin312Section1Length = 20; +const uint16_t kDaikin312Section2Length = kDaikin312StateLength - + kDaikin312Section1Length; + // Legacy defines. #define DAIKIN_COOL kDaikinCool #define DAIKIN_HEAT kDaikinHeat diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.cpp index eca1adf93..0c2a84331 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.cpp @@ -1,5 +1,5 @@ // Copyright 2017 Jonny Graham -// Copyright 2017-2021 David Conran +// Copyright 2017-2022 David Conran // Copyright 2021 siriuslzx /// @file @@ -116,6 +116,7 @@ void IRFujitsuAC::stateReset(void) { _.longcode[1] = 0x63; _.longcode[3] = 0x10; _.longcode[4] = 0x10; + _rawstatemodified = true; } /// Set up hardware to be able to send a message. @@ -142,6 +143,7 @@ bool IRFujitsuAC::updateUseLongOrShort(void) { case kFujitsuAcCmdStepHoriz: // 0x79 case kFujitsuAcCmdToggleSwingHoriz: // 0x7A _.Cmd = _cmd; + _rawstatemodified = true; break; default: switch (_model) { @@ -150,10 +152,12 @@ bool IRFujitsuAC::updateUseLongOrShort(void) { case fujitsu_ac_remote_model_t::ARREB1E: case fujitsu_ac_remote_model_t::ARREW4E: _.Cmd = 0xFE; + _rawstatemodified = true; break; case fujitsu_ac_remote_model_t::ARDB1: case fujitsu_ac_remote_model_t::ARJW2: _.Cmd = 0xFC; + _rawstatemodified = true; break; } fullCmd = true; @@ -164,7 +168,8 @@ bool IRFujitsuAC::updateUseLongOrShort(void) { /// Calculate and set the checksum values for the internal state. void IRFujitsuAC::checkSum(void) { - if (updateUseLongOrShort()) { // Is it a long code? + _rawstatemodified = true; + if (updateUseLongOrShort()) { // Is it going to be a long code? // Nr. of bytes in the message after this byte. _.RestLength = _state_length - 7; _.Protocol = (_model == fujitsu_ac_remote_model_t::ARREW4E) ? 0x31 : 0x30; @@ -179,7 +184,13 @@ void IRFujitsuAC::checkSum(void) { } } if (_model != fujitsu_ac_remote_model_t::ARRY4) { - if (_model != fujitsu_ac_remote_model_t::ARREW4E) _.Clean = false; + switch (_model) { + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARREW4E: + break; + default: + _.Clean = false; + } _.Filter = false; } // Set the On/Off/Sleep timer Nr of mins. @@ -235,13 +246,17 @@ uint8_t IRFujitsuAC::getStateLength(void) { return updateUseLongOrShort() ? _state_length : _state_length_short; } +/// Is the current binary state representation a long or a short code? +/// @return true, if long; false, if short. +bool IRFujitsuAC::isLongCode(void) const { + return _.Cmd == 0xFE || _.Cmd == 0xFC; +} + /// Get a PTR to the internal state/code for this protocol. /// @return PTR to a code for this protocol based on the current internal state. uint8_t* IRFujitsuAC::getRaw(void) { checkSum(); - if (_.Cmd == 0xFE || _.Cmd == 0xFC) - return _.longcode; - return _.shortcode; + return isLongCode() ? _.longcode : _.shortcode; } /// Build the internal state/config from the current (raw) A/C message. @@ -281,7 +296,8 @@ void IRFujitsuAC::buildFromState(const uint16_t length) { setCmd(kFujitsuAcCmdStayOn); // Currently the only way we know how to tell ARRAH2E & ARRY4 apart is if // either the raw Filter or Clean setting is on. - if (_model == fujitsu_ac_remote_model_t::ARRAH2E && (_.Filter || _.Clean)) + if (_model == fujitsu_ac_remote_model_t::ARRAH2E && (_.Filter || _.Clean) && + !get10CHeat()) setModel(fujitsu_ac_remote_model_t::ARRY4); if (_state_length == kFujitsuAcStateLength && _.OutsideQuiet) setModel(fujitsu_ac_remote_model_t::ARREB1E); @@ -312,6 +328,7 @@ bool IRFujitsuAC::setRaw(const uint8_t newState[], const uint16_t length) { _.longcode[i] = 0; } buildFromState(length); + _rawstatemodified = false; return true; } @@ -405,6 +422,7 @@ bool IRFujitsuAC::getPower(void) const { return _cmd != kFujitsuAcCmdTurnOff; } /// @param[in] on true, the setting is on. false, the setting is off. void IRFujitsuAC::setOutsideQuiet(const bool on) { _.OutsideQuiet = on; + _rawstatemodified = true; setCmd(kFujitsuAcCmdStayOn); // No special command involved. } @@ -461,6 +479,7 @@ void IRFujitsuAC::setTemp(const float temp, const bool useCelsius) { } else { _.Temp = _temp - offset; } + _rawstatemodified = true; setCmd(kFujitsuAcCmdStayOn); // No special command involved. } @@ -484,6 +503,7 @@ void IRFujitsuAC::setFanSpeed(const uint8_t fanSpeed) { _.Fan = kFujitsuAcFanHigh; // Set the fan to maximum if out of range. else _.Fan = fanSpeed; + _rawstatemodified = true; setCmd(kFujitsuAcCmdStayOn); // No special command involved. } @@ -498,6 +518,7 @@ void IRFujitsuAC::setMode(const uint8_t mode) { _.Mode = kFujitsuAcModeHeat; // Set the mode to maximum if out of range. else _.Mode = mode; + _rawstatemodified = true; setCmd(kFujitsuAcCmdStayOn); // No special command involved. } @@ -511,6 +532,7 @@ uint8_t IRFujitsuAC::getMode(void) const { return _.Mode; } /// @note Not all models support all possible swing modes. void IRFujitsuAC::setSwing(const uint8_t swingMode) { _.Swing = swingMode; + _rawstatemodified = true; switch (_model) { // No Horizontal support. case fujitsu_ac_remote_model_t::ARDB1: @@ -531,14 +553,13 @@ void IRFujitsuAC::setSwing(const uint8_t swingMode) { /// Get the requested swing operation mode of the A/C unit. /// @return The contents of the swing state/mode. -uint8_t IRFujitsuAC::getSwing(void) const { - return _.Swing; -} +uint8_t IRFujitsuAC::getSwing(void) const { return _.Swing; } /// Set the Clean mode of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. void IRFujitsuAC::setClean(const bool on) { _.Clean = on; + _rawstatemodified = true; setCmd(kFujitsuAcCmdStayOn); // No special command involved. } @@ -555,6 +576,7 @@ bool IRFujitsuAC::getClean(void) const { /// @param[in] on true, the setting is on. false, the setting is off. void IRFujitsuAC::setFilter(const bool on) { _.Filter = on; + _rawstatemodified = true; setCmd(kFujitsuAcCmdStayOn); // No special command involved. } @@ -563,7 +585,7 @@ void IRFujitsuAC::setFilter(const bool on) { bool IRFujitsuAC::getFilter(void) const { switch (_model) { case fujitsu_ac_remote_model_t::ARRY4: return _.Filter; - default: return false; + default: return false; } } @@ -572,6 +594,7 @@ bool IRFujitsuAC::getFilter(void) const { void IRFujitsuAC::set10CHeat(const bool on) { switch (_model) { // Only selected models support this. + case fujitsu_ac_remote_model_t::ARRAH2E: case fujitsu_ac_remote_model_t::ARREW4E: setClean(on); // 10C Heat uses the same bit as Clean if (on) { @@ -579,6 +602,7 @@ void IRFujitsuAC::set10CHeat(const bool on) { _.Power = true; _.Fan = kFujitsuAcFanAuto; _.Swing = kFujitsuAcSwingOff; + _rawstatemodified = true; } default: break; @@ -589,6 +613,7 @@ void IRFujitsuAC::set10CHeat(const bool on) { /// @return true, the setting is on. false, the setting is off. bool IRFujitsuAC::get10CHeat(void) const { switch (_model) { + case fujitsu_ac_remote_model_t::ARRAH2E: case fujitsu_ac_remote_model_t::ARREW4E: return (_.Clean && _.Power && _.Mode == kFujitsuAcModeFan && _.Fan == kFujitsuAcFanAuto && _.Swing == kFujitsuAcSwingOff); @@ -602,9 +627,8 @@ uint8_t IRFujitsuAC::getTimerType(void) const { switch (_model) { // These models seem to have timer support. case fujitsu_ac_remote_model_t::ARRAH2E: - case fujitsu_ac_remote_model_t::ARREB1E: - return _.TimerType; - default: return kFujitsuAcStopTimers; + case fujitsu_ac_remote_model_t::ARREB1E: return _.TimerType; + default: return kFujitsuAcStopTimers; } } @@ -620,6 +644,7 @@ void IRFujitsuAC::setTimerType(const uint8_t timertype) { break; default: _.TimerType = kFujitsuAcStopTimers; } + _rawstatemodified = true; } /// Get the On Timer setting of the A/C. @@ -634,6 +659,7 @@ uint16_t IRFujitsuAC::getOnTimer(void) const { /// @param[in] nr_mins Nr. of minutes to set the timer to. 0 means disabled. void IRFujitsuAC::setOnTimer(const uint16_t nr_mins) { _.OnTimer = std::min(kFujitsuAcTimerMax, nr_mins); // Bounds check. + _rawstatemodified = true; if (_.OnTimer) { _.TimerType = kFujitsuAcOnTimer; } else if (getTimerType() == kFujitsuAcOnTimer) { @@ -646,10 +672,8 @@ void IRFujitsuAC::setOnTimer(const uint16_t nr_mins) { uint16_t IRFujitsuAC::getOffSleepTimer(void) const { switch (getTimerType()) { case kFujitsuAcOffTimer: - case kFujitsuAcSleepTimer: - return _.OffTimer; - default: - return 0; + case kFujitsuAcSleepTimer: return _.OffTimer; + default: return 0; } } @@ -657,12 +681,13 @@ uint16_t IRFujitsuAC::getOffSleepTimer(void) const { /// @param[in] nr_mins Nr. of minutes to set the timer to. 0 means disabled. inline void IRFujitsuAC::setOffSleepTimer(const uint16_t nr_mins) { _.OffTimer = std::min(kFujitsuAcTimerMax, nr_mins); // Bounds check. + _rawstatemodified = true; } /// Set the Off Timer time for the A/C. /// @param[in] nr_mins Nr. of minutes to set the timer to. 0 means disabled. void IRFujitsuAC::setOffTimer(const uint16_t nr_mins) { - setOffSleepTimer(nr_mins); + setOffSleepTimer(nr_mins); // This will also set _rawstatemodified to true. if (nr_mins) _.TimerType = kFujitsuAcOffTimer; else if (getTimerType() != kFujitsuAcOnTimer) @@ -672,7 +697,7 @@ void IRFujitsuAC::setOffTimer(const uint16_t nr_mins) { /// Set the Sleep Timer time for the A/C. /// @param[in] nr_mins Nr. of minutes to set the timer to. 0 means disabled. void IRFujitsuAC::setSleepTimer(const uint16_t nr_mins) { - setOffSleepTimer(nr_mins); + setOffSleepTimer(nr_mins); // This will also set _rawstatemodified to true. if (nr_mins) _.TimerType = kFujitsuAcSleepTimer; else if (getTimerType() != kFujitsuAcOnTimer) @@ -706,7 +731,10 @@ bool IRFujitsuAC::validChecksum(uint8_t state[], const uint16_t length) { /// Set the device's remote ID number. /// @param[in] num The ID for the remote. Valid number range is 0 to 3. -void IRFujitsuAC::setId(const uint8_t num) { _.Id = num; } +void IRFujitsuAC::setId(const uint8_t num) { + _.Id = num; + _rawstatemodified = true; +} /// Get the current device's remote ID number. /// @return The current device's remote ID number. @@ -714,7 +742,10 @@ uint8_t IRFujitsuAC::getId(void) const { return _.Id; } /// Set the Temperature units for the A/C. /// @param[in] on true, use Celsius. false, use Fahrenheit. -void IRFujitsuAC::setCelsius(const bool on) { _.Fahrenheit = !on; } +void IRFujitsuAC::setCelsius(const bool on) { + _.Fahrenheit = !on; + _rawstatemodified = true; +} /// Get the Clean mode status of the A/C. /// @return true, the setting is on. false, the setting is off. @@ -774,35 +805,45 @@ stdAc::fanspeed_t IRFujitsuAC::toCommonFanSpeed(const uint8_t speed) { } /// Convert the current internal state into its stdAc::state_t equivalent. +/// @param[in] prev Ptr to a previous state. /// @return The stdAc equivalent of the native settings. -stdAc::state_t IRFujitsuAC::toCommon(void) const { +stdAc::state_t IRFujitsuAC::toCommon(const stdAc::state_t *prev) { stdAc::state_t result{}; + if (prev != NULL) result = *prev; result.protocol = decode_type_t::FUJITSU_AC; + checkSum(); result.model = _model; result.power = getPower(); - result.mode = toCommonMode(_.Mode); - result.celsius = getCelsius(); - result.degrees = getTemp(); - result.fanspeed = toCommonFanSpeed(_.Fan); - uint8_t swing = _.Swing; - switch (result.model) { - case fujitsu_ac_remote_model_t::ARREB1E: - case fujitsu_ac_remote_model_t::ARRAH2E: - case fujitsu_ac_remote_model_t::ARRY4: - result.clean = _.Clean; - result.filter = _.Filter; - result.swingv = (swing & kFujitsuAcSwingVert) ? stdAc::swingv_t::kAuto - : stdAc::swingv_t::kOff; - result.swingh = (swing & kFujitsuAcSwingHoriz) ? stdAc::swingh_t::kAuto - : stdAc::swingh_t::kOff; - break; - case fujitsu_ac_remote_model_t::ARDB1: - case fujitsu_ac_remote_model_t::ARJW2: - default: - result.swingv = stdAc::swingv_t::kOff; - result.swingh = stdAc::swingh_t::kOff; + // Only update these settings if it is a long message, or we have no previous + // state info for those settings. + if (isLongCode() || prev == NULL) { + result.mode = toCommonMode(_.Mode); + result.celsius = getCelsius(); + { + const float minHeat = result.celsius ? kFujitsuAcMinHeat + : kFujitsuAcMinHeatF; + result.degrees = get10CHeat() ? minHeat : getTemp(); + } + result.fanspeed = toCommonFanSpeed(_.Fan); + uint8_t swing = _.Swing; + switch (result.model) { + case fujitsu_ac_remote_model_t::ARREB1E: + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARRY4: + result.clean = _.Clean; + result.filter = _.Filter; + result.swingv = (swing & kFujitsuAcSwingVert) ? stdAc::swingv_t::kAuto + : stdAc::swingv_t::kOff; + result.swingh = (swing & kFujitsuAcSwingHoriz) ? stdAc::swingh_t::kAuto + : stdAc::swingh_t::kOff; + break; + case fujitsu_ac_remote_model_t::ARDB1: + case fujitsu_ac_remote_model_t::ARJW2: + default: + result.swingv = stdAc::swingv_t::kOff; + result.swingh = stdAc::swingh_t::kOff; + } } - result.quiet = _.Fan == kFujitsuAcFanQuiet; result.turbo = _cmd == kFujitsuAcCmdPowerful; result.econo = _cmd == kFujitsuAcCmdEcono; @@ -820,54 +861,67 @@ stdAc::state_t IRFujitsuAC::toCommon(void) const { /// @return A human readable string. String IRFujitsuAC::toString(void) const { String result = ""; - result.reserve(100); // Reserve some heap for the string to reduce fragging. + result.reserve(180); // Reserve some heap for the string to reduce fragging. fujitsu_ac_remote_model_t model = _model; result += addModelToString(decode_type_t::FUJITSU_AC, model, false); result += addIntToString(_.Id, kIdStr); result += addBoolToString(getPower(), kPowerStr); - result += addModeToString(_.Mode, kFujitsuAcModeAuto, kFujitsuAcModeCool, - kFujitsuAcModeHeat, kFujitsuAcModeDry, - kFujitsuAcModeFan); - result += addTempFloatToString(getTemp(), getCelsius()); - result += addFanToString(_.Fan, kFujitsuAcFanHigh, kFujitsuAcFanLow, - kFujitsuAcFanAuto, kFujitsuAcFanQuiet, - kFujitsuAcFanMed); - switch (model) { - // These models have no internal swing, clean. or filter state. - case fujitsu_ac_remote_model_t::ARDB1: - case fujitsu_ac_remote_model_t::ARJW2: - break; - // These models have Clean & Filter, plus Swing (via fall thru) - case fujitsu_ac_remote_model_t::ARRAH2E: - case fujitsu_ac_remote_model_t::ARREB1E: - case fujitsu_ac_remote_model_t::ARRY4: - result += addBoolToString(getClean(), kCleanStr); - result += addBoolToString(getFilter(), kFilterStr); - // FALL THRU - default: // e.g. ARREW4E - if (model == fujitsu_ac_remote_model_t::ARREW4E) - result += addBoolToString(get10CHeat(), k10CHeatStr); - result += addIntToString(_.Swing, kSwingStr); - result += kSpaceLBraceStr; - switch (_.Swing) { - case kFujitsuAcSwingOff: - result += kOffStr; - break; - case kFujitsuAcSwingVert: - result += kSwingVStr; - break; - case kFujitsuAcSwingHoriz: - result += kSwingHStr; - break; - case kFujitsuAcSwingBoth: - result += kSwingVStr; - result += '+'; - result += kSwingHStr; - break; - default: - result += kUnknownStr; - } - result += ')'; + if (_rawstatemodified || isLongCode()) { + result += addModeToString(_.Mode, kFujitsuAcModeAuto, kFujitsuAcModeCool, + kFujitsuAcModeHeat, kFujitsuAcModeDry, + kFujitsuAcModeFan); + { + const bool isCelsius = getCelsius(); + const float minHeat = isCelsius ? kFujitsuAcMinHeat : kFujitsuAcMinHeatF; + result += addTempFloatToString(get10CHeat() ? minHeat : getTemp(), + isCelsius); + } + result += addFanToString(_.Fan, kFujitsuAcFanHigh, kFujitsuAcFanLow, + kFujitsuAcFanAuto, kFujitsuAcFanQuiet, + kFujitsuAcFanMed); + switch (model) { + // These models have no internal swing, clean. or filter state. + case fujitsu_ac_remote_model_t::ARDB1: + case fujitsu_ac_remote_model_t::ARJW2: + break; + // These models have Clean & Filter, plus Swing (via fall thru) + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARREB1E: + case fujitsu_ac_remote_model_t::ARRY4: + result += addBoolToString(getClean(), kCleanStr); + result += addBoolToString(getFilter(), kFilterStr); + // FALL THRU + default: // e.g. ARREW4E + switch (model) { + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARREW4E: + result += addBoolToString(get10CHeat(), k10CHeatStr); + break; + default: + break; + } + result += addIntToString(_.Swing, kSwingStr); + result += kSpaceLBraceStr; + switch (_.Swing) { + case kFujitsuAcSwingOff: + result += kOffStr; + break; + case kFujitsuAcSwingVert: + result += kSwingVStr; + break; + case kFujitsuAcSwingHoriz: + result += kSwingHStr; + break; + case kFujitsuAcSwingBoth: + result += kSwingVStr; + result += '+'; + result += kSwingHStr; + break; + default: + result += kUnknownStr; + } + result += ')'; + } } result += kCommaSpaceStr; result += kCommandStr; @@ -902,33 +956,36 @@ String IRFujitsuAC::toString(void) const { default: result += kNAStr; } - uint16_t mins = 0; - String type_str = kTimerStr; - switch (model) { - case fujitsu_ac_remote_model_t::ARREB1E: - case fujitsu_ac_remote_model_t::ARREW4E: - result += addBoolToString(getOutsideQuiet(), kOutsideQuietStr); - // FALL THRU - // These models seem to have timer support. - case fujitsu_ac_remote_model_t::ARRAH2E: - switch (getTimerType()) { - case kFujitsuAcOnTimer: - type_str = kOnTimerStr; - mins = getOnTimer(); - break; - case kFujitsuAcOffTimer: - type_str = kOffTimerStr; - mins = getOffSleepTimer(); - break; - case kFujitsuAcSleepTimer: - type_str = kSleepTimerStr; - mins = getOffSleepTimer(); - break; - } - result += addLabeledString(mins ? minsToString(mins) : kOffStr, type_str); - break; - default: - break; + if (_rawstatemodified || isLongCode()) { + uint16_t mins = 0; + String type_str = kTimerStr; + switch (model) { + case fujitsu_ac_remote_model_t::ARREB1E: + case fujitsu_ac_remote_model_t::ARREW4E: + result += addBoolToString(getOutsideQuiet(), kOutsideQuietStr); + // FALL THRU + // These models seem to have timer support. + case fujitsu_ac_remote_model_t::ARRAH2E: + switch (getTimerType()) { + case kFujitsuAcOnTimer: + type_str = kOnTimerStr; + mins = getOnTimer(); + break; + case kFujitsuAcOffTimer: + type_str = kOffTimerStr; + mins = getOffSleepTimer(); + break; + case kFujitsuAcSleepTimer: + type_str = kSleepTimerStr; + mins = getOffSleepTimer(); + break; + } + result += addLabeledString(mins ? minsToString(mins) : kOffStr, + type_str); + break; + default: + break; + } } return result; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h index 70c0a4cf0..6e2583a0c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h @@ -1,5 +1,5 @@ // Copyright 2017 Jonny Graham -// Copyright 2018-2021 David Conran +// Copyright 2018-2022 David Conran // Copyright 2021 siriuslzx /// @file @@ -30,6 +30,7 @@ // Brand: Fujitsu, Model: AR-DL10 remote (ARDB1) // Brand: Fujitsu, Model: ASU30C1 A/C (ARDB1) // Brand: Fujitsu, Model: AR-RAH1U remote (ARREB1E) +// Brand: Fujitsu, Model: AR-RAH2U remote (ARRAH2E) // Brand: Fujitsu, Model: ASU12RLF A/C (ARREB1E) // Brand: Fujitsu, Model: AR-REW4E remote (ARREW4E) // Brand: Fujitsu, Model: ASYG09KETA-B A/C (ARREW4E) @@ -37,6 +38,9 @@ // Brand: Fujitsu, Model: ASTG09K A/C (ARREW4E) // Brand: Fujitsu, Model: ASTG18K A/C (ARREW4E) // Brand: Fujitsu, Model: AR-REW1E remote (ARREW4E) +// Brand: Fujitsu, Model: AR-REG1U remote (ARRAH2E) +// Brand: OGeneral, Model: AR-RCL1E remote (ARRAH2E) +// Brand: Fujitsu General, Model: AR-JW17 remote (ARDB1) #ifndef IR_FUJITSU_H_ #define IR_FUJITSU_H_ @@ -128,9 +132,11 @@ const uint8_t kFujitsuAcFanMed = 0x02; const uint8_t kFujitsuAcFanLow = 0x03; const uint8_t kFujitsuAcFanQuiet = 0x04; +const float kFujitsuAcMinHeat = 10; // 10C const float kFujitsuAcMinTemp = 16; // 16C const float kFujitsuAcMaxTemp = 30; // 30C const uint8_t kFujitsuAcTempOffsetC = kFujitsuAcMinTemp; +const float kFujitsuAcMinHeatF = 50; // 50F const float kFujitsuAcMinTempF = 60; // 60F const float kFujitsuAcMaxTempF = 88; // 88F const uint8_t kFujitsuAcTempOffsetF = 44; @@ -206,6 +212,7 @@ class IRFujitsuAC { bool setRaw(const uint8_t newState[], const uint16_t length); uint8_t getStateLength(void); static bool validChecksum(uint8_t* state, const uint16_t length); + bool isLongCode(void) const; void setPower(const bool on); void off(void); void on(void); @@ -233,7 +240,7 @@ class IRFujitsuAC { static uint8_t convertFan(stdAc::fanspeed_t speed); static stdAc::opmode_t toCommonMode(const uint8_t mode); static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); - stdAc::state_t toCommon(void) const; + stdAc::state_t toCommon(const stdAc::state_t *prev = NULL); String toString(void) const; #ifndef UNIT_TEST @@ -249,6 +256,7 @@ class IRFujitsuAC { fujitsu_ac_remote_model_t _model; uint8_t _state_length; uint8_t _state_length_short; + bool _rawstatemodified; void checkSum(void); bool updateUseLongOrShort(void); void buildFromState(const uint16_t length); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp index 16789b99b..ead7178e3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp @@ -162,6 +162,7 @@ void IRGreeAC::setRaw(const uint8_t new_code[]) { else _model = gree_ac_remote_model_t::YBOFB; } + if (_.Mode == kGreeEcono) _model = gree_ac_remote_model_t::YX1FSF; } /// Calculate and set the checksum values for the internal state. @@ -186,7 +187,8 @@ bool IRGreeAC::validChecksum(const uint8_t state[], const uint16_t length) { void IRGreeAC::setModel(const gree_ac_remote_model_t model) { switch (model) { case gree_ac_remote_model_t::YAW1F: - case gree_ac_remote_model_t::YBOFB: _model = model; break; + case gree_ac_remote_model_t::YBOFB: + case gree_ac_remote_model_t::YX1FSF: _model = model; break; default: _model = gree_ac_remote_model_t::YAW1F; } } @@ -291,6 +293,7 @@ void IRGreeAC::setMode(const uint8_t new_mode) { case kGreeDry: setFan(1); break; case kGreeCool: case kGreeFan: + case kGreeEcono: case kGreeHeat: break; // If we get an unexpected mode, default to AUTO. default: mode = kGreeAuto; @@ -352,11 +355,17 @@ bool IRGreeAC::getTurbo(void) const { return _.Turbo; } /// Set the Econo setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setEcono(const bool on) { _.Econo = on; } +void IRGreeAC::setEcono(const bool on) { + _.Econo = on; + if (on && getModel() == gree_ac_remote_model_t::YX1FSF) + setMode(kGreeEcono); +} /// Get the Econo setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getEcono(void) const { return _.Econo; } +bool IRGreeAC::getEcono(void) const { + return _.Econo || getMode() == kGreeEcono; +} /// Set the Vertical Swing mode of the A/C. /// @param[in] automatic Do we use the automatic setting? @@ -589,7 +598,7 @@ stdAc::state_t IRGreeAC::toCommon(void) { result.swingv = toCommonSwingV(_.SwingV); result.swingh = toCommonSwingH(_.SwingH); result.turbo = _.Turbo; - result.econo = _.Econo; + result.econo = getEcono(); result.light = _.Light; result.clean = _.Xfan; result.sleep = _.Sleep ? 0 : -1; @@ -608,8 +617,15 @@ String IRGreeAC::toString(void) { result.reserve(220); // Reserve some heap for the string to reduce fragging. result += addModelToString(decode_type_t::GREE, _model, false); result += addBoolToString(_.Power, kPowerStr); - result += addModeToString(_.Mode, kGreeAuto, kGreeCool, kGreeHeat, - kGreeDry, kGreeFan); + if (_model == gree_ac_remote_model_t::YX1FSF && _.Mode == kGreeEcono) { + result += addIntToString(_.Mode, kModeStr); + result += kSpaceLBraceStr; + result += kEconoStr; + result += ')'; + } else { + result += addModeToString(_.Mode, kGreeAuto, kGreeCool, kGreeHeat, + kGreeDry, kGreeFan); + } result += addTempToString(getTemp(), !_.UseFahrenheit); result += addFanToString(_.Fan, kGreeFanMax, kGreeFanMin, kGreeFanAuto, kGreeFanAuto, kGreeFanMed); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h index be5ac31ce..eb9d4a00c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h @@ -1,9 +1,10 @@ -// Copyright 2016 David Conran +// Copyright 2016-2022 David Conran /// @file /// @brief Support for Gree A/C protocols. /// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1508 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1821 // Supports: // Brand: Ultimate, Model: Heat Pump @@ -15,6 +16,7 @@ // Brand: Gree, Model: YAA1FBF remote // Brand: Gree, Model: YB1F2F remote // Brand: Gree, Model: YAN1F1 remote +// Brand: Gree, Model: YX1F2F remote (YX1FSF) // Brand: Gree, Model: VIR09HP115V1AH A/C // Brand: Gree, Model: VIR12HP230V1AH A/C // Brand: Amana, Model: PBC093G00CC A/C @@ -23,6 +25,7 @@ // Brand: Cooper & Hunter, Model: CH-S09FTXG A/C // Brand: Vailland, Model: YACIFB remote // Brand: Vailland, Model: VAI5-035WNI A/C +// Brand: Soleus Air, Model: window A/C (YX1FSF) #ifndef IR_GREE_H_ #define IR_GREE_H_ @@ -86,11 +89,12 @@ union GreeProtocol{ // Constants -const uint8_t kGreeAuto = 0; -const uint8_t kGreeCool = 1; -const uint8_t kGreeDry = 2; -const uint8_t kGreeFan = 3; -const uint8_t kGreeHeat = 4; +const uint8_t kGreeAuto = 0; +const uint8_t kGreeCool = 1; +const uint8_t kGreeDry = 2; +const uint8_t kGreeFan = 3; +const uint8_t kGreeHeat = 4; +const uint8_t kGreeEcono = 5; const uint8_t kGreeFanAuto = 0; const uint8_t kGreeFanMin = 1; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp index e3a5ed8a1..a60828282 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp @@ -46,7 +46,8 @@ using irutils::minsToString; _.x##Mins = mins % 60;\ } while (0) -#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) /// Send a Haier A/C formatted message. (HSU07-HEA03 remote) /// Status: STABLE / Known to be working. /// @param[in] data The message to be sent. @@ -93,6 +94,18 @@ void IRsend::sendHaierAC176(const unsigned char data[], const uint16_t nbytes, } #endif // SEND_HAIER_AC176 +#if SEND_HAIER_AC160 +/// Send a Haier 160 bit remote A/C formatted message. +/// Status: STABLE / Known to be working. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +void IRsend::sendHaierAC160(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes >= kHaierAC160StateLength) sendHaierAC(data, nbytes, repeat); +} +#endif // SEND_HAIER_AC160 + /// Class constructor /// @param[in] pin GPIO to be used when sending. /// @param[in] inverted Is the output signal to be inverted? @@ -568,7 +581,7 @@ void IRHaierAC176::checksum(void) { /// @return true, if the state has a valid checksum. Otherwise, false. bool IRHaierAC176::validChecksum(const uint8_t state[], const uint16_t length) { if (length < 2) return false; // 1 byte of data can't have a checksum. - if (length < kHaierAC176StateLength) { // Is it too short? + if (length < kHaierAC160StateLength) { // Is it too short? // Then it is just a checksum of the whole thing. return (state[length - 1] == sumBytes(state, length - 1)); } else { // It is long enough for two checksums. @@ -1323,7 +1336,8 @@ bool IRHaierACYRW02::validChecksum(const uint8_t state[], } // End of IRHaierACYRW02 class. -#if (DECODE_HAIER_AC || DECODE_HAIER_AC_YRW02) +#if (DECODE_HAIER_AC || DECODE_HAIER_AC_YRW02 || DECODE_HAIER_AC160 || \ + DECODE_HAIER_AC176) /// Decode the supplied Haier HSU07-HEA03 remote message. /// Status: STABLE / Known to be working. /// @param[in,out] results Ptr to the data to decode & where to store the decode @@ -1435,3 +1449,721 @@ bool IRrecv::decodeHaierAC176(decode_results* results, uint16_t offset, return true; } #endif // DECODE_HAIER_AC176 + +#if DECODE_HAIER_AC160 +/// Decode the supplied Haier 160 bit remote A/C message. +/// Status: STABLE / Known to be working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// 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 A boolean. True if it can decode it, false if it can't. +bool IRrecv::decodeHaierAC160(decode_results* results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict) { + if (nbits != kHaierAC160Bits) + return false; // Not strictly a HAIER_AC160 message. + } + + // The protocol is almost exactly the same as HAIER_AC + if (!decodeHaierAC(results, offset, nbits, false)) return false; + + // Compliance + if (strict) { + if (!IRHaierAC176::validChecksum(results->state, nbits / 8)) return false; + } + + // Success + // It looks correct, but we haven't check the checksum etc. + results->decode_type = HAIER_AC160; + return true; +} +#endif // DECODE_HAIER_AC160 + + +/// 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? +IRHaierAC160::IRHaierAC160(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +/// Set up hardware to be able to send a message. +void IRHaierAC160::begin(void) { _irsend.begin(); } + +#if SEND_HAIER_AC160 +/// Send the current internal state as an IR message. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRHaierAC160::send(const uint16_t repeat) { + _irsend.sendHaierAC160(getRaw(), kHaierAC160StateLength, repeat); +} +#endif // SEND_HAIER_AC160 + +/// Calculate and set the checksum values for the internal state. +void IRHaierAC160::checksum(void) { + _.Sum = sumBytes(_.raw, kHaierACYRW02StateLength - 1); + _.Sum2 = sumBytes(_.raw + kHaierACYRW02StateLength, + kHaierAC160StateLength - kHaierACYRW02StateLength - 1); +} + +/// Reset the internal state to a fixed known good state. +void IRHaierAC160::stateReset(void) { + std::memset(_.raw, 0, sizeof _.raw); + _.Model = kHaierAcYrw02ModelA; + _.Prefix = kHaierAc160Prefix; + _.Temp = kHaierAcYrw02DefTempC - kHaierAcYrw02MinTempC; + setClean(false); + setFan(kHaierAcYrw02FanAuto); + _.Power = true; + _.Button = kHaierAcYrw02ButtonPower; +} + +/// Get a PTR to the internal state/code for this protocol. +/// @return PTR to a code for this protocol based on the current internal state. +uint8_t* IRHaierAC160::getRaw(void) { + checksum(); + return _.raw; +} + +/// Set the internal state from a valid code for this protocol. +/// @param[in] new_code A valid code for this protocol. +void IRHaierAC160::setRaw(const uint8_t new_code[]) { + memcpy(_.raw, new_code, kHaierAC160StateLength); +} + +/// Set the Button/Command setting of the A/C. +/// @param[in] button The value of the button/command that was pressed. +void IRHaierAC160::setButton(uint8_t button) { + switch (button) { + case kHaierAcYrw02ButtonTempUp: + case kHaierAcYrw02ButtonTempDown: + case kHaierAcYrw02ButtonSwingV: + case kHaierAcYrw02ButtonSwingH: + case kHaierAcYrw02ButtonFan: + case kHaierAcYrw02ButtonPower: + case kHaierAcYrw02ButtonMode: + case kHaierAcYrw02ButtonHealth: + case kHaierAcYrw02ButtonTurbo: + case kHaierAcYrw02ButtonSleep: + case kHaierAcYrw02ButtonLock: + case kHaierAc160ButtonClean: + case kHaierAcYrw02ButtonCFAB: + _.Button = button; + } +} + +/// Get the Button/Command setting of the A/C. +/// @return The value of the button/command that was pressed. +uint8_t IRHaierAC160::getButton(void) const { return _.Button; } + +/// Set the operating mode of the A/C. +/// @param[in] mode The desired operating mode. +void IRHaierAC160::setMode(uint8_t mode) { + switch (mode) { + case kHaierAcYrw02Auto: + case kHaierAcYrw02Dry: + case kHaierAcYrw02Fan: + // Turbo & Quiet is only available in Cool/Heat mode. + _.Turbo = false; + _.Quiet = false; + // FALL-THRU + case kHaierAcYrw02Cool: + case kHaierAcYrw02Heat: + _.Button = kHaierAcYrw02ButtonMode; + _.Mode = mode; + break; + default: + setMode(kHaierAcYrw02Auto); // Unexpected, default to auto mode. + } + _.AuxHeating = (_.Mode == kHaierAcYrw02Heat); // Set only if heat mode. +} + +/// Get the operating mode setting of the A/C. +/// @return The current operating mode setting. +uint8_t IRHaierAC160::getMode(void) const { return _.Mode; } + +/// Set the default temperature units to use. +/// @param[in] on Use Fahrenheit as the units. +/// true is Fahrenheit, false is Celsius. +void IRHaierAC160::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; } + +/// Get the default temperature units in use. +/// @return true is Fahrenheit, false is Celsius. +bool IRHaierAC160::getUseFahrenheit(void) const { return _.UseFahrenheit; } + +/// Set the temperature. +/// @param[in] degree The temperature in degrees. +/// @param[in] fahrenheit Use units of Fahrenheit and set that as units used. +void IRHaierAC160::setTemp(const uint8_t degree, const bool fahrenheit) { + uint8_t old_temp = getTemp(); + if (old_temp == degree) return; + + if (_.UseFahrenheit == fahrenheit) { + if (old_temp > degree) + _.Button = kHaierAcYrw02ButtonTempDown; + else + _.Button = kHaierAcYrw02ButtonTempUp; + } else { + _.Button = kHaierAcYrw02ButtonCFAB; + } + _.UseFahrenheit = fahrenheit; + + uint8_t temp = degree; + if (fahrenheit) { + if (temp < kHaierAcYrw02MinTempF) + temp = kHaierAcYrw02MinTempF; + else if (temp > kHaierAcYrw02MaxTempF) + temp = kHaierAcYrw02MaxTempF; + if (degree >= 77) { temp++; } + if (degree >= 79) { temp++; } + // See at IRHaierAC160::getTemp() comments for clarification + _.ExtraDegreeF = temp % 2; + _.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1; + } else { + if (temp < kHaierAcYrw02MinTempC) + temp = kHaierAcYrw02MinTempC; + else if (temp > kHaierAcYrw02MaxTempC) + temp = kHaierAcYrw02MaxTempC; + _.Temp = temp - kHaierAcYrw02MinTempC; + } +} + +/// Get the current temperature setting. +/// 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; } + uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF; + // The way of coding the temperature in degree Fahrenheit is + // kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example + // Temp = 0b0011, ExtraDegreeF = 0b1, temperature is 60 + 3*2 + 1 = 67F + // But around 78F there is unconsistency, see table below + // + // | Fahrenheit | Temp | ExtraDegreeF | + // | 60F | 0b0000 | 0b0 | + // | 61F | 0b0000 | 0b1 | + // | 62F | 0b0001 | 0b0 | + // | 63F | 0b0001 | 0b1 | + // | 64F | 0b0010 | 0b0 | + // | 65F | 0b0010 | 0b1 | + // | 66F | 0b0011 | 0b0 | + // | 67F | 0b0011 | 0b1 | + // | 68F | 0b0100 | 0b0 | + // | 69F | 0b0100 | 0b1 | + // | 70F | 0b0101 | 0b0 | + // | 71F | 0b0101 | 0b1 | + // | 72F | 0b0110 | 0b0 | + // | 73F | 0b0110 | 0b1 | + // | 74F | 0b0111 | 0b0 | + // | 75F | 0b0111 | 0b1 | + // | 76F | 0b1000 | 0b0 | + // | Not Used | 0b1000 | 0b1 | + // | 77F | 0b1001 | 0b0 | + // | Not Used | 0b1001 | 0b1 | + // | 78F | 0b1010 | 0b0 | + // | 79F | 0b1010 | 0b1 | + // | 80F | 0b1011 | 0b0 | + // | 81F | 0b1011 | 0b1 | + // | 82F | 0b1100 | 0b0 | + // | 83F | 0b1100 | 0b1 | + // | 84F | 0b1101 | 0b0 | + // | 86F | 0b1110 | 0b0 | + // | 85F | 0b1101 | 0b1 | + if (degree >= 77) { degree--; } + if (degree >= 79) { degree--; } + return degree; +} + +/// Set the Clean setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC160::setClean(const bool on) { + _.Button = kHaierAc160ButtonClean; + _.Clean = on; + _.Clean2 = on; +} + +/// Get the Clean setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC160::getClean(void) const { return _.Clean && _.Clean2; } + +/// Get the value of the current power setting. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC160::getPower(void) const { return _.Power; } + +/// Change the power setting. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC160::setPower(const bool on) { + _.Button = kHaierAcYrw02ButtonPower; + _.Power = on; +} + +/// Change the power setting to On. +void IRHaierAC160::on(void) { setPower(true); } + +/// Change the power setting to Off. +void IRHaierAC160::off(void) { setPower(false); } + +/// Get the Sleep setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC160::getSleep(void) const { return _.Sleep; } + +/// Set the Sleep setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC160::setSleep(const bool on) { + _.Button = kHaierAcYrw02ButtonSleep; + _.Sleep = on; +} + +/// Get the Turbo setting of the A/C. +/// @return The current turbo setting. +bool IRHaierAC160::getTurbo(void) const { return _.Turbo; } + +/// Set the Turbo setting of the A/C. +/// @param[in] on The desired turbo setting. +/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode +void IRHaierAC160::setTurbo(const bool on) { + switch (getMode()) { + case kHaierAcYrw02Cool: + case kHaierAcYrw02Heat: + _.Turbo = on; + _.Button = kHaierAcYrw02ButtonTurbo; + if (on) _.Quiet = false; + } +} + +/// Get the Quiet setting of the A/C. +/// @return The current Quiet setting. +bool IRHaierAC160::getQuiet(void) const { return _.Quiet; } + +/// Set the Quiet setting of the A/C. +/// @param[in] on The desired Quiet setting. +/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode +void IRHaierAC160::setQuiet(const bool on) { + switch (getMode()) { + case kHaierAcYrw02Cool: + case kHaierAcYrw02Heat: + _.Quiet = on; + _.Button = kHaierAcYrw02ButtonTurbo; + if (on) _.Turbo = false; + } +} + +/// Get the value of the Aux Heating setting. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC160::getAuxHeating(void) const { return _.AuxHeating; } + +/// Change the Aux Heating setting. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC160::setAuxHeating(const bool on) { + _.Button = kHaierAc160ButtonAuxHeating; + _.AuxHeating = on; +} + +/// Get the value of the current Light toggle setting. +/// @return true, the setting is on. false, the setting is off. +/// @note This setting seems to be controlled just by the button setting. +bool IRHaierAC160::getLightToggle(void) const { + return _.Button == kHaierAc160ButtonLight; +} + +/// Set the Light Toggle setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +/// @note This setting seems to be controlled just by the button setting. +void IRHaierAC160::setLightToggle(const bool on) { + _.Button = on ? kHaierAc160ButtonLight : kHaierAcYrw02ButtonPower; +} + +/// Get the current fan speed setting. +/// @return The current fan speed. +uint8_t IRHaierAC160::getFan(void) const { return _.Fan; } + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +void IRHaierAC160::setFan(uint8_t speed) { + switch (speed) { + case kHaierAcYrw02FanLow: + case kHaierAcYrw02FanMed: + case kHaierAcYrw02FanHigh: + case kHaierAcYrw02FanAuto: + _.Fan = speed; + _.Fan2 = (speed == kHaierAcYrw02FanAuto) ? 0 : speed; + _.Button = kHaierAcYrw02ButtonFan; + } +} + +/// Set the Health (filter) setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC160::setHealth(const bool on) { + _.Button = kHaierAcYrw02ButtonHealth; + _.Health = on; +} + +/// Get the Health (filter) setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC160::getHealth(void) const { return _.Health; } + +/// Get the Vertical Swing position setting of the A/C. +/// @return The native position/mode. +uint8_t IRHaierAC160::getSwingV(void) const { return _.SwingV; } + +/// Set the Vertical Swing mode of the A/C. +/// @param[in] pos The position/mode to set the vanes to. +void IRHaierAC160::setSwingV(const uint8_t pos) { + switch (pos) { + case kHaierAc160SwingVOff: + case kHaierAc160SwingVAuto: + case kHaierAc160SwingVTop: + case kHaierAc160SwingVHighest: + case kHaierAc160SwingVHigh: + case kHaierAc160SwingVMiddle: + case kHaierAc160SwingVLow: + case kHaierAc160SwingVLowest: + _.Button = kHaierAcYrw02ButtonSwingV; + _.SwingV = pos; + break; + default: return; // If in doubt, Do nothing. + } +} + +/// Set the Timer operating mode. +/// @param[in] mode The timer mode to use. +void IRHaierAC160::setTimerMode(const uint8_t mode) { + _.TimerMode = (mode > kHaierAcYrw02OffThenOnTimer) ? kHaierAcYrw02NoTimers + : mode; + switch (_.TimerMode) { + case kHaierAcYrw02NoTimers: + setOnTimer(0); // Disable the On timer. + setOffTimer(0); // Disable the Off timer. + break; + case kHaierAcYrw02OffTimer: + setOnTimer(0); // Disable the On timer. + break; + case kHaierAcYrw02OnTimer: + setOffTimer(0); // Disable the Off timer. + break; + } +} + +/// Get the Timer operating mode. +/// @return The mode of the timer is currently configured to. +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); + _.OnTimerHrs = nr_mins / 60; + _.OnTimerMins = nr_mins % 60; + + const bool enabled = (nr_mins > 0); + uint8_t mode = getTimerMode(); + switch (mode) { + case kHaierAcYrw02OffTimer: + mode = enabled ? kHaierAcYrw02OffThenOnTimer : mode; + break; + case kHaierAcYrw02OnThenOffTimer: + case kHaierAcYrw02OffThenOnTimer: + mode = enabled ? kHaierAcYrw02OffThenOnTimer : kHaierAcYrw02OffTimer; + break; + default: + // Enable/Disable the On timer for the simple case. + mode = enabled << 1; + } + _.TimerMode = mode; +} + +/// Get the number of minutes of the On Timer setting. +/// @return Nr of minutes. +uint16_t IRHaierAC160::getOnTimer(void) const { + return _.OnTimerHrs * 60 + _.OnTimerMins; +} + +/// 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); + _.OffTimerHrs = nr_mins / 60; + _.OffTimerMins = nr_mins % 60; + + const bool enabled = (nr_mins > 0); + uint8_t mode = getTimerMode(); + switch (mode) { + case kHaierAcYrw02OnTimer: + mode = enabled ? kHaierAcYrw02OnThenOffTimer : mode; + break; + case kHaierAcYrw02OnThenOffTimer: + case kHaierAcYrw02OffThenOnTimer: + mode = enabled ? kHaierAcYrw02OnThenOffTimer : kHaierAcYrw02OnTimer; + break; + default: + // Enable/Disable the Off timer for the simple case. + mode = enabled; + } + _.TimerMode = mode; +} + +/// Get the number of minutes of the Off Timer setting. +/// @return Nr of minutes. +uint16_t IRHaierAC160::getOffTimer(void) const { + return _.OffTimerHrs * 60 + _.OffTimerMins; +} + +/// Get the Lock setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC160::getLock(void) const { return _.Lock; } + +/// Set the Lock setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC160::setLock(const bool on) { + _.Button = kHaierAcYrw02ButtonLock; + _.Lock = on; +} + +/// Convert a stdAc::opmode_t enum into its native mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRHaierAC160::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kHaierAcYrw02Cool; + case stdAc::opmode_t::kHeat: return kHaierAcYrw02Heat; + case stdAc::opmode_t::kDry: return kHaierAcYrw02Dry; + case stdAc::opmode_t::kFan: return kHaierAcYrw02Fan; + default: return kHaierAcYrw02Auto; + } +} + +/// Convert a stdAc::fanspeed_t enum into it's native speed. +/// @param[in] speed The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRHaierAC160::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: return kHaierAcYrw02FanLow; + case stdAc::fanspeed_t::kMedium: return kHaierAcYrw02FanMed; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: return kHaierAcYrw02FanHigh; + default: return kHaierAcYrw02FanAuto; + } +} + +/// Convert a stdAc::swingv_t enum into it's native setting. +/// @param[in] position The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRHaierAC160::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: return kHaierAc160SwingVTop; + case stdAc::swingv_t::kHigh: return kHaierAc160SwingVHigh; + case stdAc::swingv_t::kMiddle: return kHaierAc160SwingVMiddle; + case stdAc::swingv_t::kLow: return kHaierAc160SwingVLow; + case stdAc::swingv_t::kLowest: return kHaierAc160SwingVLowest; + case stdAc::swingv_t::kOff: return kHaierAc160SwingVOff; + default: return kHaierAc160SwingVAuto; + } +} + +/// Convert a native mode into its stdAc equivalent. +/// @param[in] mode The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::opmode_t IRHaierAC160::toCommonMode(const uint8_t mode) { + switch (mode) { + case kHaierAcYrw02Cool: return stdAc::opmode_t::kCool; + case kHaierAcYrw02Heat: return stdAc::opmode_t::kHeat; + case kHaierAcYrw02Dry: return stdAc::opmode_t::kDry; + case kHaierAcYrw02Fan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +/// Convert a native fan speed into its stdAc equivalent. +/// @param[in] speed The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::fanspeed_t IRHaierAC160::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kHaierAcYrw02FanHigh: return stdAc::fanspeed_t::kMax; + case kHaierAcYrw02FanMed: return stdAc::fanspeed_t::kMedium; + case kHaierAcYrw02FanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; + } +} + +/// Convert a stdAc::swingv_t enum into it's native setting. +/// @param[in] pos The enum to be converted. +/// @return The native equivalent of the enum. +stdAc::swingv_t IRHaierAC160::toCommonSwingV(const uint8_t pos) { + switch (pos) { + case kHaierAc160SwingVTop: + case kHaierAc160SwingVHighest: return stdAc::swingv_t::kHighest; + case kHaierAc160SwingVHigh: return stdAc::swingv_t::kHigh; + case kHaierAc160SwingVMiddle: return stdAc::swingv_t::kMiddle; + case kHaierAc160SwingVLow: return stdAc::swingv_t::kLow; + case kHaierAc160SwingVLowest: return stdAc::swingv_t::kLowest; + case kHaierAc160SwingVOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; + } +} + +/// Convert the current internal state into its stdAc::state_t equivalent. +/// @param[in] prev Ptr to the previous state if required. +/// @return The stdAc equivalent of the native settings. +stdAc::state_t IRHaierAC160::toCommon(const stdAc::state_t *prev) const { + stdAc::state_t result{}; + // Start with the previous state if given it. + if (prev != NULL) { + result = *prev; + } else { + // Set defaults for non-zero values that are not implicitly set for when + // there is no previous state. + // e.g. Any setting that toggles should probably go here. + result.light = false; + } + result.protocol = decode_type_t::HAIER_AC160; + result.power = _.Power; + result.mode = toCommonMode(_.Mode); + result.celsius = !_.UseFahrenheit; + result.degrees = getTemp(); + result.fanspeed = toCommonFanSpeed(_.Fan); + result.swingv = toCommonSwingV(_.SwingV); + result.swingh = stdAc::swingh_t::kOff; + result.sleep = _.Sleep ? 0 : -1; + result.turbo = _.Turbo; + result.quiet = _.Quiet; + result.clean = _.Clean && _.Clean2; + result.light ^= getLightToggle(); + result.filter = _.Health; + // Not supported. + result.model = -1; + result.econo = false; + result.beep = true; + result.clock = -1; + return result; +} + +/// Convert the current internal state into a human readable string. +/// @return A human readable string. +String IRHaierAC160::toString(void) const { + String result = ""; + result.reserve(280); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(_.Power, kPowerStr, false); + uint8_t cmd = _.Button; + result += addIntToString(cmd, kButtonStr); + result += kSpaceLBraceStr; + switch (cmd) { + case kHaierAcYrw02ButtonPower: + result += kPowerStr; + break; + case kHaierAcYrw02ButtonMode: + result += kModeStr; + break; + case kHaierAcYrw02ButtonFan: + result += kFanStr; + break; + case kHaierAcYrw02ButtonTempUp: + result += kTempUpStr; + break; + case kHaierAcYrw02ButtonTempDown: + result += kTempDownStr; + break; + case kHaierAcYrw02ButtonSleep: + result += kSleepStr; + break; + case kHaierAcYrw02ButtonHealth: + result += kHealthStr; + break; + case kHaierAcYrw02ButtonSwingV: + result += kSwingVStr; + break; + case kHaierAcYrw02ButtonSwingH: + result += kSwingHStr; + break; + case kHaierAcYrw02ButtonTurbo: + result += kTurboStr; + break; + case kHaierAcYrw02ButtonTimer: + result += kTimerStr; + break; + case kHaierAcYrw02ButtonLock: + result += kLockStr; + break; + case kHaierAc160ButtonClean: + result += kCleanStr; + break; + case kHaierAc160ButtonLight: + result += kLightStr; + break; + case kHaierAc160ButtonAuxHeating: + result += kHeatingStr; + break; + case kHaierAcYrw02ButtonCFAB: + result += kCelsiusFahrenheitStr; + break; + default: + result += kUnknownStr; + } + result += ')'; + result += addModeToString(_.Mode, kHaierAcYrw02Auto, kHaierAcYrw02Cool, + kHaierAcYrw02Heat, kHaierAcYrw02Dry, + kHaierAcYrw02Fan); + result += addTempToString(getTemp(), !_.UseFahrenheit); + result += addFanToString(_.Fan, kHaierAcYrw02FanHigh, kHaierAcYrw02FanLow, + kHaierAcYrw02FanAuto, kHaierAcYrw02FanAuto, + kHaierAcYrw02FanMed); + result += addBoolToString(_.Turbo, kTurboStr); + result += addBoolToString(_.Quiet, kQuietStr); + result += addBoolToString(_.Health, kHealthStr); + result += addIntToString(_.SwingV, kSwingVStr); + result += kSpaceLBraceStr; + switch (_.SwingV) { + case kHaierAc160SwingVOff: result += kOffStr; break; + case kHaierAc160SwingVAuto: result += kAutoStr; break; + case kHaierAc160SwingVTop: result += kTopStr; break; + case kHaierAc160SwingVHighest: result += kHighestStr; break; + case kHaierAc160SwingVHigh: result += kHighStr; break; + case kHaierAc160SwingVMiddle: result += kMiddleStr; break; + case kHaierAc160SwingVLow: result += kLowStr; break; + case kHaierAc160SwingVLowest: result += kLowestStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addBoolToString(_.Sleep, kSleepStr); + result += addBoolToString(getClean(), kCleanStr); + const uint8_t tmode = getTimerMode(); + result += addIntToString(tmode, kTimerModeStr); + result += kSpaceLBraceStr; + switch (tmode) { + case kHaierAcYrw02NoTimers: + result += kNAStr; + break; + case kHaierAcYrw02OnTimer: + result += kOnStr; + break; + case kHaierAcYrw02OffTimer: + result += kOffStr; + break; + case kHaierAcYrw02OnThenOffTimer: + result += kOnStr; + result += '-'; + result += kOffStr; + break; + case kHaierAcYrw02OffThenOnTimer: + result += kOffStr; + result += '-'; + result += kOnStr; + break; + default: + result += kUnknownStr; + } + result += ')'; + result += addLabeledString((tmode != kHaierAcYrw02NoTimers && + tmode != kHaierAcYrw02OffTimer) ? + minsToString(getOnTimer()) : kOffStr, kOnTimerStr); + result += addLabeledString((tmode != kHaierAcYrw02NoTimers && + tmode != kHaierAcYrw02OnTimer) ? + minsToString(getOffTimer()) : kOffStr, kOffTimerStr); + result += addBoolToString(_.Lock, kLockStr); + result += addBoolToString(_.AuxHeating, kHeatingStr); + return result; +} +// End of IRHaierAC160 class. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h index 4e5c8e64c..31cf4bcff 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h @@ -8,6 +8,7 @@ /// @see https://www.dropbox.com/s/mecyib3lhdxc8c6/IR%20data%20reverse%20engineering.xlsx?dl=0 /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/485 /// @see https://www.dropbox.com/sh/w0bt7egp0fjger5/AADRFV6Wg4wZskJVdFvzb8Z0a?dl=0&preview=haer2.ods +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1804 // Supports: // Brand: Haier, Model: HSU07-HEA03 remote (HAIER_AC) @@ -17,6 +18,7 @@ // Brand: Mabe, Model: MMI18HDBWCA6MI8 A/C (HAIER_AC176) // Brand: Mabe, Model: V12843 HJ200223 remote (HAIER_AC176) // Brand: Daichi, Model: D-H A/C (HAIER_AC176) +// Brand: Haier, Model: KFR-26GW/83@UI-Ge A/C (HAIER_AC160) #ifndef IR_HAIER_H_ #define IR_HAIER_H_ @@ -144,6 +146,7 @@ const uint8_t kHaierAcYrw02DefTempC = 25; const uint8_t kHaierAcYrw02ModelA = 0xA6; const uint8_t kHaierAcYrw02ModelB = 0x59; const uint8_t kHaierAc176Prefix = 0xB7; +const uint8_t kHaierAc160Prefix = 0xB5; const uint8_t kHaierAcYrw02SwingVOff = 0x0; const uint8_t kHaierAcYrw02SwingVTop = 0x1; @@ -152,6 +155,15 @@ const uint8_t kHaierAcYrw02SwingVBottom = 0x3; // Only available in heat mode. const uint8_t kHaierAcYrw02SwingVDown = 0xA; const uint8_t kHaierAcYrw02SwingVAuto = 0xC; // Airflow +const uint8_t kHaierAc160SwingVOff = 0b0000; +const uint8_t kHaierAc160SwingVTop = 0b0001; +const uint8_t kHaierAc160SwingVHighest = 0b0010; +const uint8_t kHaierAc160SwingVHigh = 0b0100; +const uint8_t kHaierAc160SwingVMiddle = 0b0110; +const uint8_t kHaierAc160SwingVLow = 0b1000; +const uint8_t kHaierAc160SwingVLowest = 0b0011; +const uint8_t kHaierAc160SwingVAuto = 0b1100; // Airflow + const uint8_t kHaierAcYrw02SwingHMiddle = 0x0; const uint8_t kHaierAcYrw02SwingHLeftMax = 0x3; const uint8_t kHaierAcYrw02SwingHLeft = 0x4; @@ -182,6 +194,9 @@ const uint8_t kHaierAcYrw02ButtonTurbo = 0b01000; const uint8_t kHaierAcYrw02ButtonSleep = 0b01011; const uint8_t kHaierAcYrw02ButtonTimer = 0b10000; const uint8_t kHaierAcYrw02ButtonLock = 0b10100; +const uint8_t kHaierAc160ButtonLight = 0b10101; +const uint8_t kHaierAc160ButtonAuxHeating = 0b10110; +const uint8_t kHaierAc160ButtonClean = 0b11001; const uint8_t kHaierAcYrw02ButtonCFAB = 0b11010; const uint8_t kHaierAcYrw02NoTimers = 0b000; @@ -260,6 +275,75 @@ union HaierAc176Protocol{ }; }; +/// Native representation of a Haier 160 bit A/C message. +union HaierAc160Protocol{ + uint8_t raw[kHaierAC160StateLength]; ///< The state in native form + struct { + // Byte 0 + uint8_t Model :8; + // Byte 1 + uint8_t SwingV :4; + uint8_t Temp :4; // 16C~30C + // Byte 2 + uint8_t :5; + uint8_t SwingH :3; + // Byte 3 + uint8_t :1; + uint8_t Health :1; + uint8_t :3; + uint8_t TimerMode :3; + // Byte 4 + uint8_t :6; + uint8_t Power :1; + uint8_t AuxHeating :1; + // Byte 5 + uint8_t OffTimerHrs :5; + uint8_t Fan :3; + // Byte 6 + uint8_t OffTimerMins:6; + uint8_t Turbo :1; + uint8_t Quiet :1; + // Byte 7 + uint8_t OnTimerHrs :5; + uint8_t Mode :3; + // Byte 8 + uint8_t OnTimerMins :6; + uint8_t :1; + uint8_t Sleep :1; + // Byte 9 + uint8_t :8; + // Byte 10 + uint8_t ExtraDegreeF :1; + uint8_t :3; + uint8_t Clean :1; + uint8_t UseFahrenheit:1; + uint8_t :2; + // Byte 11 + uint8_t :8; + // Byte 12 + uint8_t Button :5; + uint8_t Lock :1; + uint8_t :2; + // Byte 13 + uint8_t Sum :8; + // Byte 14 + uint8_t Prefix :8; + // Byte 15 + uint8_t :6; + uint8_t Clean2 :1; + uint8_t :1; + // Byte 16 + uint8_t :5; + uint8_t Fan2 :3; + // Byte 17 + uint8_t :8; + // Byte 18 + uint8_t :8; + // Byte 19 + uint8_t Sum2 :8; + }; +}; + // Legacy Haier YRW02 remote defines. #define HAIER_AC_YRW02_SWING_OFF kHaierAcYrw02SwingOff #define HAIER_AC_YRW02_SWING_TOP kHaierAcYrw02SwingTop @@ -474,4 +558,96 @@ class IRHaierACYRW02 : public IRHaierAC176 { const uint8_t state[], const uint16_t length = kHaierACYRW02StateLength); }; + +/// Class for handling detailed Haier 160 bit A/C messages. +class IRHaierAC160 { + public: + explicit IRHaierAC160(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); +#if SEND_HAIER_AC160 + virtual void send(const uint16_t repeat = kHaierAc160DefaultRepeat); + /// 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 65ms IR signal pulse at 38kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_HAIER_AC160 + void begin(void); + void stateReset(void); + + void setButton(const uint8_t button); + uint8_t getButton(void) const; + + void setUseFahrenheit(const bool on); + bool getUseFahrenheit(void) const; + void setTemp(const uint8_t temp, const bool fahrenheit = false); + uint8_t getTemp(void) const; + + void setFan(const uint8_t speed); + uint8_t getFan(void) const; + + uint8_t getMode(void) const; + void setMode(const uint8_t mode); + + bool getPower(void) const; + void setPower(const bool on); + void on(void); + void off(void); + + bool getSleep(void) const; + void setSleep(const bool on); + bool getClean(void) const; + void setClean(const bool on); + bool getLightToggle(void) const; + void setLightToggle(const bool on); + + bool getTurbo(void) const; + void setTurbo(const bool on); + bool getQuiet(void) const; + void setQuiet(const bool on); + bool getAuxHeating(void) const; + void setAuxHeating(const bool on); + + uint8_t getSwingV(void) const; + void setSwingV(const uint8_t pos); + + void setTimerMode(const uint8_t setting); + uint8_t getTimerMode(void) const; + void setOnTimer(const uint16_t mins); + uint16_t getOnTimer(void) const; + void setOffTimer(const uint16_t mins); + uint16_t getOffTimer(void) const; + + bool getLock(void) const; + void setLock(const bool on); + + bool getHealth(void) const; + void setHealth(const bool on); + + uint8_t* getRaw(void); + virtual void setRaw(const uint8_t new_code[]); + static bool validChecksum(const uint8_t state[], + const uint16_t length = kHaierAC160StateLength); + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint8_t convertFan(const stdAc::fanspeed_t speed); + static uint8_t convertSwingV(const stdAc::swingv_t position); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + static stdAc::swingv_t toCommonSwingV(const uint8_t pos); + static bool toCommonTurbo(const uint8_t speed); + static bool toCommonQuiet(const uint8_t speed); + stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const; + String toString(void) const; +#ifndef UNIT_TEST + + private: + IRsend _irsend; ///< Instance of the IR send class +#else // UNIT_TEST + /// @cond IGNORE + IRsendTest _irsend; ///< Instance of the testing IR send class + /// @endcond +#endif // UNIT_TEST + HaierAc160Protocol _; + void checksum(void); +}; #endif // IR_HAIER_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.h index 32d8d6c71..e44055e79 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Midea.h @@ -23,8 +23,10 @@ // Brand: Danby, Model: DAC100BGUWDB (MIDEA) // Brand: Danby, Model: DAC120BGUWDB (MIDEA) // Brand: Danby, Model: R09C/BCGE remote (MIDEA) +// Brand: Trotec, Model: TROTEC PAC 2100 X (MIDEA) // Brand: Trotec, Model: TROTEC PAC 3900 X (MIDEA) // Brand: Trotec, Model: RG57H(B)/BGE remote (MIDEA) +// Brand: Trotec, Model: RG57H3(B)/BGCEF-M remote (MIDEA) // Brand: Lennox, Model: RG57A6/BGEFU1 remote (MIDEA) // Brand: Lennox, Model: MWMA009S4-3P A/C (MIDEA) // Brand: Lennox, Model: MWMA012S4-3P A/C (MIDEA) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_NEC.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_NEC.h index 95da064b7..c9b0a6ec1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_NEC.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_NEC.h @@ -14,6 +14,8 @@ // Brand: Duux, Model: Blizzard Smart 10K / DXMA04 A/C // Brand: Duux, Model: YJ-A081 TR Remote // Brand: Silan Microelectronics, Model: SC6121-001 IC +// Brand: BBK, Model: SP550S 5.1 sound system +// Brand: Tanix, Model: TX3 mini Android TV Box #ifndef IR_NEC_H_ #define IR_NEC_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h index acabb3648..6c59c7af4 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h @@ -12,6 +12,7 @@ // Supports: // Brand: Samsung, Model: UA55H6300 TV (SAMSUNG) // Brand: Samsung, Model: BN59-01178B TV remote (SAMSUNG) +// Brand: Samsung, Model: UE40K5510AUXRU TV (SAMSUNG) // Brand: Samsung, Model: DB63-03556X003 remote // Brand: Samsung, Model: DB93-16761C remote // Brand: Samsung, Model: IEC-R03 remote diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp index ab3a4ec93..4a38e8e09 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.cpp @@ -77,6 +77,14 @@ const uint32_t kSanyoAc88Gap = 3675; ///< uSeconds const uint16_t kSanyoAc88Freq = 38000; ///< Hz. (Guess only) const uint8_t kSanyoAc88ExtraTolerance = 5; /// (%) Extra tolerance to use. +const uint16_t kSanyoAc152HdrMark = 3300; ///< uSeconds +const uint16_t kSanyoAc152BitMark = 440; ///< uSeconds +const uint16_t kSanyoAc152HdrSpace = 1725; ///< uSeconds +const uint16_t kSanyoAc152OneSpace = 1290; ///< uSeconds +const uint16_t kSanyoAc152ZeroSpace = 405; ///< uSeconds +const uint16_t kSanyoAc152Freq = 38000; ///< Hz. (Guess only) +const uint8_t kSanyoAc152ExtraTolerance = 13; /// (%) Extra tolerance to use. + #if SEND_SANYO /// Construct a Sanyo LC7461 message. /// @param[in] address The 13 bit value of the address(Custom) portion of the @@ -687,7 +695,7 @@ void IRsend::sendSanyoAc88(const uint8_t data[], const uint16_t nbytes, #endif // SEND_SANYO_AC88 #if DECODE_SANYO_AC88 -/// Decode the supplied SanyoAc message. +/// Decode the supplied SanyoAc88 message. /// Status: ALPHA / Untested. /// @param[in,out] results Ptr to the data to decode & where to store the decode /// @warning data's bit order may change. It is not yet confirmed. @@ -976,3 +984,61 @@ String IRSanyoAc88::toString(void) const { result += addLabeledString(minsToString(getClock()), kClockStr); return result; } + +#if SEND_SANYO_AC152 +/// Send a SanyoAc152 formatted message. +/// Status: BETA / Probably works. +/// @param[in] data An array of bytes containing the IR command. +/// @warning data's bit order may change. It is not yet confirmed. +/// @param[in] nbytes Nr. of bytes of data in the array. +/// @param[in] repeat Nr. of times the message is to be repeated. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1826 +void IRsend::sendSanyoAc152(const uint8_t data[], const uint16_t nbytes, + const uint16_t repeat) { + // (Header + Data + Footer) per repeat + sendGeneric(kSanyoAc152HdrMark, kSanyoAc152HdrSpace, + kSanyoAc152BitMark, kSanyoAc152OneSpace, + kSanyoAc152BitMark, kSanyoAc152ZeroSpace, + kSanyoAc152BitMark, kDefaultMessageGap, + data, nbytes, kSanyoAc152Freq, false, repeat, kDutyDefault); + space(kDefaultMessageGap); // Make a guess at a post message gap. +} +#endif // SEND_SANYO_AC152 + +#if DECODE_SANYO_AC152 +/// Decode the supplied SanyoAc152 message. +/// Status: BETA / Probably works. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// @warning data's bit order may change. It is not yet confirmed. +/// @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. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1503 +bool IRrecv::decodeSanyoAc152(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict && nbits != kSanyoAc152Bits) + return false; + + // Header + Data + Footer + if (!matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + kSanyoAc152HdrMark, kSanyoAc152HdrSpace, + kSanyoAc152BitMark, kSanyoAc152OneSpace, + kSanyoAc152BitMark, kSanyoAc152ZeroSpace, + kSanyoAc152BitMark, + kDefaultMessageGap, // Just a guess. + false, _tolerance + kSanyoAc152ExtraTolerance, + kMarkExcess, false)) + return false; // No match! + + // Success + results->decode_type = decode_type_t::SANYO_AC152; + results->bits = nbits; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_SANYO_AC152 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.h index 66376328f..42575cb3b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sanyo.h @@ -13,6 +13,7 @@ /// @see https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?usp=sharing /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1503 /// @see https://docs.google.com/spreadsheets/d/1weUmGAsEpfX38gg5rlDN69Uchnbr6gQl9FqHffLBIRk/edit#gid=0 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1826 // Supports: // Brand: Sanyo, Model: SA 8650B - disabled @@ -21,6 +22,8 @@ // Brand: Sanyo, Model: RCS-2HS4E remote (SANYO_AC) // Brand: Sanyo, Model: SAP-K242AH A/C (SANYO_AC) // Brand: Sanyo, Model: RCS-2S4E remote (SANYO_AC) +// Brand: Sanyo, Model: RCS-4MHVPIS4EE remote (SANYO_AC152) +// Brand: Sanyo, Model: SAP-KMRV124EHE A/C (SANYO_AC152) #ifndef IR_SANYO_H_ #define IR_SANYO_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp index 5746ee9b1..fb7b9af6f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp @@ -11,6 +11,7 @@ // Supports: // Brand: Sony, Model: HT-CT380 Soundbar (Uses 38kHz & 3 repeats) +// Brand: Sony, Model: HT-SF150 Soundbar (Uses 38kHz & 3 repeats) #include #include "IRrecv.h" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp index 1aceef44b..45e210f2b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp @@ -1,4 +1,4 @@ -// Copyright 2019, 2021 David Conran +// Copyright 2019, 2021, 2022 David Conran /// @file /// @brief Support for TCL protocols. @@ -14,10 +14,19 @@ #include "IRutils.h" // Constants - const uint8_t kTcl112AcTimerResolution = 20; // Minutes const uint16_t kTcl112AcTimerMax = 720; // Minutes (12 hrs) +const uint16_t kTcl96AcHdrMark = 1056; // uSeconds. +const uint16_t kTcl96AcHdrSpace = 550; // uSeconds. +const uint16_t kTcl96AcBitMark = 600; // uSeconds. +const uint32_t kTcl96AcGap = kDefaultMessageGap; // Just a guess. +const uint8_t kTcl96AcSpaceCount = 4; +const uint16_t kTcl96AcBitSpaces[kTcl96AcSpaceCount] = {360, // 0b00 + 838, // 0b01 + 2182, // 0b10 + 1444}; // 0b11 + using irutils::addBoolToString; using irutils::addFanToString; using irutils::addIntToString; @@ -527,3 +536,81 @@ String IRTcl112Ac::toString(void) const { /// It's the same as `decodeMitsubishi112()`. A shared routine is used. /// You can find it in: ir_Mitsubishi.cpp #endif // DECODE_TCL112AC + +#if SEND_TCL96AC +/// Send a TCL 96-bit A/C message. +/// Status: BETA / Untested on a real device working. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +void IRsend::sendTcl96Ac(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + enableIROut(38); + for (uint16_t r = 0; r <= repeat; r++) { + // Header + mark(kTcl96AcHdrMark); + space(kTcl96AcHdrSpace); + // Data + for (uint16_t pos = 0; pos < nbytes; pos++) { + uint8_t databyte = data[pos]; + for (uint8_t bits = 0; bits < 8; bits += 2) { + mark(kTcl96AcBitMark); + space(kTcl96AcBitSpaces[GETBITS8(databyte, 8 - 2, 2)]); + databyte <<= 2; + } + } + // Footer + mark(kTcl96AcBitMark); + space(kTcl96AcGap); + } +} +#endif // SEND_TCL96AC + +#if DECODE_TCL96AC +/// Decode the supplied Tcl96Ac message. +/// Status: ALPHA / Experimental. +/// @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::decodeTcl96Ac(decode_results* results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < nbits + kHeader + kFooter - 1 + offset) + return false; // Message is smaller than we expected. + if (strict && nbits != kTcl96AcBits) + return false; // Not strictly a TCL96AC message. + uint8_t data = 0; + // Header. + if (!matchMark(results->rawbuf[offset++], kTcl96AcHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kTcl96AcHdrSpace)) return false; + // Data (2 bits at a time) + for (uint16_t bits_so_far = 0; bits_so_far < nbits; bits_so_far += 2) { + if (bits_so_far % 8) + data <<= 2; // Make space for the new data bits. + else + data = 0; + if (!matchMark(results->rawbuf[offset++], kTcl96AcBitMark)) return false; + uint8_t value = 0; + while (value < kTcl96AcSpaceCount) { + if (matchSpace(results->rawbuf[offset], kTcl96AcBitSpaces[value])) { + data += value; + break; + } + value++; + } + if (value >= kTcl96AcSpaceCount) return false; // No matches. + offset++; + *(results->state + bits_so_far / 8) = data; + } + // Footer + if (!matchMark(results->rawbuf[offset++], kTcl96AcBitMark)) return false; + if (offset < results->rawlen && + !matchAtLeast(results->rawbuf[offset], kTcl96AcGap)) return false; + // Success + results->decode_type = TCL96AC; + results->bits = nbits; + return true; +} +#endif // DECODE_TCL96AC diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h index c7ae038d0..805270aa2 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h @@ -10,6 +10,7 @@ // Brand: Teknopoint, Model: GZ-055B-E1 remote (GZ055BE1) // Brand: Daewoo, Model: DSB-F0934ELH-V A/C // Brand: Daewoo, Model: GYKQ-52E remote +// Brand: TCL, Model: GYKQ-58(XM) remote (TCL96AC) #ifndef IR_TCL_H_ #define IR_TCL_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toto.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toto.cpp new file mode 100644 index 000000000..2997e760e --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toto.cpp @@ -0,0 +1,131 @@ +// Copyright 2022 David Conran (crankyoldgit) +/// @file +/// @brief Support for the Toto Toilet IR protocols. +/// @see https://www.d-resi.jp/dt/nishi-shinjuku/limited/imgs/pdf/book6.pdf +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1806 + +// Supports: +// Brand: Toto, Model: Washlet Toilet NJ + +#include +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +// Constants +const uint16_t kTotoHdrMark = 6197; +const uint16_t kTotoHdrSpace = 2754; +const uint16_t kTotoBitMark = 600; +const uint16_t kTotoOneSpace = 1634; +const uint16_t kTotoZeroSpace = 516; +const uint16_t kTotoGap = 38000; +const uint16_t kTotoSpecialGap = 42482; +const uint64_t kTotoPrefix = 0x0802; +const uint16_t kTotoPrefixBits = 15; + +#if SEND_TOTO +/// Send a Toto Toilet formatted message. +/// Status: BETA / Seems to work. +/// @param[in] data The message to be sent. +/// @param[in] nbits The number of bits of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1806 +void IRsend::sendToto(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + if (nbits <= kTotoShortBits) { // Short code message. + sendGeneric(kTotoHdrMark, kTotoHdrSpace, + kTotoBitMark, kTotoOneSpace, + kTotoBitMark, kTotoZeroSpace, + kTotoBitMark, kTotoGap, + (data << kTotoPrefixBits) | kTotoPrefix, + nbits + kTotoPrefixBits, + 38, false, repeat, kDutyDefault); + } else { // Long code message + // This is really two messages sent at least one extra time each. + sendToto(data >> kTotoShortBits, nbits - kTotoShortBits, repeat + 1); + sendToto(GETBITS64(data, 0, kTotoShortBits), kTotoShortBits, repeat + 1); + } +} +#endif // SEND_TOTO + +#if DECODE_TOTO +/// Decode the supplied Toto Toilet message. +/// Status: ALPHA / Untested. +/// @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. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1806 +bool IRrecv::decodeToto(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict && nbits != kTotoShortBits && nbits != kTotoLongBits) + return false; // We expect Toto to be a certain sized messages. + + const uint16_t repeats = (nbits > kTotoShortBits) ? kTotoDefaultRepeat + 1 + : kTotoDefaultRepeat; + const uint16_t ksections = (nbits > kTotoShortBits) ? 2 : 1; + const uint16_t ksection_bits = nbits / ksections; + + if (results->rawlen < (2 * (nbits + kTotoPrefixBits) + kHeader + kFooter) * + (repeats + 1) - 1 + offset) + return false; // We don't have enough entries to possibly match. + + uint16_t used = 0; + + // Long messages have two sections, short have only one. + for (uint16_t section = 1; section <= ksections; section++) { + results->value <<= ksection_bits; + uint64_t data = 0; + uint64_t repeat_data = 0; + for (uint16_t r = 0; r <= repeats; r++) { // We expect a repeat. + uint64_t prefix = 0; + // Header + Prefix + used = matchGeneric(results->rawbuf + offset, &prefix, + results->rawlen - offset, kTotoPrefixBits, + kTotoHdrMark, kTotoHdrSpace, + kTotoBitMark, kTotoOneSpace, + kTotoBitMark, kTotoZeroSpace, + 0, 0, false, // No Footer + kUseDefTol, kMarkExcess, false); + if (!used) return false; // Didn't match, so fail. + offset += used; + if (strict && (prefix != kTotoPrefix)) return false; + // Data + Footer + Gap + used = matchGeneric(results->rawbuf + offset, &data, + results->rawlen - offset, ksection_bits, + 0, 0, // No Header + kTotoBitMark, kTotoOneSpace, + kTotoBitMark, kTotoZeroSpace, + kTotoBitMark, kTotoGap, true, + kUseDefTol, kMarkExcess, false); + if (!used) return false; // Didn't match, so fail. + offset += used; + if (strict) { + if (r && data != repeat_data) return false; // Repeat didn't match. + // Integrity check. + uint8_t result = 0; + uint64_t check = data; + uint16_t bits = 0; + // Loop over the data 8 bits at a time. + while (bits < ksection_bits) { + result ^= (check & 0b111111111); // Xor with the last 8 bits. + bits += 8; + check >>= 8; + } + if (result) return false; // Intergrity check failed. + } + repeat_data = data; + } + results->value |= data; + } + // Success + results->bits = nbits; + results->decode_type = decode_type_t::TOTO; + results->command = GETBITS64(results->value, 0, ksection_bits - 8); + results->address = GETBITS64(results->value, ksection_bits, + ksection_bits - 8); + return true; +} +#endif // DECODE_TOTO diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.h index cf79d3458..d8ad77bcb 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Voltas.h @@ -9,6 +9,7 @@ // // Ref: https://docs.google.com/spreadsheets/d/1zzDEUQ52y7MZ7_xCU3pdjdqbRXOwZLsbTGvKWcicqCI/ // Ref: https://www.corona.co.jp/box/download.php?id=145060636229 +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/files/8646964/Voltas.Window.AC.122LZF.Remote.Instructions.pdf #ifndef IR_VOLTAS_H_ #define IR_VOLTAS_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h index a623039f0..40b85c27c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h @@ -566,6 +566,9 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_YBOFB #define D_STR_YBOFB "YBOFB" #endif // D_STR_YBOFB +#ifndef D_STR_YX1FSF +#define D_STR_YX1FSF "YX1FSF" +#endif // D_STR_YX1FSF #ifndef D_STR_V9014557_A #define D_STR_V9014557_A "V9014557-A" #endif // D_STR_V9014557_A @@ -706,6 +709,12 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_ARRIS #define D_STR_ARRIS "ARRIS" #endif // D_STR_ARRIS +#ifndef D_STR_BOSCH +#define D_STR_BOSCH "BOSCH" +#endif // D_STR_BOSCH +#ifndef D_STR_BOSCH144 +#define D_STR_BOSCH144 D_STR_BOSCH "144" +#endif // D_STR_BOSCH144 #ifndef D_STR_BOSE #define D_STR_BOSE "BOSE" #endif // D_STR_BOSE @@ -718,6 +727,12 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_CARRIER_AC64 #define D_STR_CARRIER_AC64 D_STR_CARRIER_AC "64" #endif // D_STR_CARRIER_AC64 +#ifndef D_STR_CARRIER_AC128 +#define D_STR_CARRIER_AC128 D_STR_CARRIER_AC "128" +#endif // D_STR_CARRIER_AC128 +#ifndef D_STR_CLIMABUTLER +#define D_STR_CLIMABUTLER "CLIMABUTLER" +#endif // D_STR_CLIMABUTLER #ifndef D_STR_COOLIX #define D_STR_COOLIX "COOLIX" #endif // D_STR_COOLIX @@ -731,25 +746,31 @@ D_STR_INDIRECT " " D_STR_MODE #define D_STR_DAIKIN "DAIKIN" #endif // D_STR_DAIKIN #ifndef D_STR_DAIKIN128 -#define D_STR_DAIKIN128 "DAIKIN128" +#define D_STR_DAIKIN128 D_STR_DAIKIN "128" #endif // D_STR_DAIKIN128 #ifndef D_STR_DAIKIN152 -#define D_STR_DAIKIN152 "DAIKIN152" +#define D_STR_DAIKIN152 D_STR_DAIKIN "152" #endif // D_STR_DAIKIN152 #ifndef D_STR_DAIKIN160 -#define D_STR_DAIKIN160 "DAIKIN160" +#define D_STR_DAIKIN160 D_STR_DAIKIN "160" #endif // D_STR_DAIKIN160 #ifndef D_STR_DAIKIN176 -#define D_STR_DAIKIN176 "DAIKIN176" +#define D_STR_DAIKIN176 D_STR_DAIKIN "176" #endif // D_STR_DAIKIN176 #ifndef D_STR_DAIKIN2 -#define D_STR_DAIKIN2 "DAIKIN2" +#define D_STR_DAIKIN2 D_STR_DAIKIN "2" #endif // D_STR_DAIKIN2 +#ifndef D_STR_DAIKIN200 +#define D_STR_DAIKIN200 D_STR_DAIKIN "200" +#endif // D_STR_DAIKIN200 #ifndef D_STR_DAIKIN216 -#define D_STR_DAIKIN216 "DAIKIN216" +#define D_STR_DAIKIN216 D_STR_DAIKIN "216" #endif // D_STR_DAIKIN216 +#ifndef D_STR_DAIKIN312 +#define D_STR_DAIKIN312 D_STR_DAIKIN "312" +#endif // D_STR_DAIKIN312 #ifndef D_STR_DAIKIN64 -#define D_STR_DAIKIN64 "DAIKIN64" +#define D_STR_DAIKIN64 D_STR_DAIKIN "64" #endif // D_STR_DAIKIN64 #ifndef D_STR_DELONGHI_AC #define D_STR_DELONGHI_AC "DELONGHI_AC" @@ -794,10 +815,13 @@ D_STR_INDIRECT " " D_STR_MODE #define D_STR_HAIER_AC "HAIER_AC" #endif // D_STR_HAIER_AC #ifndef D_STR_HAIER_AC_YRW02 -#define D_STR_HAIER_AC_YRW02 "HAIER_AC_YRW02" +#define D_STR_HAIER_AC_YRW02 D_STR_HAIER_AC "_YRW02" #endif // D_STR_HAIER_AC_YRW02 +#ifndef D_STR_HAIER_AC160 +#define D_STR_HAIER_AC160 D_STR_HAIER_AC "160" +#endif // D_STR_HAIER_AC160 #ifndef D_STR_HAIER_AC176 -#define D_STR_HAIER_AC176 "HAIER_AC176" +#define D_STR_HAIER_AC176 D_STR_HAIER_AC "176" #endif // D_STR_HAIER_AC176 #ifndef D_STR_HITACHI_AC #define D_STR_HITACHI_AC "HITACHI_AC" @@ -959,13 +983,16 @@ D_STR_INDIRECT " " D_STR_MODE #define D_STR_SANYO "SANYO" #endif // D_STR_SANYO #ifndef D_STR_SANYO_AC -#define D_STR_SANYO_AC "SANYO_AC" +#define D_STR_SANYO_AC D_STR_SANYO "_AC" #endif // D_STR_SANYO_AC #ifndef D_STR_SANYO_AC88 -#define D_STR_SANYO_AC88 "SANYO_AC88" +#define D_STR_SANYO_AC88 D_STR_SANYO_AC "88" #endif // D_STR_SANYO_AC88 +#ifndef D_STR_SANYO_AC152 +#define D_STR_SANYO_AC152 D_STR_SANYO_AC "152" +#endif // D_STR_SANYO_AC152 #ifndef D_STR_SANYO_LC7461 -#define D_STR_SANYO_LC7461 "SANYO_LC7461" +#define D_STR_SANYO_LC7461 D_STR_SANYO "_LC7461" #endif // D_STR_SANYO_LC7461 #ifndef D_STR_SHARP #define D_STR_SHARP "SHARP" @@ -985,6 +1012,9 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_SYMPHONY #define D_STR_SYMPHONY "SYMPHONY" #endif // D_STR_SYMPHONY +#ifndef D_STR_TCL96AC +#define D_STR_TCL96AC "TCL96AC" +#endif // D_STR_TCL96AC #ifndef D_STR_TCL112AC #define D_STR_TCL112AC "TCL112AC" #endif // D_STR_TCL112AC @@ -1000,6 +1030,9 @@ D_STR_INDIRECT " " D_STR_MODE #ifndef D_STR_TOSHIBA_AC #define D_STR_TOSHIBA_AC "TOSHIBA_AC" #endif // D_STR_TOSHIBA_AC +#ifndef D_STR_TOTO +#define D_STR_TOTO "TOTO" +#endif // D_STR_TOTO #ifndef D_STR_TRANSCOLD #define D_STR_TRANSCOLD "TRANSCOLD" #endif // D_STR_TRANSCOLD diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp index 1947ea532..15351ba61 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp @@ -623,9 +623,9 @@ TEST(TestIRac, Fujitsu) { "Model: 2 (ARDB1), Id: 0, Power: On, Mode: 1 (Cool), Temp: 19C, " "Fan: 2 (Medium), Command: N/A"; std::string arrah2e_expected = - "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 19C, " - "Fan: 2 (Medium), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Sleep Timer: 03:00"; + "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 3 (Fan), Temp: 10C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: On, " + "Swing: 0 (Off), Command: N/A, Sleep Timer: 03:00"; std::string arry4_expected = "Model: 5 (ARRY4), Id: 0, Power: On, Mode: 1 (Cool), Temp: 19C, " "Fan: 2 (Medium), Clean: On, Filter: On, Swing: 0 (Off), Command: N/A"; @@ -658,20 +658,21 @@ TEST(TestIRac, Fujitsu) { ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ac._irsend.reset(); + // Try to set the device to 10C Heat mode. irac.fujitsu(&ac, ARRAH2E, // Model true, // Power - stdAc::opmode_t::kCool, // Mode + stdAc::opmode_t::kFan, // Mode (Fan needed for 10C Heat) true, // Celsius - 19, // Degrees - stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kOff, // Vertical swing - stdAc::swingh_t::kOff, // Horizontal swing + 19, // Degrees (Ignored in 10C Heat) + stdAc::fanspeed_t::kAuto, // Fan speed (Auto needed for 10C) + stdAc::swingv_t::kOff, // Vertical swing (Ditto) + stdAc::swingh_t::kOff, // Horizontal swing (Ditto) false, // Quiet false, // Turbo (Powerful) false, // Econo true, // Filter - true, // Clean + true, // Clean (Needed for 10C Heat) 3 * 60); // Sleep ASSERT_EQ(arrah2e_expected, ac.toString()); ac._irsend.makeDecodeResult(); @@ -819,6 +820,41 @@ TEST(TestIRac, Haier) { ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); } +TEST(TestIRac, Haier160) { + IRHaierAC160 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + const char expected[] = + "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " + "Fan: 2 (Medium), Turbo: On, Quiet: Off, Health: On, " + "Swing(V): 4 (High), Sleep: On, " + "Clean: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, " + "Lock: Off, Heating: Off"; + ac.begin(); + irac.haier160(&ac, + true, // Power + stdAc::opmode_t::kCool, // Mode + true, // Celsius + 23, // Degrees + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kHigh, // Vertical swing + true, // Turbo + false, // Quiet + true, // Filter/Health + true, // Clean + true, // Light + true, // Light (prev) + 8 * 60 + 0); // Sleep time + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(HAIER_AC160, ac._irsend.capture.decode_type); + ASSERT_EQ(kHaierAC160Bits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); +} + TEST(TestIRac, Haier176) { IRHaierAC176 ac(kGpioUnused); IRac irac(kGpioUnused); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Bosch_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Bosch_test.cpp new file mode 100644 index 000000000..dd9402b69 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Bosch_test.cpp @@ -0,0 +1,100 @@ +// Copyright 2022 David Conran + +#include "IRac.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + + +TEST(TestUtils, Housekeeping) { + // Bosch144 + ASSERT_EQ("BOSCH144", typeToString(decode_type_t::BOSCH144)); + ASSERT_EQ(decode_type_t::BOSCH144, strToDecodeType("BOSCH144")); + ASSERT_TRUE(hasACState(decode_type_t::BOSCH144)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::BOSCH144)); + ASSERT_EQ(kBosch144Bits, IRsend::defaultBits(decode_type_t::BOSCH144)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::BOSCH144)); +} + +// Tests for decodeBosch144(). + +// Decode normal Bosch144 messages. +TEST(TestDecodeBosch144, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1787#issuecomment-1099993189 + // Mode: Cool; Fan: 100% ; Temp: 16°C + const uint16_t rawData[299] = { + 4380, 4400, + 528, 1646, 504, 570, 504, 1646, 504, 1646, 504, 572, 502, 570, 504, 1646, + 504, 570, 504, 572, 502, 1646, 504, 570, 502, 570, 502, 1648, 502, 1646, + 502, 570, 502, 1646, 504, 572, 502, 572, 502, 1644, 504, 1646, 504, 1646, + 504, 1646, 502, 1648, 500, 1646, 504, 1646, 504, 1646, 504, 572, 502, 570, + 504, 570, 504, 570, 504, 570, 504, 570, 506, 570, 502, 572, 502, 570, 502, + 572, 502, 572, 502, 572, 502, 572, 502, 572, 500, 1648, 502, 1644, 502, + 1646, 504, 1646, 502, 1646, 504, 1646, 504, 1644, 504, 1646, + 504, 5234, + 4360, 4422, + 504, 1646, 502, 596, 478, 1670, 478, 1646, 504, 570, 504, 572, 500, 1646, + 502, 572, 502, 572, 502, 1644, 506, 570, 502, 570, 504, 1644, 506, 1644, + 502, 574, 502, 1644, 504, 570, 504, 570, 504, 1644, 504, 1646, 504, 1644, + 506, 1644, 504, 1646, 504, 1646, 504, 1644, 504, 1646, 502, 570, 504, 570, + 504, 570, 504, 570, 502, 570, 504, 570, 502, 572, 502, 570, 504, 570, 504, + 570, 504, 570, 502, 572, 502, 570, 506, 570, 504, 1646, 502, 1646, 504, + 1646, 504, 1646, 504, 1646, 502, 1644, 504, 1644, 504, 1646, + 502, 5236, + 4360, 4424, + 504, 1646, 504, 1646, 502, 572, 504, 1644, 504, 570, 504, 1646, 504, 570, + 502, 1644, 504, 570, 504, 1644, 506, 1646, 502, 572, 502, 572, 502, 1646, + 504, 570, 504, 570, 504, 570, 502, 572, 504, 570, 504, 570, 504, 570, 502, + 572, 502, 570, 504, 570, 502, 570, 504, 572, 502, 572, 502, 1646, 504, + 570, 504, 570, 504, 570, 502, 574, 502, 572, 502, 572, 502, 572, 502, 572, + 502, 572, 502, 570, 504, 572, 502, 572, 502, 572, 502, 1646, 504, 572, + 502, 570, 502, 1646, 504, 572, 504, 570, 504, 1644, + 504}; // COOLIX B23F00 + const uint8_t expectedState[kBosch144StateLength] = { + 0xB2, 0x4D, 0x3F, 0xC0, 0x00, 0xFF, + 0xB2, 0x4D, 0x3F, 0xC0, 0x00, 0xFF, + 0xD5, 0x64, 0x00, 0x10, 0x00, 0x49}; + irsend.begin(); + irsend.reset(); + + irsend.sendRaw(rawData, 299, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::BOSCH144, irsend.capture.decode_type); + EXPECT_EQ(kBosch144Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Mode: 0 (Cool), Fan: 5 (High), Temp: 16C, Quiet: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t result, prev; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); +} + +TEST(TestDecodeBosch144, SyntheticSelfDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + const uint8_t expectedState[kBosch144StateLength] = { + 0xB2, 0x4D, 0x3F, 0xC0, 0x00, 0xFF, + 0xB2, 0x4D, 0x3F, 0xC0, 0x00, 0xFF, + 0xD5, 0x64, 0x00, 0x10, 0x00, 0x49}; + irsend.sendBosch144(expectedState); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::BOSCH144, irsend.capture.decode_type); + EXPECT_EQ(kBosch144Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Mode: 0 (Cool), Fan: 5 (High), Temp: 16C, Quiet: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t result, prev; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Carrier_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Carrier_test.cpp index caf7e46d8..fa0f07b0c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Carrier_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Carrier_test.cpp @@ -1,8 +1,9 @@ -// Copyright 2018, 2020 David Conran +// Copyright 2018-2022 David Conran #include "ir_Carrier.h" #include "IRac.h" #include "IRrecv.h" +#include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -11,7 +12,7 @@ // Test sending typical data only. TEST(TestSendCarrierAC, SendDataOnly) { - IRsendTest irsend(0); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -88,7 +89,7 @@ TEST(TestSendCarrierAC, SendDataOnly) { // Test sending typical data only. TEST(TestSendCarrierAC, SendWithRepeats) { - IRsendTest irsend(0); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -156,7 +157,7 @@ TEST(TestSendCarrierAC, SendWithRepeats) { // Decode normal "synthetic" messages. TEST(TestDecodeCarrierAC, NormalDecodeWithStrict) { - IRsendTest irsend(0); + IRsendTest irsend(kGpioUnused); IRrecv irrecv(0); irsend.begin(); @@ -196,7 +197,7 @@ TEST(TestDecodeCarrierAC, NormalDecodeWithStrict) { // Decode a "real" example message. TEST(TestDecodeCarrierAC, RealExamples) { - IRsendTest irsend(0); + IRsendTest irsend(kGpioUnused); IRrecv irrecv(0); irsend.begin(); @@ -262,6 +263,16 @@ TEST(TestUtils, Housekeeping) { IRsend::defaultBits(decode_type_t::CARRIER_AC64)); ASSERT_EQ(kCarrierAc64MinRepeat, IRsend::minRepeats(decode_type_t::CARRIER_AC64)); + + // CARRIER_AC128 + ASSERT_EQ("CARRIER_AC128", typeToString(decode_type_t::CARRIER_AC128)); + ASSERT_EQ(decode_type_t::CARRIER_AC128, strToDecodeType("CARRIER_AC128")); + ASSERT_TRUE(hasACState(decode_type_t::CARRIER_AC128)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::CARRIER_AC128)); + ASSERT_EQ(kCarrierAc128Bits, + IRsend::defaultBits(decode_type_t::CARRIER_AC128)); + ASSERT_EQ(kCarrierAc128MinRepeat, + IRsend::minRepeats(decode_type_t::CARRIER_AC128)); } /// Decode a "real" example message. @@ -610,3 +621,75 @@ TEST(TestCarrierAc64Class, ReconstructKnownState) { "Sleep: On, On Timer: Off, Off Timer: Off", ac.toString()); } + +// Decode a "real" Carrier 128bit example message. +TEST(TestDecodeCarrierAC128, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint8_t expected_state[kCarrierAc128StateLength] = { + 0x16, 0x22, 0x48, 0x19, 0x10, 0x10, 0x16, 0x28, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x80}; + irsend.begin(); + + irsend.reset(); + // Data from: + // https://docs.google.com/spreadsheets/d/1lqs1UDAvUauzAyoVRAGhARKPaSk3pgOO7iHFw9M5HJE/edit#gid=0&range=F3 + const uint16_t rawData[267] = { + 4594, 2614, + 336, 418, 336, 998, 330, 1002, 338, 416, 336, 998, 332, 424, 328, 426, + 336, 416, 336, 418, 334, 1000, 332, 420, 330, 424, 338, 418, 336, 994, + 334, 420, 332, 424, 328, 424, 338, 416, 336, 418, 336, 996, 332, 422, 330, + 424, 338, 992, 338, 416, 336, 998, 332, 424, 336, 418, 336, 994, 336, 998, + 332, 420, 340, 416, 338, 416, 334, 420, 334, 420, 332, 424, 328, 426, 336, + 994, 336, 418, 334, 422, 330, 422, 332, 422, 338, 416, 338, 416, 336, 418, + 332, 1000, 332, 424, 336, 416, 338, 418, 334, 420, 332, 1000, 332, 1002, + 336, 416, 338, 994, 334, 422, 330, 424, 338, 416, 336, 416, 336, 420, 332, + 422, 330, 1000, 342, 412, 338, 996, 334, 422, 332, 402, + 338, 20636, + 4604, 6724, + 9296, 4976, + 356, 426, 336, 418, 334, 420, 332, 420, 330, 424, 340, 414, 338, 416, 336, + 420, 334, 418, 334, 420, 332, 422, 340, 416, 336, 418, 336, 416, 336, 420, + 332, 420, 332, 424, 338, 416, 336, 418, 336, 994, 334, 422, 332, 422, 340, + 412, 338, 418, 334, 418, 334, 420, 332, 422, 332, 424, 340, 414, 338, 414, + 336, 420, 334, 420, 330, 424, 328, 426, 336, 416, 336, 418, 334, 420, 366, + 388, 362, 392, 358, 392, 360, 394, 368, 386, 368, 388, 364, 388, 366, 390, + 360, 394, 358, 394, 368, 388, 366, 386, 366, 390, 362, 392, 358, 394, 360, + 394, 370, 384, 366, 388, 362, 390, 362, 390, 362, 392, 360, 396, 368, 384, + 366, 390, 364, 390, 362, 392, 360, 954, + 336, 20638, + 4622}; + + irsend.sendRaw(rawData, 267, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(CARRIER_AC128, irsend.capture.decode_type); + EXPECT_EQ(kCarrierAc128Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +// Decode a synthetic Carrier AC 128-bit message. +TEST(TestDecodeCarrierAC128, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + const uint8_t expected_state[kCarrierAc128StateLength] = { + 0x16, 0x22, 0x48, 0x19, 0x10, 0x10, 0x16, 0x28, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x80}; + irsend.reset(); + irsend.sendCarrierAC128(expected_state); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(CARRIER_AC128, irsend.capture.decode_type); + ASSERT_EQ(kCarrierAc128Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t r, p; + ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_ClimaButler_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_ClimaButler_test.cpp new file mode 100644 index 000000000..6a9841d27 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_ClimaButler_test.cpp @@ -0,0 +1,67 @@ +// Copyright 2022 crankyoldgit + +#include "IRac.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for decodeClimaButler(). +TEST(TestDecodeClimaButler, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint16_t rawData[109] = { + 554, 3512, + 558, 1488, 580, 496, 522, 494, 546, 558, 552, 494, 548, 496, 546, 500, + 548, 558, 544, 504, 544, 502, 540, 506, 538, 570, 514, 530, 514, 532, 512, + 534, 512, 592, 512, 536, 510, 532, 510, 536, 510, 598, 510, 536, 506, 536, + 514, 534, 510, 594, 514, 534, 510, 536, 534, 510, 510, 598, 514, 534, 510, + 536, 508, 536, 534, 572, 534, 500, 512, 1536, 512, 526, 510, 1588, 512, + 1536, 510, 538, 512, 532, 510, 588, 510, 1536, 514, 532, 510, 536, 534, + 570, 512, 534, 510, 536, 514, 528, 540, 568, 540, 506, 512, 524, 510, + 1534, 516, 532, + 536, 3396, + 544}; // UNKNOWN E6CA5369 POWER OFF + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData, 109, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::CLIMABUTLER, irsend.capture.decode_type); + ASSERT_EQ(kClimaButlerBits, irsend.capture.bits); + EXPECT_EQ(0x8000000058802, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t r, p; + ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); +} + +TEST(TestDecodeClimaButler, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + irsend.sendClimaButler(0x8000000058802); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::CLIMABUTLER, irsend.capture.decode_type); + ASSERT_EQ(kClimaButlerBits, irsend.capture.bits); + EXPECT_EQ(0x8000000058802, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); +} + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("CLIMABUTLER", typeToString(decode_type_t::CLIMABUTLER)); + ASSERT_EQ(decode_type_t::CLIMABUTLER, strToDecodeType("CLIMABUTLER")); + ASSERT_FALSE(hasACState(decode_type_t::CLIMABUTLER)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::CLIMABUTLER)); + ASSERT_EQ(kClimaButlerBits, IRsend::defaultBits(decode_type_t::CLIMABUTLER)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::CLIMABUTLER)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Daikin_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Daikin_test.cpp index 783bd4e66..71641d4dc 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Daikin_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Daikin_test.cpp @@ -1552,6 +1552,20 @@ TEST(TestUtils, Housekeeping) { ASSERT_EQ(decode_type_t::DAIKIN64, strToDecodeType("DAIKIN64")); ASSERT_FALSE(hasACState(decode_type_t::DAIKIN64)); ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::DAIKIN64)); + + ASSERT_EQ("DAIKIN200", typeToString(decode_type_t::DAIKIN200)); + ASSERT_EQ(decode_type_t::DAIKIN200, strToDecodeType("DAIKIN200")); + ASSERT_TRUE(hasACState(decode_type_t::DAIKIN200)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::DAIKIN200)); + ASSERT_EQ(kDaikin200Bits, IRsend::defaultBits(decode_type_t::DAIKIN200)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::DAIKIN200)); + + ASSERT_EQ("DAIKIN312", typeToString(decode_type_t::DAIKIN312)); + ASSERT_EQ(decode_type_t::DAIKIN312, strToDecodeType("DAIKIN312")); + ASSERT_TRUE(hasACState(decode_type_t::DAIKIN312)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::DAIKIN312)); + ASSERT_EQ(kDaikin312Bits, IRsend::defaultBits(decode_type_t::DAIKIN312)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::DAIKIN312)); } // https://github.com/crankyoldgit/IRremoteESP8266/issues/582#issuecomment-453863879 @@ -3879,3 +3893,228 @@ TEST(TestDaikin176Class, UnitId) { ASSERT_EQ(0, ac.getId()); EXPECT_STATE_EQ(unita, ac.getRaw(), kDaikin176Bits); } + +TEST(TestDaikin128Class, Issue1754_HeatMode) { + // Data from "MODE HEAT" + // Mesg Desc.: Power Toggle: Off, Mode: 8 (Heat), Temp: 19C, Fan: 4 (Medium), + // Powerful: Off, Quiet: Off, Swing(V): Off, Sleep: Off, Econo: Off, + // Clock: 20:22, On Timer: Off, On Timer: 10:00, Off Timer: Off, + // Off Timer: 16:30, Light Toggle: 0 (Off) + // Ref: https://docs.google.com/document/d/1bhPlwsUE4ppL1dlX6_aYmqCSxeE6HlOumYsR35S0CKA/edit#heading=h.luu34vdlzof1 + + const uint8_t heatmode[16] = { // As recorded from a real remote. + 0x16, 0x48, 0x22, 0x20, 0x10, 0x56, 0x19, 0x34, + 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B}; + + IRDaikin128 ac(kGpioUnused); + // Try to reproduce the exact same state. + ac.setClock(20 * 60 + 22); + ac.setOnTimer(10 * 60); + ac.setOnTimerEnabled(false); + ac.setOffTimer(16 * 60 + 30); + ac.setOffTimerEnabled(false); + ac.setPowerToggle(false); + ac.setTemp(19); + ac.setFan(kDaikin128FanMed); + ac.setPowerful(false); + ac.setQuiet(false); + ac.setSwingVertical(false); + ac.setSleep(false); + ac.setEcono(false); + ac.setLightToggle(0); + ac.setMode(kDaikin128Heat); + + EXPECT_EQ( + "Power Toggle: Off, Mode: 8 (Heat), Temp: 19C, Fan: 4 (Medium), " + "Powerful: Off, Quiet: Off, Swing(V): Off, Sleep: Off, Econo: Off, " + "Clock: 20:22, On Timer: Off, On Timer: 10:00, Off Timer: Off, " + "Off Timer: 16:30, Light Toggle: 0 (Off)", + ac.toString()); + // Compare the synthetic state to the captured one. + EXPECT_STATE_EQ(heatmode, ac.getRaw(), kDaikin128Bits); +} + +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1802 +TEST(TestDecodeDaikin200, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint16_t rawData[407] = { + 4852, 2298, + 202, 1942, 202, 870, 200, 870, 202, 868, 202, 1942, 202, 870, 202, 870, + 202, 870, 202, 870, 202, 1942, 202, 870, 202, 1942, 202, 1942, 202, 868, + 202, 1942, 202, 1942, 202, 1912, 232, 1942, 202, 1942, 202, 868, 202, + 1942, 202, 870, 202, 870, 202, 868, 202, 868, 204, 868, 202, 870, 202, + 1942, 202, 868, 204, 868, 202, 1942, 202, 870, 202, 870, 200, 870, 202, + 1942, 202, 868, 202, 870, 202, 870, 202, 870, 202, 870, 202, 870, 202, + 870, 202, 870, 202, 868, 202, 868, 204, 868, 202, 870, 202, 870, 202, 870, + 202, 1942, 202, 1942, 202, 1942, 202, 868, 202, 868, 204, 1942, 202, 870, + 202, 29468, + 4880, 2266, + 256, 1888, 230, 844, 202, 868, 202, 870, 256, 1888, 230, 842, 228, 842, + 230, 842, 256, 814, 232, 1914, 254, 816, 230, 1916, 256, 1888, 256, 814, + 256, 1890, 254, 1888, 256, 1888, 256, 1888, 256, 1888, 256, 816, 230, + 1912, 258, 814, 256, 816, 256, 816, 282, 790, 280, 790, 282, 790, 282, + 1862, 258, 814, 280, 790, 282, 1862, 280, 792, 280, 790, 282, 788, 282, + 790, 282, 790, 282, 790, 282, 790, 282, 788, 282, 790, 282, 1862, 282, + 1862, 282, 790, 282, 788, 282, 1862, 282, 1864, 280, 1862, 282, 790, 280, + 790, 282, 790, 282, 790, 282, 788, 284, 790, 282, 760, 310, 790, 282, 788, + 282, 1862, 282, 788, 282, 790, 282, 788, 282, 788, 282, 1862, 284, 788, + 282, 788, 284, 788, 282, 790, 282, 788, 284, 788, 282, 790, 282, 788, 284, + 758, 312, 788, 284, 788, 282, 788, 284, 788, 282, 788, 284, 788, 282, 788, + 284, 788, 284, 758, 314, 786, 284, 788, 284, 1860, 282, 790, 282, 790, + 282, 1862, 282, 758, 312, 762, 310, 788, 284, 788, 282, 758, 314, 758, + 314, 1862, 282, 760, 312, 1860, 284, 760, 310, 788, 282, 760, 312, 788, + 284, 760, 312, 788, 282, 790, 282, 788, 284, 788, 282, 790, 282, 788, 282, + 758, 314, 788, 282, 758, 314, 1862, 282, 758, 312, 788, 284, 758, 312, + 758, 314, 788, 282, 758, 314, 758, 312, 788, 284, 788, 284, 758, 312, 760, + 312, 762, 310, 790, 284, 788, 282, 758, 314, 758, 312, 788, 282, 760, 312, + 760, 312, 760, 312, 788, 282, 758, 314, 788, 284, 788, 284, 758, 312, 788, + 282, 790, 282, 1832, 310, 758, 316, 788, 284, 1862, 282, 1862, 282, 1832, + 310, 788, 284}; // UNKNOWN 3BFB2888 + + const uint8_t expectedState[kDaikin200StateLength] = { + 0x11, 0xDA, 0x17, 0x48, 0x04, 0x00, 0x4E, // Section 1 + 0x11, 0xDA, 0x17, 0x48, 0x00, 0x73, 0x00, 0x21, 0x00, // Section 2 + 0x00, 0x24, 0x50, 0x00, 0x20, 0x00, 0x00, 0x00, 0x72}; + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData, 407, kDaikin64Freq); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::DAIKIN200, irsend.capture.decode_type); + ASSERT_EQ(kDaikin200Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t result, prev; + ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); +} + +// Decoding a message we entirely constructed based solely on a given state. +TEST(TestDecodeDaikin200, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + const uint8_t expectedState[kDaikin200StateLength] = { + 0x11, 0xDA, 0x17, 0x48, 0x04, 0x00, 0x4E, // Section 1 + 0x11, 0xDA, 0x17, 0x48, 0x00, 0x73, 0x00, 0x21, 0x00, // Section 2 + 0x00, 0x24, 0x50, 0x00, 0x20, 0x00, 0x00, 0x00, 0x72}; + + irsend.reset(); + irsend.sendDaikin200(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(DAIKIN200, irsend.capture.decode_type); + ASSERT_EQ(kDaikin200Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +/// https://github.com/crankyoldgit/IRremoteESP8266/issues/1829#issuecomment-1173077011 +TEST(TestDecodeDaikin312, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/files/9034763/on_coling_210_fan_auto.txt.out.txt + const uint16_t rawData[643] = { + 508, 390, 452, 414, 452, 414, 452, 414, 452, 414, + 452, 25104, + 3518, 1688, + 478, 1256, 478, 414, 452, 414, 452, 414, 452, 1282, 452, 414, 452, 414, + 452, 414, 452, 414, 452, 1280, 454, 414, 452, 1256, 478, 1254, 478, 414, + 452, 1280, 452, 1282, 452, 1282, 452, 1282, 478, 1256, 480, 386, 452, 414, + 452, 1282, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, + 454, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 1280, 452, 414, + 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 1282, + 452, 414, 452, 414, 452, 414, 452, 1280, 452, 1280, 452, 418, 450, 1280, + 452, 1282, 452, 414, 452, 1282, 452, 414, 452, 416, 452, 1280, 454, 414, + 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, + 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 454, 414, + 452, 414, 452, 1282, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, + 452, 414, 454, 414, 452, 414, 452, 414, 452, 414, 452, 414, 478, 388, 452, + 414, 452, 414, 452, 414, 452, 414, 452, 414, 454, 414, 452, 414, 452, 414, + 452, 414, 452, 414, 452, 414, 452, 1282, 452, 414, 452, 414, 452, 414, + 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, + 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, + 478, 388, 452, 414, 478, 388, 452, 414, 452, 414, 452, 414, 452, 414, 452, + 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, + 452, 414, 452, 414, 452, 414, 452, 414, 448, 418, 448, 418, 448, 418, 448, + 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, + 448, 418, 448, 418, 448, 418, 448, 418, 448, 420, 448, 418, 450, 418, 448, + 1286, 448, 1286, 448, 420, 448, 418, 448, 418, 448, 418, 448, 1284, 448, + 1286, + 448, 35512, + 3518, 1688, + 478, 1282, 452, 414, 452, 414, 452, 414, 452, 1282, 452, 414, 452, 414, + 452, 414, 452, 414, 452, 1280, 452, 414, 452, 1256, 478, 1254, 478, 414, + 452, 1280, 452, 1282, 452, 1282, 452, 1282, 452, 1280, 452, 414, 452, 414, + 452, 1280, 452, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, + 448, 418, 448, 418, 452, 414, 448, 418, 448, 418, 448, 418, 448, 418, 448, + 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 1286, 452, 414, 452, + 414, 452, 1280, 452, 1282, 452, 1282, 452, 414, 452, 414, 452, 414, 452, + 1256, 478, 414, 452, 1282, 452, 414, 452, 1256, 478, 414, 452, 414, 452, + 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, + 454, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 1282, 452, 414, + 452, 1256, 478, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, + 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, 414, 452, + 414, 452, 414, 452, 414, 452, 414, 452, 1286, 448, 1286, 448, 418, 448, + 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, + 448, 418, 448, 1286, 448, 1286, 448, 418, 448, 418, 448, 418, 448, 418, + 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 420, 448, + 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 1260, 474, + 418, 448, 1264, 470, 418, 448, 418, 448, 418, 448, 1258, 474, 1260, 474, + 418, 448, 418, 448, 418, 448, 418, 448, 418, 448, 418, 452, 414, 452, 414, + 452, 414, 452, 416, 452, 414, 448, 1264, 478, 384, 474, 418, 448, 418, + 448, 418, 448, 418, 448, 418, 448, 418, 448, 1260, 504, 362, 474, 418, + 448, 1260, 478, 388, 474}; // UNKNOWN 34EEF8FF + + const uint8_t expectedState[kDaikin312StateLength] = { + // Section 1 + 0x11, 0xDA, 0x27, 0x00, 0x02, 0x62, 0x4B, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, + // Section 2 + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x2A, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC5, 0x00, 0x08, 0x48}; + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData, 643, kDaikin64Freq); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::DAIKIN312, irsend.capture.decode_type); + ASSERT_EQ(kDaikin312Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t result, prev; + ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); +} + +// Decoding a message we entirely constructed based solely on a given state. +TEST(TestDecodeDaikin312, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + const uint8_t expectedState[kDaikin312StateLength] = { + // Section 1 + 0x11, 0xDA, 0x27, 0x00, 0x02, 0x62, 0x4B, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, + // Section 2 + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x2A, 0x00, 0xA0, 0x00, + 0x00, 0x06, 0x60, 0x00, 0x00, 0xC5, 0x00, 0x08, 0x48}; + + irsend.reset(); + irsend.sendDaikin312(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(DAIKIN312, irsend.capture.decode_type); + ASSERT_EQ(kDaikin312Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Fujitsu_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Fujitsu_test.cpp index b3d7cff34..ed5ee59f1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Fujitsu_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Fujitsu_test.cpp @@ -22,7 +22,7 @@ TEST(TestIRFujitsuACClass, GetRawDefault) { EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 16 * 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ("Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 24C, " - "Fan: 1 (High), Clean: Off, Filter: Off, " + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " "Swing: 3 (Swing(V)+Swing(H)), Command: N/A, Timer: Off", ac.toString()); @@ -45,7 +45,7 @@ TEST(TestIRFujitsuACClass, GetRawTurnOff) { EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 7 * 8); EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); EXPECT_EQ("Model: 1 (ARRAH2E), Id: 0, Power: Off, Mode: 1 (Cool), Temp: 24C, " - "Fan: 1 (High), Clean: Off, Filter: Off, " + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " "Swing: 3 (Swing(V)+Swing(H)), Command: N/A, Timer: Off", ac.toString()); @@ -66,8 +66,8 @@ TEST(TestIRFujitsuACClass, GetRawStepHoriz) { EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 24C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 3 (Swing(V)+Swing(H)), " - "Command: Step Swing(H), Timer: Off", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 3 (Swing(V)+Swing(H)), Command: Step Swing(H), Timer: Off", ac.toString()); } @@ -80,8 +80,8 @@ TEST(TestIRFujitsuACClass, GetRawStepVert) { EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 24C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 3 (Swing(V)+Swing(H)), " - "Command: Step Swing(V), Timer: Off", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 3 (Swing(V)+Swing(H)), Command: Step Swing(V), Timer: Off", ac.toString()); ac.setModel(ARDB1); @@ -106,7 +106,7 @@ TEST(TestIRFujitsuACClass, GetRawWithSwingHoriz) { 0x90, 0x1, 0x24, 0x0, 0x0, 0x0, 0x20, 0xFB}; EXPECT_STATE_EQ(expected, ac.getRaw(), 16 * 8); EXPECT_EQ("Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 25C, " - "Fan: 4 (Quiet), Clean: Off, Filter: Off, " + "Fan: 4 (Quiet), Clean: Off, Filter: Off, 10C Heat: Off, " "Swing: 2 (Swing(H)), Command: N/A, Timer: Off", ac.toString()); } @@ -126,7 +126,7 @@ TEST(TestIRFujitsuACClass, GetRawWithFan) { EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 16 * 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ("Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 3 (Fan), Temp: 20C, " - "Fan: 2 (Medium), Clean: Off, Filter: Off, " + "Fan: 2 (Medium), Clean: Off, Filter: Off, 10C Heat: Off, " "Swing: 2 (Swing(H)), Command: N/A, Timer: Off", ac.toString()); @@ -149,7 +149,7 @@ TEST(TestIRFujitsuACClass, SetRaw) { EXPECT_STATE_EQ(expected_default_arrah2e, ac.getRaw(), ac.getStateLength() * 8); EXPECT_EQ("Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 24C, " - "Fan: 1 (High), Clean: Off, Filter: Off, " + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " "Swing: 3 (Swing(V)+Swing(H)), Command: N/A, " "Timer: Off", ac.toString()); @@ -318,9 +318,7 @@ TEST(TestDecodeFujitsuAC, SyntheticShortMessages) { uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02, 0xFD}; EXPECT_STATE_EQ(expected_arrah2e, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Model: 1 (ARRAH2E), Id: 0, Power: Off, Mode: 0 (Auto), Temp: 16C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Model: 1 (ARRAH2E), Id: 0, Power: Off, Command: N/A", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -365,7 +363,7 @@ TEST(TestDecodeFujitsuAC, SyntheticLongMessages) { ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ("Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 18C, " - "Fan: 4 (Quiet), Clean: Off, Filter: Off, " + "Fan: 4 (Quiet), Clean: Off, Filter: Off, 10C Heat: Off, " "Swing: 1 (Swing(V)), Command: N/A, " "Timer: Off", ac.toString()); @@ -541,8 +539,8 @@ TEST(TestDecodeFujitsuAC, Issue414) { EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 4 (Heat), Temp: 24C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " + "Command: N/A, Timer: Off", ac.toString()); // Resend it using the state this time. @@ -617,9 +615,7 @@ TEST(TestIRFujitsuACClass, toCommon) { // Now test it. EXPECT_EQ( // Off mode technically has no temp, mode, fan, etc. - "Model: 1 (ARRAH2E), Id: 0, Power: Off, Mode: 0 (Auto), Temp: 16C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Model: 1 (ARRAH2E), Id: 0, Power: Off, Command: N/A", ac.toString()); ASSERT_EQ(decode_type_t::FUJITSU_AC, ac.toCommon().protocol); ASSERT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.toCommon().model); @@ -723,7 +719,7 @@ TEST(TestIRFujitsuACClass, OutsideQuiet) { // the option is set. Otheriwse they appear the same. EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 1 (Cool), Temp: 24C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), " + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " "Command: N/A, Timer: Off", ac.toString()); ac.setModel(fujitsu_ac_remote_model_t::ARREB1E); EXPECT_EQ( @@ -826,8 +822,8 @@ TEST(TestDecodeFujitsuAC, Issue726) { EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 24C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " + "Command: N/A, Timer: Off", ac.toString()); } @@ -859,16 +855,16 @@ TEST(TestIRFujitsuACClass, Clean) { EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " + "Command: N/A, Timer: Off", ac.toString()); // Now it is in ARRAH2E model mode, it shouldn't accept setting it on. ac.setClean(true); EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.getModel()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " + "Command: N/A, Timer: Off", ac.toString()); // But ARRY4 does. ac.setModel(fujitsu_ac_remote_model_t::ARRY4); @@ -905,8 +901,8 @@ TEST(TestIRFujitsuACClass, Filter) { EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Timer: Off", + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " + "Command: N/A, Timer: Off", ac.toString()); // Now it is in ARRAH2E model mode, it shouldn't accept setting it on. ac.setFilter(true); @@ -934,8 +930,8 @@ TEST(TestIRFujitsuACClass, Timers) { EXPECT_EQ(0, ac.getOffSleepTimer()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "On Timer: 12:00", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, Swing: 0 (Off), " + "Command: N/A, On Timer: 12:00", ac.toString()); const uint8_t timer_on_8h30m[kFujitsuAcStateLength] = { @@ -948,8 +944,8 @@ TEST(TestIRFujitsuACClass, Timers) { EXPECT_EQ(0, ac.getOffSleepTimer()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "On Timer: 08:30", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, On Timer: 08:30", ac.toString()); // TIMER OFF 11H @@ -963,8 +959,8 @@ TEST(TestIRFujitsuACClass, Timers) { EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Off Timer: 11:00", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, Off Timer: 11:00", ac.toString()); // TIMER OFF 0.5H @@ -978,8 +974,8 @@ TEST(TestIRFujitsuACClass, Timers) { EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Off Timer: 00:30", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, Off Timer: 00:30", ac.toString()); // TIMER SLEEP 3H @@ -993,8 +989,8 @@ TEST(TestIRFujitsuACClass, Timers) { EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Sleep Timer: 03:00", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, Sleep Timer: 03:00", ac.toString()); // Re-construct a known timer state from scratch. @@ -1011,8 +1007,8 @@ TEST(TestIRFujitsuACClass, Timers) { ac.setOffTimer(30); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Off Timer: 00:30", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, Off Timer: 00:30", ac.toString()); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_STATE_EQ(timer_off_30m, ac.getRaw(), ac.getStateLength() * 8); @@ -1020,8 +1016,8 @@ TEST(TestIRFujitsuACClass, Timers) { ac.setOnTimer(12 * 60); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "On Timer: 12:00", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, On Timer: 12:00", ac.toString()); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_EQ(12 * 60, ac.getOnTimer()); @@ -1033,8 +1029,8 @@ TEST(TestIRFujitsuACClass, Timers) { ac.setSleepTimer(3 * 60); EXPECT_EQ( "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 0 (Auto), Temp: 26C, " - "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A, " - "Sleep Timer: 03:00", + "Fan: 1 (High), Clean: Off, Filter: Off, 10C Heat: Off, " + "Swing: 0 (Off), Command: N/A, Sleep Timer: 03:00", ac.toString()); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_STATE_EQ(timer_sleep_3h, ac.getRaw(), ac.getStateLength() * 8); @@ -1122,7 +1118,7 @@ TEST(TestIRFujitsuACClass, Heat10Deg) { 0x69, 0x0B, 0x00, 0x23, 0x06, 0x23, 0x20, 0xEF}; ac.setRaw(heat_on, kFujitsuAcStateLength); EXPECT_EQ( - "Model: 6 (ARREW4E), Id: 1, Power: On, Mode: 3 (Fan), Temp: 21C, " + "Model: 6 (ARREW4E), Id: 1, Power: On, Mode: 3 (Fan), Temp: 10C, " "Fan: 0 (Auto), 10C Heat: On, Swing: 0 (Off), Command: N/A, " "Outside Quiet: Off, Timer: Off", ac.toString()); @@ -1138,7 +1134,7 @@ TEST(TestIRFujitsuACClass, Heat10Deg) { ac.set10CHeat(true); EXPECT_TRUE(ac.get10CHeat()); EXPECT_EQ( - "Model: 6 (ARREW4E), Id: 1, Power: On, Mode: 3 (Fan), Temp: 21C, " + "Model: 6 (ARREW4E), Id: 1, Power: On, Mode: 3 (Fan), Temp: 10C, " "Fan: 0 (Auto), 10C Heat: On, Swing: 0 (Off), Command: N/A, " "Outside Quiet: Off, Timer: Off", ac.toString()); @@ -1361,3 +1357,92 @@ TEST(TestIRFujitsuACClass, Discussion1701) { EXPECT_EQ(expected_raw_output, ac._irsend.outputStr()); // Success. } + +TEST(TestIRFujitsuACClass, toCommon_Issue1780HandlePrev) { + IRFujitsuAC ac(kGpioUnused); + ac.setMode(kFujitsuAcModeCool); + ac.setTemp(20); + ac.setFanSpeed(kFujitsuAcFanQuiet); + ac.setSwing(kFujitsuAcSwingBoth); + ac.on(); + ASSERT_TRUE(ac.toCommon().power); + stdAc::state_t prev = ac.toCommon(); // Copy in the state. + ac.off(); + ASSERT_FALSE(ac.toCommon().power); + ac.send(); // This should send a short code. + prev.degrees = 27; + ac.stateReset(); + IRrecv irrecv(kGpioUnused); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type); + ac.setRaw(ac._irsend.capture.state, ac._irsend.capture.bits / 8); + ASSERT_EQ(decode_type_t::FUJITSU_AC, ac.toCommon().protocol); + ASSERT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.toCommon().model); + ASSERT_FALSE(ac.toCommon().power); + ASSERT_TRUE(ac.toCommon().celsius); + ASSERT_EQ(16, ac.toCommon().degrees); + ASSERT_EQ(27, ac.toCommon(&prev).degrees); + ASSERT_FALSE(ac.toCommon().quiet); + + ASSERT_EQ(stdAc::opmode_t::kAuto, ac.toCommon().mode); + ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon(&prev).mode); + ASSERT_EQ(stdAc::fanspeed_t::kAuto, ac.toCommon().fanspeed); + ASSERT_EQ(stdAc::fanspeed_t::kMin, ac.toCommon(&prev).fanspeed); + ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv); + ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); + // Unsupported. + ASSERT_FALSE(ac.toCommon().filter); + ASSERT_FALSE(ac.toCommon().clean); + ASSERT_FALSE(ac.toCommon().turbo); + ASSERT_FALSE(ac.toCommon().light); + ASSERT_FALSE(ac.toCommon().econo); + ASSERT_FALSE(ac.toCommon().beep); + ASSERT_EQ(-1, ac.toCommon().sleep); + ASSERT_EQ(-1, ac.toCommon().clock); + + stdAc::state_t result_inc_prev; + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result_inc_prev, + &prev)); + ASSERT_EQ(27, result_inc_prev.degrees); + ASSERT_EQ(stdAc::opmode_t::kCool, result_inc_prev.mode); + ASSERT_EQ(stdAc::fanspeed_t::kMin, result_inc_prev.fanspeed); +} + +TEST(TestIRFujitsuACClass, Improve10CHeat) { + IRFujitsuAC ac(kGpioUnused); + // Data from https://docs.google.com/spreadsheets/d/1RdmJdOZ3zxYlLXzluKTp4L6VVdjDXKgizwwIyTTG8MA/edit#gid=0&range=G2 + const uint8_t Arrah2u_10CHeatOn[16] = { + 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, + 0x41, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x20, 0x64}; + ASSERT_FALSE(ac.get10CHeat()); + ac.setRaw(Arrah2u_10CHeatOn, 16); + ASSERT_TRUE(ac.get10CHeat()); + ASSERT_EQ( + "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 3 (Fan), Temp: 10C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: On, Swing: 0 (Off), " + "Command: N/A, Timer: Off", + ac.toString()); + EXPECT_EQ(decode_type_t::FUJITSU_AC, ac.toCommon().protocol); + ASSERT_TRUE(ac.get10CHeat()); + EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.toCommon().model); + EXPECT_EQ(kFujitsuAcMinHeat, ac.toCommon().degrees); + + ac.stateReset(); + // Data from https://docs.google.com/spreadsheets/d/1RdmJdOZ3zxYlLXzluKTp4L6VVdjDXKgizwwIyTTG8MA/edit#gid=0&range=G8 + const uint8_t Arreg1u_10CHeatOn[16] = { + 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, + 0x61, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x20, 0x44}; + ASSERT_FALSE(ac.get10CHeat()); + ac.setRaw(Arreg1u_10CHeatOn, 16); + ASSERT_TRUE(ac.get10CHeat()); + ASSERT_EQ( + "Model: 1 (ARRAH2E), Id: 0, Power: On, Mode: 3 (Fan), Temp: 10C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, 10C Heat: On, Swing: 0 (Off), " + "Command: N/A, Timer: Off", + ac.toString()); + EXPECT_EQ(decode_type_t::FUJITSU_AC, ac.toCommon().protocol); + ASSERT_TRUE(ac.get10CHeat()); + EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.toCommon().model); + EXPECT_EQ(kFujitsuAcMinHeat, ac.toCommon().degrees); +} 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 cb1832f61..e0160577e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp @@ -326,6 +326,9 @@ TEST(TestGreeClass, OperatingMode) { ac.setMode(kGreeHeat); EXPECT_EQ(kGreeHeat, ac.getMode()); + ac.setMode(kGreeEcono); + EXPECT_EQ(kGreeEcono, ac.getMode()); + ASSERT_NE(kGreeFanMax, 1); ac.setFan(kGreeFanMax); ac.setMode(kGreeDry); // Dry should lock the fan to speed 1. @@ -337,7 +340,7 @@ TEST(TestGreeClass, OperatingMode) { ac.setMode(kGreeFan); EXPECT_EQ(kGreeFan, ac.getMode()); - ac.setMode(kGreeHeat + 1); + ac.setMode(kGreeEcono + 1); EXPECT_EQ(kGreeAuto, ac.getMode()); ac.setMode(255); @@ -798,3 +801,40 @@ TEST(TestGreeClass, DisplayTempSource) { ac.setRaw(state); EXPECT_EQ(2, ac.getDisplayTempSource()); } + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("GREE", typeToString(decode_type_t::GREE)); + ASSERT_EQ(decode_type_t::GREE, strToDecodeType("GREE")); + ASSERT_TRUE(hasACState(decode_type_t::GREE)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::GREE)); + ASSERT_EQ(kGreeBits, IRsend::defaultBits(decode_type_t::GREE)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::GREE)); + ASSERT_EQ(gree_ac_remote_model_t::YAW1F, IRac::strToModel("YAW1F")); + ASSERT_EQ(irutils::modelToStr(decode_type_t::GREE, + gree_ac_remote_model_t::YAW1F), "YAW1F"); + ASSERT_EQ(gree_ac_remote_model_t::YBOFB, IRac::strToModel("YBOFB")); + ASSERT_EQ(irutils::modelToStr(decode_type_t::GREE, + gree_ac_remote_model_t::YBOFB), "YBOFB"); + ASSERT_EQ(gree_ac_remote_model_t::YX1FSF, IRac::strToModel("YX1FSF")); + ASSERT_EQ(irutils::modelToStr(decode_type_t::GREE, + gree_ac_remote_model_t::YX1FSF), "YX1FSF"); +} + +TEST(TestGreeClass, Issue1821EnergySaver) { + IRGreeAC ac(kGpioUnused); + ac.begin(); + + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1821#issue-1271458457 + const uint8_t energy[8] = {0x1D, 0x09, 0x60, 0x58, 0x00, 0x20, 0x00, 0xA0}; + + ac.setRaw(energy); + EXPECT_EQ(kGreeEcono, ac.getMode()); + EXPECT_TRUE(ac.getEcono()); + EXPECT_EQ(gree_ac_remote_model_t::YX1FSF, ac.getModel()); + EXPECT_EQ( + "Model: 3 (YX1FSF), Power: On, Mode: 5 (Econo), Temp: 77F, Fan: 1 (Low), " + "Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, " + "Sleep: Off, Swing(V) Mode: Manual, Swing(V): 0 (Last), " + "Swing(H): 0 (Off), Timer: Off, Display Temp: 0 (Off)", + ac.toString()); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp index b60a08f23..5f2b9a92d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp @@ -1357,6 +1357,13 @@ TEST(TestUtils, Housekeeping) { ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HAIER_AC176)); ASSERT_EQ(kHaierAC176Bits, IRsend::defaultBits(decode_type_t::HAIER_AC176)); ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::HAIER_AC176)); + + ASSERT_EQ("HAIER_AC160", typeToString(decode_type_t::HAIER_AC160)); + ASSERT_EQ(decode_type_t::HAIER_AC160, strToDecodeType("HAIER_AC160")); + ASSERT_TRUE(hasACState(decode_type_t::HAIER_AC160)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HAIER_AC160)); + ASSERT_EQ(kHaierAC160Bits, IRsend::defaultBits(decode_type_t::HAIER_AC160)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::HAIER_AC160)); } TEST(TestHaierAC176Class, BuildKnownState) { @@ -1535,3 +1542,492 @@ TEST(TestHaierAC176Class, Models) { "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } + +TEST(TestDecodeHaierAC160, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1804#issue-1236115063 + const uint16_t rawData[325] = { + 3078, 3002, + 3058, 4338, + 590, 1612, 588, 516, 584, 1588, 586, 542, 560, 540, 560, 1590, 584, 1618, + 584, 542, 558, 1592, 584, 542, 582, 1594, 584, 542, 582, 1592, 560, 1642, + 560, 516, 558, 544, 558, 542, 558, 542, 582, 518, 558, 542, 558, 516, 558, + 542, 558, 542, 582, 520, 558, 542, 558, 542, 564, 510, 608, 492, 558, 542, + 582, 520, 558, 542, 558, 544, 582, 492, 608, 1594, 558, 544, 558, 542, + 582, 494, 608, 494, 558, 544, 558, 542, 558, 544, 558, 1616, 582, 1620, + 560, 542, 558, 542, 582, 494, 558, 542, 558, 542, 558, 544, 556, 542, 582, + 520, 580, 494, 582, 520, 582, 520, 558, 542, 558, 542, 582, 520, 582, 492, + 608, 1592, 582, 520, 558, 544, 558, 516, 584, 518, 558, 542, 582, 520, + 580, 520, 582, 520, 580, 492, 584, 516, 556, 544, 582, 518, 580, 520, 580, + 520, 580, 494, 606, 494, 580, 520, 580, 520, 582, 520, 580, 520, 556, 518, + 608, 492, 580, 520, 556, 544, 580, 520, 580, 520, 580, 494, 606, 494, 580, + 520, 580, 520, 580, 520, 580, 520, 580, 494, 606, 496, 578, 522, 580, 520, + 580, 520, 580, 520, 580, 494, 606, 494, 580, 520, 580, 520, 580, 1594, + 608, 494, 580, 1620, 580, 522, 580, 520, 580, 494, 578, 1620, 582, 520, + 580, 1596, 582, 1620, 582, 1594, 608, 1594, 582, 522, 580, 1594, 582, + 1620, 582, 520, 580, 1596, 582, 520, 580, 1620, 582, 494, 606, 496, 580, + 522, 580, 522, 580, 520, 580, 520, 580, 496, 604, 496, 580, 520, 580, + 1620, 582, 1594, 582, 522, 578, 522, 580, 522, 578, 522, 580, 496, 580, + 522, 578, 522, 578, 522, 578, 524, 578, 522, 578, 496, 578, 522, 578, 522, + 578, 546, 554, 522, 578, 522, 578, 520, 556, 546, 554, 546, 554, 546, 556, + 544, 556, 546, 554, 520, 554, 544, 556, 1620, 582, 544, 556, 1594, 580, + 546, 556, 1594, 580}; // UNKNOWN B6B57D85 + const uint8_t expectedState[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x17, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15}; + + irsend.sendRaw(rawData, 325, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(HAIER_AC160, irsend.capture.decode_type); + ASSERT_EQ(kHaierAC160Bits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 26C, Fan: 3 (Low), " + "Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), Sleep: Off, " + "Clean: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off, " + "Heating: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t result, prev; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); +} + +// Decoding a message we entirely constructed based solely on a given state. +TEST(TestDecodeHaierAC160, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + const uint8_t expectedState[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x17, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15}; + + irsend.reset(); + irsend.sendHaierAC160(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(HAIER_AC160, irsend.capture.decode_type); + ASSERT_EQ(kHaierAC160Bits, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 26C, Fan: 3 (Low), " + "Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), Sleep: Off, " + "Clean: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off, " + "Heating: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t result, prev; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); +} + +// Tests for the IRHaierAC160 class. + +TEST(TestHaierAC160Class, Button) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setButton(kHaierAcYrw02ButtonPower); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonMode); + EXPECT_EQ(kHaierAcYrw02ButtonMode, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonSleep); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonFan); + + // Test unexpected values. + ac.setButton(0xFF); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); + ac.setButton(0x10); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); +} + +TEST(TestHaierAC160Class, OperatingMode) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setMode(kHaierAcYrw02Auto); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); + EXPECT_EQ(kHaierAcYrw02ButtonMode, ac.getButton()); + + ac.setMode(kHaierAcYrw02Cool); + EXPECT_EQ(kHaierAcYrw02Cool, ac.getMode()); + EXPECT_FALSE(ac.getAuxHeating()); + + ac.setMode(kHaierAcYrw02Heat); + EXPECT_EQ(kHaierAcYrw02Heat, ac.getMode()); + EXPECT_TRUE(ac.getAuxHeating()); + + ac.setMode(kHaierAcYrw02Fan); + EXPECT_EQ(kHaierAcYrw02Fan, ac.getMode()); + EXPECT_FALSE(ac.getAuxHeating()); + + ac.setMode(kHaierAcYrw02Dry); + EXPECT_EQ(kHaierAcYrw02Dry, ac.getMode()); + + ac.setMode(kHaierAcYrw02Auto - 1); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); + + ac.setMode(kHaierAcYrw02Cool); + EXPECT_EQ(kHaierAcYrw02Cool, ac.getMode()); + + ac.setMode(kHaierAcYrw02Fan + 1); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); +} + +TEST(TestHaierAC160Class, Temperature) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setTemp(kHaierAcYrw02MinTempC); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); + + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(kHaierAcYrw02MinTempC + 1); + EXPECT_EQ(kHaierAcYrw02MinTempC + 1, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempC); + EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MinTempC - 1); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempC + 1); + EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MinTempF, true); + EXPECT_EQ(kHaierAcYrw02MinTempF, ac.getTemp()); + + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(kHaierAcYrw02MinTempF + 1, true); + EXPECT_EQ(kHaierAcYrw02MinTempF + 1, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempF, true); + EXPECT_EQ(kHaierAcYrw02MaxTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MinTempF - 1, true); + EXPECT_EQ(kHaierAcYrw02MinTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempF + 1, true); + EXPECT_EQ(kHaierAcYrw02MaxTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(66, true); + EXPECT_EQ(66, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(66, true); + EXPECT_EQ(66, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + // Test specific cases for converting to Fahrenheit + ac.setTemp(76, true); + EXPECT_EQ(76, ac.getTemp()); + ac.setTemp(77, true); + EXPECT_EQ(77, ac.getTemp()); + ac.setTemp(78, true); + EXPECT_EQ(78, ac.getTemp()); + + ac.setTemp(24); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); + + ac.setTemp(0); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + + ac.setTemp(255); + EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); +} + +TEST(TestHaierAC160Class, CleanMode) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setClean(true); + EXPECT_TRUE(ac.getClean()); + EXPECT_EQ(kHaierAc160ButtonClean, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setClean(false); + EXPECT_FALSE(ac.getClean()); + EXPECT_EQ(kHaierAc160ButtonClean, ac.getButton()); + + ac.setClean(true); + EXPECT_TRUE(ac.getClean()); + EXPECT_EQ(kHaierAc160ButtonClean, ac.getButton()); + + ac.stateReset(); + EXPECT_FALSE(ac.getClean()); + // clean button pressed. + // https://docs.google.com/spreadsheets/d/1RNJ7esbArS5fy1lmiM-i1PekXSNojCMad4WuuyunsC8/edit#gid=2048081808&range=FR22 + const uint8_t clean_on[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00, + 0x10, 0x00, 0x19, 0x3B, 0xB5, 0x40, 0x60, 0x00, 0x00, 0x55}; + ac.setRaw(clean_on); + EXPECT_TRUE(ac.getClean()); + EXPECT_EQ( + "Power: On, Button: 25 (Clean), Mode: 1 (Cool), Temp: 26C, " + "Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), " + "Sleep: Off, Clean: On, Timer Mode: 0 (N/A), " + "On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off", + ac.toString()); + // No clean set. + // https://docs.google.com/spreadsheets/d/1RNJ7esbArS5fy1lmiM-i1PekXSNojCMad4WuuyunsC8/edit#gid=2048081808&range=FR4 + const uint8_t clean_off[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x17, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15}; + ac.setRaw(clean_off); + EXPECT_FALSE(ac.getClean()); + EXPECT_EQ( + "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 26C, " + "Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), " + "Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), " + "On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off", + ac.toString()); +} + +TEST(TestHaierAC160Class, Power) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + ac.off(); + EXPECT_FALSE(ac.getPower()); + ac.on(); + EXPECT_TRUE(ac.getPower()); +} + +TEST(TestHaierAC160Class, SleepMode) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); + + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); +} + +TEST(TestHaierAC160Class, Health) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setHealth(true); + EXPECT_TRUE(ac.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setHealth(false); + EXPECT_FALSE(ac.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton()); + + ac.setHealth(true); + EXPECT_TRUE(ac.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton()); +} + +TEST(TestHaierAC160Class, TurboAndQuiet) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setMode(kHaierAcYrw02Cool); // Turbo & Quiet is allowed in this mode. + ac.setTurbo(false); + ac.setQuiet(false); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); + + ac.setQuiet(true); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_TRUE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); + + ac.setTurbo(false); + ac.setQuiet(false); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); + + ac.setMode(kHaierAcYrw02Auto); // Turbo & Quiet is not allowed in this mode. + EXPECT_FALSE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + ac.setTurbo(true); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_NE(kHaierAcYrw02ButtonTurbo, ac.getButton()); + ac.setQuiet(true); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_NE(kHaierAcYrw02ButtonTurbo, ac.getButton()); +} + +TEST(TestHaierAC160Class, Fan) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setFan(kHaierAcYrw02FanAuto); + EXPECT_EQ(kHaierAcYrw02FanAuto, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + + ac.setFan(kHaierAcYrw02FanLow); + EXPECT_EQ(kHaierAcYrw02FanLow, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); + + ac.setFan(kHaierAcYrw02FanHigh); + EXPECT_EQ(kHaierAcYrw02FanHigh, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); + + ac.setFan(kHaierAcYrw02FanMed); + EXPECT_EQ(kHaierAcYrw02FanMed, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); + + // Test unexpected values. + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setFan(0x00); + EXPECT_EQ(kHaierAcYrw02FanMed, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); +} + +TEST(TestHaierAC160Class, SwingV) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setSwingV(kHaierAc160SwingVOff); + EXPECT_EQ(kHaierAc160SwingVOff, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + + ac.setSwingV(kHaierAc160SwingVAuto); + EXPECT_EQ(kHaierAc160SwingVAuto, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); + + ac.setSwingV(kHaierAc160SwingVTop); + EXPECT_EQ(kHaierAc160SwingVTop, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); + + ac.setSwingV(kHaierAc160SwingVLow); + EXPECT_EQ(kHaierAc160SwingVLow, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); + + // Test unexpected values. + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setSwingV(0xFF); + EXPECT_EQ(kHaierAc160SwingVLow, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); +} + +TEST(TestHaierAC160Class, Light) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setLightToggle(true); + EXPECT_TRUE(ac.getLightToggle()); + EXPECT_EQ(kHaierAc160ButtonLight, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setLightToggle(false); + EXPECT_FALSE(ac.getLightToggle()); + EXPECT_NE(kHaierAc160ButtonLight, ac.getButton()); + + ac.setLightToggle(true); + EXPECT_TRUE(ac.getLightToggle()); + EXPECT_EQ(kHaierAc160ButtonLight, ac.getButton()); + + const uint8_t light_press[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x15, 0x27, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15}; + ac.setRaw(light_press); + EXPECT_TRUE(ac.getLightToggle()); + EXPECT_EQ(kHaierAc160ButtonLight, ac.getButton()); + EXPECT_EQ( + "Power: On, Button: 21 (Light), Mode: 1 (Cool), Temp: 26C, " + "Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), " + "Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), " + "On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off", + ac.toString()); +} + +TEST(TestHaierAC160Class, AuxHeating) { + IRHaierAC160 ac(kGpioUnused); + ac.begin(); + + ac.setAuxHeating(true); + EXPECT_TRUE(ac.getAuxHeating()); + EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setAuxHeating(false); + EXPECT_FALSE(ac.getAuxHeating()); + EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton()); + + ac.setAuxHeating(true); + EXPECT_TRUE(ac.getAuxHeating()); + EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton()); + + // https://docs.google.com/spreadsheets/d/1RNJ7esbArS5fy1lmiM-i1PekXSNojCMad4WuuyunsC8/edit#gid=2048081808&range=A124:W143 + const uint8_t aux_button_off[kHaierAC160StateLength] = { + 0xA6, 0xAC, 0x00, 0x00, 0x40, 0x60, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x16, 0x88, 0xB5, 0x00, 0x60, 0x00, 0x00, 0x15}; + ac.setRaw(aux_button_off); + EXPECT_FALSE(ac.getAuxHeating()); + EXPECT_EQ(kHaierAc160ButtonAuxHeating, ac.getButton()); + EXPECT_EQ( + "Power: On, Button: 22 (Heating), Mode: 4 (Heat), Temp: 26C, " + "Fan: 3 (Low), Turbo: Off, Quiet: Off, Health: Off, Swing(V): 12 (Auto), " + "Sleep: Off, Clean: Off, Timer Mode: 0 (N/A), " + "On Timer: Off, Off Timer: Off, Lock: Off, Heating: Off", + ac.toString()); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sanyo_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sanyo_test.cpp index 6378e7679..bcfaef972 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sanyo_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sanyo_test.cpp @@ -284,6 +284,14 @@ TEST(TestUtils, Housekeeping) { ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::SANYO_AC88)); ASSERT_EQ(kSanyoAc88Bits, IRsend::defaultBits(decode_type_t::SANYO_AC88)); ASSERT_EQ(kSanyoAc88MinRepeat, IRsend::minRepeats(decode_type_t::SANYO_AC88)); + // Sanyo A/C 152 Bit. + ASSERT_EQ("SANYO_AC152", typeToString(decode_type_t::SANYO_AC152)); + ASSERT_EQ(decode_type_t::SANYO_AC152, strToDecodeType("SANYO_AC152")); + ASSERT_TRUE(hasACState(decode_type_t::SANYO_AC152)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SANYO_AC152)); + ASSERT_EQ(kSanyoAc152Bits, IRsend::defaultBits(decode_type_t::SANYO_AC152)); + ASSERT_EQ(kSanyoAc152MinRepeat, + IRsend::minRepeats(decode_type_t::SANYO_AC152)); } TEST(TestDecodeSanyoAc, DecodeRealExamples) { @@ -820,3 +828,70 @@ TEST(TestSanyoAc88Class, Clock) { ac.setClock(25 * 60 + 61); EXPECT_EQ(23 * 60 + 59, ac.getClock()); } + +TEST(TestDecodeSanyoAc152, DecodeRealExamples) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + // Ref: "16c" from https://github.com/crankyoldgit/IRremoteESP8266/issues/1826#issuecomment-1160708653 + const uint16_t rawData[307] = { + 3294, 1726, 420, 330, 458, 462, 382, 452, 438, 330, 456, 458, 384, 454, + 384, 1312, 422, 324, 512, 336, 454, 458, 384, 450, 438, 358, 436, 464, + 424, 326, 458, 476, 372, 458, 430, 328, 458, 464, 382, 1308, 424, 326, + 510, 1264, 424, 268, 520, 460, 380, 460, 436, 324, 462, 400, 436, 474, + 372, 456, 430, 342, 452, 450, 388, 446, 442, 1262, 422, 266, 520, 1314, + 372, 1306, 424, 1258, 370, 390, 448, 1314, 372, 1310, 426, 308, 522, 338, + 454, 470, 370, 454, 438, 330, 456, 468, 370, 456, 384, 464, 384, 1306, + 422, 328, 460, 472, 374, 448, 442, 1258, 426, 1256, 426, 268, 520, 464, + 382, 460, 430, 328, 508, 1264, 426, 262, 572, 1262, 424, 228, 604, 1262, + 372, 1312, 372, 1310, 426, 1256, 422, 1258, 424, 262, 524, 418, 428, 456, + 382, 1308, 372, 456, 386, 456, 382, 464, 378, 1308, 424, 360, 436, 454, + 430, 344, 450, 1306, 372, 1310, 424, 326, 510, 338, 452, 456, 384, 456, + 436, 328, 510, 1258, 372, 1310, 422, 338, 454, 466, 424, 328, 460, 1310, + 372, 1312, 424, 1258, 450, 262, 496, 1310, 372, 1310, 426, 1260, 424, 260, + 526, 442, 442, 1264, 426, 268, 520, 458, 380, 450, 386, 462, 436, 320, + 518, 1256, 372, 394, 446, 398, 494, 334, 506, 326, 510, 276, 518, 460, + 430, 332, 508, 326, 510, 356, 440, 448, 444, 264, 572, 336, 456, 408, 434, + 454, 438, 332, 506, 336, 454, 460, 384, 448, 444, 326, 510, 332, 456, 442, + 400, 456, 384, 456, 386, 452, 388, 454, 440, 326, 512, 272, 518, 450, 440, + 334, 454, 458, 440, 320, 516, 268, 570, 340, 452, 468, 424, 260, 574, 336, + 456, 394, 444, 458, 438, 328, 508, 1258, 370, 1312, 372, 1312, 424, 314, + 468, 1312, 450, 1232, 370, 1314, 420, 324, 514}; // UNKNOWN 584FBE80 + + const uint8_t expectedState[kSanyoAc152StateLength] = { + 0x40, 0x00, 0x14, 0x80, 0x6E, 0x80, 0x18, 0xEA, 0x23, 0x62, + 0x30, 0xEE, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77}; + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData, 307, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(SANYO_AC152, irsend.capture.decode_type); + EXPECT_EQ(kSanyoAc152Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +TEST(TestDecodeSanyoAc152, SyntheticSelfDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint8_t expectedState[kSanyoAc152StateLength] = { + 0x40, 0x00, 0x14, 0x80, 0x6E, 0x80, 0x18, 0xEA, 0x23, 0x62, + 0x30, 0xEE, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77}; + irsend.begin(); + irsend.reset(); + irsend.sendSanyoAc152(expectedState); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SANYO_AC152, irsend.capture.decode_type); + EXPECT_EQ(kSanyoAc152Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp index b7ab5301f..f1a4cf393 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 David Conran +// Copyright 2019-2022 David Conran #include "ir_Tcl.h" #include "IRac.h" @@ -22,6 +22,13 @@ TEST(TestTcl112Ac, Housekeeping) { ASSERT_EQ(tcl_ac_remote_model_t::GZ055BE1, IRac::strToModel("GZ055BE1")); ASSERT_EQ(irutils::modelToStr(decode_type_t::TCL112AC, tcl_ac_remote_model_t::GZ055BE1), "GZ055BE1"); + + ASSERT_EQ("TCL96AC", typeToString(decode_type_t::TCL96AC)); + ASSERT_EQ(decode_type_t::TCL96AC, strToDecodeType("TCL96AC")); + ASSERT_TRUE(hasACState(decode_type_t::TCL96AC)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::TCL96AC)); + ASSERT_EQ(kTcl96AcBits, IRsend::defaultBits(decode_type_t::TCL96AC)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::TCL96AC)); } // Tests for decodeTcl112Ac(). @@ -703,3 +710,64 @@ TEST(TestTcl112AcClass, Timers) { "On Timer: Off, Off Timer: 02:00", ac.toString()); } + +// Decode a real Tcl96Ac A/C example from Issue #619 +TEST(TestDecodeTcl96Ac, DecodeRealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Tcl96Ac A/C example from Issue #1810 row_data.txt + const uint16_t rawData[99] = { + 1056, 550, + 608, 2182, 608, 1444, 606, 840, 608, 2182, + 608, 360, 612, 2182, 608, 356, 616, 1446, + 608, 354, 618, 366, 608, 366, 606, 356, + 618, 356, 618, 838, 608, 364, 608, 364, + 608, 2182, 608, 360, 612, 840, 608, 838, + 610, 364, 608, 360, 612, 2182, 608, 838, + 608, 838, 608, 2182, 608, 366, 606, 1444, + 608, 358, 614, 1444, 608, 838, 608, 366, + 606, 368, 606, 366, 606, 366, 606, 366, + 608, 364, 608, 342, 632, 840, 606, 340, + 606, 364, 634, 338, 634, 340, 632, 340, + 634, 814, 632, 814, 632, 2156, 634, 2156, + 634}; // UNKNOWN AE10E0CB + + const uint8_t expectedState[kTcl96AcStateLength] = { + 0xB6, 0x23, 0x00, 0x10, 0x85, 0x09, 0x63, 0x34, 0x00, 0x04, 0x00, 0x5A}; + + irsend.sendRaw(rawData, 99, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(TCL96AC, irsend.capture.decode_type); + EXPECT_EQ(kTcl96AcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +// Decode a synthetic Tcl96Ac A/C message +TEST(TestDecodeTcl96Ac, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + + const uint8_t expectedState[kTcl96AcStateLength] = { + 0xB6, 0x23, 0x00, 0x10, 0x85, 0x09, 0x63, 0x34, 0x00, 0x04, 0x00, 0x5A}; + + irsend.sendTcl96Ac(expectedState); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(TCL96AC, irsend.capture.decode_type); + EXPECT_EQ(kTcl96AcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "", + IRAcUtils::resultAcToString(&irsend.capture)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toto_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toto_test.cpp new file mode 100644 index 000000000..050bd01e6 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toto_test.cpp @@ -0,0 +1,159 @@ +// Copyright 2022 crankyoldgit (David Conran) + +#include "IRac.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "IRutils.h" +#include "gtest/gtest.h" + + +// General housekeeping +TEST(TestToto, Housekeeping) { + ASSERT_EQ("TOTO", typeToString(TOTO)); + ASSERT_FALSE(hasACState(TOTO)); + ASSERT_EQ(kTotoBits, IRsend::defaultBits(decode_type_t::TOTO)); + ASSERT_EQ(kSingleRepeat, IRsend::minRepeats(decode_type_t::TOTO)); +} + +// Tests for decodeToto(). + +// Decode normal Toto messages. +TEST(TestDecodeToto, SyntheticShortDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + // Short Toto 24-bit message. + irsend.reset(); + irsend.sendToto(0x0D0D00); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(TOTO, irsend.capture.decode_type); + EXPECT_EQ(kTotoBits, irsend.capture.bits); + EXPECT_EQ(0x0D0D00, irsend.capture.value); + EXPECT_EQ(0, irsend.capture.address); + EXPECT_EQ(0x0D00, irsend.capture.command); +} + +// Decode real example via Issue #1806 +TEST(TestDecodeToto, RealShortDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Toto Full Flush from Issue #1806 + const uint16_t rawData[163] = { + 6266, 2734, + 598, 540, 598, 1626, 598, 512, 622, 516, 598, 514, 598, 510, 598, 514, + 628, 512, 596, 514, 600, 512, 598, 538, 600, 1622, 600, 512, 598, 540, + 602, 510, 598, 512, 598, 512, 624, 514, 598, 512, 598, 512, 598, 514, + 624, 512, 598, 514, 598, 1652, 596, 514, 598, 1626, 598, 1650, 598, 514, + 598, 512, 598, 540, 598, 514, 596, 1626, 626, 512, 574, 1648, 598, 1650, + 598, 514, 598, 512, 594, 544, 596, 514, + 598, 37996, + 6182, 2764, + 598, 514, 600, 1648, 600, 512, 596, 514, 598, 540, 598, 512, 600, 512, + 598, 512, 624, 514, 598, 514, 598, 512, 596, 1652, 598, 514, 598, 512, + 596, 540, 598, 514, 598, 512, 598, 512, 598, 540, 596, 516, 596, 514, 598, + 512, 574, 564, 598, 1626, 568, 542, 624, 1624, 626, 1622, 598, 514, 596, + 514, 598, 514, 596, 540, 600, 1622, 598, 512, 600, 1650, 598, 1624, 596, + 540, 600, 512, 598, 514, 596, 514, + 622}; // UNKNOWN 43BD67B3 + + irsend.sendRaw(rawData, 163, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(TOTO, irsend.capture.decode_type); + EXPECT_EQ(kTotoBits, irsend.capture.bits); + EXPECT_EQ(0x0D0D00, irsend.capture.value); + EXPECT_EQ(0, irsend.capture.address); + EXPECT_EQ(0x0D00, irsend.capture.command); +} + +// Decode real example via Issue #1806 +TEST(TestDecodeToto, RealLongDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Oscillate Bidet Function from Issue #1806 + const uint16_t rawData[491] = { + 6262, 2738, + 600, 538, 596, 1624, 598, 512, 652, 486, 628, 484, 600, 510, 596, 516, + 650, 488, 622, 488, 626, 484, 598, 540, 600, 1624, 602, 510, 596, 540, + 602, 510, 598, 514, 598, 512, 626, 512, 598, 512, 598, 512, 598, 514, + 626, 510, 598, 514, 598, 512, 598, 1650, 600, 1622, 600, 538, 596, 514, + 600, 510, 596, 514, 596, 542, 598, 514, 598, 1624, 626, 1622, 598, 512, + 600, 512, 620, 516, 598, 512, 598, 514, + 598, 40244, + 6184, 2764, + 598, 514, 598, 1650, 598, 514, 596, 516, 596, 542, 598, 512, 596, 516, + 600, 510, 624, 512, 598, 512, 596, 516, 598, 1652, 600, 512, 598, 512, + 598, 540, 596, 518, 594, 514, 598, 512, 596, 542, 598, 512, 596, 514, + 598, 512, 598, 540, 598, 514, 598, 1622, 624, 1626, 598, 514, 598, 512, + 626, 512, 596, 514, 596, 514, 596, 540, 598, 1624, 600, 1650, 600, 512, + 600, 510, 598, 512, 596, 540, 598, 512, + 600, 40244, + 6186, 2760, + 600, 512, 596, 1626, 624, 514, 598, 512, 600, 512, 598, 512, 626, 512, + 598, 512, 598, 512, 596, 540, 600, 510, 600, 1622, 600, 538, 596, 514, + 596, 514, 598, 514, 624, 514, 596, 516, 596, 514, 600, 512, 622, 514, 600, + 512, 600, 510, 600, 538, 602, 1622, 600, 1648, 626, 512, 572, 512, 598, + 514, 650, 488, 598, 512, 594, 516, 598, 1652, 598, 1626, 598, 514, 624, + 514, 596, 512, 600, 512, 598, 540, + 596, 40246, + 6184, 2736, + 598, 538, 598, 1624, 598, 512, 598, 540, 598, 512, 600, 512, 596, 514, + 600, 538, 626, 486, 598, 514, 596, 514, 652, 1596, 594, 516, 624, 514, + 594, 516, 598, 514, 622, 490, 596, 540, 596, 514, 624, 488, 594, 514, 598, + 538, 598, 512, 598, 514, 594, 516, 596, 540, 600, 1622, 572, 566, 600, + 512, 570, 542, 598, 512, 598, 540, 600, 512, 594, 516, 598, 1652, 600, + 512, 598, 514, 596, 514, 624, 514, + 598, 42468, + 6182, 2764, + 624, 490, 594, 1652, 600, 512, 596, 514, 596, 540, 600, 512, 598, 516, + 596, 514, 598, 538, 598, 516, 598, 512, 570, 1678, 596, 514, 596, 514, + 598, 512, 624, 512, 594, 516, 596, 514, 600, 510, 626, 512, 596, 516, + 594, 516, 598, 538, 598, 512, 596, 514, 596, 514, 596, 1652, 600, 514, + 594, 516, 622, 514, 600, 512, 598, 514, 596, 514, 624, 514, 596, 1626, + 598, 514, 622, 516, 594, 516, 598, 514, + 596, 42496, + 6184, 2764, + 596, 516, 598, 1624, 626, 512, 598, 512, 596, 516, 600, 512, 624, 514, + 598, 514, 594, 516, 596, 516, 620, 516, 600, 1624, 596, 540, 598, 514, + 600, 512, 596, 516, 596, 542, 594, 516, 598, 514, 594, 516, 624, 512, 598, + 512, 596, 514, 596, 514, 624, 514, 596, 516, 598, 1650, 594, 518, 596, + 514, 596, 516, 596, 542, 596, 514, 596, 516, 596, 514, 596, 1652, 598, + 514, 596, 514, 624, 514, 622, 488, 596}; // UNKNOWN 4AC5E8B3 + + + irsend.sendRaw(rawData, 491, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(TOTO, irsend.capture.decode_type); + EXPECT_EQ(kTotoLongBits, irsend.capture.bits); + EXPECT_EQ(0x60600080800, irsend.capture.value); + EXPECT_EQ(0x0600, irsend.capture.address); + EXPECT_EQ(0x0800, irsend.capture.command); +} + +TEST(TestDecodeToto, SyntheticLongDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + // Long Toto 48-bit message. + irsend.reset(); + irsend.sendToto(0x60600080800, kTotoLongBits); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(TOTO, irsend.capture.decode_type); + EXPECT_EQ(kTotoLongBits, irsend.capture.bits); + EXPECT_EQ(0x60600080800, irsend.capture.value); + EXPECT_EQ(0x0600, irsend.capture.address); + EXPECT_EQ(0x0800, irsend.capture.command); +} 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 e061d3c42..69149215d 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 @@ -100,7 +100,6 @@ class RawIRMessage(): def add_data_code(self, bin_str, name="", footer=True): """Add the common "data" sequence of code to send the bulk of a message.""" - # pylint: disable=no-self-use code = [] nbits = len(bin_str) code.append(f" // Data Section #{self.section_count}") @@ -115,7 +114,6 @@ class RawIRMessage(): def add_data_decode_code(self, bin_str, name="", footer=True): """Add the common "data" sequence code to decode the bulk of a message.""" - # pylint: disable=no-self-use code = [] nbits = len(bin_str) code.extend([ @@ -139,7 +137,6 @@ class RawIRMessage(): def add_data_byte_code(self, bin_str, name="", ambles=None): """Add the code to send the data from an array.""" - # pylint: disable=no-self-use code = [] nbits = len(bin_str) nbytes = nbits / 8 @@ -173,7 +170,6 @@ class RawIRMessage(): def add_data_byte_decode_code(self, bin_str, name="", ambles=None): """Add the common byte-wise "data" sequence decode code.""" - # pylint: disable=no-self-use code = [] nbits = len(bin_str) nbytes = nbits / 8