From f7b9a9c3245e76278c0f5c757d66bc236a71e747 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Wed, 12 Jan 2022 21:34:40 +0100 Subject: [PATCH] IRremoteESP8266 library from v2.8.0 to v2.8.1 --- CHANGELOG.md | 1 + .../IRremoteESP8266/IRremoteESP8266/README.md | 4 +- .../IRremoteESP8266/README_de.md | 4 +- .../IRremoteESP8266/README_fr.md | 4 +- .../IRremoteESP8266/ReleaseNotes.md | 24 + .../IRremoteESP8266/SupportedProtocols.md | 13 +- .../examples/IRMQTTServer/IRMQTTServer.ino | 2 +- .../examples/IRrecvDumpV2/IRrecvDumpV2.ino | 2 +- .../examples/IRrecvDumpV3/IRrecvDumpV3.ino | 2 +- .../IRremoteESP8266/keywords.txt | 48 ++ .../IRremoteESP8266/library.json | 2 +- .../IRremoteESP8266/library.properties | 2 +- .../IRremoteESP8266/src/IRac.cpp | 79 +++- .../IRremoteESP8266/src/IRac.h | 11 +- .../IRremoteESP8266/src/IRrecv.cpp | 40 +- .../IRremoteESP8266/src/IRrecv.h | 7 +- .../IRremoteESP8266/src/IRremoteESP8266.h | 36 +- .../IRremoteESP8266/src/IRsend.cpp | 9 +- .../IRremoteESP8266/src/IRsend.h | 146 +++--- .../IRremoteESP8266/src/IRtext.cpp | 9 + .../IRremoteESP8266/src/IRtext.h | 6 + .../IRremoteESP8266/src/IRutils.cpp | 15 + .../IRremoteESP8266/src/IRutils.h | 2 + .../IRremoteESP8266/src/ir_Airton.cpp | 302 ++++++++++++- .../IRremoteESP8266/src/ir_Airton.h | 134 ++++++ .../IRremoteESP8266/src/ir_Coolix.cpp | 72 ++- .../IRremoteESP8266/src/ir_Coolix.h | 4 + .../IRremoteESP8266/src/ir_Fujitsu.h | 4 + .../IRremoteESP8266/src/ir_Mitsubishi.cpp | 128 +++++- .../IRremoteESP8266/src/ir_Mitsubishi.h | 45 +- .../IRremoteESP8266/src/ir_Sony.cpp | 2 +- .../IRremoteESP8266/src/ir_Tcl.h | 2 + .../IRremoteESP8266/src/ir_Toshiba.cpp | 22 +- .../IRremoteESP8266/src/ir_Toshiba.h | 38 +- .../IRremoteESP8266/src/locale/defaults.h | 19 + .../IRremoteESP8266/test/IRac_test.cpp | 51 ++- .../IRremoteESP8266/test/ir_Airton_test.cpp | 268 ++++++++++- .../IRremoteESP8266/test/ir_Coolix_test.cpp | 92 ++++ .../test/ir_Mitsubishi_test.cpp | 12 +- .../IRremoteESP8266/test/ir_Toshiba_test.cpp | 52 ++- .../IRremoteESP8266/tools/Makefile | 12 +- .../IRremoteESP8266/tools/code_to_raw.cpp | 148 ++++++ .../IRremoteESP8266/tools/code_to_raw_test.sh | 65 +++ .../tools/extract_lib_version.sh | 14 + .../IRremoteESP8266/tools/mkkeywords | 5 +- .../tools/scrape_supported_devices.py | 426 ++++++++++++++++++ 46 files changed, 2199 insertions(+), 186 deletions(-) create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h create mode 100644 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp create mode 100755 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw_test.sh create mode 100755 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/extract_lib_version.sh create mode 100755 lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/scrape_supported_devices.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c2b5061..76dcd8422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Tasmota favicon to webbrowser tab (#14322) ### Changed +- IRremoteESP8266 library from v2.8.0 to v2.8.1 ### Fixed diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md index 90fd8d4c8..f392c5529 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.0 Now Available -Version 2.8.0 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.1 Now Available +Version 2.8.1 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 4dbd835c4..884628149 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.0 jetzt verfügbar -Version 2.8.0 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen. +## v2.8.1 jetzt verfügbar +Version 2.8.1 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 d7033c093..3f1a93048 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.0 disponible -Version 2.8.0 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.1 disponible +Version 2.8.1 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 0f41b562d..9c8d7df98 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md @@ -1,5 +1,29 @@ # Release Notes +## _v2.8.1 (20220101)_ + +**[Bug Fixes]** +- Arduino ESP32 Core v2.0.2+ crashes due to our timer hack. (#1715 #1713) +- SONY: Fix old Sony CD-Player Remote (12 Bit) (#1714) + +**[Features]** +- Add tool to convert protocol & code to raw timing info. (#1708 #1707 #1703) +- Add basic support for COOLIX48 protocol. (#1697 #1694) +- MITSUBISHI_AC: Added support for i-SAVE mode. (#1666) +- TOSHIBA_AC: Add Filter setting support. aka. Pure. (#1693 #1692) +- Airton: Add detailed A/C support. (#1688 #1670) + +**[Misc]** +- Add a structured library version number. (#1717) +- Workflows Split UnitTests (#1712) +- Reduce time for workflow/Build (#1709) +- Fix some compiler & linter warnings (#1699 #1700) +- Fujitsu: Update supported A/C models (#1690 #1689 #1702 #1701) +- Remove extra `const` qualifier for char pointer (#1704) +- TCL: Update supported devices. (#1698) +- ESP32-C3: Work around for some C3 specific compiler issues. (#1696 #1695) + + ## _v2.8.0 (20211119)_ **[Bug Fixes]** diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md index cf960a0eb..0b6fb06c1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md @@ -1,11 +1,11 @@ + Last generated: Fri 31 Dec 2021 21:49:00 +0000 ---> # IR Protocols supported by this library | Protocol | Brand | Model | A/C Model | Detailed A/C Support | | --- | --- | --- | --- | --- | -| [Airton](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airton.cpp) | **Airton** | RD1A1 remote
SMVH09B-2A2A3NH ref. 409730 A/C | | - | +| [Airton](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airton.cpp) | **[Airton](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airton.h)** | RD1A1 remote
SMVH09B-2A2A3NH ref. 409730 A/C | | Yes | | [Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airwell.cpp) | **[Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airwell.h)** | DLS 21 DCI R410 AW A/C
RC04 remote
RC08W remote | | Yes | | [Aiwa](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Aiwa.cpp) | **Aiwa** | RC-T501 RCU | | - | | [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 | @@ -15,6 +15,7 @@ | [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 | | [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 | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Kastron](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | RG57A7/BGEF Inverter remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Kaysun](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | Casual CF A/C | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | MS12FU-10HRDN1-QRD0GW(B) A/C
MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
RG52D/BGE Remote | | Yes | @@ -35,7 +36,7 @@ | [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-REW4E remote (ARREW4E)
AR-RY4 remote (ARRY4)
AST9RSGCW A/C (ARDB1)
ASTB09LBC A/C (ARRY4)
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](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 | | [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 | | - | @@ -79,7 +80,7 @@ | [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 | | [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Tronitechnik](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | KKG29A-C1 remote
Reykir 9000 A/C | KKG29AC1
KKG9AC1 | Yes | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | HC3000 Projector (MITSUBISHI2)
KM14A 0179213 remote
MS-GK24VA A/C
TV (MITSUBISHI) | | Yes | -| [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | 001CP T7WE10714 remote (MITSUBISHI136)
KPOA remote (MITSUBISHI112)
MLZ-RX5017AS A/C (MITSUBISHI_AC)
MSH-A24WV A/C (MITSUBISHI112)
MSZ-GV2519 A/C (MITSUBISHI_AC)
MSZ-SF25VE3 A/C (MITSUBISHI_AC)
MSZ-ZW4017S A/C (MITSUBISHI_AC)
MUH-A24WV A/C (MITSUBISHI112)
PEAD-RP71JAA Ducted A/C (MITSUBISHI136)
RH151/M21ED6426 remote (MITSUBISHI_AC)
SG153/M21EDF426 remote (MITSUBISHI_AC)
SG15D remote (MITSUBISHI_AC) | | Yes | +| [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | 001CP T7WE10714 remote (MITSUBISHI136)
KPOA remote (MITSUBISHI112)
MLZ-RX5017AS A/C (MITSUBISHI_AC)
MSH-A24WV A/C (MITSUBISHI112)
MSZ-FHnnVE A/C (MITSUBISHI_AC)
MSZ-GV2519 A/C (MITSUBISHI_AC)
MSZ-SF25VE3 A/C (MITSUBISHI_AC)
MSZ-ZW4017S A/C (MITSUBISHI_AC)
MUH-A24WV A/C (MITSUBISHI112)
PEAD-RP71JAA Ducted A/C (MITSUBISHI136)
RH151/M21ED6426 remote (MITSUBISHI_AC)
SG153/M21EDF426 remote (MITSUBISHI_AC)
SG15D remote (MITSUBISHI_AC) | | Yes | | [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 | | - | @@ -107,6 +108,7 @@ | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **SilverCrest** | SSVS 85 A1 Fan | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Symphony** | Air Cooler 3Di | | - | | [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) | **[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 | @@ -114,7 +116,7 @@ | [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 | | - | | [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-B13N3KV2
RAS-B13N3KVP-E
WC-L03SE
WH-TA04NE
WH-UB03NJ remote | | 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 | | [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 | @@ -149,6 +151,7 @@ - CARRIER_AC40 - CARRIER_AC64 - COOLIX +- COOLIX48 - CORONA_AC - DAIKIN - DAIKIN128 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino index 180c4214c..c2e427166 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino @@ -1249,7 +1249,7 @@ void handleInfo(void) { "Built: " __DATE__ " " __TIME__ "
" "Period Offset: ") + String(offset) + F("us
" - "IR Lib Version: " _IRREMOTEESP8266_VERSION_ "
" + "IR Lib Version: " _IRREMOTEESP8266_VERSION_STR "
" #if defined(ESP8266) "ESP8266 Core Version: ") + ESP.getCoreVersion() + F("
" "Free Sketch Space: ") + String(maxSketchSpace() >> 10) + F("k
" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino index ae7e21dab..70dbdba42 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/IRrecvDumpV2.ino @@ -154,7 +154,7 @@ void loop() { if (results.overflow) Serial.printf(D_WARN_BUFFERFULL "\n", kCaptureBufferSize); // Display the library version the message was captured with. - Serial.println(D_STR_LIBRARY " : v" _IRREMOTEESP8266_VERSION_ "\n"); + Serial.println(D_STR_LIBRARY " : v" _IRREMOTEESP8266_VERSION_STR "\n"); // Display the tolerance percentage if it has been change from the default. if (kTolerancePercentage != kTolerance) Serial.printf(D_STR_TOLERANCE " : %d%%\n", kTolerancePercentage); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino index fc2037368..0948ae5e9 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/IRrecvDumpV3.ino @@ -163,7 +163,7 @@ void loop() { if (results.overflow) Serial.printf(D_WARN_BUFFERFULL "\n", kCaptureBufferSize); // Display the library version the message was captured with. - Serial.println(D_STR_LIBRARY " : v" _IRREMOTEESP8266_VERSION_ "\n"); + Serial.println(D_STR_LIBRARY " : v" _IRREMOTEESP8266_VERSION_STR "\n"); // Display the tolerance percentage if it has been change from the default. if (kTolerancePercentage != kTolerance) Serial.printf(D_STR_TOLERANCE " : %d%%\n", kTolerancePercentage); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt index 592b5d99b..8e0379173 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt @@ -20,6 +20,8 @@ # Datatypes & Classes (KEYWORD1) ####################################### +CoronaSection KEYWORD1 +IRAirtonAc KEYWORD1 IRAirwellAc KEYWORD1 IRAmcorAc KEYWORD1 IRArgoAC KEYWORD1 @@ -147,6 +149,7 @@ addTempFloatToString KEYWORD2 addTempToString KEYWORD2 addToggleToString KEYWORD2 adjustRepeat KEYWORD2 +airton KEYWORD2 airwell KEYWORD2 amcor KEYWORD2 argo KEYWORD2 @@ -174,6 +177,7 @@ checkSum KEYWORD2 checkZjsSig KEYWORD2 checkZmsSig KEYWORD2 checksum KEYWORD2 +cleanState KEYWORD2 clearOnTimerFlag KEYWORD2 clearPowerSpecial KEYWORD2 clearSensorTemp KEYWORD2 @@ -211,6 +215,7 @@ decodeCOOLIX KEYWORD2 decodeCarrierAC KEYWORD2 decodeCarrierAC40 KEYWORD2 decodeCarrierAC64 KEYWORD2 +decodeCoolix48 KEYWORD2 decodeCoronaAc KEYWORD2 decodeDISH KEYWORD2 decodeDaikin KEYWORD2 @@ -339,6 +344,7 @@ fujitsu KEYWORD2 get10CHeat KEYWORD2 get3D KEYWORD2 get8CHeat KEYWORD2 +getAbsenseDetect KEYWORD2 getBeep KEYWORD2 getBit KEYWORD2 getBoost KEYWORD2 @@ -356,9 +362,11 @@ getCorrectedRawLength KEYWORD2 getCurrTime KEYWORD2 getCurrentDay KEYWORD2 getCurrentTime KEYWORD2 +getDirectIndirect KEYWORD2 getDisplay KEYWORD2 getDisplayTempSource KEYWORD2 getDryGrade KEYWORD2 +getEcocool KEYWORD2 getEcono KEYWORD2 getEconoToggle KEYWORD2 getEnableSensorTemp KEYWORD2 @@ -377,6 +385,8 @@ getHold KEYWORD2 getHumid KEYWORD2 getHumidity KEYWORD2 getIFeel KEYWORD2 +getISave10C KEYWORD2 +getISee KEYWORD2 getId KEYWORD2 getInternalStateLength KEYWORD2 getIon KEYWORD2 @@ -388,6 +398,7 @@ getLock KEYWORD2 getMax KEYWORD2 getMode KEYWORD2 getMold KEYWORD2 +getNaturalFlow KEYWORD2 getNight KEYWORD2 getOffSleepTimer KEYWORD2 getOffTime KEYWORD2 @@ -423,7 +434,9 @@ getSleepTimerEnabled KEYWORD2 getSpecial KEYWORD2 getSpeed KEYWORD2 getStartClock KEYWORD2 +getState KEYWORD2 getStateLength KEYWORD2 +getStatePrev KEYWORD2 getStopClock KEYWORD2 getSupercool KEYWORD2 getSwing KEYWORD2 @@ -474,6 +487,7 @@ haier KEYWORD2 haier176 KEYWORD2 haierYrwo2 KEYWORD2 handleSpecialState KEYWORD2 +handleToggles KEYWORD2 hasACState KEYWORD2 hasInvertedStates KEYWORD2 hasStateChanged KEYWORD2 @@ -571,6 +585,7 @@ sendCOOLIX KEYWORD2 sendCarrierAC KEYWORD2 sendCarrierAC40 KEYWORD2 sendCarrierAC64 KEYWORD2 +sendCoolix48 KEYWORD2 sendCoronaAc KEYWORD2 sendDISH KEYWORD2 sendDaikin KEYWORD2 @@ -679,6 +694,7 @@ serialPrintUint64 KEYWORD2 set10CHeat KEYWORD2 set3D KEYWORD2 set8CHeat KEYWORD2 +setAbsenseDetect KEYWORD2 setAuto KEYWORD2 setBeep KEYWORD2 setBit KEYWORD2 @@ -696,9 +712,11 @@ setCommand KEYWORD2 setCurrTime KEYWORD2 setCurrentDay KEYWORD2 setCurrentTime KEYWORD2 +setDirectIndirect KEYWORD2 setDisplay KEYWORD2 setDisplayTempSource KEYWORD2 setDryGrade KEYWORD2 +setEcocool KEYWORD2 setEcono KEYWORD2 setEconoToggle KEYWORD2 setEnableSensorTemp KEYWORD2 @@ -717,6 +735,8 @@ setHold KEYWORD2 setHumid KEYWORD2 setHumidity KEYWORD2 setIFeel KEYWORD2 +setISave10C KEYWORD2 +setISee KEYWORD2 setId KEYWORD2 setInvertedStates KEYWORD2 setIon KEYWORD2 @@ -729,6 +749,7 @@ setMax KEYWORD2 setMode KEYWORD2 setModel KEYWORD2 setMold KEYWORD2 +setNaturalFlow KEYWORD2 setNight KEYWORD2 setOffTime KEYWORD2 setOffTimeEnabled KEYWORD2 @@ -819,6 +840,7 @@ technibel KEYWORD2 teco KEYWORD2 ticksHigh KEYWORD2 ticksLow KEYWORD2 +toCommon KEYWORD2 toString KEYWORD2 toggleArrisRelease KEYWORD2 toggleRC5 KEYWORD2 @@ -896,6 +918,7 @@ CARRIER_AC40 LITERAL1 CARRIER_AC64 LITERAL1 CARRIER_AC_BITS LITERAL1 COOLIX LITERAL1 +COOLIX48 LITERAL1 COOLIX_BITS LITERAL1 CORONA_AC LITERAL1 DAIKIN LITERAL1 @@ -930,6 +953,7 @@ DECODE_CARRIER_AC LITERAL1 DECODE_CARRIER_AC40 LITERAL1 DECODE_CARRIER_AC64 LITERAL1 DECODE_COOLIX LITERAL1 +DECODE_COOLIX48 LITERAL1 DECODE_CORONA_AC LITERAL1 DECODE_DAIKIN LITERAL1 DECODE_DAIKIN128 LITERAL1 @@ -1284,6 +1308,7 @@ SEND_CARRIER_AC LITERAL1 SEND_CARRIER_AC40 LITERAL1 SEND_CARRIER_AC64 LITERAL1 SEND_COOLIX LITERAL1 +SEND_COOLIX48 LITERAL1 SEND_CORONA_AC LITERAL1 SEND_DAIKIN LITERAL1 SEND_DAIKIN128 LITERAL1 @@ -1443,13 +1468,27 @@ k8CHeatStr LITERAL1 kA705Str LITERAL1 kA903Str LITERAL1 kA907Str LITERAL1 +kAbsenseDetectStr LITERAL1 kAirFlowStr LITERAL1 +kAirtonAuto LITERAL1 kAirtonBitMark LITERAL1 kAirtonBits LITERAL1 +kAirtonCool LITERAL1 kAirtonDefaultRepeat LITERAL1 +kAirtonDry LITERAL1 +kAirtonFan LITERAL1 +kAirtonFanAuto LITERAL1 +kAirtonFanHigh LITERAL1 +kAirtonFanLow LITERAL1 +kAirtonFanMax LITERAL1 +kAirtonFanMed LITERAL1 +kAirtonFanMin LITERAL1 kAirtonFreq LITERAL1 kAirtonHdrMark LITERAL1 kAirtonHdrSpace LITERAL1 +kAirtonHeat LITERAL1 +kAirtonMaxTemp LITERAL1 +kAirtonMinTemp LITERAL1 kAirtonOneSpace LITERAL1 kAirtonZeroSpace LITERAL1 kAirwellAuto LITERAL1 @@ -1645,6 +1684,8 @@ kCommandStr LITERAL1 kCool LITERAL1 kCoolStr LITERAL1 kCoolingStr LITERAL1 +kCoolix48Bits LITERAL1 +kCoolix48ExtraTolerance LITERAL1 kCoolixAuto LITERAL1 kCoolixBitMark LITERAL1 kCoolixBitMarkTicks LITERAL1 @@ -1997,6 +2038,8 @@ kDenonZeroSpaceTicks LITERAL1 kDg11j104Str LITERAL1 kDg11j13aStr LITERAL1 kDg11j191Str LITERAL1 +kDirectIndirectModeStr LITERAL1 +kDirectStr LITERAL1 kDishBitMark LITERAL1 kDishBitMarkTicks LITERAL1 kDishBits LITERAL1 @@ -2478,6 +2521,7 @@ kHourStr LITERAL1 kHoursStr LITERAL1 kHumidStr LITERAL1 kIFeelStr LITERAL1 +kISeeStr LITERAL1 kIdStr LITERAL1 kIdleState LITERAL1 kInaxBitMark LITERAL1 @@ -2489,6 +2533,7 @@ kInaxMinRepeat LITERAL1 kInaxOneSpace LITERAL1 kInaxTick LITERAL1 kInaxZeroSpace LITERAL1 +kIndirectStr LITERAL1 kInsideStr LITERAL1 kIonStr LITERAL1 kJkeStr LITERAL1 @@ -2894,6 +2939,8 @@ kMitsubishiACStateLength LITERAL1 kMitsubishiAcAuto LITERAL1 kMitsubishiAcBitMark LITERAL1 kMitsubishiAcCool LITERAL1 +kMitsubishiAcDirect LITERAL1 +kMitsubishiAcDirectOff LITERAL1 kMitsubishiAcDry LITERAL1 kMitsubishiAcExtraTolerance LITERAL1 kMitsubishiAcFan LITERAL1 @@ -2905,6 +2952,7 @@ kMitsubishiAcFanSilent LITERAL1 kMitsubishiAcHdrMark LITERAL1 kMitsubishiAcHdrSpace LITERAL1 kMitsubishiAcHeat LITERAL1 +kMitsubishiAcIndirect LITERAL1 kMitsubishiAcMaxTemp LITERAL1 kMitsubishiAcMinTemp LITERAL1 kMitsubishiAcNoTimer LITERAL1 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json index 99160ec37..e1777f1c4 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.0", + "version": "2.8.1", "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 e7580dd2d..5ee1f5229 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.0 +version=2.8.1 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 557e5593e..f9d9647d3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp @@ -16,6 +16,7 @@ #include "IRremoteESP8266.h" #include "IRtext.h" #include "IRutils.h" +#include "ir_Airton.h" #include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" @@ -56,7 +57,7 @@ #ifndef STRCASECMP #if defined(ESP8266) #define STRCASECMP(LHS, RHS) \ - strcasecmp_P(LHS, reinterpret_cast(RHS)) + strcasecmp_P(LHS, reinterpret_cast(RHS)) #else // ESP8266 #define STRCASECMP(LHS, RHS) strcasecmp(LHS, RHS) #endif // ESP8266 @@ -152,9 +153,12 @@ stdAc::state_t IRac::getStatePrev(void) { return _prev; } /// @return true if the protocol is supported by this class, otherwise false. bool IRac::isProtocolSupported(const decode_type_t protocol) { switch (protocol) { +#if SEND_AIRTON + case decode_type_t::AIRTON: +#endif // SEND_AIRTON #if SEND_AIRWELL case decode_type_t::AIRWELL: -#endif +#endif // SEND_AIRWELL #if SEND_AMCOR case decode_type_t::AMCOR: #endif @@ -326,6 +330,44 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { } } +#if SEND_AIRTON +/// Send an Airton 56-bit A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IRAirtonAc 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] swingv The vertical swing setting. +/// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] light Turn on the LED/Display mode. +/// @param[in] econo Run the device in economical mode. +/// @param[in] filter Turn on the (ion/pollen/health/etc) filter mode. +/// @param[in] sleep Nr. of minutes for sleep mode. +/// @note -1 is Off, >= 0 is on. +void IRac::airton(IRAirtonAc *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, const bool turbo, + const bool light, const bool econo, const bool filter, + const int16_t sleep) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setSwingV(swingv != stdAc::swingv_t::kOff); + // No Quiet setting available. + ac->setLight(light); + ac->setHealth(filter); + ac->setTurbo(turbo); + ac->setEcono(econo); + // No Clean setting available. + // No Beep setting available. + ac->setSleep(sleep >= 0); // Convert to a boolean. + ac->send(); +} +#endif // SEND_AIRTON + #if SEND_AIRWELL /// Send an Airwell A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRAirwellAc object to use. @@ -1530,6 +1572,7 @@ void IRac::mitsubishi(IRMitsubishiAC *ac, ac->setVane(ac->convertSwingV(swingv)); ac->setWideVane(ac->convertSwingH(swingh)); if (quiet) ac->setFan(kMitsubishiAcFanSilent); + ac->setISave10C(false); // No Turbo setting available. // No Light setting available. // No Filter setting available. @@ -2116,11 +2159,12 @@ void IRac::teco(IRTecoAc *ac, /// @param[in] swingv The vertical swing setting. /// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] econo Run the device in economical mode. +/// @param[in] filter Turn on the (Pure/ion/pollen/etc) filter mode. void IRac::toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, - const bool turbo, const bool econo) { + const bool turbo, const bool econo, const bool filter) { ac->begin(); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -2133,7 +2177,7 @@ void IRac::toshiba(IRToshibaAC *ac, ac->setTurbo(turbo); ac->setEcono(econo); // No Light setting available. - // No Filter setting available. + ac->setFilter(filter); // No Clean setting available. // No Beep setting available. // No Sleep setting available. @@ -2603,6 +2647,16 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { #endif // (SEND_LG || SEND_SHARP_AC) // Per vendor settings & setup. switch (send.protocol) { +#if SEND_AIRTON + case AIRTON: + { + IRAirtonAc ac(_pin, _inverted, _modulation); + airton(&ac, send.power, send.mode, degC, send.fanspeed, + send.swingv, send.turbo, send.light, send.econo, send.filter, + send.sleep); + break; + } +#endif // SEND_AIRTON #if SEND_AIRWELL case AIRWELL: { @@ -3062,7 +3116,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRToshibaAC ac(_pin, _inverted, _modulation); toshiba(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, - send.turbo, send.econo); + send.turbo, send.econo, send.filter); break; } #endif // SEND_TOSHIBA_AC @@ -3507,6 +3561,13 @@ namespace IRAcUtils { /// An empty string if we can't. String resultAcToString(const decode_results * const result) { switch (result->decode_type) { +#if DECODE_AIRTON + case decode_type_t::AIRTON: { + IRAirtonAc ac(kGpioUnused); + ac.setRaw(result->value); // AIRTON uses value instead of state. + return ac.toString(); + } +#endif // DECODE_AIRTON #if DECODE_AIRWELL case decode_type_t::AIRWELL: { IRAirwellAc ac(kGpioUnused); @@ -3931,6 +3992,14 @@ namespace IRAcUtils { ) { if (decode == NULL || result == NULL) return false; // Safety check. switch (decode->decode_type) { +#if DECODE_AIRTON + case decode_type_t::AIRTON: { + IRAirtonAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } +#endif // DECODE_AIRTON #if DECODE_AIRWELL case decode_type_t::AIRWELL: { IRAirwellAc ac(kGpioUnused); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h index afa4bcee0..9954eecb0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h @@ -7,6 +7,7 @@ #include #endif #include "IRremoteESP8266.h" +#include "ir_Airton.h" #include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" @@ -109,6 +110,14 @@ class IRac { bool _inverted; ///< IR LED is lit when GPIO is LOW (true) or HIGH (false)? bool _modulation; ///< Is frequency modulation to be used? stdAc::state_t _prev; ///< The state we expect the device to currently be in. +#if SEND_AIRTON + void airton(IRAirtonAc *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, const bool turbo, + const bool light, const bool econo, const bool filter, + const int16_t sleep = -1); +#endif // SEND_AIRTON #if SEND_AIRWELL void airwell(IRAirwellAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, @@ -457,7 +466,7 @@ void electra(IRElectraAc *ac, void toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, - const bool turbo, const bool econo); + const bool turbo, const bool econo, const bool filter); #endif // SEND_TOSHIBA_AC #if SEND_TROTEC void trotec(IRTrotecESP *ac, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp index 4970dcf0b..5b9d91b88 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp @@ -13,7 +13,7 @@ extern "C" { } #endif // ESP8266 #include -#endif +#endif // UNIT_TEST #include #ifdef UNIT_TEST #include @@ -56,6 +56,20 @@ static ETSTimer timer; } // namespace _IRrecv #endif // ESP8266 #if defined(ESP32) +// We need a horrible timer hack for ESP32 Arduino framework < v2.0.0 +#if !defined(_ESP32_IRRECV_TIMER_HACK) +// Version check +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) +// No need for the hack if we are running version >= 2.0.0 +#define _ESP32_IRRECV_TIMER_HACK false +#else // Version check +// If no ESP_ARDUINO_VERSION_MAJOR is defined, or less than 2, then we are +// using an old ESP32 core, so we need the hack. +#define _ESP32_IRRECV_TIMER_HACK true +#endif // Version check +#endif // !defined(_ESP32_IRRECV_TIMER_HACK) + +#if _ESP32_IRRECV_TIMER_HACK // Required structs/types from: // https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L28-L58 // These are needed to be able to directly manipulate the timer registers from @@ -117,7 +131,7 @@ typedef struct hw_timer_s { uint8_t timer; portMUX_TYPE lock; } hw_timer_t; -// End of Horrible Hack. +#endif // _ESP32_IRRECV_TIMER_HACK / End of Horrible Hack. namespace _IRrecv { static hw_timer_t * timer = NULL; @@ -211,6 +225,7 @@ static void USE_IRAM_ATTR gpio_intr() { #if defined(ESP32) // Reset the timeout. // +#if _ESP32_IRRECV_TIMER_HACK // The following three lines of code are the equiv of: // `timerWrite(timer, 0);` // We can't call that routine safely from inside an ISR as that procedure @@ -226,6 +241,10 @@ static void USE_IRAM_ATTR gpio_intr() { // @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1350 // @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178 timer->dev->config.alarm_en = 1; +#else // _ESP32_IRRECV_TIMER_HACK + timerWrite(timer, 0); + timerAlarmEnable(timer); +#endif // _ESP32_IRRECV_TIMER_HACK #endif // ESP32 } #endif // UNIT_TEST @@ -337,7 +356,9 @@ void IRrecv::enableIRIn(const bool pullup) { // Set the timer so it only fires once, and set it's trigger in uSeconds. timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE); // Note: Interrupt needs to be attached before it can be enabled or disabled. - timerAttachInterrupt(timer, &read_timeout, true); + // Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713 + // See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227 + timerAttachInterrupt(timer, &read_timeout, false); #endif // ESP32 // Initialise state machine variables @@ -695,9 +716,9 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, if (decodeSharp(results, offset)) return true; #endif #if DECODE_COOLIX - DPRINTLN("Attempting Coolix decode"); + DPRINTLN("Attempting Coolix 24-bit decode"); if (decodeCOOLIX(results, offset)) return true; -#endif +#endif // DECODE_COOLIX #if DECODE_NIKAI DPRINTLN("Attempting Nikai decode"); if (decodeNikai(results, offset)) return true; @@ -1047,6 +1068,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Airton decode"); if (decodeAirton(results, offset)) return true; #endif // DECODE_AIRTON +#if DECODE_COOLIX48 + DPRINTLN("Attempting Coolix 48-bit decode"); + if (decodeCoolix48(results, offset)) return true; +#endif // DECODE_COOLIX48 // Typically new protocols are added above this line. } #if DECODE_HASH @@ -1079,7 +1104,7 @@ uint32_t IRrecv::ticksLow(const uint32_t usecs, const uint8_t tolerance, // max() used to ensure the result can't drop below 0 before the cast. return ((uint32_t)std::max( (int32_t)(usecs * (1.0 - _validTolerance(tolerance) / 100.0) - delta), - 0)); + (int32_t)0)); } /// Calculate the upper bound of the nr. of ticks. @@ -1162,7 +1187,8 @@ bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired, // We really should never get a value of 0, except as the last value // in the buffer. If that is the case, then assume infinity and return true. if (measured == 0) return true; - return measured >= ticksLow(std::min(desired, MS_TO_USEC(params.timeout)), + return measured >= ticksLow(std::min(desired, + (uint32_t)MS_TO_USEC(params.timeout)), tolerance, delta); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h index f4932b5a6..75070172d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h @@ -419,7 +419,12 @@ class IRrecv { bool decodeCOOLIX(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kCoolixBits, const bool strict = true); -#endif +#endif // DECODE_COOLIX +#if DECODE_COOLIX48 + bool decodeCoolix48(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kCoolix48Bits, + const bool strict = true); +#endif // DECODE_COOLIX48 #if DECODE_DENON bool decodeDenon(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kDenonBits, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h index 09a3011ce..3cd19a81d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h @@ -52,8 +52,29 @@ #include #endif // UNIT_TEST -// Library Version -#define _IRREMOTEESP8266_VERSION_ "2.8.0" +// Library Version Information +// Major version number (X.x.x) +#define _IRREMOTEESP8266_VERSION_MAJOR 2 +// Minor version number (x.X.x) +#define _IRREMOTEESP8266_VERSION_MINOR 8 +// Patch version number (x.x.X) +#define _IRREMOTEESP8266_VERSION_PATCH 1 +// Macro to convert version info into an integer +#define _IRREMOTEESP8266_VERSION_VAL(major, minor, patch) \ + ((major << 16) | (minor << 8) | (patch)) +// Macro to convert literal into a string +#define MKSTR(x) #x +// Integer version +#define _IRREMOTEESP8266_VERSION _IRREMOTEESP8266_VERSION_VAL(\ + _IRREMOTEESP8266_VERSION_MAJOR, \ + _IRREMOTEESP8266_VERSION_MINOR, \ + _IRREMOTEESP8266_VERSION_PATCH) +// String version +#define _IRREMOTEESP8266_VERSION_STR MKSTR(_IRREMOTEESP8266_VERSION_MAJOR) "." \ + MKSTR(_IRREMOTEESP8266_VERSION_MINOR) "." \ + MKSTR(_IRREMOTEESP8266_VERSION_PATCH) +// String version (DEPRECATED) +#define _IRREMOTEESP8266_VERSION_ _IRREMOTEESP8266_VERSION_STR // Set the language & locale for the library. See the `locale` dir for options. #ifndef _IR_LOCALE_ @@ -314,6 +335,13 @@ #define SEND_COOLIX _IR_ENABLE_DEFAULT_ #endif // SEND_COOLIX +#ifndef DECODE_COOLIX48 +#define DECODE_COOLIX48 _IR_ENABLE_DEFAULT_ +#endif // DECODE_COOLIX48 +#ifndef SEND_COOLIX48 +#define SEND_COOLIX48 _IR_ENABLE_DEFAULT_ +#endif // SEND_COOLIX48 + #ifndef DECODE_GLOBALCACHE #define DECODE_GLOBALCACHE false // Not applicable. #endif // DECODE_GLOBALCACHE @@ -975,8 +1003,9 @@ enum decode_type_t { ARRIS, RHOSS, AIRTON, + COOLIX48, // 110 // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = AIRTON, + kLastDecodeType = COOLIX48, }; // Message lengths & required repeat values @@ -998,6 +1027,7 @@ const uint16_t kArgoBits = kArgoStateLength * 8; const uint16_t kArgoDefaultRepeat = kNoRepeat; const uint16_t kArrisBits = 32; const uint16_t kCoolixBits = 24; +const uint16_t kCoolix48Bits = kCoolixBits * 2; const uint16_t kCoolixDefaultRepeat = kSingleRepeat; const uint16_t kCarrierAcBits = 32; const uint16_t kCarrierAcMinRepeat = kNoRepeat; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp index e20b97045..e0a66e068 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp @@ -560,6 +560,7 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) { case AIWA_RC_T501: case AMCOR: case COOLIX: + case COOLIX48: case ELITESCREENS: case GICABLE: case INAX: @@ -661,6 +662,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kDoshishaBits; // 40 case SANYO_LC7461: return kSanyoLC7461Bits; // 42 + case COOLIX48: case GOODWEATHER: case KELON: case MIDEA: @@ -829,7 +831,12 @@ bool IRsend::send(const decode_type_t type, const uint64_t data, case COOLIX: sendCOOLIX(data, nbits, min_repeat); break; -#endif +#endif // SEND_COOLIX +#if SEND_COOLIX48 + case COOLIX48: + sendCoolix48(data, nbits, min_repeat); + break; +#endif // SEND_COOLIX48 #if SEND_DAIKIN64 case DAIKIN64: sendDaikin64(data, nbits, min_repeat); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h index d55ce0238..3696eb40f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h @@ -42,78 +42,78 @@ const uint32_t kDefaultMessageGap = 100000; /// Enumerators and Structures for the Common A/C API. namespace stdAc { - /// Common A/C settings for A/C operating modes. - enum class opmode_t { - kOff = -1, - kAuto = 0, - kCool = 1, - kHeat = 2, - kDry = 3, - kFan = 4, - // Add new entries before this one, and update it to point to the last entry - kLastOpmodeEnum = kFan, - }; +/// Common A/C settings for A/C operating modes. +enum class opmode_t { + kOff = -1, + kAuto = 0, + kCool = 1, + kHeat = 2, + kDry = 3, + kFan = 4, + // Add new entries before this one, and update it to point to the last entry + kLastOpmodeEnum = kFan, +}; - /// Common A/C settings for Fan Speeds. - enum class fanspeed_t { - kAuto = 0, - kMin = 1, - kLow = 2, - kMedium = 3, - kHigh = 4, - kMax = 5, - // Add new entries before this one, and update it to point to the last entry - kLastFanspeedEnum = kMax, - }; +/// Common A/C settings for Fan Speeds. +enum class fanspeed_t { + kAuto = 0, + kMin = 1, + kLow = 2, + kMedium = 3, + kHigh = 4, + kMax = 5, + // Add new entries before this one, and update it to point to the last entry + kLastFanspeedEnum = kMax, +}; - /// Common A/C settings for Vertical Swing. - enum class swingv_t { - kOff = -1, - kAuto = 0, - kHighest = 1, - kHigh = 2, - kMiddle = 3, - kLow = 4, - kLowest = 5, - // Add new entries before this one, and update it to point to the last entry - kLastSwingvEnum = kLowest, - }; +/// Common A/C settings for Vertical Swing. +enum class swingv_t { + kOff = -1, + kAuto = 0, + kHighest = 1, + kHigh = 2, + kMiddle = 3, + kLow = 4, + kLowest = 5, + // Add new entries before this one, and update it to point to the last entry + kLastSwingvEnum = kLowest, +}; - /// Common A/C settings for Horizontal Swing. - enum class swingh_t { - kOff = -1, - kAuto = 0, // a.k.a. On. - kLeftMax = 1, - kLeft = 2, - kMiddle = 3, - kRight = 4, - kRightMax = 5, - kWide = 6, // a.k.a. left & right at the same time. - // Add new entries before this one, and update it to point to the last entry - kLastSwinghEnum = kWide, - }; +/// Common A/C settings for Horizontal Swing. +enum class swingh_t { + kOff = -1, + kAuto = 0, // a.k.a. On. + kLeftMax = 1, + kLeft = 2, + kMiddle = 3, + kRight = 4, + kRightMax = 5, + kWide = 6, // a.k.a. left & right at the same time. + // Add new entries before this one, and update it to point to the last entry + kLastSwinghEnum = kWide, +}; - /// Structure to hold a common A/C state. - typedef struct { - decode_type_t protocol; - int16_t model; - bool power; - stdAc::opmode_t mode; - float degrees; - bool celsius; - stdAc::fanspeed_t fanspeed; - stdAc::swingv_t swingv; - stdAc::swingh_t swingh; - bool quiet; - bool turbo; - bool econo; - bool light; - bool filter; - bool clean; - bool beep; - int16_t sleep; - int16_t clock; - } state_t; +/// Structure to hold a common A/C state. +struct state_t { + decode_type_t protocol; + int16_t model; + bool power; + stdAc::opmode_t mode; + float degrees; + bool celsius; + stdAc::fanspeed_t fanspeed; + stdAc::swingv_t swingv; + stdAc::swingh_t swingh; + bool quiet; + bool turbo; + bool econo; + bool light; + bool filter; + bool clean; + bool beep; + int16_t sleep; + int16_t clock; +}; }; // namespace stdAc /// Fujitsu A/C model numbers @@ -381,9 +381,13 @@ class IRsend { uint16_t repeat = kNoRepeat); #endif #if SEND_COOLIX - void sendCOOLIX(uint64_t data, uint16_t nbits = kCoolixBits, - uint16_t repeat = kCoolixDefaultRepeat); -#endif + void sendCOOLIX(const uint64_t data, const uint16_t nbits = kCoolixBits, + const uint16_t repeat = kCoolixDefaultRepeat); +#endif // SEND_COOLIX +#if SEND_COOLIX48 + void sendCoolix48(const uint64_t data, const uint16_t nbits = kCoolix48Bits, + const uint16_t repeat = kCoolixDefaultRepeat); +#endif // SEND_COOLIX48 #if SEND_WHYNTER void sendWhynter(const uint64_t data, const uint16_t nbits = kWhynterBits, const uint16_t repeat = kNoRepeat); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp index a580bff9f..077e7b0e7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp @@ -81,6 +81,14 @@ IRTEXT_CONST_STRING(kHoldStr, D_STR_HOLD); ///< "Hold" IRTEXT_CONST_STRING(kButtonStr, D_STR_BUTTON); ///< "Button" IRTEXT_CONST_STRING(k8CHeatStr, D_STR_8C_HEAT); ///< "8C Heat" IRTEXT_CONST_STRING(k10CHeatStr, D_STR_10C_HEAT); ///< "10C Heat" +IRTEXT_CONST_STRING(kISeeStr, D_STR_ISEE); ///< "ISee" +IRTEXT_CONST_STRING(kAbsenseDetectStr, D_STR_ABSENSEDETECT); + ///< "AbsenseDetect" +IRTEXT_CONST_STRING(kDirectIndirectModeStr, D_STR_DIRECTINDIRECTMODE); + ///< "Direct/Indirect mode" +IRTEXT_CONST_STRING(kDirectStr, D_STR_DIRECT); ///< "Direct" +IRTEXT_CONST_STRING(kIndirectStr, D_STR_INDIRECT); ///< "Indirect" + IRTEXT_CONST_STRING(kNightStr, D_STR_NIGHT); ///< "Night" IRTEXT_CONST_STRING(kSilentStr, D_STR_SILENT); ///< "Silent" IRTEXT_CONST_STRING(kFilterStr, D_STR_FILTER); ///< "Filter" @@ -382,6 +390,7 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) { D_STR_ARRIS "\x0" D_STR_RHOSS "\x0" D_STR_AIRTON "\x0" + D_STR_COOLIX48 "\x0" ///< New protocol strings should be added just above this line. "\x0" ///< This string requires double null termination. }; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h index ee8ea5934..031f73879 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h @@ -231,5 +231,11 @@ extern IRTEXT_CONST_PTR(kYbofbStr); extern IRTEXT_CONST_PTR(kYesStr); extern IRTEXT_CONST_PTR(kZoneFollowStr); extern IRTEXT_CONST_PTR(kAllProtocolNamesStr); +extern IRTEXT_CONST_PTR(kISeeStr); +extern IRTEXT_CONST_PTR(kEcocoolStr); +extern IRTEXT_CONST_PTR(kAbsenseDetectStr); +extern IRTEXT_CONST_PTR(kDirectIndirectModeStr); +extern IRTEXT_CONST_PTR(kDirectStr); +extern IRTEXT_CONST_PTR(kIndirectStr); #endif // IRTEXT_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp index d3a83c507..e1f889966 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp @@ -1049,6 +1049,21 @@ namespace irutils { return nibbleonly ? sum & 0xF : sum; } + /// Sum all the bytes together in an integer. + /// @param[in] data The integer to be summed. + /// @param[in] count The number of bytes to sum. Starts from LSB. Max of 8. + /// @param[in] init Starting value of the calculation to use. (Default is 0) + /// @param[in] byteonly true, the result is 8 bits. false, it's 16 bits. + /// @return The 8/16-bit calculated result of all the bytes and init value. + uint16_t sumBytes(const uint64_t data, const uint8_t count, + const uint8_t init, const bool byteonly) { + uint16_t sum = init; + uint64_t copy = data; + const uint8_t nrofbytes = (count < 8) ? count : (64 / 8); + for (uint8_t i = 0; i < nrofbytes; i++, copy >>= 8) sum += (copy & 0xFF); + return byteonly ? sum & 0xFF : sum; + } + /// Convert a byte of Binary Coded Decimal(BCD) into an Integer. /// @param[in] bcd The BCD value. /// @return A normal Integer value. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h index 61fe8b269..a5dcde043 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h @@ -94,6 +94,8 @@ namespace irutils { const uint8_t init = 0); uint8_t sumNibbles(const uint64_t data, const uint8_t count = 16, const uint8_t init = 0, const bool nibbleonly = true); + uint16_t sumBytes(const uint64_t data, const uint8_t count = 8, + const uint8_t init = 0, const bool byteonly = true); uint8_t bcdToUint8(const uint8_t bcd); uint8_t uint8ToBcd(const uint8_t integer); bool getBit(const uint64_t data, const uint8_t position, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp index 507894f37..83ad95ef7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp @@ -3,12 +3,11 @@ /// @brief Support for Airton protocol /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1670 -// Supports: -// Brand: Airton, Model: SMVH09B-2A2A3NH ref. 409730 A/C -// Brand: Airton, Model: RD1A1 remote - +#include "ir_Airton.h" +#include #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" const uint16_t kAirtonHdrMark = 6630; @@ -18,6 +17,12 @@ const uint16_t kAirtonOneSpace = 1260; const uint16_t kAirtonZeroSpace = 430; const uint16_t kAirtonFreq = 38000; // Hz. (Just a guess) +using irutils::addBoolToString; +using irutils::addModeToString; +using irutils::addFanToString; +using irutils::addTempToString; +using irutils::sumBytes; + #if SEND_AIRTON // Function should be safe up to 64 bits. /// Send a Airton formatted message. @@ -59,7 +64,8 @@ bool IRrecv::decodeAirton(decode_results *results, uint16_t offset, kAirtonBitMark, kAirtonZeroSpace, kAirtonBitMark, kDefaultMessageGap, true, kUseDefTol, kMarkExcess, false)) return false; - + // Compliance + if (strict && !IRAirtonAc::validChecksum(results->value)) return false; // Success results->decode_type = decode_type_t::AIRTON; results->bits = nbits; @@ -68,3 +74,289 @@ bool IRrecv::decodeAirton(decode_results *results, uint16_t offset, return true; } #endif // DECODE_AIRTON + +/// 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? +IRAirtonAc::IRAirtonAc(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 IRAirtonAc::begin(void) { _irsend.begin(); } + +#if SEND_AIRTON +/// Send the current internal state as an IR message. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRAirtonAc::send(const uint16_t repeat) { + _irsend.sendAirton(getRaw(), kAirtonBits, repeat); +} +#endif // SEND_AIRTON + +/// Calculate the checksum for the supplied state. +/// @param[in] state The source state to generate the checksum from. +/// @return The checksum value. +uint8_t IRAirtonAc::calcChecksum(const uint64_t state) { + return (uint8_t)(0x7F - sumBytes(state, 6)) ^ 0x2C; +} + +/// Verify the checksum is valid for a given state. +/// @param[in] state The value to verify the checksum of. +/// @return A boolean indicating if it's checksum is valid. +bool IRAirtonAc::validChecksum(const uint64_t state) { + AirtonProtocol p; + p.raw = state; + return p.Sum == IRAirtonAc::calcChecksum(state); +} + +/// Update the checksum value for the internal state. +void IRAirtonAc::checksum(void) { _.Sum = IRAirtonAc::calcChecksum(_.raw); } + +/// Reset the internals of the object to a known good state. +void IRAirtonAc::stateReset(void) { setRaw(0x11D3); } + +/// Get the raw state of the object, suitable to be sent with the appropriate +/// IRsend object method. +/// @return A copy to the internal state. +uint64_t IRAirtonAc::getRaw(void) { + checksum(); // Ensure correct bit array before returning + return _.raw; +} + +/// Set the raw state of the object. +/// @param[in] state The raw state from the native IR message. +void IRAirtonAc::setRaw(const uint64_t state) { _.raw = state; } + + +/// Set the internal state to have the power on. +void IRAirtonAc::on(void) { setPower(true); } + +/// Set the internal state to have the power off. +void IRAirtonAc::off(void) { setPower(false); } + +/// Set the internal state to have the desired power. +/// @param[in] on The desired power state. +void IRAirtonAc::setPower(const bool on) { + _.Power = on; + setMode(getMode()); // Re-do the mode incase we need to do something special. +} + +/// Get the power setting from the internal state. +/// @return A boolean indicating the power setting. +bool IRAirtonAc::getPower(void) const { return _.Power; } + +/// Get the current operation mode setting. +/// @return The current operation mode. +uint8_t IRAirtonAc::getMode(void) const { return _.Mode; } + +/// Set the desired operation mode. +/// @param[in] mode The desired operation mode. +void IRAirtonAc::setMode(const uint8_t mode) { + // Changing the mode always removes the sleep setting. + if (mode != _.Mode) setSleep(false); + // Set the actual mode. + _.Mode = (mode > kAirtonHeat) ? kAirtonAuto : mode; + // Handle special settings for each mode. + switch (_.Mode) { + case kAirtonAuto: + setTemp(25); // Auto has a fixed temp. + _.NotAutoOn = !getPower(); + break; + case kAirtonHeat: + // When powered on and in Heat mode, set a special bit. + _.HeatOn = getPower(); + // FALL-THRU + default: + _.NotAutoOn = true; + } + // Reset the economy setting if we need to. + setEcono(getEcono()); +} + +/// 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 IRAirtonAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kAirtonCool; + case stdAc::opmode_t::kHeat: return kAirtonHeat; + case stdAc::opmode_t::kDry: return kAirtonDry; + case stdAc::opmode_t::kFan: return kAirtonFan; + default: return kAirtonAuto; + } +} + +/// 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 IRAirtonAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kAirtonCool: return stdAc::opmode_t::kCool; + case kAirtonHeat: return stdAc::opmode_t::kHeat; + case kAirtonDry: return stdAc::opmode_t::kDry; + case kAirtonFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +/// Set the temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRAirtonAc::setTemp(const uint8_t degrees) { + uint8_t temp = std::max(kAirtonMinTemp, degrees); + temp = std::min(kAirtonMaxTemp, temp); + if (_.Mode == kAirtonAuto) temp = kAirtonMaxTemp; // Auto has a fixed temp. + _.Temp = temp - kAirtonMinTemp; +} + +/// Get the current temperature setting. +/// @return Get current setting for temp. in degrees celsius. +uint8_t IRAirtonAc::getTemp(void) const { return _.Temp + kAirtonMinTemp; } + + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +void IRAirtonAc::setFan(const uint8_t speed) { + _.Fan = (speed > kAirtonFanMax) ? kAirtonFanAuto : speed; +} + +/// Get the current fan speed setting. +/// @return The current fan speed. +uint8_t IRAirtonAc::getFan(void) const { return _.Fan; } + +/// 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 IRAirtonAc::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: return kAirtonFanMin; + case stdAc::fanspeed_t::kLow: return kAirtonFanLow; + case stdAc::fanspeed_t::kMedium: return kAirtonFanMed; + case stdAc::fanspeed_t::kHigh: return kAirtonFanHigh; + case stdAc::fanspeed_t::kMax: return kAirtonFanMax; + default: return kAirtonFanAuto; + } +} + +/// 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 IRAirtonAc::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kAirtonFanMax: return stdAc::fanspeed_t::kMax; + case kAirtonFanHigh: return stdAc::fanspeed_t::kHigh; + case kAirtonFanMed: return stdAc::fanspeed_t::kMedium; + case kAirtonFanLow: return stdAc::fanspeed_t::kLow; + case kAirtonFanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; + } +} + +/// Set the Vertical Swing setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRAirtonAc::setSwingV(const bool on) { _.SwingV = on; } + +/// Get the Vertical Swing setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRAirtonAc::getSwingV(void) const { return _.SwingV; } + +/// Set the Light/LED/Display setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRAirtonAc::setLight(const bool on) { _.Light = on; } + +/// Get the Light/LED/Display setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRAirtonAc::getLight(void) const { return _.Light; } + +/// Set the Economy setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +/// @note Only available in Cool mode. +void IRAirtonAc::setEcono(const bool on) { + _.Econo = on && (getMode() == kAirtonCool); +} + +/// Get the Economy setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRAirtonAc::getEcono(void) const { return _.Econo; } + +/// Set the Turbo setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRAirtonAc::setTurbo(const bool on) { + _.Turbo = on; + // Pressing the turbo button sets the fan to max as well. + if (on) setFan(kAirtonFanMax); +} + +/// Get the Turbo setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRAirtonAc::getTurbo(void) const { return _.Turbo; } + +/// Set the Sleep setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +/// @note Sleep not available in fan or auto mode. +void IRAirtonAc::setSleep(const bool on) { + switch (getMode()) { + case kAirtonAuto: + case kAirtonFan: _.Sleep = false; break; + default: _.Sleep = on; + } +} + +/// Get the Sleep setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRAirtonAc::getSleep(void) const { return _.Sleep; } + +/// Set the Health/Filter setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRAirtonAc::setHealth(const bool on) { _.Health = on; } + +/// Get the Health/Filter setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRAirtonAc::getHealth(void) const { return _.Health; } + +/// Convert the current internal state into its stdAc::state_t equivalent. +/// @return The stdAc equivalent of the native settings. +stdAc::state_t IRAirtonAc::toCommon(void) const { + stdAc::state_t result; + result.protocol = decode_type_t::AIRTON; + result.power = getPower(); + result.mode = toCommonMode(getMode()); + result.celsius = true; + result.degrees = getTemp(); + result.fanspeed = toCommonFanSpeed(getFan()); + result.swingv = getSwingV() ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; + result.econo = getEcono(); + result.turbo = getTurbo(); + result.filter = getHealth(); + result.light = getLight(); + result.sleep = getSleep() ? 0 : -1; + // Not supported. + result.model = -1; + result.swingh = stdAc::swingh_t::kOff; + result.quiet = false; + result.clean = false; + result.beep = false; + result.clock = -1; + return result; +} + +/// Convert the current internal state into a human readable string. +/// @return A human readable string. +String IRAirtonAc::toString(void) const { + String result = ""; + result.reserve(135); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(_.Mode, kAirtonAuto, kAirtonCool, + kAirtonHeat, kAirtonDry, kAirtonFan); + result += addFanToString(_.Fan, kAirtonFanHigh, kAirtonFanLow, + kAirtonFanAuto, kAirtonFanMin, kAirtonFanMed, + kAirtonFanMax); + result += addTempToString(getTemp()); + result += addBoolToString(getSwingV(), kSwingVStr); + result += addBoolToString(getEcono(), kEconoStr); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getLight(), kLightStr); + result += addBoolToString(getHealth(), kHealthStr); + result += addBoolToString(getSleep(), kSleepStr); + return result; +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h new file mode 100644 index 000000000..9b5e89f3f --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.h @@ -0,0 +1,134 @@ +// Copyright 2021 David Conran (crankyoldgit) +/// @file +/// @brief Support for Airton protocol +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1670 + +// Supports: +// Brand: Airton, Model: SMVH09B-2A2A3NH ref. 409730 A/C +// Brand: Airton, Model: RD1A1 remote + +#ifndef IR_AIRTON_H_ +#define IR_AIRTON_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +/// Native representation of a Airton 56 A/C message. +/// @see https://docs.google.com/spreadsheets/d/1Kpq7WCkh85heLnTQGlwUfCR6eeu_vfBHvhii8wtP4LU/edit?usp=sharing +union AirtonProtocol{ + uint64_t raw; ///< The state in code form. + struct { // Common + // Byte 1 & 0 (LSB) + uint16_t Header :16; // Header. (0x11D3) + // Byte 2 + uint8_t Mode :3; // Operating Mode + uint8_t Power :1; // Power Control + uint8_t Fan :3; + uint8_t Turbo :1; + // Byte 3 + uint8_t Temp :4; // Degrees Celsius (+16 offset) + uint8_t :4; // Unknown / Unused. + // Byte 4 + uint8_t SwingV :1; + uint8_t :7; // Unknown / Unused. + // Byte 5 + uint8_t Econo :1; + uint8_t Sleep :1; + uint8_t NotAutoOn :1; + uint8_t :1; // Unknown / Unused. + uint8_t HeatOn :1; + uint8_t :1; // Unknown / Unused. + uint8_t Health :1; + uint8_t Light :1; + // Byte 6 + uint8_t Sum :8; // Sepecial checksum value + }; +}; + +// Constants +const uint8_t kAirtonAuto = 0b000; // 0 +const uint8_t kAirtonCool = 0b001; // 1 +const uint8_t kAirtonDry = 0b010; // 2 +const uint8_t kAirtonFan = 0b011; // 3 +const uint8_t kAirtonHeat = 0b100; // 4 + +const uint8_t kAirtonFanAuto = 0b000; // 0 +const uint8_t kAirtonFanMin = 0b001; // 1 +const uint8_t kAirtonFanLow = 0b010; // 2 +const uint8_t kAirtonFanMed = 0b011; // 3 +const uint8_t kAirtonFanHigh = 0b100; // 4 +const uint8_t kAirtonFanMax = 0b101; // 5 + +const uint8_t kAirtonMinTemp = 16; // 16C +const uint8_t kAirtonMaxTemp = 25; // 25C + + +/// Class for handling detailed Airton 56-bit A/C messages. +class IRAirtonAc { + public: + explicit IRAirtonAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + void stateReset(void); +#if SEND_AIRTON + void send(const uint16_t repeat = kAirtonDefaultRepeat); + /// 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_AIRTON + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void) const; + void setTemp(const uint8_t degrees); + uint8_t getTemp(void) const; + void setFan(const uint8_t speed); + uint8_t getFan(void) const; + void setMode(const uint8_t mode); + uint8_t getMode(void) const; + uint64_t getRaw(void); + void setRaw(const uint64_t data); + void setLight(const bool on); + bool getLight(void) const; + void setEcono(const bool on); + bool getEcono(void) const; + void setTurbo(const bool on); + bool getTurbo(void) const; + void setHealth(const bool on); + bool getHealth(void) const; + void setSleep(const bool on); + bool getSleep(void) const; + void setSwingV(const bool on); + bool getSwingV(void) const; + static bool validChecksum(const uint64_t data); + static uint8_t calcChecksum(const uint64_t data); + 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); + stdAc::state_t toCommon(void) 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 + AirtonProtocol _; + void checksum(void); +}; +#endif // IR_AIRTON_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp index f5cacf0e7..7b5b140f0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp @@ -21,17 +21,18 @@ // pulse parameters in usec const uint16_t kCoolixTick = 276; // Approximately 10.5 cycles at 38kHz const uint16_t kCoolixBitMarkTicks = 2; -const uint16_t kCoolixBitMark = kCoolixBitMarkTicks * kCoolixTick; +const uint16_t kCoolixBitMark = kCoolixBitMarkTicks * kCoolixTick; // 552us const uint16_t kCoolixOneSpaceTicks = 6; -const uint16_t kCoolixOneSpace = kCoolixOneSpaceTicks * kCoolixTick; +const uint16_t kCoolixOneSpace = kCoolixOneSpaceTicks * kCoolixTick; // 1656us const uint16_t kCoolixZeroSpaceTicks = 2; -const uint16_t kCoolixZeroSpace = kCoolixZeroSpaceTicks * kCoolixTick; +const uint16_t kCoolixZeroSpace = kCoolixZeroSpaceTicks * kCoolixTick; // 552us const uint16_t kCoolixHdrMarkTicks = 17; -const uint16_t kCoolixHdrMark = kCoolixHdrMarkTicks * kCoolixTick; +const uint16_t kCoolixHdrMark = kCoolixHdrMarkTicks * kCoolixTick; // 4692us const uint16_t kCoolixHdrSpaceTicks = 16; -const uint16_t kCoolixHdrSpace = kCoolixHdrSpaceTicks * kCoolixTick; +const uint16_t kCoolixHdrSpace = kCoolixHdrSpaceTicks * kCoolixTick; // 4416us const uint16_t kCoolixMinGapTicks = kCoolixHdrMarkTicks + kCoolixZeroSpaceTicks; -const uint16_t kCoolixMinGap = kCoolixMinGapTicks * kCoolixTick; +const uint16_t kCoolixMinGap = kCoolixMinGapTicks * kCoolixTick; // 5244us +const uint8_t kCoolix48ExtraTolerance = 5; // Percent using irutils::addBoolToString; using irutils::addIntToString; @@ -40,7 +41,7 @@ using irutils::addModeToString; using irutils::addTempToString; #if SEND_COOLIX -/// Send a Coolix message +/// Send a Coolix 24-bit message /// Status: STABLE / Confirmed Working. /// @param[in] data The message to be sent. /// @param[in] nbits The number of bits of message to be sent. @@ -620,7 +621,7 @@ String IRCoolixAC::toString(void) const { } #if DECODE_COOLIX -/// Decode the supplied Coolix A/C message. +/// Decode the supplied Coolix 24-bit A/C message. /// Status: STABLE / Known Working. /// @param[in,out] results Ptr to the data to decode & where to store the decode /// result. @@ -699,3 +700,58 @@ bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t offset, return true; } #endif // DECODE_COOLIX + +#if SEND_COOLIX48 +/// Send a Coolix 48-bit message. +/// Status: ALPHA / Untested. +/// @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/1694 +/// @note This is effectively the same as `sendCOOLIX()` except requiring the +/// bit flipping be done prior to the call. +void IRsend::sendCoolix48(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + // Header + Data + Footer + sendGeneric(kCoolixHdrMark, kCoolixHdrSpace, + kCoolixBitMark, kCoolixOneSpace, + kCoolixBitMark, kCoolixZeroSpace, + kCoolixBitMark, kCoolixMinGap, + data, nbits, 38000, true, repeat, 33); +} +#endif // SEND_COOLIX48 + +#if DECODE_COOLIX +/// 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 +/// 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/1694 +bool IRrecv::decodeCoolix48(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict && nbits != kCoolix48Bits) + return false; // Not strictly a COOLIX48 message. + + // Header + Data + Footer + if (!matchGeneric(results->rawbuf + offset, &(results->value), + results->rawlen - offset, nbits, + kCoolixHdrMark, kCoolixHdrSpace, + kCoolixBitMark, kCoolixOneSpace, + kCoolixBitMark, kCoolixZeroSpace, + kCoolixBitMark, kCoolixMinGap, + true, _tolerance + kCoolix48ExtraTolerance, 0, true)) + return false; + + // Success + results->decode_type = COOLIX48; + results->bits = nbits; + results->address = 0; + results->command = 0; + return true; +} +#endif // DECODE_COOLIX48 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h index 42a2528d7..2155b54b0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.h @@ -6,6 +6,8 @@ /// @note Kudos: /// Hamper: For the breakdown and mapping of the bit values. /// fraschizzato: For additional ZoneFollow & SwingVStep analysis. +/// @note Timers seem to use the `COOLIX48` protocol. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1694 // Supports: // Brand: Beko, Model: RG57K7(B)/BGEF Remote @@ -21,6 +23,8 @@ // Brand: Toshiba, Model: RAS-M13YKV-E A/C // Brand: Toshiba, Model: RAS-4M27YAV-E A/C // Brand: Toshiba, Model: WH-E1YE remote +// Brand: Bosch, Model: RG36B4/BGE remote +// Brand: Bosch, Model: B1ZAI2441W/B1ZAO2441W A/C #ifndef IR_COOLIX_H_ #define IR_COOLIX_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h index 994b6f4a3..70c0a4cf0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Fujitsu.h @@ -33,6 +33,10 @@ // Brand: Fujitsu, Model: ASU12RLF A/C (ARREB1E) // Brand: Fujitsu, Model: AR-REW4E remote (ARREW4E) // Brand: Fujitsu, Model: ASYG09KETA-B A/C (ARREW4E) +// Brand: Fujitsu, Model: AR-REB4E remote (ARREB1E) +// Brand: Fujitsu, Model: ASTG09K A/C (ARREW4E) +// Brand: Fujitsu, Model: ASTG18K A/C (ARREW4E) +// Brand: Fujitsu, Model: AR-REW1E remote (ARREW4E) #ifndef IR_FUJITSU_H_ #define IR_FUJITSU_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp index 160a882bf..1e826a72d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp @@ -399,6 +399,8 @@ void IRMitsubishiAC::setTemp(const float degrees) { // Do we have a half degree celsius? _.HalfDegree = nrHalfDegrees & 1; _.Temp = static_cast(nrHalfDegrees / 2 - kMitsubishiAcMinTemp); + // If temp is modified, iSave10C cannot be ON (because temp is then > 10C) + setISave10C(false); } /// Get the current temperature setting. @@ -452,8 +454,104 @@ void IRMitsubishiAC::setMode(const uint8_t mode) { return; } _.Mode = mode; + // iSave10C can only be on in Heat mode. + if (mode != kMitsubishiAcHeat) { + setISave10C(false); + } } +/// Set the iSave10C (i-SAVE) mode of the A/C. +/// @param[in] state true, the setting is on. false, the setting is off. +/// @note Normal minimum temp is 16C; i-SAVE mode works as gate to enable AC +/// to use 10C as setting. However, when Remote control shows 10C, it still +/// emits 16C on the "Temp" bits, and instead it uses other bits to indicate +/// a target temp of 10C. +/// Slightly strange, but I guess it's to keep compatibility to systems +/// without i-SAVE. +/// i-SAVE only has this 10C functionality when the AC is already in Heat mode. +/// In all other modes, minimum temp is 16C. +/// I have found no other difference between normal Heat mode and i-SAVE +/// other than the ability to go to 10C. +/// In this implementation, i-SAVE mode is ONLY used to enable the AC +/// temperature setting to 10C. Therefore "Temp" is set to 16 disregarding +/// what the remote shows, and mode is set to Heat. +void IRMitsubishiAC::setISave10C(const bool state) { + if (state) setMode(kMitsubishiAcHeat); + if (state) setTemp(kMitsubishiAcMinTemp); + _.iSave10C = state; +} + +/// Get the iSave10C (i-SAVE) mode of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRMitsubishiAC::getISave10C(void) const { + return _.iSave10C; +} + +/// Set the requested iSee mode. +/// @param[in] state requested iSee mode. +void IRMitsubishiAC::setISee(const bool state) { + _.ISee = state; +} + +/// Get the iSee mode of the A/C. +/// @return The iSee mode setting. +bool IRMitsubishiAC::getISee(void) const { + return _.ISee; +} + +/// Set the requested Ecocool mode. +/// @param[in] state requested Ecocool mode. +void IRMitsubishiAC::setEcocool(const bool state) { + _.Ecocool = state; +} + +/// Get the Ecocool mode of the A/C. +/// @return The Ecocool mode setting. +bool IRMitsubishiAC::getEcocool(void) const { + return _.Ecocool; +} + +/// Set the requested Absense Detect mode. +/// @param[in] state requested Absense Detect mode. +void IRMitsubishiAC::setAbsenseDetect(const bool state) { + _.AbsenseDetect = state; +} + +/// Get the Absense Detect mode of the A/C. +/// @return The Absense Detect mode setting. +bool IRMitsubishiAC::getAbsenseDetect(void) const { + return _.AbsenseDetect; +} + +/// Set the requested Direct/Indirect mode. Only works if I-See mode is ON. +/// @param[in] mode requested Direct/Indirect mode. +void IRMitsubishiAC::setDirectIndirect(const uint8_t mode) { + if (_.ISee) { + _.DirectIndirect = std::min(mode, kMitsubishiAcDirect); // bounds check + } else { + _.DirectIndirect = 0; + } +} + +/// Get the Direct/Indirect mode of the A/C. +/// @return The native mode setting. +uint8_t IRMitsubishiAC::getDirectIndirect(void) const { + return _.DirectIndirect; +} + +/// Set the requested Natural Flow mode. +/// @param[in] state requested Natural Flow mode. +void IRMitsubishiAC::setNaturalFlow(const bool state) { + _.NaturalFlow = state; +} + +/// Get the Natural Flow mode of the A/C. +/// @return The Natural Flow mode setting. +bool IRMitsubishiAC::getNaturalFlow(void) const { + return _.NaturalFlow; +} + + /// Set the requested vane (Vertical Swing) operation mode of the a/c unit. /// @note On some models, this represents the Right vertical vane. /// @param[in] position The position/mode to set the vane to. @@ -463,12 +561,6 @@ void IRMitsubishiAC::setVane(const uint8_t position) { _.Vane = pos; } -/// Set the requested wide-vane (Horizontal Swing) operation mode of the a/c. -/// @param[in] position The position/mode to set the wide vane to. -void IRMitsubishiAC::setWideVane(const uint8_t position) { - _.WideVane = std::min(position, kMitsubishiAcWideVaneAuto); -} - /// Get the Vane (Vertical Swing) mode of the A/C. /// @note On some models, this represents the Right vertical vane. /// @return The native position/mode setting. @@ -476,12 +568,6 @@ uint8_t IRMitsubishiAC::getVane(void) const { return _.Vane; } -/// Get the Wide Vane (Horizontal Swing) mode of the A/C. -/// @return The native position/mode setting. -uint8_t IRMitsubishiAC::getWideVane(void) const { - return _.WideVane; -} - /// Set the requested Left Vane (Vertical Swing) operation mode of the a/c unit. /// @param[in] position The position/mode to set the vane to. void IRMitsubishiAC::setVaneLeft(const uint8_t position) { @@ -492,6 +578,18 @@ void IRMitsubishiAC::setVaneLeft(const uint8_t position) { /// @return The native position/mode setting. uint8_t IRMitsubishiAC::getVaneLeft(void) const { return _.VaneLeft; } +/// Set the requested wide-vane (Horizontal Swing) operation mode of the a/c. +/// @param[in] position The position/mode to set the wide vane to. +void IRMitsubishiAC::setWideVane(const uint8_t position) { + _.WideVane = std::min(position, kMitsubishiAcWideVaneAuto); +} + +/// Get the Wide Vane (Horizontal Swing) mode of the A/C. +/// @return The native position/mode setting. +uint8_t IRMitsubishiAC::getWideVane(void) const { + return _.WideVane; +} + /// Get the clock time of the A/C unit. /// @return Nr. of 10 minute increments past midnight. /// @note 1 = 1/6 hour (10 minutes). e.g. 4pm = 48. @@ -777,6 +875,12 @@ String IRMitsubishiAC::toString(void) const { result += ')'; } result += addBoolToString(_.WeeklyTimer, kWeeklyTimerStr); + result += addBoolToString(_.iSave10C, k10CHeatStr); + result += addBoolToString(_.ISee, kISeeStr); + result += addBoolToString(_.Ecocool, kEconoStr); + result += addBoolToString(_.AbsenseDetect, kAbsenseDetectStr); + result += addIntToString(_.DirectIndirect, kDirectIndirectModeStr); + result += addBoolToString(_.NaturalFlow, kFreshStr); return result; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.h index 1f3a42184..55afcdce6 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.h @@ -34,6 +34,7 @@ // Brand: Mitsubishi Electric, Model: MSZ-SF25VE3 A/C (MITSUBISHI_AC) // Brand: Mitsubishi Electric, Model: SG15D remote (MITSUBISHI_AC) // Brand: Mitsubishi Electric, Model: MSZ-ZW4017S A/C (MITSUBISHI_AC) +// Brand: Mitsubishi Electric, Model: MSZ-FHnnVE A/C (MITSUBISHI_AC) #ifndef IR_MITSUBISHI_H_ #define IR_MITSUBISHI_H_ @@ -62,7 +63,8 @@ union Mitsubishi144Protocol{ // Byte 6 uint8_t :3; uint8_t Mode :3; - uint8_t :2; + uint8_t ISee : 1; + uint8_t :1; // Byte 7 uint8_t Temp :4; uint8_t HalfDegree :1; @@ -72,7 +74,7 @@ union Mitsubishi144Protocol{ uint8_t WideVane:4; // SwingH // Byte 9 uint8_t Fan :3; - uint8_t Vane :3; // SwingV + uint8_t Vane :3; // SwingV or VaneRight uint8_t VaneBit :1; uint8_t FanAuto :1; // Byte 10 @@ -86,13 +88,21 @@ union Mitsubishi144Protocol{ uint8_t WeeklyTimer :1; uint8_t :4; // Byte 14 - uint8_t :8; + uint8_t :5; + uint8_t Ecocool :1; + uint8_t :2; // Byte 15 - uint8_t :8; + uint8_t DirectIndirect:2; + uint8_t AbsenseDetect :1; + uint8_t :2; + uint8_t iSave10C :1; // i-SAVE:mode=Heat & iSave=on AND 10C on remote + uint8_t :2; // Byte 16 - uint8_t :3; - uint8_t VaneLeft :3; // SwingV(Left) - uint8_t :2; + uint8_t :1; + uint8_t NaturalFlow :1; + uint8_t :1; + uint8_t VaneLeft :3; // SwingV(Left) + uint8_t :2; // Byte 17 uint8_t Sum :8; }; @@ -126,6 +136,9 @@ const uint8_t kMitsubishiAcWideVaneRight = 0b0100; // 4 const uint8_t kMitsubishiAcWideVaneRightMax = 0b0101; // 5 const uint8_t kMitsubishiAcWideVaneWide = 0b0110; // 6 const uint8_t kMitsubishiAcWideVaneAuto = 0b1000; // 8 +const uint8_t kMitsubishiAcDirectOff = 0b00; // Vanes move when AC wants to. +const uint8_t kMitsubishiAcIndirect = 0b01; +const uint8_t kMitsubishiAcDirect = 0b11; const uint8_t kMitsubishiAcNoTimer = 0; const uint8_t kMitsubishiAcStartTimer = 5; const uint8_t kMitsubishiAcStopTimer = 3; @@ -274,12 +287,24 @@ class IRMitsubishiAC { uint8_t getFan(void) const; void setMode(const uint8_t mode); uint8_t getMode(void) const; - void setVane(const uint8_t position); - void setWideVane(const uint8_t position); + void setISave10C(const bool state); + bool getISave10C(void) const; + void setISee(const bool state); + bool getISee(void) const; + void setDirectIndirect(const uint8_t position); + uint8_t getDirectIndirect(void) const; + void setEcocool(const bool state); + bool getEcocool(void) const; + void setAbsenseDetect(const bool state); + bool getAbsenseDetect(void) const; + void setNaturalFlow(const bool state); + bool getNaturalFlow(void) const; + void setVane(const uint8_t position); // controls RIGHT vane on some models uint8_t getVane(void) const; - uint8_t getWideVane(void) const; void setVaneLeft(const uint8_t position); uint8_t getVaneLeft(void) const; + void setWideVane(const uint8_t position); + uint8_t getWideVane(void) const; uint8_t* getRaw(void); void setRaw(const uint8_t* data); uint8_t getClock(void) const; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp index 0dbbec3c8..5746ee9b1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sony.cpp @@ -120,7 +120,7 @@ uint32_t IRsend::encodeSony(const uint16_t nbits, const uint16_t command, /// bits long. bool IRrecv::decodeSony(decode_results *results, uint16_t offset, const uint16_t nbits, const bool strict) { - if (results->rawlen <= 2 * nbits + kHeader - 1 + offset) + if (results->rawlen < 2 * nbits + kHeader - 1 + offset) return false; // Message is smaller than we expected. // Compliance diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h index e1696c42a..c7ae038d0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h @@ -8,6 +8,8 @@ // Brand: TCL, Model: TAC-09CHSD/XA31I A/C (TAC09CHSD) // Brand: Teknopoint, Model: Allegro SSA-09H A/C (GZ055BE1) // Brand: Teknopoint, Model: GZ-055B-E1 remote (GZ055BE1) +// Brand: Daewoo, Model: DSB-F0934ELH-V A/C +// Brand: Daewoo, Model: GYKQ-52E remote #ifndef IR_TCL_H_ #define IR_TCL_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp index 0e3ac8ba2..7333493ef 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.cpp @@ -216,9 +216,7 @@ void IRToshibaAC::setTemp(const uint8_t degrees) { /// Get the current temperature setting. /// @return The current setting for temp. in degrees celsius. -uint8_t IRToshibaAC::getTemp(void) const { - return _.Temp + kToshibaAcMinTemp; -} +uint8_t IRToshibaAC::getTemp(void) const { return _.Temp + kToshibaAcMinTemp; } /// Set the speed of the fan. /// @param[in] speed The desired setting (0 is Auto, 1-5 is the speed, 5 is Max) @@ -339,6 +337,19 @@ void IRToshibaAC::setEcono(const bool on) { } } +/// Get the filter (Pure/Ion Filter) setting of the A/C. +/// @return true, if the current setting is on. Otherwise, false. +bool IRToshibaAC::getFilter(void) const { + return (getStateLength() >= kToshibaACStateLength) ? _.Filter : false; +} + +/// Set the filter (Pure/Ion Filter) setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRToshibaAC::setFilter(const bool on) { + _.Filter = on; + if (on) setStateLength(std::min(kToshibaACStateLength, getStateLength())); +} + /// 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. @@ -421,6 +432,7 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const { result.fanspeed = toCommonFanSpeed(getFan()); result.turbo = getTurbo(); result.econo = getEcono(); + result.filter = getFilter(); } switch (getSwing()) { case kToshibaAcSwingOn: @@ -436,7 +448,6 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const { } // Not supported. result.light = false; - result.filter = false; result.swingh = stdAc::swingh_t::kOff; result.quiet = false; result.clean = false; @@ -450,7 +461,7 @@ stdAc::state_t IRToshibaAC::toCommon(const stdAc::state_t *prev) const { /// @return A human readable string. String IRToshibaAC::toString(void) const { String result = ""; - result.reserve(80); + result.reserve(95); result += addTempToString(getTemp(), true, false); switch (getStateLength()) { case kToshibaACStateLengthShort: @@ -477,6 +488,7 @@ String IRToshibaAC::toString(void) const { kToshibaAcFanMed); result += addBoolToString(getTurbo(), kTurboStr); result += addBoolToString(getEcono(), kEconoStr); + result += addBoolToString(getFilter(), kFilterStr); } return result; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h index 3ebf5e693..1314cf54d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Toshiba.h @@ -8,6 +8,7 @@ /// @see https://docs.google.com/spreadsheets/d/1yidE2fvaO9kpCHfKafIdH31q4uaskYR1OwwrkyOxbp0/edit?usp=drivesdk /// @see https://www.toshiba-carrier.co.jp/global/about/index.htm /// @see http://www.toshiba-carrier.co.th/AboutUs/Pages/CompanyProfile.aspx +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1692 // Supports: // Brand: Toshiba, Model: RAS-B13N3KV2 @@ -18,6 +19,8 @@ // Brand: Toshiba, Model: WC-L03SE // Brand: Toshiba, Model: WH-UB03NJ remote // Brand: Toshiba, Model: RAS-2558V A/C +// Brand: Toshiba, Model: WH-TA01JE remote +// Brand: Toshiba, Model: RAS-25SKVP2-ND A/C // Brand: Carrier, Model: 42NQV060M2 / 38NYV060M2 A/C // Brand: Carrier, Model: 42NQV050M2 / 38NYV050M2 A/C // Brand: Carrier, Model: 42NQV035M2 / 38NYV035M2 A/C @@ -50,28 +53,31 @@ union ToshibaProtocol{ ///< 1 (56 bit message) ///< 3 (72 bit message) ///< 4 (80 bit message) - uint8_t Length :8; + uint8_t Length :8; // Byte[3] - The bit-inverted value of the "length" byte. - uint8_t :8; + uint8_t :8; // Byte[4] - uint8_t :3; - uint8_t LongMsg :1; - uint8_t :1; - uint8_t ShortMsg:1; - uint8_t :2; + uint8_t :3; + uint8_t LongMsg :1; + uint8_t :1; + uint8_t ShortMsg :1; + uint8_t :2; // Byte[5] - uint8_t Swing :3; - uint8_t :1; - uint8_t Temp :4; + uint8_t Swing :3; + uint8_t :1; + uint8_t Temp :4; // Byte[6] - uint8_t Mode :3; - uint8_t :2; - uint8_t Fan :3; + uint8_t Mode :3; + uint8_t :2; + uint8_t Fan :3; // Byte[7] - uint8_t :8; + uint8_t :4; + uint8_t Filter :1; + uint8_t :3; + // Byte[8] // (Checksum for 72 bit messages, Eco/Turbo for long 80 bit messages) - uint8_t EcoTurbo :8; + uint8_t EcoTurbo :8; }; }; @@ -144,6 +150,8 @@ class IRToshibaAC { bool getTurbo(void) const; void setEcono(const bool on); bool getEcono(void) const; + void setFilter(const bool on); + bool getFilter(void) const; void setMode(const uint8_t mode); uint8_t getMode(const bool raw = false) const; void setRaw(const uint8_t newState[], diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h index 0fcc04791..d8142e20e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h @@ -120,6 +120,9 @@ #ifndef D_STR_IFEEL #define D_STR_IFEEL "IFeel" #endif // D_STR_IFEEL +#ifndef D_STR_ISEE +#define D_STR_ISEE "ISee" +#endif // D_STR_ISEE #ifndef D_STR_HUMID #define D_STR_HUMID "Humid" #endif // D_STR_HUMID @@ -207,6 +210,19 @@ #ifndef D_STR_SENSOR #define D_STR_SENSOR "Sensor" #endif // D_STR_SENSOR +#ifndef D_STR_ABSENSEDETECT +#define D_STR_ABSENSEDETECT "Absense detect" +#endif // D_STR_ABSENSEDETECT +#ifndef D_STR_DIRECT +#define D_STR_DIRECT "Direct" +#endif // D_STR_DIRECT +#ifndef D_STR_INDIRECT +#define D_STR_INDIRECT "Indirect" +#endif // D_STR_INDIRECT +#ifndef D_STR_DIRECTINDIRECTMODE +#define D_STR_DIRECTINDIRECTMODE D_STR_DIRECT " / " \ +D_STR_INDIRECT " " D_STR_MODE +#endif // D_STR_DIRECTINDIRECTMODE #ifndef D_STR_DISPLAY #define D_STR_DISPLAY "Display" #endif // D_STR_DISPLAY @@ -702,6 +718,9 @@ #ifndef D_STR_COOLIX #define D_STR_COOLIX "COOLIX" #endif // D_STR_COOLIX +#ifndef D_STR_COOLIX48 +#define D_STR_COOLIX48 D_STR_COOLIX "48" +#endif // D_STR_COOLIX48 #ifndef D_STR_CORONA_AC #define D_STR_CORONA_AC "CORONA_AC" #endif // D_STR_CORONA_AC diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp index d43cfcd9d..2988e4b4b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp @@ -1,6 +1,7 @@ // Copyright 2019-2021 David Conran #include +#include "ir_Airton.h" #include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" @@ -44,6 +45,36 @@ // Tests for IRac class. +TEST(TestIRac, Airton) { + IRAirtonAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + const char expected[] = + "Power: On, Mode: 1 (Cool), Fan: 5 (Maximum), Temp: 18C, " + "Swing(V): On, Econo: On, Turbo: On, Light: On, Health: On, Sleep: On"; + + ac.begin(); + irac.airton(&ac, + true, // Power + stdAc::opmode_t::kCool, // Mode + 18, // Celsius + stdAc::fanspeed_t::kMax, // Fan speed + stdAc::swingv_t::kAuto, // Vertical Swing + true, // Turbo + true, // Light/Display/LED + true, // Econo (Eco) + true, // Filter (Health) + 9 * 60 + 12); // Sleep (09:12) + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(AIRTON, ac._irsend.capture.decode_type); + ASSERT_EQ(kAirtonBits, 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, Airwell) { IRAirwellAc ac(kGpioUnused); IRac irac(kGpioUnused); @@ -1418,7 +1449,9 @@ TEST(TestIRac, Mitsubishi) { "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 2 (Medium), " "Swing(V): 0 (Auto), Swing(H): 3 (Middle), " "Clock: 14:30, On Timer: 00:00, Off Timer: 00:00, Timer: -, " - "Weekly Timer: Off"; + "Weekly Timer: Off" + ", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, " + "Direct / Indirect Mode: 0, Fresh: Off"; ac.begin(); irac.mitsubishi(&ac, @@ -1958,7 +1991,7 @@ TEST(TestIRac, Toshiba) { IRrecv capture(kGpioUnused); char expected[] = "Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), " - "Turbo: Off, Econo: On"; + "Turbo: Off, Econo: On, Filter: Off"; ac.begin(); irac.toshiba(&ac, @@ -1968,7 +2001,8 @@ TEST(TestIRac, Toshiba) { stdAc::fanspeed_t::kLow, // Fan speed stdAc::swingv_t::kOff, // Vertical Swing false, // Turbo - true); // Econo + true, // Econo + false); // Filter ASSERT_EQ(expected, ac.toString()); ASSERT_EQ(kToshibaACStateLengthLong, ac.getStateLength()); ac._irsend.makeDecodeResult(); @@ -2873,7 +2907,7 @@ TEST(TestIRac, Issue1250) { // Now send the state so we can actually decode/capture what we sent. char expected_on[] = "Temp: 19C, Power: On, Mode: 4 (Fan), Fan: 0 (Auto), " - "Turbo: Off, Econo: Off"; + "Turbo: Off, Econo: Off, Filter: Off"; ac._irsend.reset(); irac.toshiba(&ac, irac.next.power, // Power @@ -2882,7 +2916,8 @@ TEST(TestIRac, Issue1250) { irac.next.fanspeed, // Fan speed irac.next.swingv, // Vertical Swing irac.next.turbo, // Turbo - irac.next.econo); // Econo + irac.next.econo, // Econo + irac.next.filter); // Filter ASSERT_EQ(expected_on, ac.toString()); ASSERT_EQ(kToshibaACStateLength, ac.getStateLength()); ac._irsend.makeDecodeResult(); @@ -2898,7 +2933,8 @@ TEST(TestIRac, Issue1250) { irac.sendAc(); // Now send the state so we can actually decode/capture what we sent. char expected_off[] = - "Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off"; + "Temp: 19C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, " + "Filter: Off"; ac._irsend.reset(); irac.toshiba(&ac, irac.next.power, // Power @@ -2907,7 +2943,8 @@ TEST(TestIRac, Issue1250) { irac.next.fanspeed, // Fan speed irac.next.swingv, // Vertical Swing irac.next.turbo, // Turbo - irac.next.econo); // Econo + irac.next.econo, // Econo + irac.next.filter); // Filter ASSERT_EQ(expected_off, ac.toString()); ASSERT_EQ(kToshibaACStateLength, ac.getStateLength()); ac._irsend.makeDecodeResult(); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp index e4e66ee13..2f2bb0bac 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp @@ -1,5 +1,6 @@ // Copyright 2021 crankyoldgit +#include "ir_Airton.h" #include "IRac.h" #include "IRrecv.h" #include "IRrecv_test.h" @@ -34,6 +35,13 @@ TEST(TestDecodeAirton, RealExample) { EXPECT_EQ(0x5E1400090C11D3, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_EQ( + "Power: On, Mode: 4 (Heat), Fan: 0 (Auto), Temp: 25C, " + "Swing(V): Off, Econo: Off, Turbo: Off, Light: Off, " + "Health: Off, Sleep: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); } TEST(TestDecodeAirton, SyntheticExample) { @@ -56,7 +64,265 @@ TEST(TestUtils, Housekeeping) { ASSERT_EQ("AIRTON", typeToString(decode_type_t::AIRTON)); ASSERT_EQ(decode_type_t::AIRTON, strToDecodeType("AIRTON")); ASSERT_FALSE(hasACState(decode_type_t::AIRTON)); - ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::AIRTON)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::AIRTON)); ASSERT_EQ(kAirtonBits, IRsend::defaultBits(decode_type_t::AIRTON)); ASSERT_EQ(kAirtonDefaultRepeat, IRsend::minRepeats(decode_type_t::AIRTON)); } + +// Tests for IRAirtonAc class. + +TEST(TestIRAirtonAcClass, Power) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.on(); + EXPECT_TRUE(ac.getPower()); + + ac.off(); + EXPECT_FALSE(ac.getPower()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); +} + +TEST(TestIRAirtonAcClass, Checksums) { + ASSERT_TRUE(IRAirtonAc::validChecksum(0x5E1400090C11D3)); + ASSERT_EQ(0x5E, IRAirtonAc::calcChecksum(0x5E1400090C11D3)); + ASSERT_FALSE(IRAirtonAc::validChecksum(0x551400090C11D3)); + ASSERT_TRUE(IRAirtonAc::validChecksum(0x2F8801060911D3)); + ASSERT_TRUE(IRAirtonAc::validChecksum(0xDB8800021A11D3)); +} + +TEST(TestIRAirtonAcClass, Temperature) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + ac.setMode(kAirtonCool); // Cool mode allows the entire temp range. + ac.setTemp(0); + EXPECT_EQ(kAirtonMinTemp, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kAirtonMaxTemp, ac.getTemp()); + + ac.setTemp(kAirtonMinTemp); + EXPECT_EQ(kAirtonMinTemp, ac.getTemp()); + + ac.setTemp(kAirtonMaxTemp); + EXPECT_EQ(kAirtonMaxTemp, ac.getTemp()); + + ac.setTemp(kAirtonMinTemp - 1); + EXPECT_EQ(kAirtonMinTemp, ac.getTemp()); + + ac.setTemp(kAirtonMaxTemp + 1); + EXPECT_EQ(kAirtonMaxTemp, ac.getTemp()); + + ac.setTemp(17); + EXPECT_EQ(17, ac.getTemp()); + + ac.setTemp(21); + EXPECT_EQ(21, ac.getTemp()); + + ac.setTemp(20); + EXPECT_EQ(20, ac.getTemp()); +} + +TEST(TestIRAirtonAcClass, OperatingMode) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.setMode(kAirtonCool); + EXPECT_EQ(kAirtonCool, ac.getMode()); + ac.setMode(kAirtonDry); + EXPECT_EQ(kAirtonDry, ac.getMode()); + ac.setMode(kAirtonFan); + EXPECT_EQ(kAirtonFan, ac.getMode()); + EXPECT_NE(kAirtonMaxTemp, ac.getTemp()); + ac.setMode(kAirtonAuto); + EXPECT_EQ(kAirtonAuto, ac.getMode()); + EXPECT_EQ(kAirtonMaxTemp, ac.getTemp()); + ac.setMode(kAirtonHeat); + EXPECT_EQ(kAirtonHeat, ac.getMode()); + + ac.setMode(kAirtonHeat + 1); + EXPECT_EQ(kAirtonAuto, ac.getMode()); + ac.setMode(255); + EXPECT_EQ(kAirtonAuto, ac.getMode()); +} + +TEST(TestIRAirtonAcClass, FanSpeed) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + ac.setMode(kAirtonCool); // All fan speeds available in this mode. + + ac.setFan(0); + EXPECT_EQ(kAirtonFanAuto, ac.getFan()); + + ac.setFan(255); + EXPECT_EQ(kAirtonFanAuto, ac.getFan()); + + ac.setFan(kAirtonFanHigh); + EXPECT_EQ(kAirtonFanHigh, ac.getFan()); + + ac.setFan(kAirtonFanLow); + EXPECT_EQ(kAirtonFanLow, ac.getFan()); + + ac.setFan(kAirtonFanMax); + EXPECT_EQ(kAirtonFanMax, ac.getFan()); + + ac.setFan(kAirtonFanMin); + EXPECT_EQ(kAirtonFanMin, ac.getFan()); + + ac.setFan(kAirtonFanMed); + EXPECT_EQ(kAirtonFanMed, ac.getFan()); + + ac.setFan(kAirtonFanMax + 1); + EXPECT_EQ(kAirtonFanAuto, ac.getFan()); +} + +TEST(TestIRAirtonAcClass, SwingV) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.setSwingV(false); + EXPECT_FALSE(ac.getSwingV()); + ac.setSwingV(true); + EXPECT_TRUE(ac.getSwingV()); + ac.setSwingV(false); + EXPECT_FALSE(ac.getSwingV()); + + // Known swingv on state + ac.setRaw(0xBC0401050111D3); + EXPECT_TRUE(ac.getSwingV()); +} + +TEST(TestIRAirtonAcClass, Light) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.setLight(false); + EXPECT_FALSE(ac.getLight()); + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); + ac.setLight(false); + EXPECT_FALSE(ac.getLight()); + + // Known light on state + ac.setRaw(0x298801040911D3); + EXPECT_TRUE(ac.getLight()); +} + +TEST(TestIRAirtonAcClass, ConstructKnownExamples) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + ac.stateReset(); + ac.on(); + ac.setMode(kAirtonHeat); + ac.setFan(kAirtonFanAuto); + ac.setTemp(25); + ac.setSwingV(false); + ac.setLight(false); + ac.setTurbo(false); + ac.setSleep(false); + ac.setEcono(false); + ac.setHealth(false); + EXPECT_EQ( + "Power: On, Mode: 4 (Heat), Fan: 0 (Auto), Temp: 25C, " + "Swing(V): Off, Econo: Off, Turbo: Off, Light: Off, " + "Health: Off, Sleep: Off", + ac.toString()); + EXPECT_EQ(0x5E1400090C11D3, ac.getRaw()); +} + +TEST(TestIRAirtonAcClass, Turbo) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.setTurbo(false); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_NE(kAirtonFanMax, ac.getFan()); + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + EXPECT_EQ(kAirtonFanMax, ac.getFan()); + ac.setTurbo(false); + EXPECT_FALSE(ac.getTurbo()); + + // Known Turbo on state + ac.setRaw(0x92040000D911D3); + EXPECT_TRUE(ac.getTurbo()); +} + +TEST(TestIRAirtonAcClass, Sleep) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.setMode(kAirtonCool); // Sleep is available in Cool mode. + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + + ac.setSleep(true); + // Sleep is available in Heat mode, but changing modes resets it. + ac.setMode(kAirtonHeat); + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + + ac.setMode(kAirtonAuto); // Sleep is NOT available in Auto mode. + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_FALSE(ac.getSleep()); + + ac.setMode(kAirtonFan); // Sleep is NOT available in Fan mode. + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_FALSE(ac.getSleep()); + + // Known Sleep on state + ac.setRaw(0xA00600000911D3); + EXPECT_TRUE(ac.getSleep()); + EXPECT_NE(kAirtonAuto, ac.getMode()); + EXPECT_NE(kAirtonFan, ac.getMode()); +} + +TEST(TestIRAirtonAcClass, Health) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + + ac.setHealth(false); + EXPECT_FALSE(ac.getHealth()); + ac.setHealth(true); + EXPECT_TRUE(ac.getHealth()); + ac.setHealth(false); + EXPECT_FALSE(ac.getHealth()); + + // Known Health on state + ac.setRaw(0xE5C900000911D3); + EXPECT_TRUE(ac.getHealth()); +} + +TEST(TestIRAirtonAcClass, Econo) { + IRAirtonAc ac(kGpioUnused); + ac.begin(); + ac.setMode(kAirtonCool); // Econo is only available in Cool. + ac.setEcono(false); + EXPECT_FALSE(ac.getEcono()); + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); + ac.setEcono(false); + EXPECT_FALSE(ac.getEcono()); + + ac.setEcono(true); + ac.setMode(kAirtonHeat); // Econo is only available in Cool, not Heat! + EXPECT_FALSE(ac.getEcono()); + ac.setEcono(true); + EXPECT_FALSE(ac.getEcono()); + + // Known Econo on state + ac.setRaw(0xE5C900000911D3); + EXPECT_TRUE(ac.getEcono()); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp index 46c554882..62e0d6b0e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Coolix_test.cpp @@ -6,6 +6,25 @@ #include "IRsend_test.h" #include "gtest/gtest.h" + +TEST(TestUtils, Housekeeping) { + // COOLIX + ASSERT_EQ("COOLIX", typeToString(decode_type_t::COOLIX)); + ASSERT_EQ(decode_type_t::COOLIX, strToDecodeType("COOLIX")); + ASSERT_FALSE(hasACState(decode_type_t::COOLIX)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::COOLIX)); + ASSERT_EQ(kCoolixBits, IRsend::defaultBits(decode_type_t::COOLIX)); + ASSERT_EQ(kSingleRepeat, IRsend::minRepeats(decode_type_t::COOLIX)); + + // COOLIX48 + ASSERT_EQ("COOLIX48", typeToString(decode_type_t::COOLIX48)); + ASSERT_EQ(decode_type_t::COOLIX48, strToDecodeType("COOLIX48")); + ASSERT_FALSE(hasACState(decode_type_t::COOLIX48)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::COOLIX48)); + ASSERT_EQ(kCoolix48Bits, IRsend::defaultBits(decode_type_t::COOLIX48)); + ASSERT_EQ(kSingleRepeat, IRsend::minRepeats(decode_type_t::COOLIX48)); +} + // Tests for sendCOOLIX(). // Test sending typical data only. @@ -941,3 +960,76 @@ TEST(TestCoolixACClass, VerifyZoneFollowFan) { "Zone Follow: On, Sensor Temp: 19C", ac.toString()); } + +TEST(TestDecodeCoolix48, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1694#issue-1068786691 + // Off Timer: 1 hour + const uint16_t rawData[199] = { + 4342, 4454, 486, 1724, 436, 658, 438, 1748, 464, 1718, 462, 634, 440, 656, + 462, 1696, 488, 634, 462, 634, 436, 1722, 516, 608, 462, 660, 436, 1694, + 488, 1720, 440, 630, 488, 1700, 488, 1704, 458, 660, 462, 1698, 490, 632, + 462, 634, 436, 684, 436, 1700, 464, 1748, 462, 634, 462, 1720, 436, 658, + 462, 1700, 488, 1692, 512, 1696, 438, 684, 410, 686, 434, 688, 408, 1696, + 488, 1694, 464, 682, 414, 1748, 436, 1722, 488, 632, 438, 686, 408, 662, + 462, 1696, 488, 1722, 462, 1696, 462, 1746, 436, 1798, 386, 1694, 490, + 1720, 516, 5234, 4370, 4446, 490, 1690, 492, 658, 434, 1726, 436, 1746, + 464, 604, 488, 658, 412, 1718, 490, 636, 460, 660, 438, 1698, 460, 662, + 458, 632, 436, 1718, 490, 1720, 488, 608, 436, 1754, 462, 1726, 438, 682, + 414, 1748, 464, 632, 460, 660, 410, 658, 438, 1748, 464, 1694, 464, 660, + 436, 1720, 488, 634, 460, 1726, 462, 1724, 462, 1692, 490, 606, 462, 714, + 384, 660, 460, 1722, 460, 1722, 490, 606, 464, 1718, 490, 1670, 486, 634, + 462, 662, 410, 660, 460, 1722, 464, 1718, 460, 1696, 464, 1720, 462, 1720, + 462, 1722, 486, 1700, 462}; // UNKNOWN 1F691B97 + + irsend.begin(); + irsend.reset(); + + irsend.sendRaw(rawData, 199, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(COOLIX48, irsend.capture.decode_type); + EXPECT_EQ(kCoolix48Bits, irsend.capture.bits); + EXPECT_EQ(0xB24DA35C6C7F, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); +} + +TEST(TestDecodeCoolix48, SyntheticSelfDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + irsend.sendCoolix48(0xB24DA35C6C7F); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(COOLIX48, irsend.capture.decode_type); + EXPECT_EQ(kCoolix48Bits, irsend.capture.bits); + EXPECT_EQ(0xB24DA35C6C7F, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); + + EXPECT_EQ( + "f38000d33" + "m4692s4416" // Message. + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s552m552s552m552s1656m552s1656" + "m552s552m552s1656m552s552m552s1656m552s1656m552s1656m552s552m552s552" + "m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s552m552s552" + "m552s552m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s5244" + "m4692s4416" // Repeat + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s552m552s552m552s1656m552s1656" + "m552s552m552s1656m552s552m552s1656m552s1656m552s1656m552s552m552s552" + "m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s552m552s552" + "m552s552m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s5244", + irsend.outputStr()); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mitsubishi_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mitsubishi_test.cpp index 28cc04d8e..815d4f996 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mitsubishi_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mitsubishi_test.cpp @@ -913,7 +913,9 @@ TEST(TestMitsubishiACClass, HumanReadable) { "Power: On, Mode: 1 (Heat), Temp: 22C, Fan: 6 (Quiet), " "Swing(V): 0 (Auto), Swing(H): 3 (Middle), " "Clock: 17:10, On Timer: 00:00, Off Timer: 00:00, Timer: -, " - "Weekly Timer: Off", + "Weekly Timer: Off" + ", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, " + "Direct / Indirect Mode: 0, Fresh: Off", ac.toString()); ac.setTemp(21.5); ac.setWeeklyTimerEnabled(true); @@ -921,7 +923,9 @@ TEST(TestMitsubishiACClass, HumanReadable) { "Power: On, Mode: 1 (Heat), Temp: 21.5C, Fan: 6 (Quiet), " "Swing(V): 0 (Auto), Swing(H): 3 (Middle), " "Clock: 17:10, On Timer: 00:00, Off Timer: 00:00, Timer: -, " - "Weekly Timer: On", + "Weekly Timer: On" + ", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, " + "Direct / Indirect Mode: 0, Fresh: Off", ac.toString()); } @@ -1434,7 +1438,9 @@ TEST(TestDecodeMitsubishiAC, Issue891) { "Power: Off, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), " "Swing(V): 0 (Auto), Swing(H): 3 (Middle), " "Clock: 00:00, On Timer: 00:00, Off Timer: 00:00, Timer: -, " - "Weekly Timer: Off", + "Weekly Timer: Off" + ", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, " + "Direct / Indirect Mode: 0, Fresh: Off", ac.toString()); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp index 1785b3895..4a63780d5 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Toshiba_test.cpp @@ -312,20 +312,21 @@ TEST(TestToshibaACClass, HumanReadableOutput) { ac.setRaw(initial_state); EXPECT_EQ("Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), " - "Turbo: Off, Econo: Off", + "Turbo: Off, Econo: Off, Filter: Off", ac.toString()); ac.setRaw(modified_state); EXPECT_EQ("Temp: 17C, Power: On, Mode: 1 (Cool), Fan: 5 (High), " - "Turbo: Off, Econo: Off", + "Turbo: Off, Econo: Off, Filter: Off", ac.toString()); ac.setTemp(25); ac.setFan(3); ac.setMode(kToshibaAcDry); EXPECT_EQ("Temp: 25C, Power: On, Mode: 2 (Dry), Fan: 3 (Medium), " - "Turbo: Off, Econo: Off", + "Turbo: Off, Econo: Off, Filter: Off", ac.toString()); ac.off(); - EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off", + EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off, " + "Filter: Off", ac.toString()); } @@ -379,7 +380,7 @@ TEST(TestDecodeToshibaAC, SyntheticExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( "Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, " - "Econo: Off", + "Econo: Off, Filter: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -555,6 +556,7 @@ TEST(TestToshibaACClass, toCommon) { ac.setMode(kToshibaAcCool); ac.setTemp(20); ac.setFan(kToshibaAcFanMax); + ac.setFilter(true); // Now test it. ASSERT_EQ(decode_type_t::TOSHIBA_AC, ac.toCommon().protocol); ASSERT_EQ(-1, ac.toCommon().model); @@ -563,13 +565,13 @@ TEST(TestToshibaACClass, toCommon) { ASSERT_EQ(20, ac.toCommon().degrees); ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); + ASSERT_TRUE(ac.toCommon().filter); // Unsupported. ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv); ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); ASSERT_FALSE(ac.toCommon().turbo); ASSERT_FALSE(ac.toCommon().econo); ASSERT_FALSE(ac.toCommon().light); - ASSERT_FALSE(ac.toCommon().filter); ASSERT_FALSE(ac.toCommon().clean); ASSERT_FALSE(ac.toCommon().beep); ASSERT_FALSE(ac.toCommon().quiet); @@ -626,7 +628,7 @@ TEST(TestDecodeToshibaAC, RealLongExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( "Temp: 22C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: On, " - "Econo: Off", + "Econo: Off, Filter: Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -731,7 +733,7 @@ TEST(TestToshibaACClass, ConstructLongState) { ac.setEcono(true); EXPECT_EQ( "Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), " - "Turbo: Off, Econo: On", + "Turbo: Off, Econo: On, Filter: Off", ac.toString()); EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength()); const uint8_t expectedState[kToshibaACStateLengthLong] = { @@ -781,7 +783,8 @@ TEST(TestDecodeToshibaAC, RealExample_WHUB03NJ) { EXPECT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off", + "Temp: 20C, Power: Off, Fan: 0 (Auto), Turbo: Off, Econo: Off, " + "Filter: Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -828,3 +831,34 @@ TEST(TestToshibaACClass, SwingCodes) { "Temp: 17C, Swing(V): 4 (Toggle)", ac.toString()); } + +// For https://github.com/crankyoldgit/IRremoteESP8266/issues/1692 +TEST(TestToshibaACClass, Filter) { + IRToshibaAC ac(kGpioUnused); + ac.begin(); + EXPECT_FALSE(ac.getFilter()); + + ac.setFilter(true); + EXPECT_TRUE(ac.getFilter()); + + + ac.setFilter(false); + EXPECT_FALSE(ac.getFilter()); + + ac.setFilter(true); + EXPECT_TRUE(ac.getFilter()); + + const uint8_t pure_off[kToshibaACStateLength] = { + 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x40, 0x03, 0x00, 0x42}; + ac.setRaw(pure_off); + EXPECT_FALSE(ac.getFilter()); + + const uint8_t pure_on[kToshibaACStateLength] = { + 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x40, 0x03, 0x10, 0x52}; + ac.setRaw(pure_on); + EXPECT_TRUE(ac.getFilter()); + + // Convert a known filter/pure on state to a known off filter/pure state. + ac.setFilter(false); + EXPECT_STATE_EQ(pure_off, ac.getRaw(), ac.getStateLength() * 8); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile index 15f192efd..bf65a996d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile @@ -27,7 +27,9 @@ CPPFLAGS += -DUNIT_TEST -D_IR_LOCALE_=en-AU # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11 -all : gc_decode mode2_decode +objects = $(patsubst %.cpp,%,$(wildcard *.cpp)) + +all : $(objects) run_tests : all failed=""; \ @@ -35,6 +37,10 @@ run_tests : all echo "RUNNING: $${py_unittest}"; \ python3 ./$${py_unittest} || failed="$${failed} $${py_unittest}"; \ done; \ + for shell_unittest in *_test.sh; do \ + echo "RUNNING: $${shell_unittest}"; \ + bash ./$${shell_unittest} || failed="$${failed} $${shell_unittest}"; \ + done; \ if [ -n "$${failed}" ]; then \ echo "FAIL: :-( :-( Unit test(s)$${failed} failed! :-( :-("; exit 1; \ else \ @@ -46,7 +52,7 @@ run-% : all python3 ./$*.py; clean : - rm -f *.o *.pyc gc_decode mode2_decode + rm -f *.o *.pyc $(objects) # Keep all intermediate files. @@ -80,7 +86,7 @@ IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP82 # new specific targets goes above this line -%_decode : $(COMMON_OBJ) %_decode.o +$(objects) : %: $(COMMON_OBJ) %.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ ir_%.o : $(USER_DIR)/ir_%.h $(USER_DIR)/ir_%.cpp $(COMMON_DEPS) $(GTEST_HEADERS) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp new file mode 100644 index 000000000..7358f16da --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw.cpp @@ -0,0 +1,148 @@ +// Quick and dirty tool to convert a protocol's (hex) codes to raw timings. +// Copyright 2021 David Conran + +#include +#include +#include +#include +#include +#include "IRac.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "IRutils.h" + + +void usage_error(char *name) { + std::cerr << "Usage: " << name + << " --protocol PROTOCOL_NAME" + << " --code " + << " [--bits 1-" << kStateSizeMax * 8 << "]" + << " [--timinginfo]" + << std::endl; +} + +int main(int argc, char *argv[]) { + int argv_offset = 1; + int repeats = 0; + uint64_t code = 0; + uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0. + decode_type_t input_type = decode_type_t::UNKNOWN; + bool timinginfo = false; + + // Check the invocation/calling usage. + if (argc < 5 || argc > 8) { + usage_error(argv[0]); + return 1; + } + + if (strncmp("--protocol", argv[argv_offset], 11) == 0) { + argv_offset++; + input_type = strToDecodeType(argv[argv_offset]); + switch (input_type) { + // Unsupported types + case decode_type_t::UNUSED: + case decode_type_t::UNKNOWN: + case decode_type_t::GLOBALCACHE: + case decode_type_t::PRONTO: + case decode_type_t::RAW: + std::cerr << "The protocol specified is not supported by this program." + << std::endl; + return 1; + default: + break; + } + argv_offset++; + } + + uint16_t nbits = IRsend::defaultBits(input_type); + uint16_t stateSize = nbits / 8; + if (strncmp("--code", argv[argv_offset], 7) == 0) { + argv_offset++; + String hexstr = String(argv[argv_offset]); + uint64_t strOffset = 0; + if (hexstr.rfind("0x", 0) || hexstr.rfind("0X", 0)) strOffset = 2; + + // Calculate how many hexadecimal characters there are. + uint64_t hexstrlength = hexstr.length() - strOffset; + + // Ptr to the least significant byte of the resulting state for this + // protocol. + uint8_t *statePtr = &state[stateSize - 1]; + + // Convert the string into a state array of the correct length. + for (uint16_t i = 0; i < hexstrlength; i++) { + // Grab the next least sigificant hexadecimal digit from the string. + uint8_t c = tolower(hexstr[hexstrlength + strOffset - i - 1]); + if (isxdigit(c)) { + if (isdigit(c)) + c -= '0'; + else + c = c - 'a' + 10; + } else { + std::cerr << "Code " << argv[argv_offset] + << " contains non-hexidecimal characters." << std::endl; + return 3; + } + if (i % 2 == 1) { // Odd: Upper half of the byte. + *statePtr += (c << 4); + statePtr--; // Advance up to the next least significant byte of state. + } else { // Even: Lower half of the byte. + *statePtr = c; + } + } + if (!hasACState(input_type)) + code = std::stoull(argv[argv_offset], nullptr, 16); + argv_offset++; + } + + if (argc - argv_offset > 0 && strncmp("--bits", argv[argv_offset], 7) == 0) { + argv_offset++; + nbits = std::stoul(argv[argv_offset], nullptr, 10); + if (nbits == 0 && (nbits <= kStateSizeMax * 8)) { + std::cerr << "Nr. of bits " << argv[argv_offset] + << " is invalid." << std::endl; + return 1; + } + stateSize = nbits / 8; + argv_offset++; + } + + if (argc - argv_offset > 0 && + strncmp("--timinginfo", argv[argv_offset], 13) == 0) { + argv_offset++; + timinginfo = true; + } + + if (argc - argv_offset != 0) { + usage_error(argv[0]); + return 1; + } + + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + + if (hasACState(input_type)) // Is it larger than 64 bits? + irsend.send(input_type, state, stateSize); + else + irsend.send(input_type, code, nbits, repeats); + + irsend.makeDecodeResult(); + irrecv.decode(&irsend.capture); + + std::cout << "Code type: " << irsend.capture.decode_type << " (" + << typeToString(irsend.capture.decode_type) << ")" << std::endl + << "Code bits: " << irsend.capture.bits << std::endl; + if (hasACState(irsend.capture.decode_type)) { + String description = IRAcUtils::resultAcToString(&irsend.capture); + if (description.length()) { + std::cout << "Description: " << description.c_str() << std::endl; + } + } + + std::cout << std::endl << resultToSourceCode(&irsend.capture) << std::endl; + if (timinginfo) std::cout << resultToTimingInfo(&irsend.capture); + + return 0; +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw_test.sh b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw_test.sh new file mode 100755 index 000000000..fd587f2ad --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/code_to_raw_test.sh @@ -0,0 +1,65 @@ +#! /bin/bash +CODE_TO_RAW=./code_to_raw +if [[ ! -x ${CODE_TO_RAW} ]]; then + echo "'raw_to_code' failed to compile and produce an executable." + exit 1 +fi + +function unittest_success() +{ + COMMAND=$1 + EXPECTED="$2" + echo -n "Testing: \"${COMMAND}\" ..." + OUTPUT="$(${COMMAND})" + STATUS=$? + FAILURE="" + if [[ ${STATUS} -ne 0 ]]; then + FAILURE="Non-Zero Exit status: ${STATUS}. " + fi + if [[ "${OUTPUT}" != "${EXPECTED}" ]]; then + FAILURE="${FAILURE} Unexpected Output: \"${OUTPUT}\" != \"${EXPECTED}\"" + fi + if [[ -z ${FAILURE} ]]; then + echo " ok!" + return 0 + else + echo + echo "FAILED: ${FAILURE}" + return 1 + fi +} + +read -r -d '' OUT << EOM +Code type: 4 (SONY) +Code bits: 12 + +uint16_t rawData[78] = {2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, 24600, 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, 24600, 2400, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 600, 600, 600, 600, 600, 24600 }; // SONY F50 +uint32_t address = 0x1; +uint32_t command = 0x2F; +uint64_t data = 0xF50; +EOM + +unittest_success "${CODE_TO_RAW} --protocol Sony --code 0xf50 --bits 12" "${OUT}" + +read -r -d '' OUT << EOM +Code type: 7 (SAMSUNG) +Code bits: 32 + +uint16_t rawData[68] = {4480, 4480, 560, 1680, 560, 1680, 560, 1680, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1680, 560, 1680, 560, 1680, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1680, 560, 560, 560, 560, 560, 1680, 560, 1680, 560, 560, 560, 560, 560, 1680, 560, 560, 560, 1680, 560, 1680, 560, 560, 560, 560, 560, 1680, 560, 1680, 560, 560, 560, 47040 }; // SAMSUNG E0E09966 +uint32_t address = 0x7; +uint32_t command = 0x99; +uint64_t data = 0xE0E09966; +EOM + +unittest_success "${CODE_TO_RAW} --protocol SAMSUNG --code 0xE0E09966" "${OUT}" + +read -r -d '' OUT << xEOMx +Code type: 18 (KELVINATOR) +Code bits: 128 +Description: Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 1 (Low), Turbo: Off, Quiet: Off, XFan: On, Ion: Off, Light: Off, Swing(H): Off, Swing(V): Off + +uint16_t rawData[280] = {9010, 4504, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 19974, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 39950, 9010, 4504, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 19974, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 510, 680, 1530, 680, 1530, 680, 1530, 680, 1530, 680, 39950 }; // KELVINATOR +uint8_t state[16] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0, 0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xF0}; +xEOMx + +unittest_success "${CODE_TO_RAW} --protocol KELVINATOR --code 0x190B8050000000E0190B8070000010F0" "${OUT}" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/extract_lib_version.sh b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/extract_lib_version.sh new file mode 100755 index 000000000..8bea94334 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/extract_lib_version.sh @@ -0,0 +1,14 @@ +#!/bin/bash -e +# Copyright 2021 crankyoldgit +# Extract and constuct the string version of the IRremoteESP8266 Library Version +function getVerNum() +{ + echo $(egrep "^#define\s+_IRREMOTEESP8266_VERSION_$1\s+" \ + src/IRremoteESP8266.h | awk '{print $3;}') +} + +MAJOR=$(getVerNum "MAJOR") +MINOR=$(getVerNum "MINOR") +PATCH=$(getVerNum "PATCH") +LIB_VERSION="${MAJOR}.${MINOR}.${PATCH}" +echo $LIB_VERSION diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords index e050e4964..34def1332 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords @@ -30,7 +30,8 @@ cat << EndOfTextEndOfTextEndOfText EndOfTextEndOfTextEndOfText -CLASSES=$(egrep -h "^ *((enum|class) |} [a-zA-Z0-9_]+_t;$)" src/*.h | +CLASSES=$(egrep -h \ + "^ *((enum|class|struct) [a-zA-Z0-9_]+|} [a-zA-Z0-9_]+_t;$)" src/*.h | sed 's/^ *//;s/enum class//;s/\;$//' | cut -d' ' -f2 | sort -u | grep -v "^__") for i in ${CLASSES}; do @@ -45,7 +46,7 @@ cat << EndOfTextEndOfTextEndOfText EndOfTextEndOfTextEndOfText CTYPES="u?int(8|16|32|64)?(_t)?|void|bool|char|float|long|double|String|static" -OURTYPES="match_result_t|state_t|decode_type_t" +OURTYPES="match_result_t|stdAc::state_t|decode_type_t" METHODS=$(egrep -h "^[ ]{0,2}(${CTYPES}|${OURTYPES})\*? [^ ]*\(" src/*.cpp | sed 's/^ //' | cut -d' ' -f2 | sed 's/^\([^:]*::\| *\* *\)//' | cut -d'(' -f1 | sort -u | grep -v RAM_ATTR) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/scrape_supported_devices.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/scrape_supported_devices.py new file mode 100755 index 000000000..f40b3e959 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/scrape_supported_devices.py @@ -0,0 +1,426 @@ +#!/usr/bin/env python3 +"""Generate SupportedProtocols.md by scraping source code files""" +import pathlib +import argparse +import subprocess +from io import StringIO +import sys +import re +import time + +CODE_URL = "https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_" + +BRAND_MODEL = re.compile(r""" + Brand:\s{1,20} # "Brand:" label followd by between 1 and 20 whitespace chars. + \b(?P.{1,40})\b # The actual brand of the device, max 40 chars. + \s{0,10}, # Followed by at most 10 whitespace chars, then a comma. + \s{1,20} # The between 1 and 20 whitespace chars. + Model:\s{1,20} # "Model:" label followd by between 1 and 20 whitespace chars. + \b(?P.{1,80}) # The model info of the device, max 80 chars. + \s{0,5}$ # Followed by at most 5 whitespaces before the end of line. + """, re.VERBOSE) +ENUMS = re.compile(r"enum (\w{1,60}) {(.{1,5000}?)};", re.DOTALL) +ENUM_ENTRY = re.compile(r"^\s{1,80}(\w{1,80})", re.MULTILINE) +DECODED_PROTOCOLS = re.compile(r""" + .{0,80} # Ignore upto an 80 char line of whitespace/code etc. + # Now look for code that looks like we are assigning the Protocol type. + # There are two typical styles used: + (?:results->decode_type # The first style. + | # Or + typeguess) # The second style + \s{0,5}=\s{0,5} # The assignment operator and potential whitespace + (?:decode_type_t::)? # The protocol could have an optional type prefix. + (\w{1,40}); # Finally, the last word of code should be the Protocol. + """, re.VERBOSE) +AC_FN = re.compile(r"ir_(.{1,80})\.h") +AC_MODEL_ENUM_RE = re.compile(r"(.{1,40})_ac_remote_model_t") +IRSEND_FN_RE = re.compile(r"IRsend\.h") +ALL_FN = re.compile(r"ir_(.{1,80})\.(h|cpp)") + +EXCLUDED_PROTOCOLS = ["UNKNOWN", "UNUSED", "kLastDecodeType", "typeguess"] +EXCLUDED_ACS = ["Magiquest", "NEC"] + +def getgitcommittime(): + """Call git to get time of last commit + """ + try: + label = subprocess.check_output(\ + ["git", "show", "-s", "--format=%ct", "HEAD"]).strip() + return int(label) + except FileNotFoundError as err: + print("Git failed, which is ok, no git binary found?:", err) + return None + except subprocess.SubprocessError as err: + print("Git failed, which is ok, see output, maybe no git checkout?:", err) + return None + +def getmarkdownheader(): + """Get the generated header + """ + srctime = getgitcommittime() + # pylint: disable=C0209 + return """""".format( + time.strftime("%a %d %b %Y %H:%M:%S +0000", time.gmtime(srctime))) + # pylint: enable=C0209 + + + +def getallprotocols(): + """Return all protocls configured in IRremoteESP8266.h + """ + irremote = ARGS.directory / "IRremoteESP8266.h" + enums = getenums(irremote)["decode_type_t"] + if not enums: + errorexit("Error getting ENUMS from IRremoteESP8266.h") + return enums + + +def getdecodedprotocols(): + """All protocols that include decoding support""" + ret = set() + for path in ARGS.directory.iterdir(): + if path.suffix != ".cpp": + continue + matches = DECODED_PROTOCOLS.finditer(path.open(encoding="utf-8").read()) + for match in matches: + protocol = match.group(1) + if protocol not in EXCLUDED_PROTOCOLS: + ret.add(protocol) + return ret + + +def getallacs(): + """All supported A/C codes""" + ret = {} + for path in ARGS.directory.iterdir(): + match = AC_FN.match(path.name) + if match: + acprotocol = match.group(1) + rawmodels = getenums(path) + models = set() + for model in rawmodels: + model = model.upper() + model = model.replace(f"K{acprotocol.upper()}", "") + if model and model not in EXCLUDED_PROTOCOLS: + models.add(model) + if acprotocol in ret: + ret[acprotocol].update(models) + else: + ret[acprotocol] = models + # Parse IRsend.h's enums + match = IRSEND_FN_RE.match(path.name) + if match: + rawmodels = getenums(path) + for acprotocol, acmodels in rawmodels.items(): + models = set() + for model in acmodels: + model = model.upper() + model = model.replace(f"K{acprotocol.upper()}", "") + if model and model not in EXCLUDED_PROTOCOLS: + models.add(model) + if acprotocol in ret: + ret[acprotocol].update(models) + else: + ret[acprotocol] = models + return ret + +class FnSets(): + """Container for getalldevices""" + def __init__(self): + self.allcodes = {} + self.fnnomatch = set() + self.allhfileprotos = set() + self.fnhmatch = set() + self.fncppmatch = set() + + def add(self, supports, path): + """add the path to correct set based on supports""" + if path.suffix == ".h": + self.allhfileprotos.add(path.stem) + if supports: + if path.suffix == ".h": + self.fnhmatch.add(path.stem) + elif path.suffix == ".cpp": + self.fncppmatch.add(path.stem) + else: + self.fnnomatch.add(path.stem) + + def printwarnings(self): + """print warnings""" + # all protos with support in .cpp file, when there is a .h file + # meaning that the documentation should probably be moved to .h + # in the future, with doxygen, that might change + protosincppwithh = list(self.fncppmatch & self.allhfileprotos) + if protosincppwithh: + protosincppwithh.sort() + print("The following files has supports section in .cpp, expected in .h") + for path in protosincppwithh: + print(f"\t{path}") + + protosincppandh = list(self.fncppmatch & self.fnhmatch) + if protosincppandh: + protosincppandh.sort() + print("The following files has supports section in both .h and .cpp") + for path in protosincppandh: + print(f"\t{path}") + + nosupports = self.getnosupports() + if nosupports: + nosupports.sort() + print("The following files had no supports section:") + for path in nosupports: + print(f"\t{path}") + + return protosincppwithh or protosincppandh or nosupports + + def getnosupports(self): + """get protos without supports sections""" + return list(self.fnnomatch - self.fnhmatch - self.fncppmatch) + + +def getalldevices(): + """All devices and associated branding and model information (if available) + """ + sets = FnSets() + for path in ARGS.directory.iterdir(): + match = ALL_FN.match(path.name) + if not match: + continue + supports = extractsupports(path) + sets.add(supports, path) + protocol = match.group(1) + for brand, model in supports: + protocolbrand = (protocol, brand) + pbset = sets.allcodes.get(protocolbrand, []) + if model in pbset: + print(f"Model {model} is duplicated for {protocol}, {brand}") + sets.allcodes[protocolbrand] = pbset + [model] + + for fnprotocol in sets.getnosupports(): + sets.allcodes[(fnprotocol[3:], "Unknown")] = [] + return sets + + +def getenums(path): + """Returns the keys for the first enum type in path + """ + ret = {} + for enums in ENUMS.finditer(path.open(encoding="utf-8").read()): + if enums: + enum_name = AC_MODEL_ENUM_RE.search(enums.group(1)) + if enum_name: + enum_name = enum_name.group(1).capitalize() + else: + enum_name = enums.group(1) + ret[enum_name] = set() + for enum in ENUM_ENTRY.finditer(enums.group(2)): + enum = enum.group(1) + if enum in EXCLUDED_PROTOCOLS: + continue + ret[enum_name].add(enum) + return ret + + +ARGS = None + + +def initargs(): + """Init the command line arguments""" + global ARGS # pylint: disable=global-statement + parser = argparse.ArgumentParser() + parser.add_argument( + "-n", + "--noout", + help="generate no output data, combine with --alert to only check", + action="store_true", + ) + parser.add_argument( + "-s", + "--stdout", + help="output to stdout rather than SupportedProtocols.md", + action="store_true", + ) + parser.add_argument("-v", + "--verbose", + help="increase output verbosity", + action="store_true") + parser.add_argument( + "-a", + "--alert", + help="alert if a file does not have a supports section, " + "non zero exit code if issues where found", + action="store_true", + ) + parser.add_argument( + "directory", + nargs="?", + help="directory of the source git checkout", + default=None, + ) + ARGS = parser.parse_args() + if ARGS.directory is None: + src = pathlib.Path("../src") + if not src.is_dir(): + src = pathlib.Path("./src") + else: + src = pathlib.Path(ARGS.directory) / "src" + if not src.is_dir(): + errorexit(f"Directory not valid: {src!s}") + ARGS.directory = src + return ARGS + +def getmdfile(): + """Resolves SupportedProtocols.md path""" + foutpath = ARGS.directory / "../SupportedProtocols.md" + return foutpath.resolve() + +def errorexit(msg): + """Print an error and exit on critical error""" + sys.stderr.write(f"{msg}\n") + sys.exit(1) + +def extractsupports(path): + """Extract all of the Supports: sections and associated brands and models + """ + supports = [] + insupports = False + for line in path.open(encoding="utf-8"): + if not line.startswith("//"): + continue + line = line[2:].strip() + if line == "Supports:": + insupports = True + continue + if insupports: + match = BRAND_MODEL.match(line) + if match: + supports.append((match.group("brand"), match.group("model"))) + else: + insupports = False + continue + # search and inform about any legacy formated supports data + elif any(x in line for x in [ \ + "seems compatible with", + "be compatible with", + "it working with here"]): + print(f"\t{path.name} Legacy supports format found\n\t\t{line}") + return supports + + +def makeurl(txt, path): + """Make a Markup URL from given filename""" + return f"[{txt}]({CODE_URL + path})" + + +def outputprotocols(fout, protocols): + """For a given protocol set, sort and output the markdown""" + protocols = list(protocols) + protocols.sort() + for protocol in protocols: + fout.write(f"- {protocol}\n") + + +def generate(fout): + """Generate data to fout + return True on any issues (when alert is active)""" + decodedprotocols = getdecodedprotocols() + sendonly = getallprotocols() - decodedprotocols + allacs = getallacs() + + sets = getalldevices() + allcodes = sets.allcodes + allbrands = list(allcodes.keys()) + allbrands.sort() + + fout.write("\n# IR Protocols supported by this library\n\n") + fout.write( + "| Protocol | Brand | Model | A/C Model | Detailed A/C Support |\n") + fout.write("| --- | --- | --- | --- | --- |\n") + + for protocolbrand in allbrands: + protocol, brand = protocolbrand + codes = allcodes[protocolbrand] + codes.sort() + acmodels = [] + acsupport = "-" + if protocol in allacs: + acmodels = list(allacs[protocol]) + acmodels.sort() + brand = makeurl(brand, protocol + ".h") + if protocol not in EXCLUDED_ACS: + acsupport = "Yes" + # pylint: disable=C0209 + fout.write("| {} | **{}** | {} | {} | {} |\n".format( + makeurl(protocol, protocol + ".cpp"), + brand, + "
".join(codes).replace("|", "\\|"), + "
".join(acmodels), + acsupport, + )) + # pylint: enable=C0209 + + fout.write("\n\n## Send only protocols:\n\n") + outputprotocols(fout, sendonly) + + fout.write("\n\n## Send & decodable protocols:\n\n") + outputprotocols(fout, decodedprotocols) + + return ARGS.alert and sets.printwarnings() + +def generatenone(): + """No out write + return True on any issues""" + return generate(StringIO()) + +def generatestdout(): + """Standard out write + return True on any issues""" + fout = sys.stdout + fout.write(getmarkdownheader()) + return generate(fout) + +def generatefile(): + """File write, extra detection of changes in existing file + return True on any issues, but only if there is changes""" + # get file path + foutpath = getmdfile() + if ARGS.verbose: + print(f"Output path: {foutpath!s}") + # write data to temp memorystream + ftemp = StringIO() + ret = generate(ftemp) + # get old filedata, skipping header + with getmdfile().open("r", encoding="utf-8") as forg: + olddata = forg.readlines()[3:] + # get new data, skip first empty line + ftemp.seek(0) + newdata = ftemp.readlines()[1:] + # if new data is same as old we don't need to write anything + if newdata == olddata: + print("No changes, exit without write") + return False + # write output + with foutpath.open("w", encoding="utf-8") as fout: + fout.write(getmarkdownheader()) + fout.write(ftemp.getvalue()) + + return ret + +def main(): + """Default main function + return True on any issues""" + initargs() + if ARGS.verbose: + print(f"Looking for files in: {ARGS.directory.resolve()!s}") + if ARGS.noout: + return generatenone() + if ARGS.stdout: + return generatestdout() + # default file + return generatefile() + + +if __name__ == "__main__": + sys.exit(1 if main() else 0)