IRremoteESP8266 upgraded to v2.8.5 (#18610)

* IRremoteESP8266 upgraded to v2.8.5 (from v2.8.4)

* Fix ir panasonic esp8266 (#18013)

* revert part of #16179 for ESP8266

* Revert "revert part of #16179 for ESP8266"

This reverts commit b8e6126407.

* try to revert #16179 for esp8266

* Build: removed redundand USE_IR_REMOTE_FULL flag

Tasmota32-ir PIO had both FIRMWARE_IR and USE_IR_REMOTE_FULL defined.
The latter is redundand and yielded unnecessary build warns.
See: tasmota_configurations.h

---------

Co-authored-by: Mateusz Bronk <2566147+mbronk@users.noreply.github.com>
Co-authored-by: Barbudor <barbudor@barbudor.net>
This commit is contained in:
Mateusz Bronk 2023-05-08 19:04:25 +02:00 committed by GitHub
parent 6fe1bbd617
commit faff39ca11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 6840 additions and 575 deletions

View File

@ -7,9 +7,31 @@ on:
branches: [ master ] branches: [ master ]
jobs: jobs:
Build_Examples: Gen_Matrix:
outputs:
matrix: ${{ steps.files.outputs.matrix }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Generate Matrix of all examples
id: files
run: |
JSONI=$(find . -name platformio.ini -type f | sed 's,/platformio.ini$,,' | xargs -n 1 -I {} echo -e '"{}",')
# Remove last "," and add closing brackets
if [[ $JSONI == *, ]]; then
JSONI="${JSONI%?}"
fi
JSONI=${JSONI//$'\n'}
echo $JSONI
# Set output
echo "::set-output name=matrix::[${JSONI}]"
Build_Example:
needs: Gen_Matrix
runs-on: ubuntu-latest
strategy:
matrix:
project: ${{fromJson(needs.Gen_Matrix.outputs.matrix)}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -24,14 +46,29 @@ jobs:
uses: actions/cache@v2 uses: actions/cache@v2
with: with:
path: ~/.platformio path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} key: ${{ runner.os }}-${{ hashFiles('**/platformio.ini') }}
- name: Cache PlatformIO build
uses: actions/cache@v2
with:
path: .pio
key: pio-${{ runner.os }}-${{ matrix.project }}
restore-keys: |
pio-${{ runner.os }}-
pio-
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
- name: Install PlatformIO - name: Install PlatformIO
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install --upgrade platformio pip install --upgrade platformio
- name: Build all the examples - name: Build example
env: env:
PLATFORMIO_BUILD_CACHE_DIR: "../../.pio/buildcache" PLATFORMIO_BUILD_CACHE_DIR: "../../.pio/buildcache"
run: find . -name platformio.ini -type f | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir run: pio run --jobs 2 --project-dir ${{ matrix.project }}
Build_Examples:
needs: Build_Example
runs-on: ubuntu-latest
steps:
- name: done
run: echo ok

View File

@ -37,7 +37,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Check all the version numbers match. - name: Check all the version numbers match.
run: | run: |
LIB_VERSION=$(egrep "^#define\s+_IRREMOTEESP8266_VERSION_\s+" src/IRremoteESP8266.h | cut -d\" -f2) LIB_VERSION=$(tools/extract_lib_version.sh)
test ${LIB_VERSION} == "$(jq -r .version library.json)" test ${LIB_VERSION} == "$(jq -r .version library.json)"
grep -q "^version=${LIB_VERSION}$" library.properties grep -q "^version=${LIB_VERSION}$" library.properties
examples-have-platformio_ini: examples-have-platformio_ini:

View File

@ -3,21 +3,28 @@ name: Tests
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
Unit_Tests: Tools_Tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
MAKEFLAGS: "-j 2"
steps:
- uses: actions/checkout@v2
- name: Build tools unit tests
run: (cd tools; make all)
- name: Run tools unit tests
run: (cd tools; make run_tests)
Unit_Tests:
runs-on: ubuntu-latest
env:
MAKEFLAGS: "-j 2"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install the Google test suite - name: Install the Google test suite
env:
MAKEFLAGS: "-j 2"
run: (cd test; make install-googletest) run: (cd test; make install-googletest)
- name: Build and run the library unit tests. - name: Build base unit test
env: run: (cd test; make IRac_test)
MAKEFLAGS: "-j 2" - name: Build library unit tests
run: (cd test; make all)
- name: Run library unit tests
run: (cd test; make run) run: (cd test; make run)
- name: Build and run the tools unit tests.
env:
MAKEFLAGS: "-j 2"
run: (cd tools; make all; make run_tests)

View File

@ -0,0 +1,72 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
schedule:
- cron: '38 1 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@ -40,6 +40,7 @@ tools/*.o
tools/*.a tools/*.a
tools/gc_decode tools/gc_decode
tools/mode2_decode tools/mode2_decode
tools/code_to_raw
.pioenvs .pioenvs
.piolibdeps .piolibdeps
@ -51,3 +52,4 @@ tools/mode2_decode
# Mac extended attributes # Mac extended attributes
.DS_Store .DS_Store
/.vs

View File

@ -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 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. [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.4 Now Available ## v2.8.5 Now Available
Version 2.8.4 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. Version 2.8.5 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 #### 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. 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.

View File

@ -11,8 +11,8 @@
Diese Programmbibliothek ermöglicht das **Senden _und_ Empfangen** von Infrarotsignalen mit [ESP8266](https://github.com/esp8266/Arduino)- und 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. [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.4 jetzt verfügbar ## v2.8.5 jetzt verfügbar
Version 2.8.4 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen. Version 2.8.5 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 #### 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. 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.

View File

@ -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 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. [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.4 disponible ## v2.8.5 disponible
Version 2.8.4 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. Version 2.8.5 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 #### 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. 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.

View File

@ -0,0 +1,89 @@
![IRremoteESP8266 Library](./assets/images/banner.svg)
[![Build-Status](https://github.com/crankyoldgit/IRremoteESP8266/actions/workflows/Build.yml/badge.svg)](../../actions/workflows/Build.yml/badge.svg)
[![Code-Lint](https://github.com/crankyoldgit/IRremoteESP8266/actions/workflows/Lint.yml/badge.svg)](../../actions/workflows/Lint.yml)
[![Tests](https://github.com/crankyoldgit/IRremoteESP8266/actions/workflows/UnitTests.yml/badge.svg)](../../ctions/workflows/UnitTests.yml)
[![Dokumentation](https://github.com/crankyoldgit/IRremoteESP8266/actions/workflows/Documentation.yml/badge.svg)](../../actions/workflows/Documentation.yml)
[![arduino-library-badge](https://www.ardu-badge.com/badge/IRremoteESP8266.svg?)](https://www.ardu-badge.com/IRremoteESP8266)
[![Arduino-Bibliothek-Abzeichen](https://www.ardu-badge.com/badge/IRremoteESP8266.svg?)](https://www.ardu-badge.com/IRremoteESP8266)
[![Git-Lizenz](https://gitlicense.com/badge/crankyoldgit/IRremoteESP8266)](https://gitlicense.com/license/crankyoldgit/IRremoteESP8266)
Deze library maakt het mogelijk om Infraroodsignalen **te versturen en ontvangen** via het [Arduino framework](https://www.arduino.cc/) met veelgebruikte 940nm IR LEDs en IR ontvang modules. b.v. TSOP{17,22,24,36,38,44,48}* demodulatoren enz.
## v2.8.5 nu beschikbaar
Versie 2.8.5 van de bibliotheek is nu [beschikbaar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Bekijk de [Release Notes](ReleaseNotes.md) voor alle belangrijke veranderingen.
#### Upgraden vanaf pre-v2.0
Het gebruik van de bibliotheek is enigszins gewijzigd in v2.0. Je zult het gebruik moeten aanpassen om te kunnen werken met v2.0 en hoger. Je kunt meer lezen over de vereiste aanpassingen op onze [Upgraden naar v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) pagina.
#### Upgraden vanaf pre-v2.5
De bibliotheek defineert constanten nu niet meer als `#define`, maar gebruikt
[const](https://google.github.io/styleguide/cppguide.html#Constant_Names) met
de juiste naamgeving volgens de
[C++ style guide](https://google.github.io/styleguide/cppguide.html).
Dit kan ertoe leiden dat oude programma's niet compileren.
De meest extern gebruikte `#define`s zijn _gealiased_ voor beperkte
compatibiliteit voor projecten die de oude stijl gebruiken. In de toekomst zal alleen de
nieuwe `kConstantName` stijl worden ondersteund voor nieuwe protocoltoevoegingen.
In het onwaarschijnlijke geval dat het je code breekt, dan heb je misschien verwezen naar
iets wat je waarschijnlijk niet had moeten doen. Gelukkig is het redelijk simpel om de nieuwe naam
te bepalen vanaf de oude, b.v. `CONSTANT_NAME` naar `kConstantName`.
Gebruik gezond verstand of onderzoek de code van de bibliotheek als dit van toepassing is op jouw code.
## Ondersteunde Protocollen
De details van de ondersteunde protocollen en apparaten staan
[hier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/SupportedProtocols.md) vermeld.
## Probleemoplossing
Voordat je een probleem meldt of om hulp vraagt, graag eerst onze [Probleemoplossingsgids](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide) volgen.
## Veelgestelde Vragen
Enkele antwoorden op veel veelgestelde vragen en problemen staan op onze [F.A.Q. wiki pagina](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions).
## Bibliotheek API Documentatie
De bibliotheek gebruikt [Doxygen](https://www.doxygen.nl/index.html) om [automatisch documentatie](https://crankyoldgit.github.io/IRremoteESP8266/doxygen/html/) toe te voegen aan de [API](https://en.wikipedia.org/wiki/Application_programming_interface) van de [bibliotheek](https://crankyoldgit.github.io/IRremoteESP8266/doxygen/html/).
Je kunt de documentatie [hier](https://crankyoldgit.github.io/IRremoteESP8266/doxygen/html/) vinden.
## Installatie
##### Officiële versies via de Arduino IDE v1.8+ (Windows & Linux)
1. Klik op de _"Schets"_ -> _"Bibliotheek gebruiken"_ -> _"Bibliotheken beheren..."_ menuknoppen.
1. Vul `IRremoteESP8266` in bij _"Filter je zoekresultaten..."_ rechtsboven de pop-up.
1. Klik op het IRremoteESP8266 resultaat van de zoekopdracht.
1. Selecteer de versie die je wilt installeren en klik op _"Installeren"_.
##### Handmatige installatie voor Windows
1. Klik op de _"Clone or Download"_ knop, en kies dan _"[Download ZIP](https://github.com/crankyoldgit/IRremoteESP8266/archive->master.zip)"_.
1. Pak de inhoud van de gedownloade zip uit.
1. Hernoem de uitgepakte map naar _"IRremoteESP8266"_.
1. Verplaats de map naar de bibliotheken map. (voor Windows: `C:\Gebruikers\GEBRUIKERSNAAM\Documenten\Arduino\libraries\`)
1. Herstart de Arduino IDE.
1. Bekijk de voorbeelden.
##### Git gebruiken om de bibliotheken te installeren ( Linux )
```
cd ~/Arduino/libraries
git clone https://github.com/crankyoldgit/IRremoteESP8266.git
```
###### Om de bibliotheken te updaten naar de laatste versie
```
cd ~/Arduino/libraries/IRremoteESP8266 && git pull
```
## Bijdragen
Als je wilt [bijdragen](.github/CONTRIBUTING.md#how-can-i-contribute) aan dit project, hulp is altijd welkom bij:
- Het [melden](.github/CONTRIBUTING.md#reporting-bugs) van problemen en foutmeldingen
- Ideeën voor verbeteringen
- Verbeteringen van de documentatie
- [Het aanmaken van issues](.github/CONTRIBUTING.md#reporting-bugs) en [pull requests](.github/CONTRIBUTING.md#pull-requests)
- Het delen van deze bibliotheek
## Bijdragers
Bekijk alle bijdragers [hier](.github/Contributors.md)
## Bibliotheek Geschiedenis
Deze bibliotheek was oorspronkelijk gebaseerd op het werk van Ken Shirriff (https://github.com/shirriff/Arduino-IRremote/)
[Mark Szabo](https://github.com/crankyoldgit/IRremoteESP8266) heeft de IRsend class bijgewerkt om te werken op een ESP8266 en [Sebastien Warin](https://github.com/sebastienwarin/IRremoteESP8266) de ontvang & decodeer class (IRrecv).
Voor v2.0 is de bibliotheek bijna volledig herschreven met de mogelijkheden van de ESP8266 in het achterhoofd.

View File

@ -1,5 +1,41 @@
# Release Notes # Release Notes
## _v2.8.5 (20230508)_
**[Bug Fixes]**
- Fix a bug where we never detached the timer interrupt on ESP32s. (#1984 #1983)
- Missing argument in use of midea function (#1959 #1958)
- IRMQTTServer: Improve HA MQTT climate handling. (#1911)
- SEND_SANYO_AC88: Fix poor cut-n-paste error (#1905 #1897)
**[Features]**
- Add support for a 40bit variant of the standard Panasonic protocol (#1977 @1976)
- Initial support for York AC protocol (#1889)
- IRMQTTServer: SHT-3x Temperature Sensor Support (#1951)
- IRMQTTServer: HA multi output discovery (#1947)
- IRMQTTServer: extended with new A/C common fields (#1940)
- IRMQTTServer: Sync the on state to power from mode for HA (#1946)
- Experimental basic support for Carrier 84-bit protocol. (#1945 #1943)
- Add support the WowWee 11-Bit RoboRaptor-X protocol. (#1939 #1938)
- Added 'sensorTemperature' and 'iFeel' to IRac (common) (#1928)
- Added extra 'mid' option for Fan & SwingV to IRac (#1929)
- Added "commandType" to IRAc (#1921)
- Added support for Argo WREM-3 A/C remote protocol [part1] (#1920)
- Added Dutch (nl-NL) translation (#1907)
- ARGO: Improve code & add support for decoding 32bit sensor msgs. (#1906 #1859)
- Added support for Gorenje cooker hood IR protocol (#1888 #1887)
**[Misc]**
- Add Electrolux YKR-H/531E as a supported device (#1981 #1980)
- Update `XMP` status to Stable (#1944)
- upgrade to a later version of `googletest` (#1936)
- MITSUBISHI128: Added model to supported protocol (#1924)
- Added Dutch (nl-NL) README (#1908)
- Added GMock to UT Makefile (#1902)
- Update HA example config for HA 2022.6+ (#1901 #1900)
- Add a `d1_mini_noMDNS` build option to `IRMQTTServer`. (#1985)
## _v2.8.4 (20220918)_ ## _v2.8.4 (20220918)_
**[Bug Fixes]** **[Bug Fixes]**

View File

@ -1,6 +1,6 @@
<!--- WARNING: Do NOT edit this file directly. <!--- WARNING: Do NOT edit this file directly.
It is generated by './tools/scrape_supported_devices.py'. It is generated by './tools/scrape_supported_devices.py'.
Last generated: Thu 15 Sep 2022 12:54:42 +0000 ---> Last generated: Mon 08 May 2023 07:06:16 +0000 --->
# IR Protocols supported by this library # IR Protocols supported by this library
| Protocol | Brand | Model | A/C Model | Detailed A/C Support | | Protocol | Brand | Model | A/C Model | Detailed A/C Support |
@ -9,11 +9,11 @@
| [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<BR>RC04 remote<BR>RC08W remote | | 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<BR>RC04 remote<BR>RC08W remote | | Yes |
| [Aiwa](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Aiwa.cpp) | **Aiwa** | RC-T501 RCU | | - | | [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<BR>TAC-444 remote<BR>TAC-495 remote | | Yes | | [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<BR>TAC-444 remote<BR>TAC-495 remote | | Yes |
| [Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.cpp) | **[Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.h)** | Ulisse 13 DCI Mobile Split A/C | | Yes | | [Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.cpp) | **[Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.h)** | Ulisse 13 DCI Mobile Split A/C [WREM2 remote]<BR>Ulisse Eco Mobile Split A/C (Wifi) [WREM3 remote] | SAC_WREM2<BR>SAC_WREM3 | Yes |
| [Arris](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Arris.cpp) | **Arris** | 120A V1.0 A18 remote<BR>VIP1113M Set-top box | | - | | [Arris](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Arris.cpp) | **Arris** | 120A V1.0 A18 remote<BR>VIP1113M Set-top box | | - |
| [Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bosch.cpp) | **[Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bosch.h)** | CL3000i-Set 26 E A/C<BR>RG10A(G2S)BGEF remote | | Yes | | [Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bosch.cpp) | **[Bosch](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bosch.h)** | CL3000i-Set 26 E A/C<BR>RG10A(G2S)BGEF remote | | Yes |
| [Bose](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bose.cpp) | **Bose** | Bose TV Speaker | | - | | [Bose](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bose.cpp) | **Bose** | Bose TV Speaker | | - |
| [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 40GKX0E2006 remote (CARRIER_AC128) | | Yes | | [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 3021203 RR03-S-Remote (CARRIER_AC84)<BR>342WM100CT A/C (CARRIER_AC84)<BR>40GKX0E2006 remote (CARRIER_AC128) | | Yes |
| [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier/Surrey](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 42QG5A55970 remote<BR>53NGK009/012 Inverter<BR>619EGX0090E0 A/C<BR>619EGX0120E0 A/C<BR>619EGX0180E0 A/C<BR>619EGX0220E0 A/C | | Yes | | [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier/Surrey](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 42QG5A55970 remote<BR>53NGK009/012 Inverter<BR>619EGX0090E0 A/C<BR>619EGX0120E0 A/C<BR>619EGX0180E0 A/C<BR>619EGX0220E0 A/C | | Yes |
| [ClimaButler](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_ClimaButler.cpp) | **Clima-Butler** | AR-715 remote<BR>RCS-SD43UWI A/C | | - | | [ClimaButler](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_ClimaButler.cpp) | **Clima-Butler** | AR-715 remote<BR>RCS-SD43UWI A/C | | - |
| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | RC08B remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | RC08B remote | | Yes |
@ -35,6 +35,7 @@
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C<BR>YKR-T/011 remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C<BR>YKR-T/011 remote | | Yes |
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Centek](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SCT-65Q09 A/C<BR>YKR-P/002E remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Centek](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SCT-65Q09 A/C<BR>YKR-P/002E remote | | Yes |
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | Classic INV 17 / AXW12DCS A/C<BR>YKR-M/003E remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | Classic INV 17 / AXW12DCS A/C<BR>YKR-M/003E remote | | Yes |
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Electrolux](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | YKR-H/531E A/C | | Yes |
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Frigidaire](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | FGPC102AB1 A/C | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Frigidaire](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | FGPC102AB1 A/C | | Yes |
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Subtropic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SUB-07HN1_18Y A/C<BR>YKR-H/102E remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Subtropic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SUB-07HN1_18Y A/C<BR>YKR-H/102E remote | | Yes |
| [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Elite Screens** | CineTension2 / CineTension3 series<BR>Home2 / Home3 series<BR>Spectrum series<BR>VMAX Plus4 series<BR>VMAX2 / VMAX2 Plus series<BR>ZSP-IR-B / ZSP-IR-W remote | | - | | [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Elite Screens** | CineTension2 / CineTension3 series<BR>Home2 / Home3 series<BR>Spectrum series<BR>VMAX Plus4 series<BR>VMAX2 / VMAX2 Plus series<BR>ZSP-IR-B / ZSP-IR-W remote | | - |
@ -46,6 +47,7 @@
| [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **G.I. Cable** | XRC-200 remote | | - | | [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 | | - | | [GlobalCache](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Global Cache** | Control Tower IR DB | | - |
| [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes | | [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes |
| [Gorenje](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gorenje.cpp) | **Gorenje** | DKF 2600 MWT Cooker Hood | | - |
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Amana](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | PBC093G00CC A/C<BR>YX1FF remote | YAW1F<BR>YBOFB<BR>YX1FSF | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Amana](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | PBC093G00CC A/C<BR>YX1FF remote | YAW1F<BR>YBOFB<BR>YX1FSF | Yes |
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Cooper & Hunter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | CH-S09FTXG A/C<BR>YB1F2 remote | YAW1F<BR>YBOFB<BR>YX1FSF | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Cooper & Hunter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | CH-S09FTXG A/C<BR>YB1F2 remote | YAW1F<BR>YBOFB<BR>YX1FSF | Yes |
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F<BR>YBOFB<BR>YX1FSF | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F<BR>YBOFB<BR>YX1FSF | Yes |
@ -89,7 +91,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<BR>KKG9AC1 | Yes | | [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | VLU series A/C | KKG29AC1<BR>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<BR>Reykir 9000 A/C | KKG29AC1<BR>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<BR>Reykir 9000 A/C | KKG29AC1<BR>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)<BR>KM14A 0179213 remote<BR>MS-GK24VA A/C<BR>TV (MITSUBISHI) | | 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)<BR>KM14A 0179213 remote<BR>MS-GK24VA A/C<BR>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)<BR>KPOA remote (MITSUBISHI112)<BR>MLZ-RX5017AS A/C (MITSUBISHI_AC)<BR>MSH-A24WV A/C (MITSUBISHI112)<BR>MSZ-FHnnVE A/C (MITSUBISHI_AC)<BR>MSZ-GV2519 A/C (MITSUBISHI_AC)<BR>MSZ-SF25VE3 A/C (MITSUBISHI_AC)<BR>MSZ-ZW4017S A/C (MITSUBISHI_AC)<BR>MUH-A24WV A/C (MITSUBISHI112)<BR>PEAD-RP71JAA Ducted A/C (MITSUBISHI136)<BR>RH151 remote (MITSUBISHI_AC)<BR>RH151/M21ED6426 remote (MITSUBISHI_AC)<BR>SG153/M21EDF426 remote (MITSUBISHI_AC)<BR>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)<BR>KPOA remote (MITSUBISHI112)<BR>MLZ-RX5017AS A/C (MITSUBISHI_AC)<BR>MSH-A24WV A/C (MITSUBISHI112)<BR>MSZ-FHnnVE A/C (MITSUBISHI_AC)<BR>MSZ-GV2519 A/C (MITSUBISHI_AC)<BR>MSZ-SF25VE3 A/C (MITSUBISHI_AC)<BR>MSZ-ZW4017S A/C (MITSUBISHI_AC)<BR>MUH-A24WV A/C (MITSUBISHI112)<BR>PAR-FA32MA remote (MITSUBISHI136)<BR>PEAD-RP71JAA Ducted A/C (MITSUBISHI136)<BR>RH151 remote (MITSUBISHI_AC)<BR>RH151/M21ED6426 remote (MITSUBISHI_AC)<BR>SG153/M21EDF426 remote (MITSUBISHI_AC)<BR>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)<BR>RLA502A700B remote (152 bit)<BR>SRKxxZJ-S A/C (88 bit)<BR>SRKxxZM-S A/C (152 bit)<BR>SRKxxZMXA-S A/C (152 bit) | | 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)<BR>RLA502A700B remote (152 bit)<BR>SRKxxZJ-S A/C (88 bit)<BR>SRKxxZM-S A/C (152 bit)<BR>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 | | - | | [Multibrackets](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Multibrackets.cpp) | **Multibrackets** | Motorized Swing mount large - 4500 | | - |
| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Aloka](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SleepyLights LED Lamp | | - | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Aloka](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SleepyLights LED Lamp | | - |
@ -137,7 +139,9 @@
| [Voltas](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Voltas.cpp) | **[Voltas](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Voltas.h)** | 122LZF 4011252 Window A/C | 122LZF | Yes | | [Voltas](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Voltas.cpp) | **[Voltas](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Voltas.h)** | 122LZF 4011252 Window A/C | 122LZF | Yes |
| [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote<BR>DG11J1-3A remote<BR>DG11J1-91 remote<BR>SPIS409L A/C<BR>SPIS412L A/C<BR>SPIW409L A/C<BR>SPIW412L A/C<BR>SPIW418L A/C | DG11J13A<BR>DG11J191 | Yes | | [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote<BR>DG11J1-3A remote<BR>DG11J1-91 remote<BR>SPIS409L A/C<BR>SPIS412L A/C<BR>SPIW409L A/C<BR>SPIW412L A/C<BR>SPIW418L A/C | DG11J13A<BR>DG11J191 | Yes |
| [Whynter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whynter.cpp) | **Whynter** | ARC-110WD A/C | | - | | [Whynter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whynter.cpp) | **Whynter** | ARC-110WD A/C | | - |
| [Wowwee](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Wowwee.cpp) | **WowWee** | RoboRapter-X | | - |
| [Xmp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Xmp.cpp) | **Xfinity** | XR11 remote<BR>XR2 remote | | - | | [Xmp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Xmp.cpp) | **Xfinity** | XR11 remote<BR>XR2 remote | | - |
| [York](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_York.cpp) | **[York](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_York.h)** | GRYLH2A remote<BR>MHH07P17 A/C | | Yes |
| [Zepeal](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Zepeal.cpp) | **Zepeal** | DRT-A3311(BG) 5 button remote<BR>DRT-A3311(BG) floor fan | | - | | [Zepeal](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Zepeal.cpp) | **Zepeal** | DRT-A3311(BG) 5 button remote<BR>DRT-A3311(BG) floor fan | | - |
@ -164,6 +168,7 @@
- CARRIER_AC128 - CARRIER_AC128
- CARRIER_AC40 - CARRIER_AC40
- CARRIER_AC64 - CARRIER_AC64
- CARRIER_AC84
- CLIMABUTLER - CLIMABUTLER
- COOLIX - COOLIX
- COOLIX48 - COOLIX48
@ -189,6 +194,7 @@
- FUJITSU_AC - FUJITSU_AC
- GICABLE - GICABLE
- GOODWEATHER - GOODWEATHER
- GORENJE
- GREE - GREE
- HAIER_AC - HAIER_AC
- HAIER_AC160 - HAIER_AC160
@ -267,5 +273,7 @@
- VOLTAS - VOLTAS
- WHIRLPOOL_AC - WHIRLPOOL_AC
- WHYNTER - WHYNTER
- WOWWEE
- XMP - XMP
- YORK
- ZEPEAL - ZEPEAL

View File

@ -132,6 +132,8 @@ const uint32_t kMqttReconnectTime = 5000; // Delay(ms) between reconnect tries.
#define MQTT_CLIMATE "ac" // Sub-topic for the climate topics. #define MQTT_CLIMATE "ac" // Sub-topic for the climate topics.
#define MQTT_CLIMATE_CMND "cmnd" // Sub-topic for the climate command topics. #define MQTT_CLIMATE_CMND "cmnd" // Sub-topic for the climate command topics.
#define MQTT_CLIMATE_STAT "stat" // Sub-topic for the climate stat topics. #define MQTT_CLIMATE_STAT "stat" // Sub-topic for the climate stat topics.
// Sub-topic for the temperature/humidity sensor stat topics.
#define MQTT_SENSOR_STAT "sensor"
// Enable sending/receiving climate via JSON. `true` cost ~5k of program space. // Enable sending/receiving climate via JSON. `true` cost ~5k of program space.
#define MQTT_CLIMATE_JSON false #define MQTT_CLIMATE_JSON false
@ -221,6 +223,25 @@ const uint16_t kMinUnknownSize = 2 * 10;
// actual a/c unit. // actual a/c unit.
#define REPLAY_DECODED_AC_MESSAGE false #define REPLAY_DECODED_AC_MESSAGE false
// ------------------------ SHT-3x Support -------------------------------------
// To enable SHT-3x sensor support (such as the Lolin SHT30 Shield), connected
// to GPIOs 4 and 5 (D2 and D1), do the following:
// - uncomment the line in platformio.ini to enable the SHT-3x library
// - uncomment the following #define line
// #define SHT3X_SUPPORT true
// Default address for SHT-3x sensor.
#define SHT3X_I2C_ADDRESS 0x44
// Requires MQTT_DISCOVERY_ENABLE to be true as well.
// If set, will send HA MQTT Discovery messages for the SHT-3x sensor.
#define SHT3X_MQTT_DISCOVERY_ENABLE true
// I2C SDA pin for SHT-3x sensor (D2).
#define SHT3X_I2C_SDA 4
// I2C SCL pin for SHT-3x sensor (D1).
#define SHT3X_I2C_SCL 5
// Check frequency for SHT-3x sensor (in seconds).
#define SHT3X_CHECK_FREQ 60
// ------------------------ Advanced Usage Only -------------------------------- // ------------------------ Advanced Usage Only --------------------------------
// Reports the input voltage to the ESP chip. **NOT** the input voltage // Reports the input voltage to the ESP chip. **NOT** the input voltage
@ -238,6 +259,7 @@ const uint16_t kMinUnknownSize = 2 * 10;
#define KEY_POWER "power" #define KEY_POWER "power"
#define KEY_MODE "mode" #define KEY_MODE "mode"
#define KEY_TEMP "temp" #define KEY_TEMP "temp"
#define KEY_HUMIDITY "humidity"
#define KEY_FANSPEED "fanspeed" #define KEY_FANSPEED "fanspeed"
#define KEY_SWINGV "swingv" #define KEY_SWINGV "swingv"
#define KEY_SWINGH "swingh" #define KEY_SWINGH "swingh"
@ -253,6 +275,9 @@ const uint16_t kMinUnknownSize = 2 * 10;
#define KEY_JSON "json" #define KEY_JSON "json"
#define KEY_RESEND "resend" #define KEY_RESEND "resend"
#define KEY_VCC "vcc" #define KEY_VCC "vcc"
#define KEY_COMMAND "command"
#define KEY_SENSORTEMP "sensortemp"
#define KEY_IFEEL "ifeel"
// HTML arguments we will parse for IR code information. // HTML arguments we will parse for IR code information.
#define KEY_TYPE "type" // KEY_PROTOCOL is also checked too. #define KEY_TYPE "type" // KEY_PROTOCOL is also checked too.
@ -260,11 +285,17 @@ const uint16_t kMinUnknownSize = 2 * 10;
#define KEY_BITS "bits" #define KEY_BITS "bits"
#define KEY_REPEAT "repeats" #define KEY_REPEAT "repeats"
#define KEY_CHANNEL "channel" // Which IR TX channel to send on. #define KEY_CHANNEL "channel" // Which IR TX channel to send on.
#define KEY_SENSORTEMP_DISABLED "sensortemp_disabled" // For HTML form only,
// not sent via MQTT
// nor JSON
// GPIO html/config keys // GPIO html/config keys
#define KEY_TX_GPIO "tx" #define KEY_TX_GPIO "tx"
#define KEY_RX_GPIO "rx" #define KEY_RX_GPIO "rx"
// Miscellaneous constants
#define TOGGLE_JS_FN_NAME "ToggleInputBasedOnCheckbox"
// Text for Last Will & Testament status messages. // Text for Last Will & Testament status messages.
const char* const kLwtOnline = "Online"; const char* const kLwtOnline = "Online";
const char* const kLwtOffline = "Offline"; const char* const kLwtOffline = "Offline";
@ -290,7 +321,7 @@ const uint16_t kJsonAcStateMaxSize = 1024; // Bytes
// ----------------- End of User Configuration Section ------------------------- // ----------------- End of User Configuration Section -------------------------
// Constants // Constants
#define _MY_VERSION_ "v1.7.0" #define _MY_VERSION_ "v1.8.2"
const uint8_t kRebootTime = 15; // Seconds const uint8_t kRebootTime = 15; // Seconds
const uint8_t kQuickDisplayTime = 2; // Seconds const uint8_t kQuickDisplayTime = 2; // Seconds
@ -358,7 +389,8 @@ static const char kClimateTopics[] PROGMEM =
"(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|" "(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|"
KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|" KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|"
KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|" KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|"
KEY_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS "|" KEY_RESEND KEY_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS "|" KEY_RESEND "|" KEY_COMMAND "|"
"|" KEY_SENSORTEMP "|" KEY_IFEEL
#if MQTT_CLIMATE_JSON #if MQTT_CLIMATE_JSON
"|" KEY_JSON "|" KEY_JSON
#endif // MQTT_CLIMATE_JSON #endif // MQTT_CLIMATE_JSON
@ -367,6 +399,7 @@ static const char* const kMqttTopics[] = {
KEY_PROTOCOL, KEY_MODEL, KEY_POWER, KEY_MODE, KEY_TEMP, KEY_FANSPEED, KEY_PROTOCOL, KEY_MODEL, KEY_POWER, KEY_MODE, KEY_TEMP, KEY_FANSPEED,
KEY_SWINGV, KEY_SWINGH, KEY_QUIET, KEY_TURBO, KEY_LIGHT, KEY_BEEP, KEY_SWINGV, KEY_SWINGH, KEY_QUIET, KEY_TURBO, KEY_LIGHT, KEY_BEEP,
KEY_ECONO, KEY_SLEEP, KEY_FILTER, KEY_CLEAN, KEY_CELSIUS, KEY_RESEND, KEY_ECONO, KEY_SLEEP, KEY_FILTER, KEY_CLEAN, KEY_CELSIUS, KEY_RESEND,
KEY_COMMAND, KEY_SENSORTEMP, KEY_IFEEL
KEY_JSON}; // KEY_JSON needs to be the last one. KEY_JSON}; // KEY_JSON needs to be the last one.
@ -410,7 +443,8 @@ int8_t getDefaultTxGpio(void);
String genStatTopic(const uint16_t channel = 0); String genStatTopic(const uint16_t channel = 0);
String listOfTxGpios(void); String listOfTxGpios(void);
bool hasUnsafeHTMLChars(String input); bool hasUnsafeHTMLChars(String input);
String htmlHeader(const String title, const String h1_text = ""); String htmlHeader(const String title, const String h1_text = "",
const String headScriptsJS = "");
String htmlEnd(void); String htmlEnd(void);
String htmlButton(const String url, const String button, String htmlButton(const String url, const String button,
const String text = ""); const String text = "");
@ -418,9 +452,13 @@ String htmlMenu(void);
void handleRoot(void); void handleRoot(void);
String addJsReloadUrl(const String url, const uint16_t timeout_s, String addJsReloadUrl(const String url, const uint16_t timeout_s,
const bool notify); const bool notify);
String getJsToggleCheckbox(const String functionName = TOGGLE_JS_FN_NAME);
void handleExamples(void); void handleExamples(void);
String htmlOptionItem(const String value, const String text, bool selected); String htmlOptionItem(const String value, const String text, bool selected);
String htmlSelectBool(const String name, const bool def); String htmlSelectBool(const String name, const bool def);
String htmlDisableCheckbox(const String name, const String targetControlId,
const bool checked,
const String toggleJsFnName = TOGGLE_JS_FN_NAME);
String htmlSelectClimateProtocol(const String name, const decode_type_t def); String htmlSelectClimateProtocol(const String name, const decode_type_t def);
String htmlSelectAcStateProtocol(const String name, const decode_type_t def, String htmlSelectAcStateProtocol(const String name, const decode_type_t def,
const bool simple); const bool simple);
@ -449,6 +487,9 @@ bool parseStringAndSendPronto(IRsend *irsend, const String str,
#if SEND_RAW #if SEND_RAW
bool parseStringAndSendRaw(IRsend *irsend, const String str); bool parseStringAndSendRaw(IRsend *irsend, const String str);
#endif // SEND_RAW #endif // SEND_RAW
#if SHT3X_SUPPORT
void sendMQTTDiscoverySensor(const char *topic, String type);
#endif // SH3X_SUPPORT
void handleIr(void); void handleIr(void);
void handleNotFound(void); void handleNotFound(void);
void setup_wifi(void); void setup_wifi(void);

View File

@ -231,6 +231,49 @@
* *
* In HA's configuration.yaml, add: * In HA's configuration.yaml, add:
* *
* #### New format (Post Home Assistant 2022.6 release)
*
* mqtt:
* climate:
* - name: Living Room Aircon
* modes:
* - "off"
* - "auto"
* - "cool"
* - "heat"
* - "dry"
* - "fan_only"
* fan_modes:
* - "Auto"
* - "Min"
* - "Low"
* - "Medium"
* - "High"
* - "Max"
* swing_modes:
* - "Off"
* - "Auto"
* - "Highest"
* - "High"
* - "Middle"
* - "Low"
* - "Lowest"
* power_command_topic: "ir_server/ac/cmnd/power"
* mode_command_topic: "ir_server/ac/cmnd/mode"
* mode_state_topic: "ir_server/ac/stat/mode"
* temperature_command_topic: "ir_server/ac/cmnd/temp"
* temperature_state_topic: "ir_server/ac/stat/temp"
* fan_mode_command_topic: "ir_server/ac/cmnd/fanspeed"
* fan_mode_state_topic: "ir_server/ac/stat/fanspeed"
* swing_mode_command_topic: "ir_server/ac/cmnd/swingv"
* swing_mode_state_topic: "ir_server/ac/stat/swingv"
* min_temp: 16
* max_temp: 32
* temp_step: 1
* retain: false
*
* #### Old format (Pre Home Assistant 2022.6 release)
*
* climate: * climate:
* - platform: mqtt * - platform: mqtt
* name: Living Room Aircon * name: Living Room Aircon
@ -256,8 +299,7 @@
* - "Middle" * - "Middle"
* - "Low" * - "Low"
* - "Lowest" * - "Lowest"
* # `power_command_topic` is probably not needed for most HA configurations * power_command_topic: "ir_server/ac/cmnd/power"
* # power_command_topic: "ir_server/ac/cmnd/power"
* mode_command_topic: "ir_server/ac/cmnd/mode" * mode_command_topic: "ir_server/ac/cmnd/mode"
* mode_state_topic: "ir_server/ac/stat/mode" * mode_state_topic: "ir_server/ac/stat/mode"
* temperature_command_topic: "ir_server/ac/cmnd/temp" * temperature_command_topic: "ir_server/ac/cmnd/temp"
@ -377,6 +419,10 @@ using irutils::msToString;
ADC_MODE(ADC_VCC); ADC_MODE(ADC_VCC);
#endif // REPORT_VCC #endif // REPORT_VCC
#ifdef SHT3X_SUPPORT
#include <WEMOS_SHT3X.h>
#endif
// Globals // Globals
uint8_t _sanity = 0; uint8_t _sanity = 0;
#if defined(ESP8266) #if defined(ESP8266)
@ -453,9 +499,15 @@ String MqttClimateCmnd; // Sub-topic for the climate command topics.
#if MQTT_DISCOVERY_ENABLE #if MQTT_DISCOVERY_ENABLE
String MqttDiscovery; String MqttDiscovery;
String MqttUniqueId; String MqttUniqueId;
#if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
String MqttDiscoverySensor;
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
#endif // MQTT_DISCOVERY_ENABLE #endif // MQTT_DISCOVERY_ENABLE
String MqttHAName; String MqttHAName;
String MqttClientId; String MqttClientId;
#if SHT3X_SUPPORT
String MqttSensorStat;
#endif // SHT3X_SUPPORT
// Primative lock file for gating MQTT state broadcasts. // Primative lock file for gating MQTT state broadcasts.
bool lockMqttBroadcast = true; bool lockMqttBroadcast = true;
@ -495,6 +547,11 @@ bool isSerialGpioUsedByIr(void) {
return false; // Not in use as far as we can tell. return false; // Not in use as far as we can tell.
} }
#if SHT3X_SUPPORT
SHT3X TemperatureSensor(SHT3X_I2C_ADDRESS);
TimerMs statSensorReadTime = TimerMs();
#endif // SHT3X_SUPPORT
// Debug messages get sent to the serial port. // Debug messages get sent to the serial port.
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
@ -905,7 +962,7 @@ void handleExamples(void) {
#endif // EXAMPLES_ENABLE #endif // EXAMPLES_ENABLE
String htmlSelectBool(const String name, const bool def) { String htmlSelectBool(const String name, const bool def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (uint16_t i = 0; i < 2; i++) for (uint16_t i = 0; i < 2; i++)
html += htmlOptionItem(IRac::boolToString(i), IRac::boolToString(i), html += htmlOptionItem(IRac::boolToString(i), IRac::boolToString(i),
i == def); i == def);
@ -913,8 +970,20 @@ String htmlSelectBool(const String name, const bool def) {
return html; return html;
} }
String htmlDisableCheckbox(const String name, const String targetControlId,
const bool checked, const String toggleJsFnName) {
String html = String(F("<input type='checkbox' name='")) + name + F("' id='")
+ name + F("' onclick=\"") + toggleJsFnName + F("(this, '") +
targetControlId + F("')\"");
if (checked) {
html += F(" checked");
}
html += "/><label for='" + name + F("'>Disabled</label>");
return html;
}
String htmlSelectClimateProtocol(const String name, const decode_type_t def) { String htmlSelectClimateProtocol(const String name, const decode_type_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (uint8_t i = 1; i <= decode_type_t::kLastDecodeType; i++) { for (uint8_t i = 1; i <= decode_type_t::kLastDecodeType; i++) {
if (IRac::isProtocolSupported((decode_type_t)i)) { if (IRac::isProtocolSupported((decode_type_t)i)) {
html += htmlOptionItem(String(i), typeToString((decode_type_t)i), html += htmlOptionItem(String(i), typeToString((decode_type_t)i),
@ -926,7 +995,7 @@ String htmlSelectClimateProtocol(const String name, const decode_type_t def) {
} }
String htmlSelectModel(const String name, const int16_t def) { String htmlSelectModel(const String name, const int16_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (int16_t i = -1; i <= 6; i++) { for (int16_t i = -1; i <= 6; i++) {
String num = String(i); String num = String(i);
String text; String text;
@ -942,9 +1011,21 @@ String htmlSelectModel(const String name, const int16_t def) {
return html; return html;
} }
String htmlSelectCommandType(const String name, const stdAc::ac_command_t def) {
String html = String(F("<select name='")) + name + F("'>");
for (uint8_t i = 0;
i <= (int8_t)stdAc::ac_command_t::kLastAcCommandEnum;
i++) {
String mode = IRac::commandTypeToString((stdAc::ac_command_t)i);
html += htmlOptionItem(mode, mode, (stdAc::ac_command_t)i == def);
}
html += F("</select>");
return html;
}
String htmlSelectUint(const String name, const uint16_t max, String htmlSelectUint(const String name, const uint16_t max,
const uint16_t def) { const uint16_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (uint16_t i = 0; i < max; i++) { for (uint16_t i = 0; i < max; i++) {
String num = String(i); String num = String(i);
html += htmlOptionItem(num, num, i == def); html += htmlOptionItem(num, num, i == def);
@ -955,7 +1036,7 @@ String htmlSelectUint(const String name, const uint16_t max,
String htmlSelectGpio(const String name, const int16_t def, String htmlSelectGpio(const String name, const int16_t def,
const int8_t list[], const int16_t length) { const int8_t list[], const int16_t length) {
String html = F(": <select name='") + name + F("'>"); String html = String(F(": <select name='")) + name + F("'>");
for (int16_t i = 0; i < length; i++) { for (int16_t i = 0; i < length; i++) {
String num = String(list[i]); String num = String(list[i]);
html += htmlOptionItem(num, list[i] == kGpioUnused ? F("Unused") : num, html += htmlOptionItem(num, list[i] == kGpioUnused ? F("Unused") : num,
@ -967,7 +1048,7 @@ String htmlSelectGpio(const String name, const int16_t def,
} }
String htmlSelectMode(const String name, const stdAc::opmode_t def) { String htmlSelectMode(const String name, const stdAc::opmode_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (int8_t i = -1; i <= (int8_t)stdAc::opmode_t::kLastOpmodeEnum; i++) { for (int8_t i = -1; i <= (int8_t)stdAc::opmode_t::kLastOpmodeEnum; i++) {
String mode = IRac::opmodeToString((stdAc::opmode_t)i); String mode = IRac::opmodeToString((stdAc::opmode_t)i);
html += htmlOptionItem(mode, mode, (stdAc::opmode_t)i == def); html += htmlOptionItem(mode, mode, (stdAc::opmode_t)i == def);
@ -977,7 +1058,7 @@ String htmlSelectMode(const String name, const stdAc::opmode_t def) {
} }
String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) { String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (int8_t i = 0; i <= (int8_t)stdAc::fanspeed_t::kLastFanspeedEnum; i++) { for (int8_t i = 0; i <= (int8_t)stdAc::fanspeed_t::kLastFanspeedEnum; i++) {
String speed = IRac::fanspeedToString((stdAc::fanspeed_t)i); String speed = IRac::fanspeedToString((stdAc::fanspeed_t)i);
html += htmlOptionItem(speed, speed, (stdAc::fanspeed_t)i == def); html += htmlOptionItem(speed, speed, (stdAc::fanspeed_t)i == def);
@ -987,7 +1068,7 @@ String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
} }
String htmlSelectSwingv(const String name, const stdAc::swingv_t def) { String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (int8_t i = -1; i <= (int8_t)stdAc::swingv_t::kLastSwingvEnum; i++) { for (int8_t i = -1; i <= (int8_t)stdAc::swingv_t::kLastSwingvEnum; i++) {
String swing = IRac::swingvToString((stdAc::swingv_t)i); String swing = IRac::swingvToString((stdAc::swingv_t)i);
html += htmlOptionItem(swing, swing, (stdAc::swingv_t)i == def); html += htmlOptionItem(swing, swing, (stdAc::swingv_t)i == def);
@ -997,7 +1078,7 @@ String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
} }
String htmlSelectSwingh(const String name, const stdAc::swingh_t def) { String htmlSelectSwingh(const String name, const stdAc::swingh_t def) {
String html = F("<select name='") + name + F("'>"); String html = String(F("<select name='")) + name + F("'>");
for (int8_t i = -1; i <= (int8_t)stdAc::swingh_t::kLastSwinghEnum; i++) { for (int8_t i = -1; i <= (int8_t)stdAc::swingh_t::kLastSwinghEnum; i++) {
String swing = IRac::swinghToString((stdAc::swingh_t)i); String swing = IRac::swinghToString((stdAc::swingh_t)i);
html += htmlOptionItem(swing, swing, (stdAc::swingh_t)i == def); html += htmlOptionItem(swing, swing, (stdAc::swingh_t)i == def);
@ -1006,14 +1087,20 @@ String htmlSelectSwingh(const String name, const stdAc::swingh_t def) {
return html; return html;
} }
String htmlHeader(const String title, const String h1_text) { String htmlHeader(const String title, const String h1_text,
const String headScriptsJS) {
String html = F("<html><head><title>"); String html = F("<html><head><title>");
html += title; html += title;
html += F("</title><meta http-equiv=\"Content-Type\" " html += F("</title><meta http-equiv=\"Content-Type\" "
"content=\"text/html;charset=utf-8\">" "content=\"text/html;charset=utf-8\">"
"<meta name=\"viewport\" content=\"width=device-width," "<meta name=\"viewport\" content=\"width=device-width,"
"initial-scale=1.0,minimum-scale=1.0,maximum-scale=5.0\">" "initial-scale=1.0,minimum-scale=1.0,maximum-scale=5.0\">");
"</head><body><center><h1>"); if (headScriptsJS.length()) {
html += F("<script type=\"text/javascript\">\n");
html += headScriptsJS;
html += F("</script>\n");
}
html += F("</head><body><center><h1>");
if (h1_text.length()) if (h1_text.length())
html += h1_text; html += h1_text;
else else
@ -1036,15 +1123,26 @@ String htmlButton(const String url, const String button, const String text) {
return html; return html;
} }
String getJsToggleCheckbox(const String functionName) {
const String javascript =
String(F(" function ")) + functionName + F("(checkbox, targetInputId) {\n"
" var targetControl = document.getElementById(targetInputId);\n"
" targetControl.disabled = checkbox.checked;\n"
" if (!targetControl.disabled) { targetControl.focus(); }\n"
" }\n");
return javascript;
}
// Admin web page // Admin web page
void handleAirCon(void) { void handleAirCon(void) {
String html = htmlHeader(F("Air Conditioner Control")); String html = htmlHeader(F("Air Conditioner Control"), "",
getJsToggleCheckbox());
html += htmlMenu(); html += htmlMenu();
if (kNrOfIrTxGpios > 1) { if (kNrOfIrTxGpios > 1) {
html += F("<form method='POST' action='/aircon/set'" html += String(F("<form method='POST' action='/aircon/set'"
" enctype='multipart/form-data'>" " enctype='multipart/form-data'>"
"<table>" "<table>"
"<tr><td><b>Climate #</b></td><td>") + "<tr><td><b>Climate #</b></td><td>")) +
htmlSelectUint(KEY_CHANNEL, kNrOfIrTxGpios, chan) + htmlSelectUint(KEY_CHANNEL, kNrOfIrTxGpios, chan) +
F("<input type='submit' value='Change'>" F("<input type='submit' value='Change'>"
"</td></tr>" "</td></tr>"
@ -1053,11 +1151,12 @@ void handleAirCon(void) {
"<hr>"); "<hr>");
} }
if (climate[chan] != NULL) { if (climate[chan] != NULL) {
html += F("<h3>Current Settings</h3>" bool noSensorTemp = (climate[chan]->next.sensorTemperature == kNoTempValue);
html += String(F("<h3>Current Settings</h3>"
"<form method='POST' action='/aircon/set'" "<form method='POST' action='/aircon/set'"
" enctype='multipart/form-data'>" " enctype='multipart/form-data'>"
"<input type='hidden' name='" KEY_CHANNEL "' value='") + String(chan) + "<input type='hidden' name='" KEY_CHANNEL "' value='")) + String(chan)
F("'>") + + F("'>") +
F("<table style='width:33%'>" F("<table style='width:33%'>"
"<tr><td>" D_STR_PROTOCOL "</td><td>") + "<tr><td>" D_STR_PROTOCOL "</td><td>") +
htmlSelectClimateProtocol(KEY_PROTOCOL, htmlSelectClimateProtocol(KEY_PROTOCOL,
@ -1066,6 +1165,9 @@ void handleAirCon(void) {
"<tr><td>" D_STR_MODEL "</td><td>") + "<tr><td>" D_STR_MODEL "</td><td>") +
htmlSelectModel(KEY_MODEL, climate[chan]->next.model) + htmlSelectModel(KEY_MODEL, climate[chan]->next.model) +
F("</td></tr>" F("</td></tr>"
"<tr><td>" D_STR_COMMAND "</td><td>") +
htmlSelectCommandType(KEY_COMMAND, climate[chan]->next.command) +
F("</td></tr>"
"<tr><td>" D_STR_POWER "</td><td>") + "<tr><td>" D_STR_POWER "</td><td>") +
htmlSelectBool(KEY_POWER, climate[chan]->next.power) + htmlSelectBool(KEY_POWER, climate[chan]->next.power) +
F("</td></tr>" F("</td></tr>"
@ -1084,6 +1186,16 @@ void handleAirCon(void) {
(!climate[chan]->next.celsius ? " selected='selected'" : "") + (!climate[chan]->next.celsius ? " selected='selected'" : "") +
F(">F</option>" F(">F</option>"
"</select></td></tr>" "</select></td></tr>"
"<tr><td>" D_STR_SENSORTEMP "</td><td>"
"<input type='number' name='" KEY_SENSORTEMP "' "
"id='" KEY_SENSORTEMP "' min='16' max='90' step='0.5' value='") +
(noSensorTemp ? String(climate[chan]->next.degrees, 1) :
String(climate[chan]->next.sensorTemperature, 1)) +
F("'") +
(noSensorTemp ? " disabled" : "") + F(">") +
htmlDisableCheckbox(KEY_SENSORTEMP_DISABLED, KEY_SENSORTEMP,
noSensorTemp) +
F("</td></tr>"
"<tr><td>" D_STR_FAN "</td><td>") + "<tr><td>" D_STR_FAN "</td><td>") +
htmlSelectFanspeed(KEY_FANSPEED, climate[chan]->next.fanspeed) + htmlSelectFanspeed(KEY_FANSPEED, climate[chan]->next.fanspeed) +
F("</td></tr>" F("</td></tr>"
@ -1096,6 +1208,9 @@ void handleAirCon(void) {
"<tr><td>" D_STR_QUIET "</td><td>") + "<tr><td>" D_STR_QUIET "</td><td>") +
htmlSelectBool(KEY_QUIET, climate[chan]->next.quiet) + htmlSelectBool(KEY_QUIET, climate[chan]->next.quiet) +
F("</td></tr>" F("</td></tr>"
"<tr><td>" D_STR_IFEEL "</td><td>") +
htmlSelectBool(KEY_IFEEL, climate[chan]->next.iFeel) +
F("</td></tr>"
"<tr><td>" D_STR_TURBO "</td><td>") + "<tr><td>" D_STR_TURBO "</td><td>") +
htmlSelectBool(KEY_TURBO, climate[chan]->next.turbo) + htmlSelectBool(KEY_TURBO, climate[chan]->next.turbo) +
F("</td></tr>" F("</td></tr>"
@ -1190,7 +1305,13 @@ void handleAdmin(void) {
#if MQTT_DISCOVERY_ENABLE #if MQTT_DISCOVERY_ENABLE
html += htmlButton( html += htmlButton(
kUrlSendDiscovery, F("Send MQTT Discovery"), kUrlSendDiscovery, F("Send MQTT Discovery"),
F("Send a Climate MQTT discovery message to Home Assistant.<br><br>")); #if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
F("Send a Climate and Sensor MQTT"
#else
F("Send a Climate MQTT"
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
" discovery message to Home Assistant.<br><br>"));
#endif // MQTT_DISCOVERY_ENABLE #endif // MQTT_DISCOVERY_ENABLE
#if MQTT_CLEAR_ENABLE #if MQTT_CLEAR_ENABLE
html += htmlButton( html += htmlButton(
@ -1244,8 +1365,8 @@ void handleInfo(void) {
String html = htmlHeader(F("IR MQTT server info")); String html = htmlHeader(F("IR MQTT server info"));
html += htmlMenu(); html += htmlMenu();
html += html +=
F("<h3>General</h3>" String(F("<h3>General</h3>"
"<p>Hostname: ") + String(Hostname) + F("<br>" "<p>Hostname: ")) + String(Hostname) + F("<br>"
"IP address: ") + WiFi.localIP().toString() + F("<br>" "IP address: ") + WiFi.localIP().toString() + F("<br>"
"MAC address: ") + WiFi.macAddress() + F("<br>" "MAC address: ") + WiFi.macAddress() + F("<br>"
"Booted: ") + timeSince(1) + F("<br>") + "Booted: ") + timeSince(1) + F("<br>") +
@ -1392,6 +1513,10 @@ bool clearMqttSavedStates(const String topic_base) {
#if MQTT_DISCOVERY_ENABLE #if MQTT_DISCOVERY_ENABLE
// Clear the HA climate discovery message. // Clear the HA climate discovery message.
success &= mqtt_client.publish(MqttDiscovery.c_str(), "", true); success &= mqtt_client.publish(MqttDiscovery.c_str(), "", true);
#if SHT3X_SUPPORT && MQTT_DISCOVERY_ENABLE
// Clear the HA sensor discovery message.
success &= mqtt_client.publish(MqttDiscoverySensor.c_str(), "", true);
#endif // SHT3X_SUPPORT && MQTT_DISCOVERY_ENABLE
#endif // MQTT_DISCOVERY_ENABLE #endif // MQTT_DISCOVERY_ENABLE
for (size_t channel = 0; for (size_t channel = 0;
channel <= kNrOfIrTxGpios; channel <= kNrOfIrTxGpios;
@ -2106,13 +2231,20 @@ void init_vars(void) {
MqttClimateCmnd = MqttClimate + '/' + MQTT_CLIMATE_CMND + '/'; MqttClimateCmnd = MqttClimate + '/' + MQTT_CLIMATE_CMND + '/';
// Sub-topic for the climate stat topics. // Sub-topic for the climate stat topics.
#if MQTT_DISCOVERY_ENABLE #if MQTT_DISCOVERY_ENABLE
MqttDiscovery = "homeassistant/climate/" + String(Hostname) + "/config"; MqttDiscovery = "homeassistant/climate/" + String(Hostname);
#if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
MqttDiscoverySensor = "homeassistant/sensor/" + String(Hostname);
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
MqttUniqueId = WiFi.macAddress(); MqttUniqueId = WiFi.macAddress();
MqttUniqueId.replace(":", ""); MqttUniqueId.replace(":", "");
#endif // MQTT_DISCOVERY_ENABLE #endif // MQTT_DISCOVERY_ENABLE
MqttHAName = String(Hostname) + "_aircon"; MqttHAName = String(Hostname) + "_aircon";
// Create a unique MQTT client id. // Create a unique MQTT client id.
MqttClientId = String(Hostname) + String(kChipId, HEX); MqttClientId = String(Hostname) + String(kChipId, HEX);
#if SHT3X_SUPPORT
// Sub-topic for the climate stat topics.
MqttSensorStat = String(MqttPrefix) + '/' + MQTT_SENSOR_STAT + '/';
#endif // SHT3X_SUPPORT
#endif // MQTT_ENABLE #endif // MQTT_ENABLE
} }
@ -2418,6 +2550,9 @@ void handleSendMqttDiscovery(void) {
htmlMenu() + htmlMenu() +
F("<p>The Home Assistant MQTT Discovery message is being sent to topic: ") F("<p>The Home Assistant MQTT Discovery message is being sent to topic: ")
+ MqttDiscovery + + MqttDiscovery +
#if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
F(" and ") + MqttDiscoverySensor +
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
F(". It will show up in Home Assistant in a few seconds." F(". It will show up in Home Assistant in a few seconds."
"</p>" "</p>"
"<h3>Warning!</h3>" "<h3>Warning!</h3>"
@ -2425,7 +2560,15 @@ void handleSendMqttDiscovery(void) {
" is sent.</p>") + " is sent.</p>") +
addJsReloadUrl(kUrlRoot, kRebootTime, true) + addJsReloadUrl(kUrlRoot, kRebootTime, true) +
htmlEnd()); htmlEnd());
sendMQTTDiscovery(MqttDiscovery.c_str()); for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) {
String channel_id = "";
if (i > 0) channel_id = "_" + String(i);
sendMQTTDiscovery(MqttDiscovery.c_str(), channel_id);
}
#if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
sendMQTTDiscoverySensor(MqttDiscoverySensor.c_str(), KEY_TEMP);
sendMQTTDiscoverySensor(MqttDiscoverySensor.c_str(), KEY_HUMIDITY);
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
} }
#endif // MQTT_DISCOVERY_ENABLE #endif // MQTT_DISCOVERY_ENABLE
@ -2598,12 +2741,13 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
} }
#if MQTT_DISCOVERY_ENABLE #if MQTT_DISCOVERY_ENABLE
void sendMQTTDiscovery(const char *topic) { void sendMQTTDiscovery(const char *topic, String channel_id) {
String pub_topic = String(topic) + channel_id + F("/config");
if (mqtt_client.publish( if (mqtt_client.publish(
topic, String( pub_topic.c_str(), String(
F("{" F("{"
"\"~\":\"") + MqttClimate + F("\"," "\"~\":\"") + MqttClimate + channel_id + F("\","
"\"name\":\"") + MqttHAName + F("\"," "\"name\":\"") + MqttHAName + channel_id + F("\","
#if (!MQTT_CLIMATE_HA_MODE) #if (!MQTT_CLIMATE_HA_MODE)
// Typically we don't need or use the power command topic if we are using // Typically we don't need or use the power command topic if we are using
// our Home Assistant Climate compatiblity mode. It causes odd behaviour // our Home Assistant Climate compatiblity mode. It causes odd behaviour
@ -2629,9 +2773,12 @@ void sendMQTTDiscovery(const char *topic) {
"\"swing_modes\":[\"" D_STR_OFF "\",\"" D_STR_AUTO "\",\"" D_STR_HIGHEST "\"swing_modes\":[\"" D_STR_OFF "\",\"" D_STR_AUTO "\",\"" D_STR_HIGHEST
"\",\"" D_STR_HIGH "\",\"" D_STR_MIDDLE "\",\"" "\",\"" D_STR_HIGH "\",\"" D_STR_MIDDLE "\",\""
D_STR_LOW "\",\"" D_STR_LOWEST "\"]," D_STR_LOW "\",\"" D_STR_LOWEST "\"],"
"\"uniq_id\":\"") + MqttUniqueId + F("\"," #if SHT3X_SUPPORT
"\"curr_temp_t\":\"") + MqttSensorStat + F(KEY_TEMP "\","
#endif // SHT3X_SUPPORT
"\"uniq_id\":\"") + MqttUniqueId + channel_id + F("\","
"\"device\":{" "\"device\":{"
"\"identifiers\":[\"") + MqttUniqueId + F("\"]," "\"identifiers\":[\"") + MqttUniqueId + channel_id + F("\"],"
"\"connections\":[[\"mac\",\"") + WiFi.macAddress() + F("\"]]," "\"connections\":[[\"mac\",\"") + WiFi.macAddress() + F("\"]],"
"\"manufacturer\":\"IRremoteESP8266\"," "\"manufacturer\":\"IRremoteESP8266\","
"\"model\":\"IRMQTTServer\"," "\"model\":\"IRMQTTServer\","
@ -2647,6 +2794,47 @@ void sendMQTTDiscovery(const char *topic) {
mqttLog(PSTR("MQTT climate discovery FAILED to send.")); mqttLog(PSTR("MQTT climate discovery FAILED to send."));
} }
} }
#if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
// Send the MQTT Discovery data for the SHT3X sensor.
// type must be a String of either KEY_TEMP or KEY_HUMIDITY.
void sendMQTTDiscoverySensor(const char *topic, String type) {
String pub_topic = String(topic) + F("_") + type + F("/config");
String uom = "%";
String ha_class = type;
// XXX Update units of measure for temperature.
if (type == KEY_TEMP) {
uom = "°C";
ha_class = "temperature";
}
if (mqtt_client.publish(
pub_topic.c_str(), String(
F("{"
"\"name\":\"") + MqttHAName + "_" + type + F("\","
"\"stat_t\":\"") + MqttSensorStat + type + F("\","
"\"dev_cla\":\"") + ha_class + F("\","
"\"unit_of_meas\":\"") + uom + F("\","
"\"uniq_id\":\"") + MqttUniqueId + type + F("\","
"\"device\":{"
"\"identifiers\":[\"") + MqttUniqueId + type + F("\"],"
"\"connections\":[[\"mac\",\"") + WiFi.macAddress() + F("\"]],"
"\"manufacturer\":\"IRremoteESP8266\","
"\"model\":\"IRMQTTServer\","
"\"name\":\"") + Hostname + F("\","
"\"sw_version\":\"" _MY_VERSION_ "\""
"}"
"}")).c_str(), true)) {
mqttLog(PSTR("MQTT sensor discovery successful sent."));
hasDiscoveryBeenSent = true;
lastDiscovery.reset();
mqttSentCounter++;
} else {
mqttLog(PSTR("MQTT sensor discovery FAILED to send."));
}
}
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
#endif // MQTT_DISCOVERY_ENABLE #endif // MQTT_DISCOVERY_ENABLE
#endif // MQTT_ENABLE #endif // MQTT_ENABLE
@ -2678,8 +2866,8 @@ void loop(void) {
boot = false; boot = false;
} else { } else {
mqttLog(String( mqttLog(String(
F("IRMQTTServer just (re)connected to MQTT. " String(F("IRMQTTServer just (re)connected to MQTT. "
"Lost connection about ") "Lost connection about "))
+ timeSince(lastConnectedTime)).c_str()); + timeSince(lastConnectedTime)).c_str());
} }
lastConnectedTime = now; lastConnectedTime = now;
@ -2715,6 +2903,29 @@ void loop(void) {
} }
// Periodically send all of the climate state via MQTT. // Periodically send all of the climate state via MQTT.
doBroadcast(&lastBroadcast, kBroadcastPeriodMs, climate, false, false); doBroadcast(&lastBroadcast, kBroadcastPeriodMs, climate, false, false);
#if SHT3X_SUPPORT
// Check if it's time to read the SHT3x sensor.
if (statSensorReadTime.elapsed() > SHT3X_CHECK_FREQ * 1000) {
byte result = TemperatureSensor.get();
if (result == 0) {
// Success
float temp = TemperatureSensor.cTemp;
// XXX Convert units
float humidity = TemperatureSensor.humidity;
// Publish the temp and humidity to MQTT.
String mqttTempTopic = MqttSensorStat + KEY_TEMP;
String mqttHumidityTopic = MqttSensorStat + KEY_HUMIDITY;
mqtt_client.publish(mqttTempTopic.c_str(), String(temp).c_str());
mqtt_client.publish(mqttHumidityTopic.c_str(),
String(humidity).c_str());
} else {
// Error
mqttLog((String(F("SHT3x sensor read error: ")) +
String(result)).c_str());
}
statSensorReadTime.reset();
}
#endif // SHT3X_SUPPORT
} }
#endif // MQTT_ENABLE #endif // MQTT_ENABLE
#if IR_RX #if IR_RX
@ -2934,6 +3145,7 @@ void sendJsonState(const stdAc::state_t state, const String topic,
DynamicJsonDocument json(kJsonAcStateMaxSize); DynamicJsonDocument json(kJsonAcStateMaxSize);
json[KEY_PROTOCOL] = typeToString(state.protocol); json[KEY_PROTOCOL] = typeToString(state.protocol);
json[KEY_MODEL] = state.model; json[KEY_MODEL] = state.model;
json[KEY_COMMAND] = IRac::commandToString(state.command);
json[KEY_POWER] = IRac::boolToString(state.power); json[KEY_POWER] = IRac::boolToString(state.power);
json[KEY_MODE] = IRac::opmodeToString(state.mode, ha_mode); json[KEY_MODE] = IRac::opmodeToString(state.mode, ha_mode);
// Home Assistant wants mode to be off if power is also off & vice-versa. // Home Assistant wants mode to be off if power is also off & vice-versa.
@ -2943,10 +3155,12 @@ void sendJsonState(const stdAc::state_t state, const String topic,
} }
json[KEY_CELSIUS] = IRac::boolToString(state.celsius); json[KEY_CELSIUS] = IRac::boolToString(state.celsius);
json[KEY_TEMP] = state.degrees; json[KEY_TEMP] = state.degrees;
json[KEY_SENSORTEMP] = state.sensorTemperature;
json[KEY_FANSPEED] = IRac::fanspeedToString(state.fanspeed); json[KEY_FANSPEED] = IRac::fanspeedToString(state.fanspeed);
json[KEY_SWINGV] = IRac::swingvToString(state.swingv); json[KEY_SWINGV] = IRac::swingvToString(state.swingv);
json[KEY_SWINGH] = IRac::swinghToString(state.swingh); json[KEY_SWINGH] = IRac::swinghToString(state.swingh);
json[KEY_QUIET] = IRac::boolToString(state.quiet); json[KEY_QUIET] = IRac::boolToString(state.quiet);
json[KEY_IFEEL] = IRac::boolToString(state.iFeel);
json[KEY_TURBO] = IRac::boolToString(state.turbo); json[KEY_TURBO] = IRac::boolToString(state.turbo);
json[KEY_ECONO] = IRac::boolToString(state.econo); json[KEY_ECONO] = IRac::boolToString(state.econo);
json[KEY_LIGHT] = IRac::boolToString(state.light); json[KEY_LIGHT] = IRac::boolToString(state.light);
@ -2984,6 +3198,10 @@ stdAc::state_t jsonToState(const stdAc::state_t current, const char *str) {
result.model = IRac::strToModel(json[KEY_MODEL].as<char*>()); result.model = IRac::strToModel(json[KEY_MODEL].as<char*>());
else if (validJsonInt(json, KEY_MODEL)) else if (validJsonInt(json, KEY_MODEL))
result.model = json[KEY_MODEL]; result.model = json[KEY_MODEL];
if (validJsonStr(json, KEY_COMMAND))
result.command = IRac::strToCommand(json[KEY_COMMAND].as<char*>());
else if (validJsonInt(json, KEY_COMMAND))
result.command = json[KEY_COMMAND];
if (validJsonStr(json, KEY_MODE)) if (validJsonStr(json, KEY_MODE))
result.mode = IRac::strToOpmode(json[KEY_MODE]); result.mode = IRac::strToOpmode(json[KEY_MODE]);
if (validJsonStr(json, KEY_FANSPEED)) if (validJsonStr(json, KEY_FANSPEED))
@ -2994,10 +3212,14 @@ stdAc::state_t jsonToState(const stdAc::state_t current, const char *str) {
result.swingh = IRac::strToSwingH(json[KEY_SWINGH]); result.swingh = IRac::strToSwingH(json[KEY_SWINGH]);
if (json.containsKey(KEY_TEMP)) if (json.containsKey(KEY_TEMP))
result.degrees = json[KEY_TEMP]; result.degrees = json[KEY_TEMP];
if (json.containsKey(KEY_SENSORTEMP))
result.sensorTemperature = json[KEY_SENSORTEMP];
if (validJsonInt(json, KEY_SLEEP)) if (validJsonInt(json, KEY_SLEEP))
result.sleep = json[KEY_SLEEP]; result.sleep = json[KEY_SLEEP];
if (validJsonStr(json, KEY_POWER)) if (validJsonStr(json, KEY_POWER))
result.power = IRac::strToBool(json[KEY_POWER]); result.power = IRac::strToBool(json[KEY_POWER]);
if (validJsonStr(json, KEY_IFEEL))
result.iFeel = IRac::strToBool(json[KEY_IFEEL]);
if (validJsonStr(json, KEY_QUIET)) if (validJsonStr(json, KEY_QUIET))
result.quiet = IRac::strToBool(json[KEY_QUIET]); result.quiet = IRac::strToBool(json[KEY_QUIET]);
if (validJsonStr(json, KEY_TURBO)) if (validJsonStr(json, KEY_TURBO))
@ -3029,6 +3251,8 @@ void updateClimate(stdAc::state_t *state, const String str,
state->protocol = strToDecodeType(payload.c_str()); state->protocol = strToDecodeType(payload.c_str());
} else if (str.equals(prefix + F(KEY_MODEL))) { } else if (str.equals(prefix + F(KEY_MODEL))) {
state->model = IRac::strToModel(payload.c_str()); state->model = IRac::strToModel(payload.c_str());
} else if (str.equals(prefix + F(KEY_COMMAND))) {
state->command = IRac::strToCommandType(payload.c_str());
} else if (str.equals(prefix + F(KEY_POWER))) { } else if (str.equals(prefix + F(KEY_POWER))) {
state->power = IRac::strToBool(payload.c_str()); state->power = IRac::strToBool(payload.c_str());
#if MQTT_CLIMATE_HA_MODE #if MQTT_CLIMATE_HA_MODE
@ -3039,16 +3263,32 @@ void updateClimate(stdAc::state_t *state, const String str,
state->mode = IRac::strToOpmode(payload.c_str()); state->mode = IRac::strToOpmode(payload.c_str());
#if MQTT_CLIMATE_HA_MODE #if MQTT_CLIMATE_HA_MODE
// When in Home Assistant mode, a Mode of Off, means turn the Power off too. // When in Home Assistant mode, a Mode of Off, means turn the Power off too.
if (state->mode == stdAc::opmode_t::kOff) state->power = false; if (state->mode == stdAc::opmode_t::kOff) {
state->power = false;
} else {
state->power = true;
}
#endif // MQTT_CLIMATE_HA_MODE #endif // MQTT_CLIMATE_HA_MODE
} else if (str.equals(prefix + F(KEY_TEMP))) { } else if (str.equals(prefix + F(KEY_TEMP))) {
state->degrees = payload.toFloat(); state->degrees = payload.toFloat();
} else if (str.equals(prefix + F(KEY_SENSORTEMP))) {
state->sensorTemperature = payload.toFloat();
} else if (str.equals(prefix + F(KEY_SENSORTEMP_DISABLED))) {
// The "disabled" html form field appears after the actual sensorTemp field
// and the spec guarantees the form POST field order preserves body order
// => this will always execute after KEY_SENSORTEMP has been parsed already
if (IRac::strToBool(payload.c_str())) {
// UI control was disabled, ignore the value
state->sensorTemperature = kNoTempValue;
}
} else if (str.equals(prefix + F(KEY_FANSPEED))) { } else if (str.equals(prefix + F(KEY_FANSPEED))) {
state->fanspeed = IRac::strToFanspeed(payload.c_str()); state->fanspeed = IRac::strToFanspeed(payload.c_str());
} else if (str.equals(prefix + F(KEY_SWINGV))) { } else if (str.equals(prefix + F(KEY_SWINGV))) {
state->swingv = IRac::strToSwingV(payload.c_str()); state->swingv = IRac::strToSwingV(payload.c_str());
} else if (str.equals(prefix + F(KEY_SWINGH))) { } else if (str.equals(prefix + F(KEY_SWINGH))) {
state->swingh = IRac::strToSwingH(payload.c_str()); state->swingh = IRac::strToSwingH(payload.c_str());
} else if (str.equals(prefix + F(KEY_IFEEL))) {
state->iFeel = IRac::strToBool(payload.c_str());
} else if (str.equals(prefix + F(KEY_QUIET))) { } else if (str.equals(prefix + F(KEY_QUIET))) {
state->quiet = IRac::strToBool(payload.c_str()); state->quiet = IRac::strToBool(payload.c_str());
} else if (str.equals(prefix + F(KEY_TURBO))) { } else if (str.equals(prefix + F(KEY_TURBO))) {
@ -3086,14 +3326,16 @@ bool sendClimate(const String topic_prefix, const bool retain,
diff = true; diff = true;
success &= sendInt(topic_prefix + KEY_MODEL, next.model, retain); success &= sendInt(topic_prefix + KEY_MODEL, next.model, retain);
} }
if (prev.command != next.command || forceMQTT) {
String command_str = IRac::commandTypeToString(next.command);
diff = true;
success &= sendString(topic_prefix + KEY_COMMAND, command_str, retain);
}
#ifdef MQTT_CLIMATE_HA_MODE #ifdef MQTT_CLIMATE_HA_MODE
String mode_str = IRac::opmodeToString(next.mode, MQTT_CLIMATE_HA_MODE); String mode_str = IRac::opmodeToString(next.mode, MQTT_CLIMATE_HA_MODE);
#else // MQTT_CLIMATE_HA_MODE #else // MQTT_CLIMATE_HA_MODE
String mode_str = IRac::opmodeToString(next.mode); String mode_str = IRac::opmodeToString(next.mode);
#endif // MQTT_CLIMATE_HA_MODE #endif // MQTT_CLIMATE_HA_MODE
// I don't know why, but the modes need to be lower case to work with
// Home Assistant & Google Home.
mode_str.toLowerCase();
#if MQTT_CLIMATE_HA_MODE #if MQTT_CLIMATE_HA_MODE
// Home Assistant want's these two bound together. // Home Assistant want's these two bound together.
if (prev.power != next.power || prev.mode != next.mode || forceMQTT) { if (prev.power != next.power || prev.mode != next.mode || forceMQTT) {
@ -3107,6 +3349,10 @@ bool sendClimate(const String topic_prefix, const bool retain,
} }
if (prev.mode != next.mode || forceMQTT) { if (prev.mode != next.mode || forceMQTT) {
#endif // MQTT_CLIMATE_HA_MODE #endif // MQTT_CLIMATE_HA_MODE
// I don't know why, but the modes need to be lower case to work with
// Home Assistant & Google Home.
mode_str.toLowerCase();
success &= sendString(topic_prefix + KEY_MODE, mode_str, retain); success &= sendString(topic_prefix + KEY_MODE, mode_str, retain);
diff = true; diff = true;
} }
@ -3118,6 +3364,11 @@ bool sendClimate(const String topic_prefix, const bool retain,
diff = true; diff = true;
success &= sendBool(topic_prefix + KEY_CELSIUS, next.celsius, retain); success &= sendBool(topic_prefix + KEY_CELSIUS, next.celsius, retain);
} }
if (prev.sensorTemperature != next.sensorTemperature || forceMQTT) {
diff = true;
success &= sendFloat(topic_prefix + KEY_SENSORTEMP,
next.sensorTemperature, retain);
}
if (prev.fanspeed != next.fanspeed || forceMQTT) { if (prev.fanspeed != next.fanspeed || forceMQTT) {
diff = true; diff = true;
success &= sendString(topic_prefix + KEY_FANSPEED, success &= sendString(topic_prefix + KEY_FANSPEED,
@ -3133,6 +3384,10 @@ bool sendClimate(const String topic_prefix, const bool retain,
success &= sendString(topic_prefix + KEY_SWINGH, success &= sendString(topic_prefix + KEY_SWINGH,
IRac::swinghToString(next.swingh), retain); IRac::swinghToString(next.swingh), retain);
} }
if (prev.iFeel != next.iFeel || forceMQTT) {
diff = true;
success &= sendBool(topic_prefix + KEY_IFEEL, next.iFeel, retain);
}
if (prev.quiet != next.quiet || forceMQTT) { if (prev.quiet != next.quiet || forceMQTT) {
diff = true; diff = true;
success &= sendBool(topic_prefix + KEY_QUIET, next.quiet, retain); success &= sendBool(topic_prefix + KEY_QUIET, next.quiet, retain);

View File

@ -15,6 +15,8 @@ lib_deps_builtin =
lib_deps_external = lib_deps_external =
PubSubClient@>=2.8.0 PubSubClient@>=2.8.0
ArduinoJson@>=6.0 ArduinoJson@>=6.0
# Uncomment the following to enable SHT-3x support.
# https://github.com/wemos/WEMOS_SHT3x_Arduino_Library.git
[common_esp8266] [common_esp8266]
lib_deps_external = lib_deps_external =
@ -36,6 +38,14 @@ lib_deps = ${common_esp8266.lib_deps_external}
board = d1_mini board = d1_mini
lib_deps = ${common_esp8266.lib_deps_external} lib_deps = ${common_esp8266.lib_deps_external}
[env:d1_mini_noMDNS]
board = d1_mini
build_flags =
${env.build_flags}
-DMQTT_SERVER_AUTODETECT_ENABLE=false
-DMDNS_ENABLE=false
lib_deps = ${common_esp8266.lib_deps_external}
[env:d1_mini_no_mqtt] [env:d1_mini_no_mqtt]
board = d1_mini board = d1_mini
build_flags = build_flags =

View File

@ -20,11 +20,14 @@
# Datatypes & Classes (KEYWORD1) # Datatypes & Classes (KEYWORD1)
####################################### #######################################
Config KEYWORD1
CoronaSection KEYWORD1 CoronaSection KEYWORD1
IRAirtonAc KEYWORD1 IRAirtonAc KEYWORD1
IRAirwellAc KEYWORD1 IRAirwellAc KEYWORD1
IRAmcorAc KEYWORD1 IRAmcorAc KEYWORD1
IRArgoAC KEYWORD1 IRArgoAC KEYWORD1
IRArgoACBase KEYWORD1
IRArgoAC_WREM3 KEYWORD1
IRBosch144AC KEYWORD1 IRBosch144AC KEYWORD1
IRCarrierAc64 KEYWORD1 IRCarrierAc64 KEYWORD1
IRCoolixAC KEYWORD1 IRCoolixAC KEYWORD1
@ -83,11 +86,21 @@ IRTrumaAc KEYWORD1
IRVestelAc KEYWORD1 IRVestelAc KEYWORD1
IRVoltas KEYWORD1 IRVoltas KEYWORD1
IRWhirlpoolAc KEYWORD1 IRWhirlpoolAc KEYWORD1
IRYorkAc KEYWORD1
IRac KEYWORD1 IRac KEYWORD1
IRrecv KEYWORD1 IRrecv KEYWORD1
IRsend KEYWORD1 IRsend KEYWORD1
IRtimer KEYWORD1 IRtimer KEYWORD1
Timer KEYWORD1
TimerMs KEYWORD1 TimerMs KEYWORD1
ac_command_t KEYWORD1
argoFan_t KEYWORD1
argoFlap_t KEYWORD1
argoIrMessageType_t KEYWORD1
argoMode_t KEYWORD1
argoTimerType_t KEYWORD1
argoWeekday KEYWORD1
argo_ac_remote_model_t KEYWORD1
decode_results KEYWORD1 decode_results KEYWORD1
decode_type_t KEYWORD1 decode_type_t KEYWORD1
fanspeed_t KEYWORD1 fanspeed_t KEYWORD1
@ -116,6 +129,7 @@ whirlpool_ac_remote_model_t KEYWORD1
_backupState KEYWORD2 _backupState KEYWORD2
_cancelOffTimer KEYWORD2 _cancelOffTimer KEYWORD2
_cancelOnTimer KEYWORD2 _cancelOnTimer KEYWORD2
_checksum KEYWORD2
_delayMicroseconds KEYWORD2 _delayMicroseconds KEYWORD2
_getEconoToggle KEYWORD2 _getEconoToggle KEYWORD2
_getOffTimer KEYWORD2 _getOffTimer KEYWORD2
@ -137,6 +151,7 @@ _setSleepTimer KEYWORD2
_setTemp KEYWORD2 _setTemp KEYWORD2
_setTime KEYWORD2 _setTime KEYWORD2
_setTimer KEYWORD2 _setTimer KEYWORD2
_stateReset KEYWORD2
_toString KEYWORD2 _toString KEYWORD2
_validTolerance KEYWORD2 _validTolerance KEYWORD2
add KEYWORD2 add KEYWORD2
@ -152,12 +167,17 @@ addSwingHToString KEYWORD2
addSwingVToString KEYWORD2 addSwingVToString KEYWORD2
addTempFloatToString KEYWORD2 addTempFloatToString KEYWORD2
addTempToString KEYWORD2 addTempToString KEYWORD2
addTimerModeToString KEYWORD2
addToggleToString KEYWORD2 addToggleToString KEYWORD2
adjustRepeat KEYWORD2 adjustRepeat KEYWORD2
airton KEYWORD2 airton KEYWORD2
airwell KEYWORD2 airwell KEYWORD2
amcor KEYWORD2 amcor KEYWORD2
argo KEYWORD2 argo KEYWORD2
argoWrem3_ACCommand KEYWORD2
argoWrem3_ConfigSet KEYWORD2
argoWrem3_SetTimer KEYWORD2
argoWrem3_iFeelReport KEYWORD2
bcdToUint8 KEYWORD2 bcdToUint8 KEYWORD2
begin KEYWORD2 begin KEYWORD2
boolToString KEYWORD2 boolToString KEYWORD2
@ -178,6 +198,7 @@ cancelOnTimer KEYWORD2
cancelTimers KEYWORD2 cancelTimers KEYWORD2
carrier64 KEYWORD2 carrier64 KEYWORD2
celsiusToFahrenheit KEYWORD2 celsiusToFahrenheit KEYWORD2
channelToString KEYWORD2
checkInvertedBytePairs KEYWORD2 checkInvertedBytePairs KEYWORD2
checkSum KEYWORD2 checkSum KEYWORD2
checkZjsSig KEYWORD2 checkZjsSig KEYWORD2
@ -189,6 +210,7 @@ clearPowerSpecial KEYWORD2
clearSensorTemp KEYWORD2 clearSensorTemp KEYWORD2
clearSleepTimerFlag KEYWORD2 clearSleepTimerFlag KEYWORD2
cmpStates KEYWORD2 cmpStates KEYWORD2
commandTypeToString KEYWORD2
compare KEYWORD2 compare KEYWORD2
convertFan KEYWORD2 convertFan KEYWORD2
convertMode KEYWORD2 convertMode KEYWORD2
@ -209,12 +231,15 @@ daikin176 KEYWORD2
daikin2 KEYWORD2 daikin2 KEYWORD2
daikin216 KEYWORD2 daikin216 KEYWORD2
daikin64 KEYWORD2 daikin64 KEYWORD2
dayToString KEYWORD2
daysBitmaskToString KEYWORD2
decode KEYWORD2 decode KEYWORD2
decodeAirton KEYWORD2 decodeAirton KEYWORD2
decodeAirwell KEYWORD2 decodeAirwell KEYWORD2
decodeAiwaRCT501 KEYWORD2 decodeAiwaRCT501 KEYWORD2
decodeAmcor KEYWORD2 decodeAmcor KEYWORD2
decodeArgo KEYWORD2 decodeArgo KEYWORD2
decodeArgoWREM3 KEYWORD2
decodeArris KEYWORD2 decodeArris KEYWORD2
decodeBosch144 KEYWORD2 decodeBosch144 KEYWORD2
decodeBose KEYWORD2 decodeBose KEYWORD2
@ -223,6 +248,7 @@ decodeCarrierAC KEYWORD2
decodeCarrierAC128 KEYWORD2 decodeCarrierAC128 KEYWORD2
decodeCarrierAC40 KEYWORD2 decodeCarrierAC40 KEYWORD2
decodeCarrierAC64 KEYWORD2 decodeCarrierAC64 KEYWORD2
decodeCarrierAC84 KEYWORD2
decodeClimaButler KEYWORD2 decodeClimaButler KEYWORD2
decodeCoolix48 KEYWORD2 decodeCoolix48 KEYWORD2
decodeCoronaAc KEYWORD2 decodeCoronaAc KEYWORD2
@ -247,6 +273,7 @@ decodeEpson KEYWORD2
decodeFujitsuAC KEYWORD2 decodeFujitsuAC KEYWORD2
decodeGICable KEYWORD2 decodeGICable KEYWORD2
decodeGoodweather KEYWORD2 decodeGoodweather KEYWORD2
decodeGorenje KEYWORD2
decodeGree KEYWORD2 decodeGree KEYWORD2
decodeHaierAC KEYWORD2 decodeHaierAC KEYWORD2
decodeHaierAC160 KEYWORD2 decodeHaierAC160 KEYWORD2
@ -318,7 +345,9 @@ decodeVestelAc KEYWORD2
decodeVoltas KEYWORD2 decodeVoltas KEYWORD2
decodeWhirlpoolAC KEYWORD2 decodeWhirlpoolAC KEYWORD2
decodeWhynter KEYWORD2 decodeWhynter KEYWORD2
decodeWowwee KEYWORD2
decodeXmp KEYWORD2 decodeXmp KEYWORD2
decodeYork KEYWORD2
decodeZepeal KEYWORD2 decodeZepeal KEYWORD2
defaultBits KEYWORD2 defaultBits KEYWORD2
delonghiac KEYWORD2 delonghiac KEYWORD2
@ -371,6 +400,8 @@ getBreeze KEYWORD2
getBufSize KEYWORD2 getBufSize KEYWORD2
getButton KEYWORD2 getButton KEYWORD2
getCelsius KEYWORD2 getCelsius KEYWORD2
getChannel KEYWORD2
getChecksum KEYWORD2
getClean KEYWORD2 getClean KEYWORD2
getCleanToggle KEYWORD2 getCleanToggle KEYWORD2
getClock KEYWORD2 getClock KEYWORD2
@ -381,10 +412,13 @@ getCorrectedRawLength KEYWORD2
getCurrTime KEYWORD2 getCurrTime KEYWORD2
getCurrentDay KEYWORD2 getCurrentDay KEYWORD2
getCurrentTime KEYWORD2 getCurrentTime KEYWORD2
getCurrentTimeMinutes KEYWORD2
getDelayTimerMinutes KEYWORD2
getDirectIndirect KEYWORD2 getDirectIndirect KEYWORD2
getDisplay KEYWORD2 getDisplay KEYWORD2
getDisplayTempSource KEYWORD2 getDisplayTempSource KEYWORD2
getDryGrade KEYWORD2 getDryGrade KEYWORD2
getEco KEYWORD2
getEcocool KEYWORD2 getEcocool KEYWORD2
getEcono KEYWORD2 getEcono KEYWORD2
getEconoToggle KEYWORD2 getEconoToggle KEYWORD2
@ -438,8 +472,10 @@ getPurify KEYWORD2
getQuiet KEYWORD2 getQuiet KEYWORD2
getRClevel KEYWORD2 getRClevel KEYWORD2
getRaw KEYWORD2 getRaw KEYWORD2
getRoomTemp KEYWORD2 getRawByteLength KEYWORD2
getSave KEYWORD2 getSave KEYWORD2
getScheduleTimerStartMinutes KEYWORD2
getScheduleTimerStopMinutes KEYWORD2
getSectionByte KEYWORD2 getSectionByte KEYWORD2
getSectionChecksum KEYWORD2 getSectionChecksum KEYWORD2
getSensor KEYWORD2 getSensor KEYWORD2
@ -455,6 +491,7 @@ getSpeed KEYWORD2
getStartClock KEYWORD2 getStartClock KEYWORD2
getState KEYWORD2 getState KEYWORD2
getStateLength KEYWORD2 getStateLength KEYWORD2
getStateLengthForIrMsgType KEYWORD2
getStatePrev KEYWORD2 getStatePrev KEYWORD2
getStopClock KEYWORD2 getStopClock KEYWORD2
getSupercool KEYWORD2 getSupercool KEYWORD2
@ -476,6 +513,7 @@ getTempUnit KEYWORD2
getTempUnits KEYWORD2 getTempUnits KEYWORD2
getTime KEYWORD2 getTime KEYWORD2
getTimer KEYWORD2 getTimer KEYWORD2
getTimerActiveDaysBitmap KEYWORD2
getTimerEnabled KEYWORD2 getTimerEnabled KEYWORD2
getTimerMode KEYWORD2 getTimerMode KEYWORD2
getTimerTime KEYWORD2 getTimerTime KEYWORD2
@ -511,6 +549,7 @@ handleToggles KEYWORD2
hasACState KEYWORD2 hasACState KEYWORD2
hasInvertedStates KEYWORD2 hasInvertedStates KEYWORD2
hasStateChanged KEYWORD2 hasStateChanged KEYWORD2
hasValidPreamble KEYWORD2
hitachi KEYWORD2 hitachi KEYWORD2
hitachi1 KEYWORD2 hitachi1 KEYWORD2
hitachi264 KEYWORD2 hitachi264 KEYWORD2
@ -521,6 +560,7 @@ htmlEscape KEYWORD2
initState KEYWORD2 initState KEYWORD2
int64ToString KEYWORD2 int64ToString KEYWORD2
invertBits KEYWORD2 invertBits KEYWORD2
irCommandTypeToString KEYWORD2
is8CHeatToggle KEYWORD2 is8CHeatToggle KEYWORD2
isCleanToggle KEYWORD2 isCleanToggle KEYWORD2
isEconoToggle KEYWORD2 isEconoToggle KEYWORD2
@ -546,6 +586,7 @@ isTimeCommand KEYWORD2
isTimerActive KEYWORD2 isTimerActive KEYWORD2
isTurboToggle KEYWORD2 isTurboToggle KEYWORD2
isValidLgAc KEYWORD2 isValidLgAc KEYWORD2
isValidWrem3Message KEYWORD2
isVaneSwingV KEYWORD2 isVaneSwingV KEYWORD2
kelon KEYWORD2 kelon KEYWORD2
kelvinator KEYWORD2 kelvinator KEYWORD2
@ -606,6 +647,7 @@ sendAirwell KEYWORD2
sendAiwaRCT501 KEYWORD2 sendAiwaRCT501 KEYWORD2
sendAmcor KEYWORD2 sendAmcor KEYWORD2
sendArgo KEYWORD2 sendArgo KEYWORD2
sendArgoWREM3 KEYWORD2
sendArris KEYWORD2 sendArris KEYWORD2
sendBosch144 KEYWORD2 sendBosch144 KEYWORD2
sendBose KEYWORD2 sendBose KEYWORD2
@ -614,6 +656,7 @@ sendCarrierAC KEYWORD2
sendCarrierAC128 KEYWORD2 sendCarrierAC128 KEYWORD2
sendCarrierAC40 KEYWORD2 sendCarrierAC40 KEYWORD2
sendCarrierAC64 KEYWORD2 sendCarrierAC64 KEYWORD2
sendCarrierAC84 KEYWORD2
sendClimaButler KEYWORD2 sendClimaButler KEYWORD2
sendCoolix48 KEYWORD2 sendCoolix48 KEYWORD2
sendCoronaAc KEYWORD2 sendCoronaAc KEYWORD2
@ -642,6 +685,7 @@ sendGC KEYWORD2
sendGICable KEYWORD2 sendGICable KEYWORD2
sendGeneric KEYWORD2 sendGeneric KEYWORD2
sendGoodweather KEYWORD2 sendGoodweather KEYWORD2
sendGorenje KEYWORD2
sendGree KEYWORD2 sendGree KEYWORD2
sendHaierAC KEYWORD2 sendHaierAC KEYWORD2
sendHaierAC160 KEYWORD2 sendHaierAC160 KEYWORD2
@ -728,7 +772,9 @@ sendVestelAc KEYWORD2
sendVoltas KEYWORD2 sendVoltas KEYWORD2
sendWhirlpoolAC KEYWORD2 sendWhirlpoolAC KEYWORD2
sendWhynter KEYWORD2 sendWhynter KEYWORD2
sendWowwee KEYWORD2
sendXmp KEYWORD2 sendXmp KEYWORD2
sendYork KEYWORD2
sendZepeal KEYWORD2 sendZepeal KEYWORD2
serialPrintUint64 KEYWORD2 serialPrintUint64 KEYWORD2
set10CHeat KEYWORD2 set10CHeat KEYWORD2
@ -745,6 +791,7 @@ setBoost KEYWORD2
setBreeze KEYWORD2 setBreeze KEYWORD2
setButton KEYWORD2 setButton KEYWORD2
setCelsius KEYWORD2 setCelsius KEYWORD2
setChannel KEYWORD2
setCheckSumS3 KEYWORD2 setCheckSumS3 KEYWORD2
setClean KEYWORD2 setClean KEYWORD2
setCleanToggle KEYWORD2 setCleanToggle KEYWORD2
@ -752,13 +799,18 @@ setClock KEYWORD2
setCmd KEYWORD2 setCmd KEYWORD2
setComfort KEYWORD2 setComfort KEYWORD2
setCommand KEYWORD2 setCommand KEYWORD2
setConfigEntry KEYWORD2
setCurrTime KEYWORD2 setCurrTime KEYWORD2
setCurrentDay KEYWORD2 setCurrentDay KEYWORD2
setCurrentDayOfWeek KEYWORD2
setCurrentTime KEYWORD2 setCurrentTime KEYWORD2
setCurrentTimeMinutes KEYWORD2
setDelayTimerMinutes KEYWORD2
setDirectIndirect KEYWORD2 setDirectIndirect KEYWORD2
setDisplay KEYWORD2 setDisplay KEYWORD2
setDisplayTempSource KEYWORD2 setDisplayTempSource KEYWORD2
setDryGrade KEYWORD2 setDryGrade KEYWORD2
setEco KEYWORD2
setEcocool KEYWORD2 setEcocool KEYWORD2
setEcono KEYWORD2 setEcono KEYWORD2
setEconoToggle KEYWORD2 setEconoToggle KEYWORD2
@ -790,6 +842,7 @@ setLight KEYWORD2
setLightToggle KEYWORD2 setLightToggle KEYWORD2
setLock KEYWORD2 setLock KEYWORD2
setMax KEYWORD2 setMax KEYWORD2
setMessageType KEYWORD2
setMode KEYWORD2 setMode KEYWORD2
setModel KEYWORD2 setModel KEYWORD2
setMold KEYWORD2 setMold KEYWORD2
@ -813,8 +866,10 @@ setPowerful KEYWORD2
setPurify KEYWORD2 setPurify KEYWORD2
setQuiet KEYWORD2 setQuiet KEYWORD2
setRaw KEYWORD2 setRaw KEYWORD2
setRoomTemp KEYWORD2
setSave KEYWORD2 setSave KEYWORD2
setScheduleTimerActiveDays KEYWORD2
setScheduleTimerStartMinutes KEYWORD2
setScheduleTimerStopMinutes KEYWORD2
setSensor KEYWORD2 setSensor KEYWORD2
setSensorTemp KEYWORD2 setSensorTemp KEYWORD2
setSensorTempRaw KEYWORD2 setSensorTempRaw KEYWORD2
@ -917,6 +972,7 @@ xorBytes KEYWORD2
A705 LITERAL1 A705 LITERAL1
A903 LITERAL1 A903 LITERAL1
A907 LITERAL1 A907 LITERAL1
AC_CONTROL LITERAL1
AIRTON LITERAL1 AIRTON LITERAL1
AIRWELL LITERAL1 AIRWELL LITERAL1
AIWA_RC_T501 LITERAL1 AIWA_RC_T501 LITERAL1
@ -956,14 +1012,18 @@ ARREB1E LITERAL1
ARREW4E LITERAL1 ARREW4E LITERAL1
ARRIS LITERAL1 ARRIS LITERAL1
ARRY4 LITERAL1 ARRY4 LITERAL1
AUTO LITERAL1
BOSCH144 LITERAL1 BOSCH144 LITERAL1
BOSE LITERAL1 BOSE LITERAL1
CARRIER_AC LITERAL1 CARRIER_AC LITERAL1
CARRIER_AC128 LITERAL1 CARRIER_AC128 LITERAL1
CARRIER_AC40 LITERAL1 CARRIER_AC40 LITERAL1
CARRIER_AC64 LITERAL1 CARRIER_AC64 LITERAL1
CARRIER_AC84 LITERAL1
CARRIER_AC_BITS LITERAL1 CARRIER_AC_BITS LITERAL1
CLIMABUTLER LITERAL1 CLIMABUTLER LITERAL1
CONFIG_PARAM_SET LITERAL1
COOL LITERAL1
COOLIX LITERAL1 COOLIX LITERAL1
COOLIX48 LITERAL1 COOLIX48 LITERAL1
COOLIX_BITS LITERAL1 COOLIX_BITS LITERAL1
@ -1003,6 +1063,7 @@ DECODE_CARRIER_AC LITERAL1
DECODE_CARRIER_AC128 LITERAL1 DECODE_CARRIER_AC128 LITERAL1
DECODE_CARRIER_AC40 LITERAL1 DECODE_CARRIER_AC40 LITERAL1
DECODE_CARRIER_AC64 LITERAL1 DECODE_CARRIER_AC64 LITERAL1
DECODE_CARRIER_AC84 LITERAL1
DECODE_CLIMABUTLER LITERAL1 DECODE_CLIMABUTLER LITERAL1
DECODE_COOLIX LITERAL1 DECODE_COOLIX LITERAL1
DECODE_COOLIX48 LITERAL1 DECODE_COOLIX48 LITERAL1
@ -1029,6 +1090,7 @@ DECODE_FUJITSU_AC LITERAL1
DECODE_GICABLE LITERAL1 DECODE_GICABLE LITERAL1
DECODE_GLOBALCACHE LITERAL1 DECODE_GLOBALCACHE LITERAL1
DECODE_GOODWEATHER LITERAL1 DECODE_GOODWEATHER LITERAL1
DECODE_GORENJE LITERAL1
DECODE_GREE LITERAL1 DECODE_GREE LITERAL1
DECODE_HAIER_AC LITERAL1 DECODE_HAIER_AC LITERAL1
DECODE_HAIER_AC160 LITERAL1 DECODE_HAIER_AC160 LITERAL1
@ -1105,8 +1167,11 @@ DECODE_VESTEL_AC LITERAL1
DECODE_VOLTAS LITERAL1 DECODE_VOLTAS LITERAL1
DECODE_WHIRLPOOL_AC LITERAL1 DECODE_WHIRLPOOL_AC LITERAL1
DECODE_WHYNTER LITERAL1 DECODE_WHYNTER LITERAL1
DECODE_WOWWEE LITERAL1
DECODE_XMP LITERAL1 DECODE_XMP LITERAL1
DECODE_YORK LITERAL1
DECODE_ZEPEAL LITERAL1 DECODE_ZEPEAL LITERAL1
DELAY_TIMER LITERAL1
DELONGHI_AC LITERAL1 DELONGHI_AC LITERAL1
DENON LITERAL1 DENON LITERAL1
DENON_48_BITS LITERAL1 DENON_48_BITS LITERAL1
@ -1117,11 +1182,29 @@ DG11J191 LITERAL1
DISH LITERAL1 DISH LITERAL1
DISH_BITS LITERAL1 DISH_BITS LITERAL1
DOSHISHA LITERAL1 DOSHISHA LITERAL1
DRY LITERAL1
ECOCLIM LITERAL1 ECOCLIM LITERAL1
ELECTRA_AC LITERAL1 ELECTRA_AC LITERAL1
ELITESCREENS LITERAL1 ELITESCREENS LITERAL1
ENABLE_NOISE_FILTER_OPTION LITERAL1 ENABLE_NOISE_FILTER_OPTION LITERAL1
EPSON LITERAL1 EPSON LITERAL1
FAN LITERAL1
FAN_AUTO LITERAL1
FAN_HIGH LITERAL1
FAN_HIGHEST LITERAL1
FAN_LOW LITERAL1
FAN_LOWER LITERAL1
FAN_LOWEST LITERAL1
FAN_MEDIUM LITERAL1
FLAP_1 LITERAL1
FLAP_2 LITERAL1
FLAP_3 LITERAL1
FLAP_4 LITERAL1
FLAP_5 LITERAL1
FLAP_6 LITERAL1
FLAP_AUTO LITERAL1
FLAP_FULL LITERAL1
FRIDAY LITERAL1
FUJITSU_AC LITERAL1 FUJITSU_AC LITERAL1
FUJITSU_AC_BITS LITERAL1 FUJITSU_AC_BITS LITERAL1
FUJITSU_AC_CMD_STAY_ON LITERAL1 FUJITSU_AC_CMD_STAY_ON LITERAL1
@ -1154,6 +1237,7 @@ GICABLE LITERAL1
GICABLE_BITS LITERAL1 GICABLE_BITS LITERAL1
GLOBALCACHE LITERAL1 GLOBALCACHE LITERAL1
GOODWEATHER LITERAL1 GOODWEATHER LITERAL1
GORENJE LITERAL1
GREE LITERAL1 GREE LITERAL1
GREE_AUTO LITERAL1 GREE_AUTO LITERAL1
GREE_COOL LITERAL1 GREE_COOL LITERAL1
@ -1233,6 +1317,7 @@ HAIER_AC_YRW02_SWING_MIDDLE LITERAL1
HAIER_AC_YRW02_SWING_OFF LITERAL1 HAIER_AC_YRW02_SWING_OFF LITERAL1
HAIER_AC_YRW02_SWING_TOP LITERAL1 HAIER_AC_YRW02_SWING_TOP LITERAL1
HAIER_AC_YRW02_TURBO_OFF LITERAL1 HAIER_AC_YRW02_TURBO_OFF LITERAL1
HEAT LITERAL1
HIGH LITERAL1 HIGH LITERAL1
HITACHI_AC LITERAL1 HITACHI_AC LITERAL1
HITACHI_AC1 LITERAL1 HITACHI_AC1 LITERAL1
@ -1250,7 +1335,7 @@ HITACHI_AC344 LITERAL1
HITACHI_AC424 LITERAL1 HITACHI_AC424 LITERAL1
HITACHI_AC_BITS LITERAL1 HITACHI_AC_BITS LITERAL1
HITACHI_AC_STATE_LENGTH LITERAL1 HITACHI_AC_STATE_LENGTH LITERAL1
ICACHE_RAM_ATTR LITERAL1 IFEEL_TEMP_REPORT LITERAL1
INAX LITERAL1 INAX LITERAL1
JVC LITERAL1 JVC LITERAL1
JVC_BITS LITERAL1 JVC_BITS LITERAL1
@ -1325,6 +1410,7 @@ MITSUBISHI_AC_VANE_AUTO_MOVE LITERAL1
MITSUBISHI_BITS LITERAL1 MITSUBISHI_BITS LITERAL1
MITSUBISHI_HEAVY_152 LITERAL1 MITSUBISHI_HEAVY_152 LITERAL1
MITSUBISHI_HEAVY_88 LITERAL1 MITSUBISHI_HEAVY_88 LITERAL1
MONDAY LITERAL1
MULTIBRACKETS LITERAL1 MULTIBRACKETS LITERAL1
MWM LITERAL1 MWM LITERAL1
NEC LITERAL1 NEC LITERAL1
@ -1334,6 +1420,7 @@ NEOCLIMA LITERAL1
NIKAI LITERAL1 NIKAI LITERAL1
NIKAI_BITS LITERAL1 NIKAI_BITS LITERAL1
NOTHING LITERAL1 NOTHING LITERAL1
NO_TIMER LITERAL1
ONCE LITERAL1 ONCE LITERAL1
PANASONIC LITERAL1 PANASONIC LITERAL1
PANASONIC_AC LITERAL1 PANASONIC_AC LITERAL1
@ -1356,6 +1443,8 @@ RCMM_BITS LITERAL1
RHOSS LITERAL1 RHOSS LITERAL1
R_LT0541_HTA_A LITERAL1 R_LT0541_HTA_A LITERAL1
R_LT0541_HTA_B LITERAL1 R_LT0541_HTA_B LITERAL1
SAC_WREM2 LITERAL1
SAC_WREM3 LITERAL1
SAMSUNG LITERAL1 SAMSUNG LITERAL1
SAMSUNG36 LITERAL1 SAMSUNG36 LITERAL1
SAMSUNG_AC LITERAL1 SAMSUNG_AC LITERAL1
@ -1367,6 +1456,10 @@ SANYO_AC88 LITERAL1
SANYO_LC7461 LITERAL1 SANYO_LC7461 LITERAL1
SANYO_LC7461_BITS LITERAL1 SANYO_LC7461_BITS LITERAL1
SANYO_SA8650B_BITS LITERAL1 SANYO_SA8650B_BITS LITERAL1
SATURDAY LITERAL1
SCHEDULE_TIMER_1 LITERAL1
SCHEDULE_TIMER_2 LITERAL1
SCHEDULE_TIMER_3 LITERAL1
SEND_AIRTON LITERAL1 SEND_AIRTON LITERAL1
SEND_AIRWELL LITERAL1 SEND_AIRWELL LITERAL1
SEND_AIWA_RC_T501 LITERAL1 SEND_AIWA_RC_T501 LITERAL1
@ -1379,6 +1472,7 @@ SEND_CARRIER_AC LITERAL1
SEND_CARRIER_AC128 LITERAL1 SEND_CARRIER_AC128 LITERAL1
SEND_CARRIER_AC40 LITERAL1 SEND_CARRIER_AC40 LITERAL1
SEND_CARRIER_AC64 LITERAL1 SEND_CARRIER_AC64 LITERAL1
SEND_CARRIER_AC84 LITERAL1
SEND_CLIMABUTLER LITERAL1 SEND_CLIMABUTLER LITERAL1
SEND_COOLIX LITERAL1 SEND_COOLIX LITERAL1
SEND_COOLIX48 LITERAL1 SEND_COOLIX48 LITERAL1
@ -1405,6 +1499,7 @@ SEND_FUJITSU_AC LITERAL1
SEND_GICABLE LITERAL1 SEND_GICABLE LITERAL1
SEND_GLOBALCACHE LITERAL1 SEND_GLOBALCACHE LITERAL1
SEND_GOODWEATHER LITERAL1 SEND_GOODWEATHER LITERAL1
SEND_GORENJE LITERAL1
SEND_GREE LITERAL1 SEND_GREE LITERAL1
SEND_HAIER_AC LITERAL1 SEND_HAIER_AC LITERAL1
SEND_HAIER_AC160 LITERAL1 SEND_HAIER_AC160 LITERAL1
@ -1481,7 +1576,9 @@ SEND_VESTEL_AC LITERAL1
SEND_VOLTAS LITERAL1 SEND_VOLTAS LITERAL1
SEND_WHIRLPOOL_AC LITERAL1 SEND_WHIRLPOOL_AC LITERAL1
SEND_WHYNTER LITERAL1 SEND_WHYNTER LITERAL1
SEND_WOWWEE LITERAL1
SEND_XMP LITERAL1 SEND_XMP LITERAL1
SEND_YORK LITERAL1
SEND_ZEPEAL LITERAL1 SEND_ZEPEAL LITERAL1
SHARP LITERAL1 SHARP LITERAL1
SHARP_AC LITERAL1 SHARP_AC LITERAL1
@ -1493,6 +1590,7 @@ SONY_12_BITS LITERAL1
SONY_15_BITS LITERAL1 SONY_15_BITS LITERAL1
SONY_20_BITS LITERAL1 SONY_20_BITS LITERAL1
SONY_38K LITERAL1 SONY_38K LITERAL1
SUNDAY LITERAL1
SYMPHONY LITERAL1 SYMPHONY LITERAL1
TAC09CHSD LITERAL1 TAC09CHSD LITERAL1
TCL112AC LITERAL1 TCL112AC LITERAL1
@ -1500,7 +1598,9 @@ TCL96AC LITERAL1
TECHNIBEL_AC LITERAL1 TECHNIBEL_AC LITERAL1
TECO LITERAL1 TECO LITERAL1
TEKNOPOINT LITERAL1 TEKNOPOINT LITERAL1
THURSDAY LITERAL1
TIMEOUT_MS LITERAL1 TIMEOUT_MS LITERAL1
TIMER_COMMAND LITERAL1
TOSHIBA_AC LITERAL1 TOSHIBA_AC LITERAL1
TOSHIBA_AC_AUTO LITERAL1 TOSHIBA_AC_AUTO LITERAL1
TOSHIBA_AC_COOL LITERAL1 TOSHIBA_AC_COOL LITERAL1
@ -1528,6 +1628,7 @@ TROTEC_MAX_TEMP LITERAL1
TROTEC_MAX_TIMER LITERAL1 TROTEC_MAX_TIMER LITERAL1
TROTEC_MIN_TEMP LITERAL1 TROTEC_MIN_TEMP LITERAL1
TRUMA LITERAL1 TRUMA LITERAL1
TUESDAY LITERAL1
UNKNOWN LITERAL1 UNKNOWN LITERAL1
UNUSED LITERAL1 UNUSED LITERAL1
USE_IRAM_ATTR LITERAL1 USE_IRAM_ATTR LITERAL1
@ -1535,12 +1636,15 @@ V9014557_A LITERAL1
V9014557_B LITERAL1 V9014557_B LITERAL1
VESTEL_AC LITERAL1 VESTEL_AC LITERAL1
VOLTAS LITERAL1 VOLTAS LITERAL1
WEDNESDAY LITERAL1
WHIRLPOOL_AC LITERAL1 WHIRLPOOL_AC LITERAL1
WHYNTER LITERAL1 WHYNTER LITERAL1
WHYNTER_BITS LITERAL1 WHYNTER_BITS LITERAL1
WOWWEE LITERAL1
XMP LITERAL1 XMP LITERAL1
YAW1F LITERAL1 YAW1F LITERAL1
YBOFB LITERAL1 YBOFB LITERAL1
YORK LITERAL1
YX1FSF LITERAL1 YX1FSF LITERAL1
ZEPEAL LITERAL1 ZEPEAL LITERAL1
k0Str LITERAL1 k0Str LITERAL1
@ -1649,6 +1753,10 @@ kAmcorVentOn LITERAL1
kAmcorZeroMark LITERAL1 kAmcorZeroMark LITERAL1
kAmcorZeroSpace LITERAL1 kAmcorZeroSpace LITERAL1
kArdb1Str LITERAL1 kArdb1Str LITERAL1
kArgo3AcControlStateLength LITERAL1
kArgo3ConfigStateLength LITERAL1
kArgo3TimerStateLength LITERAL1
kArgo3iFeelReportStateLength LITERAL1
kArgoAuto LITERAL1 kArgoAuto LITERAL1
kArgoBitMark LITERAL1 kArgoBitMark LITERAL1
kArgoBits LITERAL1 kArgoBits LITERAL1
@ -1667,6 +1775,7 @@ kArgoFlap5 LITERAL1
kArgoFlap6 LITERAL1 kArgoFlap6 LITERAL1
kArgoFlapAuto LITERAL1 kArgoFlapAuto LITERAL1
kArgoFlapFull LITERAL1 kArgoFlapFull LITERAL1
kArgoFrequency LITERAL1
kArgoGap LITERAL1 kArgoGap LITERAL1
kArgoHdrMark LITERAL1 kArgoHdrMark LITERAL1
kArgoHdrSpace LITERAL1 kArgoHdrSpace LITERAL1
@ -1674,13 +1783,26 @@ kArgoHeat LITERAL1
kArgoHeatAuto LITERAL1 kArgoHeatAuto LITERAL1
kArgoHeatBit LITERAL1 kArgoHeatBit LITERAL1
kArgoHeatBlink LITERAL1 kArgoHeatBlink LITERAL1
kArgoMaxChannel LITERAL1
kArgoMaxRoomTemp LITERAL1 kArgoMaxRoomTemp LITERAL1
kArgoMaxTemp LITERAL1 kArgoMaxTemp LITERAL1
kArgoMinTemp LITERAL1 kArgoMinTemp LITERAL1
kArgoOff LITERAL1 kArgoOff LITERAL1
kArgoOneSpace LITERAL1 kArgoOneSpace LITERAL1
kArgoPost LITERAL1
kArgoPreamble1 LITERAL1
kArgoPreamble2 LITERAL1
kArgoSensorCheck LITERAL1
kArgoSensorFixed LITERAL1
kArgoShortBits LITERAL1
kArgoShortStateLength LITERAL1
kArgoStateLength LITERAL1 kArgoStateLength LITERAL1
kArgoTempDelta LITERAL1 kArgoTempDelta LITERAL1
kArgoWrem2Str LITERAL1
kArgoWrem3Postfix_ACControl LITERAL1
kArgoWrem3Postfix_Timer LITERAL1
kArgoWrem3Preamble LITERAL1
kArgoWrem3Str LITERAL1
kArgoZeroSpace LITERAL1 kArgoZeroSpace LITERAL1
kArjw2Str LITERAL1 kArjw2Str LITERAL1
kArrah2eStr LITERAL1 kArrah2eStr LITERAL1
@ -1785,6 +1907,16 @@ kCarrierAc64OneSpace LITERAL1
kCarrierAc64TimerMax LITERAL1 kCarrierAc64TimerMax LITERAL1
kCarrierAc64TimerMin LITERAL1 kCarrierAc64TimerMin LITERAL1
kCarrierAc64ZeroSpace LITERAL1 kCarrierAc64ZeroSpace LITERAL1
kCarrierAc84Bits LITERAL1
kCarrierAc84ExtraBits LITERAL1
kCarrierAc84ExtraTolerance LITERAL1
kCarrierAc84Gap LITERAL1
kCarrierAc84HdrMark LITERAL1
kCarrierAc84HdrSpace LITERAL1
kCarrierAc84MinRepeat LITERAL1
kCarrierAc84One LITERAL1
kCarrierAc84StateLength LITERAL1
kCarrierAc84Zero LITERAL1
kCarrierAcBitMark LITERAL1 kCarrierAcBitMark LITERAL1
kCarrierAcBits LITERAL1 kCarrierAcBits LITERAL1
kCarrierAcFreq LITERAL1 kCarrierAcFreq LITERAL1
@ -1798,6 +1930,7 @@ kCeilingStr LITERAL1
kCelsiusFahrenheitStr LITERAL1 kCelsiusFahrenheitStr LITERAL1
kCelsiusStr LITERAL1 kCelsiusStr LITERAL1
kCentreStr LITERAL1 kCentreStr LITERAL1
kChStr LITERAL1
kChangeStr LITERAL1 kChangeStr LITERAL1
kCirculateStr LITERAL1 kCirculateStr LITERAL1
kCkpStr LITERAL1 kCkpStr LITERAL1
@ -1816,6 +1949,10 @@ kColonSpaceStr LITERAL1
kComfortStr LITERAL1 kComfortStr LITERAL1
kCommaSpaceStr LITERAL1 kCommaSpaceStr LITERAL1
kCommandStr LITERAL1 kCommandStr LITERAL1
kConfigCommand LITERAL1
kConfigCommandStr LITERAL1
kControlCommand LITERAL1
kControlCommandStr LITERAL1
kCool LITERAL1 kCool LITERAL1
kCoolStr LITERAL1 kCoolStr LITERAL1
kCoolingStr LITERAL1 kCoolingStr LITERAL1
@ -2413,6 +2550,15 @@ kGoodweatherSwingSlow LITERAL1
kGoodweatherTempMax LITERAL1 kGoodweatherTempMax LITERAL1
kGoodweatherTempMin LITERAL1 kGoodweatherTempMin LITERAL1
kGoodweatherZeroSpace LITERAL1 kGoodweatherZeroSpace LITERAL1
kGorenjeBitMark LITERAL1
kGorenjeBits LITERAL1
kGorenjeFreq LITERAL1
kGorenjeHdrMark LITERAL1
kGorenjeHdrSpace LITERAL1
kGorenjeMinGap LITERAL1
kGorenjeOneSpace LITERAL1
kGorenjeTolerance LITERAL1
kGorenjeZeroSpace LITERAL1
kGpioUnused LITERAL1 kGpioUnused LITERAL1
kGreeAuto LITERAL1 kGreeAuto LITERAL1
kGreeBitMark LITERAL1 kGreeBitMark LITERAL1
@ -2735,6 +2881,7 @@ kHoldStr LITERAL1
kHourStr LITERAL1 kHourStr LITERAL1
kHoursStr LITERAL1 kHoursStr LITERAL1
kHumidStr LITERAL1 kHumidStr LITERAL1
kIFeelReportStr LITERAL1
kIFeelStr LITERAL1 kIFeelStr LITERAL1
kISeeStr LITERAL1 kISeeStr LITERAL1
kIdStr LITERAL1 kIdStr LITERAL1
@ -2836,6 +2983,7 @@ kKelvinatorSwingVUpperMiddle LITERAL1
kKelvinatorTick LITERAL1 kKelvinatorTick LITERAL1
kKelvinatorZeroSpace LITERAL1 kKelvinatorZeroSpace LITERAL1
kKelvinatorZeroSpaceTicks LITERAL1 kKelvinatorZeroSpaceTicks LITERAL1
kKeyStr LITERAL1
kKkg29ac1Str LITERAL1 kKkg29ac1Str LITERAL1
kKkg9ac1Str LITERAL1 kKkg9ac1Str LITERAL1
kLasertagBits LITERAL1 kLasertagBits LITERAL1
@ -2846,6 +2994,7 @@ kLasertagMinRepeat LITERAL1
kLasertagMinSamples LITERAL1 kLasertagMinSamples LITERAL1
kLasertagTick LITERAL1 kLasertagTick LITERAL1
kLasertagTolerance LITERAL1 kLasertagTolerance LITERAL1
kLastAcCommandEnum LITERAL1
kLastDecodeType LITERAL1 kLastDecodeType LITERAL1
kLastFanspeedEnum LITERAL1 kLastFanspeedEnum LITERAL1
kLastOpmodeEnum LITERAL1 kLastOpmodeEnum LITERAL1
@ -2983,8 +3132,10 @@ kMaxRightStr LITERAL1
kMaxStr LITERAL1 kMaxStr LITERAL1
kMaxTimeoutMs LITERAL1 kMaxTimeoutMs LITERAL1
kMaximumStr LITERAL1 kMaximumStr LITERAL1
kMedHighStr LITERAL1
kMedStr LITERAL1 kMedStr LITERAL1
kMedium LITERAL1 kMedium LITERAL1
kMediumHigh LITERAL1
kMediumStr LITERAL1 kMediumStr LITERAL1
kMetzAddressBits LITERAL1 kMetzAddressBits LITERAL1
kMetzBitMark LITERAL1 kMetzBitMark LITERAL1
@ -3392,6 +3543,7 @@ kNikaiZeroSpaceTicks LITERAL1
kNkeStr LITERAL1 kNkeStr LITERAL1
kNoRepeat LITERAL1 kNoRepeat LITERAL1
kNoStr LITERAL1 kNoStr LITERAL1
kNoTempValue LITERAL1
kNowStr LITERAL1 kNowStr LITERAL1
kOff LITERAL1 kOff LITERAL1
kOffStr LITERAL1 kOffStr LITERAL1
@ -3400,6 +3552,8 @@ kOnStr LITERAL1
kOnTimerStr LITERAL1 kOnTimerStr LITERAL1
kOutsideQuietStr LITERAL1 kOutsideQuietStr LITERAL1
kOutsideStr LITERAL1 kOutsideStr LITERAL1
kPanasonic40Bits LITERAL1
kPanasonic40Manufacturer LITERAL1
kPanasonicAc32Auto LITERAL1 kPanasonicAc32Auto LITERAL1
kPanasonicAc32BitMark LITERAL1 kPanasonicAc32BitMark LITERAL1
kPanasonicAc32Bits LITERAL1 kPanasonicAc32Bits LITERAL1
@ -3773,11 +3927,14 @@ kSanyoSa8650bOneMark LITERAL1
kSanyoSa8650bRptLength LITERAL1 kSanyoSa8650bRptLength LITERAL1
kSanyoSa8650bZeroMark LITERAL1 kSanyoSa8650bZeroMark LITERAL1
kSaveStr LITERAL1 kSaveStr LITERAL1
kScheduleStr LITERAL1
kSecondStr LITERAL1 kSecondStr LITERAL1
kSecondsStr LITERAL1 kSecondsStr LITERAL1
kSensorStr LITERAL1 kSensorStr LITERAL1
kSensorTempReport LITERAL1
kSensorTempStr LITERAL1 kSensorTempStr LITERAL1
kSetStr LITERAL1 kSetStr LITERAL1
kSetTimerCommandStr LITERAL1
kSharpAcAuto LITERAL1 kSharpAcAuto LITERAL1
kSharpAcBitMark LITERAL1 kSharpAcBitMark LITERAL1
kSharpAcBits LITERAL1 kSharpAcBits LITERAL1
@ -4002,6 +4159,8 @@ kTempUpStr LITERAL1
kThreeLetterDayOfWeekStr LITERAL1 kThreeLetterDayOfWeekStr LITERAL1
kTimeSep LITERAL1 kTimeSep LITERAL1
kTimeoutMs LITERAL1 kTimeoutMs LITERAL1
kTimerActiveDaysStr LITERAL1
kTimerCommand LITERAL1
kTimerModeStr LITERAL1 kTimerModeStr LITERAL1
kTimerStr LITERAL1 kTimerStr LITERAL1
kToggleStr LITERAL1 kToggleStr LITERAL1
@ -4147,10 +4306,13 @@ kTypeStr LITERAL1
kUnknownStr LITERAL1 kUnknownStr LITERAL1
kUnknownThreshold LITERAL1 kUnknownThreshold LITERAL1
kUpStr LITERAL1 kUpStr LITERAL1
kUpperMiddle LITERAL1
kUpperMiddleStr LITERAL1
kUpperStr LITERAL1 kUpperStr LITERAL1
kUseDefTol LITERAL1 kUseDefTol LITERAL1
kV9014557AStr LITERAL1 kV9014557AStr LITERAL1
kV9014557BStr LITERAL1 kV9014557BStr LITERAL1
kValueStr LITERAL1
kVaneStr LITERAL1 kVaneStr LITERAL1
kVestelAcAuto LITERAL1 kVestelAcAuto LITERAL1
kVestelAcBitMark LITERAL1 kVestelAcBitMark LITERAL1
@ -4259,6 +4421,14 @@ kWhynterZeroSpaceTicks LITERAL1
kWide LITERAL1 kWide LITERAL1
kWideStr LITERAL1 kWideStr LITERAL1
kWifiStr LITERAL1 kWifiStr LITERAL1
kWowweeBitMark LITERAL1
kWowweeBits LITERAL1
kWowweeDefaultRepeat LITERAL1
kWowweeFreq LITERAL1
kWowweeHdrMark LITERAL1
kWowweeHdrSpace LITERAL1
kWowweeOneSpace LITERAL1
kWowweeZeroSpace LITERAL1
kXFanStr LITERAL1 kXFanStr LITERAL1
kXmpBaseSpace LITERAL1 kXmpBaseSpace LITERAL1
kXmpBits LITERAL1 kXmpBits LITERAL1
@ -4274,6 +4444,26 @@ kXmpWordSize LITERAL1
kYaw1fStr LITERAL1 kYaw1fStr LITERAL1
kYbofbStr LITERAL1 kYbofbStr LITERAL1
kYesStr LITERAL1 kYesStr LITERAL1
kYorkAuto LITERAL1
kYorkBitMark LITERAL1
kYorkBits LITERAL1
kYorkCool LITERAL1
kYorkDry LITERAL1
kYorkFan LITERAL1
kYorkFanAuto LITERAL1
kYorkFanHigh LITERAL1
kYorkFanLow LITERAL1
kYorkFanMedium LITERAL1
kYorkFreq LITERAL1
kYorkHdrMark LITERAL1
kYorkHdrSpace LITERAL1
kYorkHeat LITERAL1
kYorkKnownGoodState LITERAL1
kYorkMaxTemp LITERAL1
kYorkMinTemp LITERAL1
kYorkOneSpace LITERAL1
kYorkStateLength LITERAL1
kYorkZeroSpace LITERAL1
kYx1fsfStr LITERAL1 kYx1fsfStr LITERAL1
kZepealBits LITERAL1 kZepealBits LITERAL1
kZepealCommandOffOn LITERAL1 kZepealCommandOffOn LITERAL1

View File

@ -1,6 +1,6 @@
{ {
"name": "IRremoteESP8266", "name": "IRremoteESP8266",
"version": "2.8.4", "version": "2.8.5",
"keywords": "infrared, ir, remote, esp8266, esp32", "keywords": "infrared, ir, remote, esp8266, esp32",
"description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)",
"repository": "repository":

View File

@ -1,5 +1,5 @@
name=IRremoteESP8266 name=IRremoteESP8266
version=2.8.4 version=2.8.5
author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff
maintainer=David Conran, Mark Szabo, Sebastien Warin, Roi Dayan, Massimiliano Pinto, Christian Nilsson maintainer=David Conran, Mark Szabo, Sebastien Warin, Roi Dayan, Massimiliano Pinto, Christian Nilsson
sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32) sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32)

View File

@ -12,6 +12,7 @@
#ifndef ARDUINO #ifndef ARDUINO
#include <string> #include <string>
#endif #endif
#include <cmath>
#include "IRsend.h" #include "IRsend.h"
#include "IRremoteESP8266.h" #include "IRremoteESP8266.h"
#include "IRtext.h" #include "IRtext.h"
@ -64,6 +65,36 @@
#endif // ESP8266 #endif // ESP8266
#endif // STRCASECMP #endif // STRCASECMP
#ifndef UNIT_TEST
#define OUTPUT_DECODE_RESULTS_FOR_UT(ac)
#else
/* NOTE: THIS IS NOT A DOXYGEN COMMENT (would require ENABLE_PREPROCESSING-YES)
/// If compiling for UT *and* a test receiver @c IRrecv is provided via the
/// @c _utReceived param, this injects an "output" gadget @c _lastDecodeResults
/// into the @c IRAc::sendAc method, so that the UT code may parse the "sent"
/// value and drive further assertions
///
/// @note The @c decode_results "returned" is a shallow copy (empty rawbuf),
/// mostly b/c the class does not have a custom/deep copy c-tor
/// and defining it would be an overkill for this purpose
/// @note For future maintainers: If @c IRAc class is ever refactored to use
/// polymorphism (static or dynamic)... this macro should be removed
/// and replaced with proper GMock injection.
*/
#define OUTPUT_DECODE_RESULTS_FOR_UT(ac) \
{ \
if (_utReceiver) { \
_lastDecodeResults = nullptr; \
(ac)._irsend.makeDecodeResult(); \
if (_utReceiver->decode(&(ac)._irsend.capture)) { \
_lastDecodeResults = std::unique_ptr<decode_results>( \
new decode_results((ac)._irsend.capture)); \
_lastDecodeResults->rawbuf = nullptr; \
} \
} \
}
#endif // UNIT_TEST
/// Class constructor /// Class constructor
/// @param[in] pin Gpio pin to use when transmitting IR messages. /// @param[in] pin Gpio pin to use when transmitting IR messages.
/// @param[in] inverted true, gpio output defaults to high. false, to low. /// @param[in] inverted true, gpio output defaults to high. false, to low.
@ -331,6 +362,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) {
#endif #endif
#if SEND_VOLTAS #if SEND_VOLTAS
case decode_type_t::VOLTAS: case decode_type_t::VOLTAS:
#endif
#if SEND_YORK
case decode_type_t::YORK:
#endif #endif
case decode_type_t::WHIRLPOOL_AC: case decode_type_t::WHIRLPOOL_AC:
return true; return true;
@ -439,19 +473,27 @@ void IRac::amcor(IRAmcorAc *ac,
/// @param[in] on The power setting. /// @param[in] on The power setting.
/// @param[in] mode The operation mode setting. /// @param[in] mode The operation mode setting.
/// @param[in] degrees The temperature setting in degrees. /// @param[in] degrees The temperature setting in degrees.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading in degrees
/// Celsius.
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting. /// @param[in] swingv The vertical swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] sleep Nr. of minutes for sleep mode. /// @param[in] sleep Nr. of minutes for sleep mode.
/// @note -1 is Off, >= 0 is on. /// @note -1 is Off, >= 0 is on.
void IRac::argo(IRArgoAC *ac, void IRac::argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees, const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const float sensorTemp, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool iFeel,
const bool turbo, const int16_t sleep) { const bool turbo, const int16_t sleep) {
ac->begin(); ac->begin();
ac->setPower(on); ac->setPower(on);
ac->setMode(ac->convertMode(mode)); ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees); ac->setTemp(static_cast<uint8_t>(std::round(degrees)));
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
}
ac->setiFeel(iFeel);
ac->setFan(ac->convertFan(fan)); ac->setFan(ac->convertFan(fan));
ac->setFlap(ac->convertSwingV(swingv)); ac->setFlap(ac->convertSwingV(swingv));
// No Quiet setting available. // No Quiet setting available.
@ -464,6 +506,121 @@ void IRac::argo(IRArgoAC *ac,
ac->setNight(sleep >= 0); // Convert to a boolean. ac->setNight(sleep >= 0); // Convert to a boolean.
ac->send(); ac->send();
} }
/// Send an Argo A/C WREM-3 AC **control** message with the supplied settings.
/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use.
/// @param[in] on The power setting.
/// @param[in] mode The operation mode setting.
/// @param[in] degrees The set temperature setting in degrees Celsius.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading in degrees
/// Celsius.
/// @warning The @c sensorTemp param is assumed to be in 0..255 range (uint8_t)
/// The overflow is *not* checked, though.
/// @note The value is rounded to nearest integer, rounding halfway cases
/// away from zero. E.g. 1.5 [C] becomes 2 [C].
/// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] night Enable night mode (raises temp by +1*C after 1h).
/// @param[in] econo Enable eco mode (limits power consumed).
/// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] filter Enable filter mode
/// @param[in] light Enable device display/LEDs
void IRac::argoWrem3_ACCommand(IRArgoAC_WREM3 *ac, const bool on,
const stdAc::opmode_t mode, const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool iFeel,
const bool night, const bool econo, const bool turbo, const bool filter,
const bool light) {
ac->begin();
ac->setMessageType(argoIrMessageType_t::AC_CONTROL);
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
}
ac->setiFeel(iFeel);
ac->setFan(ac->convertFan(fan));
ac->setFlap(ac->convertSwingV(swingv));
ac->setNight(night);
ac->setEco(econo);
ac->setMax(turbo);
ac->setFilter(filter);
ac->setLight(light);
// No Clean setting available.
// No Beep setting available - always beeps in this mode :)
ac->send();
}
/// Send an Argo A/C WREM-3 iFeel (room temp) silent (no beep) report.
/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use.
/// @param[in] sensorTemp The room (iFeel) temperature setting
/// in degrees Celsius.
/// @warning The @c sensorTemp param is assumed to be in 0..255 range (uint8_t)
/// The overflow is *not* checked, though.
/// @note The value is rounded to nearest integer, rounding halfway cases
/// away from zero. E.g. 1.5 [C] becomes 2 [C].
void IRac::argoWrem3_iFeelReport(IRArgoAC_WREM3 *ac, const float sensorTemp) {
ac->begin();
ac->setMessageType(argoIrMessageType_t::IFEEL_TEMP_REPORT);
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
ac->send();
}
/// Send an Argo A/C WREM-3 Config command.
/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use.
/// @param[in] param The parameter ID.
/// @param[in] value The parameter value.
/// @param[in] safe If true, will only allow setting the below parameters
/// in order to avoid accidentally setting a restricted
/// vendor-specific param and breaking the A/C device
/// @note Known parameters (P<xx>, where xx is the @c param)
/// P05 - Temperature Scale (0-Celsius, 1-Fahrenheit)
/// P06 - Transmission channel (0..3)
/// P12 - ECO mode power input limit (30..99, default: 75)
void IRac::argoWrem3_ConfigSet(IRArgoAC_WREM3 *ac, const uint8_t param,
const uint8_t value, bool safe /*= true*/) {
if (safe) {
switch (param) {
case 5: // temp. scale (note this is likely excess as not transmitted)
if (value > 1) { return; /* invalid */ }
break;
case 6: // channel (note this is likely excess as not transmitted)
if (value > 3) { return; /* invalid */ }
break;
case 12: // eco power limit
if (value < 30 || value > 99) { return; /* invalid */ }
break;
default:
return; /* invalid */
}
}
ac->begin();
ac->setMessageType(argoIrMessageType_t::CONFIG_PARAM_SET);
ac->setConfigEntry(param, value);
ac->send();
}
/// Send an Argo A/C WREM-3 Delay timer command.
/// @param[in, out] ac A Ptr to an IRArgoAC_WREM3 object to use.
/// @param[in] on Whether the unit is currently on. The timer, upon elapse
/// will toggle this state
/// @param[in] currentTime currentTime in minutes, starting from 00:00
/// @note For timer mode, this value is not really used much so can be zero.
/// @param[in] delayMinutes Number of minutes after which the @c on state should
/// be toggled
/// @note Schedule timers are not exposed via this interface
void IRac::argoWrem3_SetTimer(IRArgoAC_WREM3 *ac, bool on,
const uint16_t currentTime, const uint16_t delayMinutes) {
ac->begin();
ac->setMessageType(argoIrMessageType_t::TIMER_COMMAND);
ac->setPower(on);
ac->setTimerType(argoTimerType_t::DELAY_TIMER);
ac->setCurrentTimeMinutes(currentTime);
// Note: Day of week is not set (no need)
ac->setDelayTimerMinutes(delayMinutes);
ac->send();
}
#endif // SEND_ARGO #endif // SEND_ARGO
#if SEND_BOSCH144 #if SEND_BOSCH144
@ -546,9 +703,12 @@ void IRac::carrier64(IRCarrierAc64 *ac,
/// @param[in] on The power setting. /// @param[in] on The power setting.
/// @param[in] mode The operation mode setting. /// @param[in] mode The operation mode setting.
/// @param[in] degrees The temperature setting in degrees. /// @param[in] degrees The temperature setting in degrees.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading in degrees
/// Celsius.
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting. /// @param[in] swingv The vertical swing setting.
/// @param[in] swingh The horizontal swing setting. /// @param[in] swingh The horizontal swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] light Turn on the LED/Display mode. /// @param[in] light Turn on the LED/Display mode.
/// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc /// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc
@ -556,10 +716,11 @@ void IRac::carrier64(IRCarrierAc64 *ac,
/// @note -1 is Off, >= 0 is on. /// @note -1 is Off, >= 0 is on.
void IRac::coolix(IRCoolixAC *ac, void IRac::coolix(IRCoolixAC *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool light, const bool clean, const bool iFeel, const bool turbo, const bool light,
const int16_t sleep) { const bool clean, const int16_t sleep) {
ac->begin(); ac->begin();
ac->setPower(on); ac->setPower(on);
if (!on) { if (!on) {
@ -576,6 +737,12 @@ void IRac::coolix(IRCoolixAC *ac,
// No Clock setting available. // No Clock setting available.
// No Econo setting available. // No Econo setting available.
// No Quiet setting available. // No Quiet setting available.
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
} else {
ac->clearSensorTemp();
}
ac->setZoneFollow(iFeel);
ac->send(); // Send the state, which will also power on the unit. ac->send(); // Send the state, which will also power on the unit.
// The following are all options/settings that create their own special // The following are all options/settings that create their own special
// messages. Often they only make sense to be sent after the unit is turned // messages. Often they only make sense to be sent after the unit is turned
@ -940,13 +1107,16 @@ void IRac::delonghiac(IRDelonghiAc *ac,
/// @param[in] on The power setting. /// @param[in] on The power setting.
/// @param[in] mode The operation mode setting. /// @param[in] mode The operation mode setting.
/// @param[in] degrees The temperature setting in degrees. /// @param[in] degrees The temperature setting in degrees.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading in degrees
/// Celsius.
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on.
/// @param[in] clock The time in Nr. of mins since midnight. < 0 is ignore. /// @param[in] clock The time in Nr. of mins since midnight. < 0 is ignore.
void IRac::ecoclim(IREcoclimAc *ac, void IRac::ecoclim(IREcoclimAc *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const int16_t sleep, const int16_t clock) { const stdAc::fanspeed_t fan, const int16_t sleep,
const int16_t clock) {
ac->begin(); ac->begin();
ac->setPower(on); ac->setPower(on);
uint8_t new_mode; uint8_t new_mode;
@ -956,8 +1126,13 @@ void IRac::ecoclim(IREcoclimAc *ac,
new_mode = ac->convertMode(mode); // Not Sleep, so use the supplied mode. new_mode = ac->convertMode(mode); // Not Sleep, so use the supplied mode.
ac->setMode(new_mode); ac->setMode(new_mode);
ac->setTemp(degrees); ac->setTemp(degrees);
ac->setSensorTemp(degrees); //< Set to the desired temp until we cab disable.
ac->setFan(ac->convertFan(fan)); ac->setFan(ac->convertFan(fan));
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
} else {
ac->setSensorTemp(degrees); //< Set to the desired temp
// until we can disable.
}
// No SwingV setting available // No SwingV setting available
// No SwingH setting available // No SwingH setting available
// No Quiet setting available. // No Quiet setting available.
@ -979,22 +1154,28 @@ void IRac::ecoclim(IREcoclimAc *ac,
/// @param[in] on The power setting. /// @param[in] on The power setting.
/// @param[in] mode The operation mode setting. /// @param[in] mode The operation mode setting.
/// @param[in] degrees The temperature setting in degrees. /// @param[in] degrees The temperature setting in degrees.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading in degrees
/// Celsius.
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting. /// @param[in] swingv The vertical swing setting.
/// @param[in] swingh The horizontal swing setting. /// @param[in] swingh The horizontal swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] lighttoggle Should we toggle the LED/Display? /// @param[in] lighttoggle Should we toggle the LED/Display?
/// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc /// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc
void IRac::electra(IRElectraAc *ac, void IRac::electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const stdAc::swingv_t swingv, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh, const bool turbo, const stdAc::swingh_t swingh, const bool iFeel,
const bool lighttoggle, const bool clean) { const bool turbo, const bool lighttoggle, const bool clean) {
ac->begin(); ac->begin();
ac->setPower(on); ac->setPower(on);
ac->setMode(ac->convertMode(mode)); ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees); ac->setTemp(degrees);
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
}
ac->setFan(ac->convertFan(fan)); ac->setFan(ac->convertFan(fan));
ac->setSwingV(swingv != stdAc::swingv_t::kOff); ac->setSwingV(swingv != stdAc::swingv_t::kOff);
ac->setSwingH(swingh != stdAc::swingh_t::kOff); ac->setSwingH(swingh != stdAc::swingh_t::kOff);
@ -1007,6 +1188,7 @@ void IRac::electra(IRElectraAc *ac,
// No Beep setting available. // No Beep setting available.
// No Sleep setting available. // No Sleep setting available.
// No Clock setting available. // No Clock setting available.
ac->setIFeel(iFeel);
ac->send(); ac->send();
} }
#endif // SEND_ELECTRA_AC #endif // SEND_ELECTRA_AC
@ -1132,6 +1314,7 @@ void IRac::goodweather(IRGoodweatherAc *ac,
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting. /// @param[in] swingv The vertical swing setting.
/// @param[in] swingh The horizontal swing setting. /// @param[in] swingh The horizontal swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] econo Toggle the device's economical mode. /// @param[in] econo Toggle the device's economical mode.
/// @param[in] light Turn on the LED/Display mode. /// @param[in] light Turn on the LED/Display mode.
@ -1141,8 +1324,8 @@ void IRac::gree(IRGreeAC *ac, const gree_ac_remote_model_t model,
const bool on, const stdAc::opmode_t mode, const bool celsius, const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool econo, const bool light, const bool iFeel, const bool turbo, const bool econo,
const bool clean, const int16_t sleep) { const bool light, const bool clean, const int16_t sleep) {
ac->begin(); ac->begin();
ac->setModel(model); ac->setModel(model);
ac->setPower(on); ac->setPower(on);
@ -1152,6 +1335,7 @@ void IRac::gree(IRGreeAC *ac, const gree_ac_remote_model_t model,
ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag. ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag.
ac->convertSwingV(swingv)); ac->convertSwingV(swingv));
ac->setSwingHorizontal(ac->convertSwingH(swingh)); ac->setSwingHorizontal(ac->convertSwingH(swingh));
ac->setIFeel(iFeel);
ac->setLight(light); ac->setLight(light);
ac->setTurbo(turbo); ac->setTurbo(turbo);
ac->setEcono(econo); ac->setEcono(econo);
@ -1661,8 +1845,11 @@ void IRac::lg(IRLgAc *ac, const lg_ac_remote_model_t model,
/// @param[in] mode The operation mode setting. /// @param[in] mode The operation mode setting.
/// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit. /// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit.
/// @param[in] degrees The temperature setting in degrees. /// @param[in] degrees The temperature setting in degrees.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading
/// in degrees.
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting. /// @param[in] swingv The vertical swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] quiet Run the device in quiet/silent mode. /// @param[in] quiet Run the device in quiet/silent mode.
/// @param[in] quiet_prev The device's previous quiet/silent mode. /// @param[in] quiet_prev The device's previous quiet/silent mode.
/// @param[in] turbo Toggle the device's turbo/powerful mode. /// @param[in] turbo Toggle the device's turbo/powerful mode.
@ -1673,9 +1860,9 @@ void IRac::lg(IRLgAc *ac, const lg_ac_remote_model_t model,
/// @note On Danby A/C units, swingv controls the Ion Filter instead. /// @note On Danby A/C units, swingv controls the Ion Filter instead.
void IRac::midea(IRMideaAC *ac, void IRac::midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius, const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const stdAc::swingv_t swingv, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool quiet, const bool quiet_prev, const bool iFeel, const bool quiet, const bool quiet_prev,
const bool turbo, const bool econo, const bool light, const bool turbo, const bool econo, const bool light,
const bool clean, const int16_t sleep) { const bool clean, const int16_t sleep) {
ac->begin(); ac->begin();
@ -1683,6 +1870,10 @@ void IRac::midea(IRMideaAC *ac,
ac->setMode(ac->convertMode(mode)); ac->setMode(ac->convertMode(mode));
ac->setUseCelsius(celsius); ac->setUseCelsius(celsius);
ac->setTemp(degrees, celsius); ac->setTemp(degrees, celsius);
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(sensorTemp, celsius);
}
ac->setEnableSensorTemp(iFeel);
ac->setFan(ac->convertFan(fan)); ac->setFan(ac->convertFan(fan));
ac->setSwingVToggle(swingv != stdAc::swingv_t::kOff); ac->setSwingVToggle(swingv != stdAc::swingv_t::kOff);
// No Horizontal swing setting available. // No Horizontal swing setting available.
@ -2080,19 +2271,29 @@ void IRac::samsung(IRSamsungAc *ac,
/// @param[in] on The power setting. /// @param[in] on The power setting.
/// @param[in] mode The operation mode setting. /// @param[in] mode The operation mode setting.
/// @param[in] degrees The temperature setting in degrees. /// @param[in] degrees The temperature setting in degrees.
/// @param[in] sensorTemp The room (iFeel) temperature sensor reading in degrees
/// Celsius.
/// @param[in] fan The speed setting for the fan. /// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting. /// @param[in] swingv The vertical swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] beep Enable/Disable beeps when receiving IR messages. /// @param[in] beep Enable/Disable beeps when receiving IR messages.
/// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on.
void IRac::sanyo(IRSanyoAc *ac, void IRac::sanyo(IRSanyoAc *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const stdAc::swingv_t swingv, const bool beep, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const int16_t sleep) { const bool iFeel, const bool beep, const int16_t sleep) {
ac->begin(); ac->begin();
ac->setPower(on); ac->setPower(on);
ac->setMode(ac->convertMode(mode)); ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees); ac->setTemp(degrees);
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
} else {
ac->setSensorTemp(degrees); // Set the sensor temp to the desired
// (normal) temp.
}
ac->setSensor(!iFeel);
ac->setFan(ac->convertFan(fan)); ac->setFan(ac->convertFan(fan));
ac->setSwingV(ac->convertSwingV(swingv)); ac->setSwingV(ac->convertSwingV(swingv));
// No Horizontal swing setting available. // No Horizontal swing setting available.
@ -2105,10 +2306,6 @@ void IRac::sanyo(IRSanyoAc *ac,
ac->setBeep(beep); ac->setBeep(beep);
ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean. ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
// No Clock setting available. // No Clock setting available.
// Extra
ac->setSensor(true); // Set the A/C to use the temp sensor in the Unit/Wall.
ac->setSensorTemp(degrees); // Set the sensor temp to the desired temp.
ac->send(); ac->send();
} }
#endif // SEND_SANYO_AC #endif // SEND_SANYO_AC
@ -2801,6 +2998,11 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
// Convert the temp from Fahrenheit to Celsius if we are not in Celsius mode. // Convert the temp from Fahrenheit to Celsius if we are not in Celsius mode.
float degC __attribute__((unused)) = float degC __attribute__((unused)) =
desired.celsius ? desired.degrees : fahrenheitToCelsius(desired.degrees); desired.celsius ? desired.degrees : fahrenheitToCelsius(desired.degrees);
// Convert the sensorTemp from Fahrenheit to Celsius if we are not in Celsius
// mode.
float sensorTempC __attribute__((unused)) =
desired.sensorTemperature ? desired.sensorTemperature
: fahrenheitToCelsius(desired.sensorTemperature);
// special `state_t` that is required to be sent based on that. // special `state_t` that is required to be sent based on that.
stdAc::state_t send = this->handleToggles(this->cleanState(desired), prev); stdAc::state_t send = this->handleToggles(this->cleanState(desired), prev);
// Some protocols expect a previous state for power. // Some protocols expect a previous state for power.
@ -2850,9 +3052,36 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
#if SEND_ARGO #if SEND_ARGO
case ARGO: case ARGO:
{ {
IRArgoAC ac(_pin, _inverted, _modulation); if (send.model == argo_ac_remote_model_t::SAC_WREM3) {
argo(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, IRArgoAC_WREM3 ac(_pin, _inverted, _modulation);
send.turbo, send.sleep); switch (send.command) {
case stdAc::ac_command_t::kSensorTempReport:
argoWrem3_iFeelReport(&ac, sensorTempC);
break;
case stdAc::ac_command_t::kConfigCommand:
/// @warning: this is ABUSING current **common** parameters:
/// @c clock and @c sleep as config key and value
/// Hence, value pre-validation is performed (safe-mode)
/// to avoid accidental device misconfiguration
argoWrem3_ConfigSet(&ac, send.clock, send.sleep, true);
break;
case stdAc::ac_command_t::kTimerCommand:
argoWrem3_SetTimer(&ac, send.power, send.clock, send.sleep);
break;
case stdAc::ac_command_t::kControlCommand:
default:
argoWrem3_ACCommand(&ac, send.power, send.mode, degC, sensorTempC,
send.fanspeed, send.swingv, send.iFeel, send.quiet, send.econo,
send.turbo, send.filter, send.light);
break;
}
OUTPUT_DECODE_RESULTS_FOR_UT(ac);
} else {
IRArgoAC ac(_pin, _inverted, _modulation);
argo(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.swingv, send.iFeel, send.turbo, send.sleep);
OUTPUT_DECODE_RESULTS_FOR_UT(ac);
}
break; break;
} }
#endif // SEND_ARGO #endif // SEND_ARGO
@ -2877,8 +3106,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case COOLIX: case COOLIX:
{ {
IRCoolixAC ac(_pin, _inverted, _modulation); IRCoolixAC ac(_pin, _inverted, _modulation);
coolix(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, coolix(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.swingh, send.turbo, send.light, send.clean, send.sleep); send.swingv, send.swingh, send.iFeel, send.turbo, send.light,
send.clean, send.sleep);
break; break;
} }
#endif // SEND_COOLIX #endif // SEND_COOLIX
@ -2976,7 +3206,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case ECOCLIM: case ECOCLIM:
{ {
IREcoclimAc ac(_pin, _inverted, _modulation); IREcoclimAc ac(_pin, _inverted, _modulation);
ecoclim(&ac, send.power, send.mode, degC, send.fanspeed, send.clock); ecoclim(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.iFeel, send.clock);
break; break;
} }
#endif // SEND_ECOCLIM #endif // SEND_ECOCLIM
@ -2984,8 +3215,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case ELECTRA_AC: case ELECTRA_AC:
{ {
IRElectraAc ac(_pin, _inverted, _modulation); IRElectraAc ac(_pin, _inverted, _modulation);
electra(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, electra(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.swingh, send.turbo, send.light, send.clean); send.swingv, send.swingh, send.iFeel, send.turbo, send.light,
send.clean);
break; break;
} }
#endif // SEND_ELECTRA_AC #endif // SEND_ELECTRA_AC
@ -3153,8 +3385,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
{ {
IRMideaAC ac(_pin, _inverted, _modulation); IRMideaAC ac(_pin, _inverted, _modulation);
midea(&ac, send.power, send.mode, send.celsius, send.degrees, midea(&ac, send.power, send.mode, send.celsius, send.degrees,
send.fanspeed, send.swingv, send.quiet, prev_quiet, send.turbo, send.sensorTemperature, send.fanspeed, send.swingv, send.iFeel,
send.econo, send.light, send.sleep); send.quiet, prev_quiet, send.turbo, send.econo, send.light,
send.clean, send.sleep);
break; break;
} }
#endif // SEND_MIDEA #endif // SEND_MIDEA
@ -3263,8 +3496,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case SANYO_AC: case SANYO_AC:
{ {
IRSanyoAc ac(_pin, _inverted, _modulation); IRSanyoAc ac(_pin, _inverted, _modulation);
sanyo(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, sanyo(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.beep, send.sleep); send.swingv, send.iFeel, send.beep, send.sleep);
break; break;
} }
#endif // SEND_SANYO_AC #endif // SEND_SANYO_AC
@ -3421,7 +3654,9 @@ bool IRac::cmpStates(const stdAc::state_t a, const stdAc::state_t b) {
a.fanspeed != b.fanspeed || a.swingv != b.swingv || a.fanspeed != b.fanspeed || a.swingv != b.swingv ||
a.swingh != b.swingh || a.quiet != b.quiet || a.turbo != b.turbo || a.swingh != b.swingh || a.quiet != b.quiet || a.turbo != b.turbo ||
a.econo != b.econo || a.light != b.light || a.filter != b.filter || a.econo != b.econo || a.light != b.light || a.filter != b.filter ||
a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep; a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep ||
a.command != b.command || a.sensorTemperature != b.sensorTemperature ||
a.iFeel != b.iFeel;
} }
/// Check if the internal state has changed from what was previously sent. /// Check if the internal state has changed from what was previously sent.
@ -3429,6 +3664,26 @@ bool IRac::cmpStates(const stdAc::state_t a, const stdAc::state_t b) {
/// @return True if it has changed, False if not. /// @return True if it has changed, False if not.
bool IRac::hasStateChanged(void) { return cmpStates(next, _prev); } bool IRac::hasStateChanged(void) { return cmpStates(next, _prev); }
/// Convert the supplied str into the appropriate enum.
/// @param[in] str A Ptr to a C-style string to be converted.
/// @param[in] def The enum to return if no conversion was possible.
/// @return The equivalent enum.
stdAc::ac_command_t IRac::strToCommandType(const char *str,
const stdAc::ac_command_t def) {
if (!STRCASECMP(str, kControlCommandStr))
return stdAc::ac_command_t::kControlCommand;
else if (!STRCASECMP(str, kIFeelReportStr) ||
!STRCASECMP(str, kIFeelStr))
return stdAc::ac_command_t::kSensorTempReport;
else if (!STRCASECMP(str, kSetTimerCommandStr) ||
!STRCASECMP(str, kTimerStr))
return stdAc::ac_command_t::kTimerCommand;
else if (!STRCASECMP(str, kConfigCommandStr))
return stdAc::ac_command_t::kConfigCommand;
else
return def;
}
/// Convert the supplied str into the appropriate enum. /// Convert the supplied str into the appropriate enum.
/// @param[in] str A Ptr to a C-style string to be converted. /// @param[in] str A Ptr to a C-style string to be converted.
/// @param[in] def The enum to return if no conversion was possible. /// @param[in] def The enum to return if no conversion was possible.
@ -3492,6 +3747,8 @@ stdAc::fanspeed_t IRac::strToFanspeed(const char *str,
!STRCASECMP(str, kMaximumStr) || !STRCASECMP(str, kMaximumStr) ||
!STRCASECMP(str, kHighestStr)) !STRCASECMP(str, kHighestStr))
return stdAc::fanspeed_t::kMax; return stdAc::fanspeed_t::kMax;
else if (!STRCASECMP(str, kMedHighStr))
return stdAc::fanspeed_t::kMediumHigh;
else else
return def; return def;
} }
@ -3524,6 +3781,8 @@ stdAc::swingv_t IRac::strToSwingV(const char *str,
!STRCASECMP(str, kMediumStr) || !STRCASECMP(str, kMediumStr) ||
!STRCASECMP(str, kCentreStr)) !STRCASECMP(str, kCentreStr))
return stdAc::swingv_t::kMiddle; return stdAc::swingv_t::kMiddle;
else if (!STRCASECMP(str, kUpperMiddleStr))
return stdAc::swingv_t::kUpperMiddle;
else if (!STRCASECMP(str, kHighStr) || else if (!STRCASECMP(str, kHighStr) ||
!STRCASECMP(str, kHiStr)) !STRCASECMP(str, kHiStr))
return stdAc::swingv_t::kHigh; return stdAc::swingv_t::kHigh;
@ -3666,6 +3925,11 @@ int16_t IRac::strToModel(const char *str, const int16_t def) {
return whirlpool_ac_remote_model_t::DG11J13A; return whirlpool_ac_remote_model_t::DG11J13A;
} else if (!STRCASECMP(str, kDg11j191Str)) { } else if (!STRCASECMP(str, kDg11j191Str)) {
return whirlpool_ac_remote_model_t::DG11J191; return whirlpool_ac_remote_model_t::DG11J191;
// Argo A/C models
} else if (!STRCASECMP(str, kArgoWrem2Str)) {
return argo_ac_remote_model_t::SAC_WREM2;
} else if (!STRCASECMP(str, kArgoWrem3Str)) {
return argo_ac_remote_model_t::SAC_WREM3;
} else { } else {
int16_t number = atoi(str); int16_t number = atoi(str);
if (number > 0) if (number > 0)
@ -3701,6 +3965,19 @@ String IRac::boolToString(const bool value) {
return value ? kOnStr : kOffStr; return value ? kOnStr : kOffStr;
} }
/// Convert the supplied operation mode into the appropriate String.
/// @param[in] cmdType The enum to be converted.
/// @return The equivalent String for the locale.
String IRac::commandTypeToString(const stdAc::ac_command_t cmdType) {
switch (cmdType) {
case stdAc::ac_command_t::kControlCommand: return kControlCommandStr;
case stdAc::ac_command_t::kSensorTempReport: return kIFeelReportStr;
case stdAc::ac_command_t::kTimerCommand: return kSetTimerCommandStr;
case stdAc::ac_command_t::kConfigCommand: return kConfigCommandStr;
default: return kUnknownStr;
}
}
/// Convert the supplied operation mode into the appropriate String. /// Convert the supplied operation mode into the appropriate String.
/// @param[in] mode The enum to be converted. /// @param[in] mode The enum to be converted.
/// @param[in] ha A flag to indicate we want GoogleHome/HomeAssistant output. /// @param[in] ha A flag to indicate we want GoogleHome/HomeAssistant output.
@ -3722,13 +3999,14 @@ String IRac::opmodeToString(const stdAc::opmode_t mode, const bool ha) {
/// @return The equivalent String for the locale. /// @return The equivalent String for the locale.
String IRac::fanspeedToString(const stdAc::fanspeed_t speed) { String IRac::fanspeedToString(const stdAc::fanspeed_t speed) {
switch (speed) { switch (speed) {
case stdAc::fanspeed_t::kAuto: return kAutoStr; case stdAc::fanspeed_t::kAuto: return kAutoStr;
case stdAc::fanspeed_t::kMax: return kMaxStr; case stdAc::fanspeed_t::kMax: return kMaxStr;
case stdAc::fanspeed_t::kHigh: return kHighStr; case stdAc::fanspeed_t::kHigh: return kHighStr;
case stdAc::fanspeed_t::kMedium: return kMediumStr; case stdAc::fanspeed_t::kMedium: return kMediumStr;
case stdAc::fanspeed_t::kLow: return kLowStr; case stdAc::fanspeed_t::kMediumHigh: return kMedHighStr;
case stdAc::fanspeed_t::kMin: return kMinStr; case stdAc::fanspeed_t::kLow: return kLowStr;
default: return kUnknownStr; case stdAc::fanspeed_t::kMin: return kMinStr;
default: return kUnknownStr;
} }
} }
@ -3737,14 +4015,15 @@ String IRac::fanspeedToString(const stdAc::fanspeed_t speed) {
/// @return The equivalent String for the locale. /// @return The equivalent String for the locale.
String IRac::swingvToString(const stdAc::swingv_t swingv) { String IRac::swingvToString(const stdAc::swingv_t swingv) {
switch (swingv) { switch (swingv) {
case stdAc::swingv_t::kOff: return kOffStr; case stdAc::swingv_t::kOff: return kOffStr;
case stdAc::swingv_t::kAuto: return kAutoStr; case stdAc::swingv_t::kAuto: return kAutoStr;
case stdAc::swingv_t::kHighest: return kHighestStr; case stdAc::swingv_t::kHighest: return kHighestStr;
case stdAc::swingv_t::kHigh: return kHighStr; case stdAc::swingv_t::kHigh: return kHighStr;
case stdAc::swingv_t::kMiddle: return kMiddleStr; case stdAc::swingv_t::kMiddle: return kMiddleStr;
case stdAc::swingv_t::kLow: return kLowStr; case stdAc::swingv_t::kUpperMiddle: return kUpperMiddleStr;
case stdAc::swingv_t::kLowest: return kLowestStr; case stdAc::swingv_t::kLow: return kLowStr;
default: return kUnknownStr; case stdAc::swingv_t::kLowest: return kLowestStr;
default: return kUnknownStr;
} }
} }
@ -3796,8 +4075,14 @@ namespace IRAcUtils {
#endif // DECODE_AMCOR #endif // DECODE_AMCOR
#if DECODE_ARGO #if DECODE_ARGO
case decode_type_t::ARGO: { case decode_type_t::ARGO: {
if (IRArgoAC_WREM3::isValidWrem3Message(result->state, result->bits,
true)) {
IRArgoAC_WREM3 ac(kGpioUnused);
ac.setRaw(result->state, result->bits / 8);
return ac.toString();
}
IRArgoAC ac(kGpioUnused); IRArgoAC ac(kGpioUnused);
ac.setRaw(result->state); ac.setRaw(result->state, result->bits / 8);
return ac.toString(); return ac.toString();
} }
#endif // DECODE_ARGO #endif // DECODE_ARGO
@ -4211,6 +4496,13 @@ namespace IRAcUtils {
return ac.toString(); return ac.toString();
} }
#endif // DECODE_WHIRLPOOL_AC #endif // DECODE_WHIRLPOOL_AC
#if DECODE_YORK
case decode_type_t::YORK: {
IRYorkAc ac(kGpioUnused);
ac.setRaw(result->state);
return ac.toString();
}
#endif // DECODE_YORK
default: default:
return ""; return "";
} }
@ -4258,9 +4550,24 @@ namespace IRAcUtils {
#endif // DECODE_AMCOR #endif // DECODE_AMCOR
#if DECODE_ARGO #if DECODE_ARGO
case decode_type_t::ARGO: { case decode_type_t::ARGO: {
IRArgoAC ac(kGpioUnused); const uint16_t length = decode->bits / 8;
ac.setRaw(decode->state); if (IRArgoAC_WREM3::isValidWrem3Message(decode->state,
*result = ac.toCommon(); decode->bits, true)) {
IRArgoAC_WREM3 ac(kGpioUnused);
ac.setRaw(decode->state, length);
*result = ac.toCommon();
} else {
IRArgoAC ac(kGpioUnused);
switch (length) {
case kArgoStateLength:
case kArgoShortStateLength:
ac.setRaw(decode->state, length);
*result = ac.toCommon();
break;
default:
return false;
}
}
break; break;
} }
#endif // DECODE_ARGO #endif // DECODE_ARGO
@ -4732,6 +5039,14 @@ namespace IRAcUtils {
break; break;
} }
#endif // DECODE_WHIRLPOOL_AC #endif // DECODE_WHIRLPOOL_AC
#if DECODE_YORK
case decode_type_t::YORK: {
IRYorkAc ac(kGpioUnused);
ac.setRaw(decode->state);
*result = ac.toCommon(prev);
break;
}
#endif // DECODE_YORK
default: default:
return false; return false;
} }

View File

@ -5,6 +5,8 @@
#ifndef UNIT_TEST #ifndef UNIT_TEST
#include <Arduino.h> #include <Arduino.h>
#else
#include <memory>
#endif #endif
#include "IRremoteESP8266.h" #include "IRremoteESP8266.h"
#include "ir_Airton.h" #include "ir_Airton.h"
@ -47,6 +49,7 @@
#include "ir_Vestel.h" #include "ir_Vestel.h"
#include "ir_Voltas.h" #include "ir_Voltas.h"
#include "ir_Whirlpool.h" #include "ir_Whirlpool.h"
#include "ir_York.h"
// Constants // Constants
const int8_t kGpioUnused = -1; ///< A placeholder for not using an actual GPIO. const int8_t kGpioUnused = -1; ///< A placeholder for not using an actual GPIO.
@ -84,6 +87,8 @@ class IRac {
static bool cmpStates(const stdAc::state_t a, const stdAc::state_t b); static bool cmpStates(const stdAc::state_t a, const stdAc::state_t b);
static bool strToBool(const char *str, const bool def = false); static bool strToBool(const char *str, const bool def = false);
static int16_t strToModel(const char *str, const int16_t def = -1); static int16_t strToModel(const char *str, const int16_t def = -1);
static stdAc::ac_command_t strToCommandType(const char *str,
const stdAc::ac_command_t def = stdAc::ac_command_t::kControlCommand);
static stdAc::opmode_t strToOpmode( static stdAc::opmode_t strToOpmode(
const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto); const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto);
static stdAc::fanspeed_t strToFanspeed( static stdAc::fanspeed_t strToFanspeed(
@ -94,6 +99,7 @@ class IRac {
static stdAc::swingh_t strToSwingH( static stdAc::swingh_t strToSwingH(
const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff); const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff);
static String boolToString(const bool value); static String boolToString(const bool value);
static String commandTypeToString(const stdAc::ac_command_t cmdType);
static String opmodeToString(const stdAc::opmode_t mode, static String opmodeToString(const stdAc::opmode_t mode,
const bool ha = false); const bool ha = false);
static String fanspeedToString(const stdAc::fanspeed_t speed); static String fanspeedToString(const stdAc::fanspeed_t speed);
@ -103,10 +109,17 @@ class IRac {
stdAc::state_t getStatePrev(void); stdAc::state_t getStatePrev(void);
bool hasStateChanged(void); bool hasStateChanged(void);
stdAc::state_t next; ///< The state we want the device to be in after we send stdAc::state_t next; ///< The state we want the device to be in after we send
#ifndef UNIT_TEST #ifdef UNIT_TEST
/// @cond IGNORE
/// UT-specific
/// See @c OUTPUT_DECODE_RESULTS_FOR_UT macro description in IRac.cpp
std::shared_ptr<IRrecv> _utReceiver = nullptr;
std::unique_ptr<decode_results> _lastDecodeResults = nullptr;
/// @endcond
#else
private: private:
#endif #endif // UNIT_TEST
uint16_t _pin; ///< The GPIO to use to transmit messages from. uint16_t _pin; ///< The GPIO to use to transmit messages from.
bool _inverted; ///< IR LED is lit when GPIO is LOW (true) or HIGH (false)? bool _inverted; ///< IR LED is lit when GPIO is LOW (true) or HIGH (false)?
bool _modulation; ///< Is frequency modulation to be used? bool _modulation; ///< Is frequency modulation to be used?
@ -132,15 +145,26 @@ class IRac {
#if SEND_ARGO #if SEND_ARGO
void argo(IRArgoAC *ac, void argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees, const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const float sensorTemp, const stdAc::fanspeed_t fan,
const bool turbo, const int16_t sleep = -1); const stdAc::swingv_t swingv, const bool iFeel, const bool turbo,
const int16_t sleep = -1);
void argoWrem3_ACCommand(IRArgoAC_WREM3 *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const float sensorTemp, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool iFeel, const bool night,
const bool econo, const bool turbo, const bool filter, const bool light);
void argoWrem3_iFeelReport(IRArgoAC_WREM3 *ac, const float sensorTemp);
void argoWrem3_ConfigSet(IRArgoAC_WREM3 *ac, const uint8_t param,
const uint8_t value, bool safe = true);
void argoWrem3_SetTimer(IRArgoAC_WREM3 *ac, bool on,
const uint16_t currentTime, const uint16_t delayMinutes);
#endif // SEND_ARGO #endif // SEND_ARGO
#if SEND_BOSCH144 #if SEND_BOSCH144
void bosch144(IRBosch144AC *ac, void bosch144(IRBosch144AC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees, const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::fanspeed_t fan,
const bool quiet); const bool quiet);
#endif // SEND_COOLIX #endif // SEND_BOSCH144
#if SEND_CARRIER_AC64 #if SEND_CARRIER_AC64
void carrier64(IRCarrierAc64 *ac, void carrier64(IRCarrierAc64 *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
@ -150,10 +174,10 @@ void carrier64(IRCarrierAc64 *ac,
#if SEND_COOLIX #if SEND_COOLIX
void coolix(IRCoolixAC *ac, void coolix(IRCoolixAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees, const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const float sensorTemp, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool light, const bool clean, const bool iFeel, const bool turbo, const bool light,
const int16_t sleep = -1); const bool clean, const int16_t sleep = -1);
#endif // SEND_COOLIX #endif // SEND_COOLIX
#if SEND_CORONA_AC #if SEND_CORONA_AC
void corona(IRCoronaAc *ac, void corona(IRCoronaAc *ac,
@ -231,15 +255,16 @@ void daikin216(IRDaikin216 *ac,
#if SEND_ECOCLIM #if SEND_ECOCLIM
void ecoclim(IREcoclimAc *ac, void ecoclim(IREcoclimAc *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const int16_t sleep = -1, const int16_t clock = -1); const stdAc::fanspeed_t fan, const int16_t sleep = -1,
const int16_t clock = -1);
#endif // SEND_ECOCLIM #endif // SEND_ECOCLIM
#if SEND_ELECTRA_AC #if SEND_ELECTRA_AC
void electra(IRElectraAc *ac, void electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode, const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const stdAc::swingv_t swingv, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh, const bool turbo, const stdAc::swingh_t swingh, const bool iFeel, const bool turbo,
const bool lighttoggle, const bool clean); const bool lighttoggle, const bool clean);
#endif // SEND_ELECTRA_AC #endif // SEND_ELECTRA_AC
#if SEND_FUJITSU_AC #if SEND_FUJITSU_AC
@ -265,8 +290,8 @@ void electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius, const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool econo, const bool light, const bool iFeel, const bool turbo, const bool econo,
const bool clean, const int16_t sleep = -1); const bool light, const bool clean, const int16_t sleep = -1);
#endif // SEND_GREE #endif // SEND_GREE
#if SEND_HAIER_AC #if SEND_HAIER_AC
void haier(IRHaierAC *ac, void haier(IRHaierAC *ac,
@ -363,11 +388,11 @@ void electra(IRElectraAc *ac,
#if SEND_MIDEA #if SEND_MIDEA
void midea(IRMideaAC *ac, void midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius, const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan, const float degrees, const float sensorTemp,
const stdAc::swingv_t swingv, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool quiet, const bool quiet_prev, const bool turbo, const bool iFeel, const bool quiet, const bool quiet_prev,
const bool econo, const bool light, const bool clean, const bool turbo, const bool econo, const bool light,
const int16_t sleep = -1); const bool clean, const int16_t sleep = -1);
#endif // SEND_MIDEA #endif // SEND_MIDEA
#if SEND_MIRAGE #if SEND_MIRAGE
void mirage(IRMirageAc *ac, const stdAc::state_t state); void mirage(IRMirageAc *ac, const stdAc::state_t state);
@ -451,8 +476,9 @@ void electra(IRElectraAc *ac,
#if SEND_SANYO_AC #if SEND_SANYO_AC
void sanyo(IRSanyoAc *ac, void sanyo(IRSanyoAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees, const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const float sensorTemp, const stdAc::fanspeed_t fan,
const bool beep, const int16_t sleep = -1); const stdAc::swingv_t swingv, const bool iFeel, const bool beep,
const int16_t sleep = -1);
#endif // SEND_SANYO_AC #endif // SEND_SANYO_AC
#if SEND_SANYO_AC88 #if SEND_SANYO_AC88
void sanyo88(IRSanyoAc88 *ac, void sanyo88(IRSanyoAc88 *ac,

View File

@ -34,7 +34,7 @@
#if !VA_OPT_SUPPORTED #if !VA_OPT_SUPPORTED
// #pragma message("Compiler without __VA_OPT__ support") // #pragma message("Compiler without __VA_OPT__ support")
#define COND(cond, a, b) a #define COND(cond, a, b) a
#else #else // !VA_OPT_SUPPORTED
#define NOTHING #define NOTHING
#define EXPAND(...) __VA_ARGS__ #define EXPAND(...) __VA_ARGS__
#define STUFF_P(a, ...) __VA_OPT__(a) #define STUFF_P(a, ...) __VA_OPT__(a)
@ -44,7 +44,7 @@
#define NEGATE(a) VA_TEST(a, a) #define NEGATE(a) VA_TEST(a, a)
#define COND_P(cond, a, b) STUFF(a, cond)STUFF(b, NEGATE(cond)) #define COND_P(cond, a, b) STUFF(a, cond)STUFF(b, NEGATE(cond))
#define COND(cond, a, b) EXPAND(COND_P(cond, a, b)) #define COND(cond, a, b) EXPAND(COND_P(cond, a, b))
#endif #endif // !VA_OPT_SUPPORTED
/// @endcond /// @endcond
/** /**
* end of COND() set of macros * end of COND() set of macros

View File

@ -399,6 +399,7 @@ void IRrecv::disableIRIn(void) {
#endif // ESP8266 #endif // ESP8266
#if defined(ESP32) #if defined(ESP32)
timerAlarmDisable(timer); timerAlarmDisable(timer);
timerDetachInterrupt(timer);
timerEnd(timer); timerEnd(timer);
#endif // ESP32 #endif // ESP32
detachInterrupt(params.recvpin); detachInterrupt(params.recvpin);
@ -709,9 +710,12 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
return true; return true;
#endif #endif
#if DECODE_PANASONIC #if DECODE_PANASONIC
DPRINTLN("Attempting Panasonic decode"); DPRINTLN("Attempting Panasonic (48-bit) decode");
if (decodePanasonic(results, offset)) return true; if (decodePanasonic(results, offset)) return true;
#endif DPRINTLN("Attempting Panasonic (40-bit) decode");
if (decodePanasonic(results, offset, kPanasonic40Bits, true,
kPanasonic40Manufacturer)) return true;
#endif // DECODE_PANASONIC
#if DECODE_LG #if DECODE_LG
DPRINTLN("Attempting LG (28-bit) decode"); DPRINTLN("Attempting LG (28-bit) decode");
if (decodeLG(results, offset, kLgBits, true)) return true; if (decodeLG(results, offset, kLgBits, true)) return true;
@ -951,8 +955,21 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
return true; return true;
#endif #endif
#if DECODE_ARGO #if DECODE_ARGO
DPRINTLN("Attempting Argo decode"); DPRINTLN("Attempting Argo WREM3 decode (AC Control)");
if (decodeArgo(results, offset)) return true; if (decodeArgoWREM3(results, offset, kArgo3AcControlStateLength * 8, true))
return true;
DPRINTLN("Attempting Argo WREM3 decode (iFeel report)");
if (decodeArgoWREM3(results, offset, kArgo3iFeelReportStateLength * 8, true))
return true;
DPRINTLN("Attempting Argo WREM3 decode (Config)");
if (decodeArgoWREM3(results, offset, kArgo3ConfigStateLength * 8, true))
return true;
DPRINTLN("Attempting Argo WREM3 decode (Timer)");
if (decodeArgoWREM3(results, offset, kArgo3TimerStateLength * 8, true))
return true;
DPRINTLN("Attempting Argo WREM2 decode");
if (decodeArgo(results, offset, kArgoBits) ||
decodeArgo(results, offset, kArgoShortBits, false)) return true;
#endif // DECODE_ARGO #endif // DECODE_ARGO
#if DECODE_SHARP_AC #if DECODE_SHARP_AC
DPRINTLN("Attempting SHARP_AC decode"); DPRINTLN("Attempting SHARP_AC decode");
@ -1160,6 +1177,22 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Daikin 312-bit decode"); DPRINTLN("Attempting Daikin 312-bit decode");
if (decodeDaikin312(results, offset)) return true; if (decodeDaikin312(results, offset)) return true;
#endif // DECODE_DAIKIN312 #endif // DECODE_DAIKIN312
#if DECODE_GORENJE
DPRINTLN("Attempting GORENJE decode");
if (decodeGorenje(results, offset)) return true;
#endif // DECODE_GORENJE
#if DECODE_WOWWEE
DPRINTLN("Attempting WOWWEE decode");
if (decodeWowwee(results, offset)) return true;
#endif // DECODE_WOWWEE
#if DECODE_CARRIER_AC84
DPRINTLN("Attempting Carrier A/C 84-bit decode");
if (decodeCarrierAC84(results, offset)) return true;
#endif // DECODE_CARRIER_AC84
#if DECODE_YORK
DPRINTLN("Attempting York decode");
if (decodeYork(results, offset, kYorkBits)) return true;
#endif // DECODE_YORK
// Typically new protocols are added above this line. // Typically new protocols are added above this line.
} }
#if DECODE_HASH #if DECODE_HASH

View File

@ -294,6 +294,9 @@ class IRrecv {
#if DECODE_ARGO #if DECODE_ARGO
bool decodeArgo(decode_results *results, uint16_t offset = kStartOffset, bool decodeArgo(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kArgoBits, const bool strict = true); const uint16_t nbits = kArgoBits, const bool strict = true);
bool decodeArgoWREM3(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kArgo3AcControlStateLength * 8,
const bool strict = true);
#endif // DECODE_ARGO #endif // DECODE_ARGO
#if DECODE_ARRIS #if DECODE_ARRIS
bool decodeArris(decode_results *results, uint16_t offset = kStartOffset, bool decodeArris(decode_results *results, uint16_t offset = kStartOffset,
@ -580,6 +583,12 @@ class IRrecv {
const uint16_t nbits = kCarrierAc40Bits, const uint16_t nbits = kCarrierAc40Bits,
const bool strict = true); const bool strict = true);
#endif // DECODE_CARRIER_AC40 #endif // DECODE_CARRIER_AC40
#if DECODE_CARRIER_AC84
bool decodeCarrierAC84(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kCarrierAc84Bits,
const bool strict = true);
#endif // DECODE_CARRIER_AC84
#if DECODE_CARRIER_AC64 #if DECODE_CARRIER_AC64
bool decodeCarrierAC64(decode_results *results, bool decodeCarrierAC64(decode_results *results,
uint16_t offset = kStartOffset, uint16_t offset = kStartOffset,
@ -598,6 +607,11 @@ class IRrecv {
const uint16_t nbits = kGoodweatherBits, const uint16_t nbits = kGoodweatherBits,
const bool strict = true); const bool strict = true);
#endif // DECODE_GOODWEATHER #endif // DECODE_GOODWEATHER
#if DECODE_GORENJE
bool decodeGorenje(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kGorenjeBits,
const bool strict = true);
#endif // DECODE_GORENJE
#if DECODE_GREE #if DECODE_GREE
bool decodeGree(decode_results *results, uint16_t offset = kStartOffset, bool decodeGree(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kGreeBits, const uint16_t nbits = kGreeBits,
@ -857,6 +871,18 @@ class IRrecv {
const uint16_t nbits = kBosch144Bits, const uint16_t nbits = kBosch144Bits,
const bool strict = true); const bool strict = true);
#endif // DECODE_BOSCH144 #endif // DECODE_BOSCH144
#if DECODE_WOWWEE
bool decodeWowwee(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kWowweeBits,
const bool strict = true);
#endif // DECODE_WOWWEE
#if DECODE_YORK
bool decodeYork(decode_results *results,
uint16_t kStartOffset,
const uint16_t kYorkBits,
const bool strict = true);
#endif // DECODE_YORK
}; };
#endif // IRRECV_H_ #endif // IRRECV_H_

View File

@ -58,7 +58,7 @@
// Minor version number (x.X.x) // Minor version number (x.X.x)
#define _IRREMOTEESP8266_VERSION_MINOR 8 #define _IRREMOTEESP8266_VERSION_MINOR 8
// Patch version number (x.x.X) // Patch version number (x.x.X)
#define _IRREMOTEESP8266_VERSION_PATCH 4 #define _IRREMOTEESP8266_VERSION_PATCH 5
// Macro to convert version info into an integer // Macro to convert version info into an integer
#define _IRREMOTEESP8266_VERSION_VAL(major, minor, patch) \ #define _IRREMOTEESP8266_VERSION_VAL(major, minor, patch) \
(((major) << 16) | ((minor) << 8) | (patch)) (((major) << 16) | ((minor) << 8) | (patch))
@ -924,6 +924,34 @@
#define SEND_DAIKIN312 _IR_ENABLE_DEFAULT_ #define SEND_DAIKIN312 _IR_ENABLE_DEFAULT_
#endif // SEND_DAIKIN312 #endif // SEND_DAIKIN312
#ifndef DECODE_GORENJE
#define DECODE_GORENJE _IR_ENABLE_DEFAULT_
#endif // DECODE_GORENJE
#ifndef SEND_GORENJE
#define SEND_GORENJE _IR_ENABLE_DEFAULT_
#endif // SEND_GORENJE
#ifndef DECODE_WOWWEE
#define DECODE_WOWWEE _IR_ENABLE_DEFAULT_
#endif // DECODE_WOWWEE
#ifndef SEND_WOWWEE
#define SEND_WOWWEE _IR_ENABLE_DEFAULT_
#endif // SEND_WOWWEE
#ifndef DECODE_CARRIER_AC84
#define DECODE_CARRIER_AC84 _IR_ENABLE_DEFAULT_
#endif // DECODE_CARRIER_AC84
#ifndef SEND_CARRIER_AC84
#define SEND_CARRIER_AC84 _IR_ENABLE_DEFAULT_
#endif // SEND_CARRIER_AC84
#ifndef DECODE_YORK
#define DECODE_YORK _IR_ENABLE_DEFAULT_
#endif // DECODE_YORK
#ifndef SEND_YORK
#define SEND_YORK _IR_ENABLE_DEFAULT_
#endif // SEND_YORK
#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \ #if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \ DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \ DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
@ -942,6 +970,7 @@
DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \ DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \
DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \ DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \
DECODE_BOSCH144 || DECODE_SANYO_AC152 || DECODE_DAIKIN312 || \ DECODE_BOSCH144 || DECODE_SANYO_AC152 || DECODE_DAIKIN312 || \
DECODE_CARRIER_AC84 || DECODE_YORK || \
false) false)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax) // Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function // you might also want to add the protocol to hasACState function
@ -1104,8 +1133,12 @@ enum decode_type_t {
BOSCH144, // 120 BOSCH144, // 120
SANYO_AC152, SANYO_AC152,
DAIKIN312, DAIKIN312,
GORENJE,
WOWWEE,
CARRIER_AC84, // 125
YORK,
// Add new entries before this one, and update it to point to the last entry. // Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = DAIKIN312, kLastDecodeType = YORK,
}; };
// Message lengths & required repeat values // Message lengths & required repeat values
@ -1123,7 +1156,13 @@ const uint16_t kAmcorStateLength = 8;
const uint16_t kAmcorBits = kAmcorStateLength * 8; const uint16_t kAmcorBits = kAmcorStateLength * 8;
const uint16_t kAmcorDefaultRepeat = kSingleRepeat; const uint16_t kAmcorDefaultRepeat = kSingleRepeat;
const uint16_t kArgoStateLength = 12; const uint16_t kArgoStateLength = 12;
const uint16_t kArgoShortStateLength = 4;
const uint16_t kArgoBits = kArgoStateLength * 8; const uint16_t kArgoBits = kArgoStateLength * 8;
const uint16_t kArgoShortBits = kArgoShortStateLength * 8;
const uint16_t kArgo3AcControlStateLength = 6; // Bytes
const uint16_t kArgo3iFeelReportStateLength = 2; // Bytes
const uint16_t kArgo3TimerStateLength = 9; // Bytes
const uint16_t kArgo3ConfigStateLength = 4; // Bytes
const uint16_t kArgoDefaultRepeat = kNoRepeat; const uint16_t kArgoDefaultRepeat = kNoRepeat;
const uint16_t kArrisBits = 32; const uint16_t kArrisBits = 32;
const uint16_t kBosch144StateLength = 18; const uint16_t kBosch144StateLength = 18;
@ -1137,6 +1176,9 @@ const uint16_t kCarrierAc40Bits = 40;
const uint16_t kCarrierAc40MinRepeat = 2; const uint16_t kCarrierAc40MinRepeat = 2;
const uint16_t kCarrierAc64Bits = 64; const uint16_t kCarrierAc64Bits = 64;
const uint16_t kCarrierAc64MinRepeat = kNoRepeat; const uint16_t kCarrierAc64MinRepeat = kNoRepeat;
const uint16_t kCarrierAc84StateLength = 11;
const uint16_t kCarrierAc84Bits = kCarrierAc84StateLength * 8 - 4;
const uint16_t kCarrierAc84MinRepeat = kNoRepeat;
const uint16_t kCarrierAc128StateLength = 16; const uint16_t kCarrierAc128StateLength = 16;
const uint16_t kCarrierAc128Bits = kCarrierAc128StateLength * 8; const uint16_t kCarrierAc128Bits = kCarrierAc128StateLength * 8;
const uint16_t kCarrierAc128MinRepeat = kNoRepeat; const uint16_t kCarrierAc128MinRepeat = kNoRepeat;
@ -1203,6 +1245,7 @@ const uint16_t kGicableBits = 16;
const uint16_t kGicableMinRepeat = kSingleRepeat; const uint16_t kGicableMinRepeat = kSingleRepeat;
const uint16_t kGoodweatherBits = 48; const uint16_t kGoodweatherBits = 48;
const uint16_t kGoodweatherMinRepeat = kNoRepeat; const uint16_t kGoodweatherMinRepeat = kNoRepeat;
const uint16_t kGorenjeBits = 8;
const uint16_t kGreeStateLength = 8; const uint16_t kGreeStateLength = 8;
const uint16_t kGreeBits = kGreeStateLength * 8; const uint16_t kGreeBits = kGreeStateLength * 8;
const uint16_t kGreeDefaultRepeat = kNoRepeat; const uint16_t kGreeDefaultRepeat = kNoRepeat;
@ -1292,6 +1335,8 @@ const uint16_t kNeoclimaBits = kNeoclimaStateLength * 8;
const uint16_t kNeoclimaMinRepeat = kNoRepeat; const uint16_t kNeoclimaMinRepeat = kNoRepeat;
const uint16_t kPanasonicBits = 48; const uint16_t kPanasonicBits = 48;
const uint32_t kPanasonicManufacturer = 0x4004; const uint32_t kPanasonicManufacturer = 0x4004;
const uint32_t kPanasonic40Manufacturer = 0x34;
const uint16_t kPanasonic40Bits = 40;
const uint16_t kPanasonicAcStateLength = 27; const uint16_t kPanasonicAcStateLength = 27;
const uint16_t kPanasonicAcStateShortLength = 16; const uint16_t kPanasonicAcStateShortLength = 16;
const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8; const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8;
@ -1372,6 +1417,8 @@ const uint16_t kWhirlpoolAcStateLength = 21;
const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8; const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8;
const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat; const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat;
const uint16_t kWhynterBits = 32; const uint16_t kWhynterBits = 32;
const uint16_t kWowweeBits = 11;
const uint16_t kWowweeDefaultRepeat = kNoRepeat;
const uint8_t kVestelAcBits = 56; const uint8_t kVestelAcBits = 56;
const uint16_t kXmpBits = 64; const uint16_t kXmpBits = 64;
const uint16_t kZepealBits = 16; const uint16_t kZepealBits = 16;
@ -1386,6 +1433,8 @@ const uint16_t kRhossStateLength = 12;
const uint16_t kRhossBits = kRhossStateLength * 8; const uint16_t kRhossBits = kRhossStateLength * 8;
const uint16_t kRhossDefaultRepeat = 0; const uint16_t kRhossDefaultRepeat = 0;
const uint16_t kClimaButlerBits = 52; const uint16_t kClimaButlerBits = 52;
const uint16_t kYorkBits = 136;
const uint16_t kYorkStateLength = 17;
// Legacy defines. (Deprecated) // Legacy defines. (Deprecated)

View File

@ -603,7 +603,10 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) {
uint16_t IRsend::defaultBits(const decode_type_t protocol) { uint16_t IRsend::defaultBits(const decode_type_t protocol) {
switch (protocol) { switch (protocol) {
case MULTIBRACKETS: case MULTIBRACKETS:
case GORENJE:
return 8; return 8;
case WOWWEE:
return 11;
case RC5: case RC5:
case SYMPHONY: case SYMPHONY:
return 12; return 12;
@ -690,6 +693,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kBosch144Bits; return kBosch144Bits;
case CORONA_AC: case CORONA_AC:
return kCoronaAcBits; return kCoronaAcBits;
case CARRIER_AC84:
return kCarrierAc84Bits;
case CARRIER_AC128: case CARRIER_AC128:
return kCarrierAc128Bits; return kCarrierAc128Bits;
case DAIKIN: case DAIKIN:
@ -791,6 +796,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kWhirlpoolAcBits; return kWhirlpoolAcBits;
case XMP: case XMP:
return kXmpBits; return kXmpBits;
case YORK:
return kYorkBits;
// No default amount of bits. // No default amount of bits.
case FUJITSU_AC: case FUJITSU_AC:
case MWM: case MWM:
@ -916,6 +923,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendGoodweather(data, nbits, min_repeat); sendGoodweather(data, nbits, min_repeat);
break; break;
#endif #endif
#if SEND_GORENJE
case GORENJE:
sendGorenje(data, nbits, min_repeat);
break;
#endif
#if SEND_GREE #if SEND_GREE
case GREE: case GREE:
sendGree(data, nbits, min_repeat); sendGree(data, nbits, min_repeat);
@ -1114,6 +1126,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendWhynter(data, nbits, min_repeat); sendWhynter(data, nbits, min_repeat);
break; break;
#endif #endif
#if SEND_WOWWEE
case WOWWEE:
sendWowwee(data, nbits, min_repeat);
break;
#endif // SEND_WOWWEE
#if SEND_XMP #if SEND_XMP
case XMP: case XMP:
sendXmp(data, nbits, min_repeat); sendXmp(data, nbits, min_repeat);
@ -1159,6 +1176,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendBosch144(state, nbytes); sendBosch144(state, nbytes);
break; break;
#endif // SEND_BOSCH144 #endif // SEND_BOSCH144
#if SEND_CARRIER_AC84
case CARRIER_AC84:
sendCarrierAC84(state, nbytes);
break;
#endif // SEND_CARRIER_AC84
#if SEND_CARRIER_AC128 #if SEND_CARRIER_AC128
case CARRIER_AC128: case CARRIER_AC128:
sendCarrierAC128(state, nbytes); sendCarrierAC128(state, nbytes);
@ -1407,6 +1429,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendWhirlpoolAC(state, nbytes); sendWhirlpoolAC(state, nbytes);
break; break;
#endif // SEND_WHIRLPOOL_AC #endif // SEND_WHIRLPOOL_AC
#if SEND_YORK
case YORK:
sendYork(state, nbytes);
break;
#endif // SEND_YORK
default: default:
return false; return false;
} }

View File

@ -39,6 +39,9 @@ const uint8_t kDutyMax = 100; // Percentage
const uint16_t kMaxAccurateUsecDelay = 16383; const uint16_t kMaxAccurateUsecDelay = 16383;
// Usecs to wait between messages we don't know the proper gap time. // Usecs to wait between messages we don't know the proper gap time.
const uint32_t kDefaultMessageGap = 100000; const uint32_t kDefaultMessageGap = 100000;
/// Placeholder for missing sensor temp value
/// @note Not using "-1" as it may be a valid external temp
const float kNoTempValue = -100.0;
/// Enumerators and Structures for the Common A/C API. /// Enumerators and Structures for the Common A/C API.
namespace stdAc { namespace stdAc {
@ -56,14 +59,15 @@ enum class opmode_t {
/// Common A/C settings for Fan Speeds. /// Common A/C settings for Fan Speeds.
enum class fanspeed_t { enum class fanspeed_t {
kAuto = 0, kAuto = 0,
kMin = 1, kMin = 1,
kLow = 2, kLow = 2,
kMedium = 3, kMedium = 3,
kHigh = 4, kHigh = 4,
kMax = 5, kMax = 5,
kMediumHigh = 6,
// Add new entries before this one, and update it to point to the last entry // Add new entries before this one, and update it to point to the last entry
kLastFanspeedEnum = kMax, kLastFanspeedEnum = kMediumHigh,
}; };
/// Common A/C settings for Vertical Swing. /// Common A/C settings for Vertical Swing.
@ -75,8 +79,21 @@ enum class swingv_t {
kMiddle = 3, kMiddle = 3,
kLow = 4, kLow = 4,
kLowest = 5, kLowest = 5,
kUpperMiddle = 6,
// Add new entries before this one, and update it to point to the last entry // Add new entries before this one, and update it to point to the last entry
kLastSwingvEnum = kLowest, kLastSwingvEnum = kUpperMiddle,
};
/// @brief Tyoe of A/C command (if the remote uses different codes for each)
/// @note Most remotes support only a single command or aggregate multiple
/// into one (e.g. control+timer). Use @c kControlCommand in such case
enum class ac_command_t {
kControlCommand = 0,
kSensorTempReport = 1,
kTimerCommand = 2,
kConfigCommand = 3,
// Add new entries before this one, and update it to point to the last entry
kLastAcCommandEnum = kConfigCommand,
}; };
/// Common A/C settings for Horizontal Swing. /// Common A/C settings for Horizontal Swing.
@ -113,6 +130,9 @@ struct state_t {
bool beep = false; bool beep = false;
int16_t sleep = -1; // `-1` means off. int16_t sleep = -1; // `-1` means off.
int16_t clock = -1; // `-1` means not set. int16_t clock = -1; // `-1` means not set.
stdAc::ac_command_t command = stdAc::ac_command_t::kControlCommand;
bool iFeel = false;
float sensorTemperature = kNoTempValue; // `kNoTempValue` means not set.
}; };
}; // namespace stdAc }; // namespace stdAc
@ -202,6 +222,11 @@ enum lg_ac_remote_model_t {
LG6711A20083V, // (5) Same as GE6711AR2853M, but only SwingV toggle. LG6711A20083V, // (5) Same as GE6711AR2853M, but only SwingV toggle.
}; };
/// Argo A/C model numbers
enum argo_ac_remote_model_t {
SAC_WREM2 = 1, // (1) ARGO WREM2 remote (default)
SAC_WREM3 // (2) ARGO WREM3 remote (touch buttons), bit-len vary by cmd
};
// Classes // Classes
@ -519,14 +544,22 @@ class IRsend {
const uint16_t nbits = kGoodweatherBits, const uint16_t nbits = kGoodweatherBits,
const uint16_t repeat = kGoodweatherMinRepeat); const uint16_t repeat = kGoodweatherMinRepeat);
#endif // SEND_GOODWEATHER #endif // SEND_GOODWEATHER
#if SEND_GORENJE
void sendGorenje(const uint64_t data, const uint16_t nbits = kGorenjeBits,
const uint16_t repeat = kNoRepeat);
#endif // SEND_GORENJE
#if SEND_PRONTO #if SEND_PRONTO
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat); void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
#endif #endif
#if SEND_ARGO #if SEND_ARGO
void sendArgo(const unsigned char data[], void sendArgo(const unsigned char data[],
const uint16_t nbytes = kArgoStateLength,
const uint16_t repeat = kArgoDefaultRepeat,
bool sendFooter = false);
void sendArgoWREM3(const unsigned char data[],
const uint16_t nbytes = kArgoStateLength, const uint16_t nbytes = kArgoStateLength,
const uint16_t repeat = kArgoDefaultRepeat); const uint16_t repeat = kArgoDefaultRepeat);
#endif #endif // SEND_ARGO
#if SEND_TROTEC #if SEND_TROTEC
void sendTrotec(const unsigned char data[], void sendTrotec(const unsigned char data[],
const uint16_t nbytes = kTrotecStateLength, const uint16_t nbytes = kTrotecStateLength,
@ -575,6 +608,11 @@ class IRsend {
void sendCarrierAC64(uint64_t data, uint16_t nbits = kCarrierAc64Bits, void sendCarrierAC64(uint64_t data, uint16_t nbits = kCarrierAc64Bits,
uint16_t repeat = kCarrierAc64MinRepeat); uint16_t repeat = kCarrierAc64MinRepeat);
#endif #endif
#if SEND_CARRIER_AC84
void sendCarrierAC84(const uint8_t data[],
const uint16_t nbytes = kCarrierAc84StateLength,
const uint16_t repeat = kNoRepeat);
#endif // SEND_CARRIER_AC84
#if SEND_CARRIER_AC128 #if SEND_CARRIER_AC128
void sendCarrierAC128(const uint8_t data[], void sendCarrierAC128(const uint8_t data[],
uint16_t nbytes = kCarrierAc128StateLength, uint16_t nbytes = kCarrierAc128StateLength,
@ -837,6 +875,15 @@ class IRsend {
const uint16_t nbytes = kBosch144StateLength, const uint16_t nbytes = kBosch144StateLength,
const uint16_t repeat = kNoRepeat); const uint16_t repeat = kNoRepeat);
#endif // SEND_BOSCH144 #endif // SEND_BOSCH144
#if SEND_WOWWEE
void sendWowwee(const uint64_t data, const uint16_t nbits = kWowweeBits,
const uint16_t repeat = kWowweeDefaultRepeat);
#endif // SEND_WOWWEE
#if SEND_YORK
void sendYork(const unsigned char data[],
const uint16_t nbytes = kYorkStateLength,
const uint16_t repeat = kNoRepeat);
#endif // SEND_YORK
protected: protected:
#ifdef UNIT_TEST #ifdef UNIT_TEST

View File

@ -68,10 +68,13 @@ IRTEXT_CONST_STRING(kOffTimerStr, D_STR_OFFTIMER); ///< "Off Timer"
IRTEXT_CONST_STRING(kTimerModeStr, D_STR_TIMERMODE); ///< "Timer Mode" IRTEXT_CONST_STRING(kTimerModeStr, D_STR_TIMERMODE); ///< "Timer Mode"
IRTEXT_CONST_STRING(kClockStr, D_STR_CLOCK); ///< "Clock" IRTEXT_CONST_STRING(kClockStr, D_STR_CLOCK); ///< "Clock"
IRTEXT_CONST_STRING(kCommandStr, D_STR_COMMAND); ///< "Command" IRTEXT_CONST_STRING(kCommandStr, D_STR_COMMAND); ///< "Command"
IRTEXT_CONST_STRING(kConfigCommandStr, D_STR_CONFIG); ///< "Config"
IRTEXT_CONST_STRING(kControlCommandStr, D_STR_CONTROL); ///< "Control"
IRTEXT_CONST_STRING(kXFanStr, D_STR_XFAN); ///< "XFan" IRTEXT_CONST_STRING(kXFanStr, D_STR_XFAN); ///< "XFan"
IRTEXT_CONST_STRING(kHealthStr, D_STR_HEALTH); ///< "Health" IRTEXT_CONST_STRING(kHealthStr, D_STR_HEALTH); ///< "Health"
IRTEXT_CONST_STRING(kModelStr, D_STR_MODEL); ///< "Model" IRTEXT_CONST_STRING(kModelStr, D_STR_MODEL); ///< "Model"
IRTEXT_CONST_STRING(kTempStr, D_STR_TEMP); ///< "Temp" IRTEXT_CONST_STRING(kTempStr, D_STR_TEMP); ///< "Temp"
IRTEXT_CONST_STRING(kIFeelReportStr, D_STR_IFEELREPORT); ///< "IFeel Report"
IRTEXT_CONST_STRING(kIFeelStr, D_STR_IFEEL); ///< "IFeel" IRTEXT_CONST_STRING(kIFeelStr, D_STR_IFEEL); ///< "IFeel"
IRTEXT_CONST_STRING(kHumidStr, D_STR_HUMID); ///< "Humid" IRTEXT_CONST_STRING(kHumidStr, D_STR_HUMID); ///< "Humid"
IRTEXT_CONST_STRING(kSaveStr, D_STR_SAVE); ///< "Save" IRTEXT_CONST_STRING(kSaveStr, D_STR_SAVE); ///< "Save"
@ -123,6 +126,7 @@ IRTEXT_CONST_STRING(kOutsideStr, D_STR_OUTSIDE); ///< "Outside"
IRTEXT_CONST_STRING(kLoudStr, D_STR_LOUD); ///< "Loud" IRTEXT_CONST_STRING(kLoudStr, D_STR_LOUD); ///< "Loud"
IRTEXT_CONST_STRING(kLowerStr, D_STR_LOWER); ///< "Lower" IRTEXT_CONST_STRING(kLowerStr, D_STR_LOWER); ///< "Lower"
IRTEXT_CONST_STRING(kUpperStr, D_STR_UPPER); ///< "Upper" IRTEXT_CONST_STRING(kUpperStr, D_STR_UPPER); ///< "Upper"
IRTEXT_CONST_STRING(kUpperMiddleStr, D_STR_UPPER_MIDDLE); ///< "Upper-Middle"
IRTEXT_CONST_STRING(kBreezeStr, D_STR_BREEZE); ///< "Breeze" IRTEXT_CONST_STRING(kBreezeStr, D_STR_BREEZE); ///< "Breeze"
IRTEXT_CONST_STRING(kCirculateStr, D_STR_CIRCULATE); ///< "Circulate" IRTEXT_CONST_STRING(kCirculateStr, D_STR_CIRCULATE); ///< "Circulate"
IRTEXT_CONST_STRING(kCeilingStr, D_STR_CEILING); ///< "Ceiling" IRTEXT_CONST_STRING(kCeilingStr, D_STR_CEILING); ///< "Ceiling"
@ -160,6 +164,7 @@ IRTEXT_CONST_STRING(kMaxStr, D_STR_MAX); ///< "Max"
IRTEXT_CONST_STRING(kMaximumStr, D_STR_MAXIMUM); ///< "Maximum" IRTEXT_CONST_STRING(kMaximumStr, D_STR_MAXIMUM); ///< "Maximum"
IRTEXT_CONST_STRING(kMinStr, D_STR_MIN); ///< "Min" IRTEXT_CONST_STRING(kMinStr, D_STR_MIN); ///< "Min"
IRTEXT_CONST_STRING(kMinimumStr, D_STR_MINIMUM); ///< "Minimum" IRTEXT_CONST_STRING(kMinimumStr, D_STR_MINIMUM); ///< "Minimum"
IRTEXT_CONST_STRING(kMedHighStr, D_STR_MED_HIGH); ///< "Med-high"
IRTEXT_CONST_STRING(kMedStr, D_STR_MED); ///< "Med" IRTEXT_CONST_STRING(kMedStr, D_STR_MED); ///< "Med"
IRTEXT_CONST_STRING(kMediumStr, D_STR_MEDIUM); ///< "Medium" IRTEXT_CONST_STRING(kMediumStr, D_STR_MEDIUM); ///< "Medium"
@ -205,6 +210,13 @@ IRTEXT_CONST_STRING(kSwingVModeStr, D_STR_SWINGVMODE); ///< "Swing(V) Mode"
IRTEXT_CONST_STRING(kSwingVToggleStr, D_STR_SWINGVTOGGLE); ///< IRTEXT_CONST_STRING(kSwingVToggleStr, D_STR_SWINGVTOGGLE); ///<
///< "Swing(V) Toggle" ///< "Swing(V) Toggle"
IRTEXT_CONST_STRING(kTurboToggleStr, D_STR_TURBOTOGGLE); ///< "Turbo Toggle" IRTEXT_CONST_STRING(kTurboToggleStr, D_STR_TURBOTOGGLE); ///< "Turbo Toggle"
IRTEXT_CONST_STRING(kSetTimerCommandStr, D_STR_SET_TIMER); ///< "Set Timer"
IRTEXT_CONST_STRING(kScheduleStr, D_STR_SCHEDULE); ///< "Schedule"
IRTEXT_CONST_STRING(kChStr, D_STR_CH); ///< "CH#"
IRTEXT_CONST_STRING(kTimerActiveDaysStr, D_STR_TIMER_ACTIVE_DAYS);
///< "TimerActiveDays"
IRTEXT_CONST_STRING(kKeyStr, D_STR_KEY); ///< "Key"
IRTEXT_CONST_STRING(kValueStr, D_STR_VALUE); ///< "Value"
// Separators & Punctuation // Separators & Punctuation
const char kTimeSep = D_CHR_TIME_SEP; ///< ':' const char kTimeSep = D_CHR_TIME_SEP; ///< ':'
@ -281,6 +293,8 @@ IRTEXT_CONST_STRING(k122lzfStr, D_STR_122LZF); ///< "122LZF"
IRTEXT_CONST_STRING(kDg11j13aStr, D_STR_DG11J13A); ///< "DG11J13A" IRTEXT_CONST_STRING(kDg11j13aStr, D_STR_DG11J13A); ///< "DG11J13A"
IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104" IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104"
IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191" IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191"
IRTEXT_CONST_STRING(kArgoWrem2Str, D_STR_ARGO_WREM2); ///< "WREM3"
IRTEXT_CONST_STRING(kArgoWrem3Str, D_STR_ARGO_WREM3); ///< "WREM3"
#define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as #define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as
// a question mark, check for length > 1 // a question mark, check for length > 1
@ -533,6 +547,14 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_SANYO_AC152, D_STR_UNSUPPORTED) "\x0" D_STR_SANYO_AC152, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_DAIKIN312 || SEND_DAIKIN312, COND(DECODE_DAIKIN312 || SEND_DAIKIN312,
D_STR_DAIKIN312, D_STR_UNSUPPORTED) "\x0" D_STR_DAIKIN312, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_GORENJE || SEND_GORENJE,
D_STR_GORENJE, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_WOWWEE || SEND_WOWWEE,
D_STR_WOWWEE, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_CARRIER_AC84 || SEND_CARRIER_AC84,
D_STR_CARRIER_AC84, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_YORK || SEND_YORK,
D_STR_YORK, D_STR_UNSUPPORTED) "\x0"
///< New protocol (macro) strings should be added just above this line. ///< New protocol (macro) strings should be added just above this line.
"\x0" ///< This string requires double null termination. "\x0" ///< This string requires double null termination.
}; };

View File

@ -39,6 +39,8 @@ extern IRTEXT_CONST_PTR(kAkb73757604Str);
extern IRTEXT_CONST_PTR(kAkb74955603Str); extern IRTEXT_CONST_PTR(kAkb74955603Str);
extern IRTEXT_CONST_PTR(kAkb75215403Str); extern IRTEXT_CONST_PTR(kAkb75215403Str);
extern IRTEXT_CONST_PTR(kArdb1Str); extern IRTEXT_CONST_PTR(kArdb1Str);
extern IRTEXT_CONST_PTR(kArgoWrem2Str);
extern IRTEXT_CONST_PTR(kArgoWrem3Str);
extern IRTEXT_CONST_PTR(kArjw2Str); extern IRTEXT_CONST_PTR(kArjw2Str);
extern IRTEXT_CONST_PTR(kArrah2eStr); extern IRTEXT_CONST_PTR(kArrah2eStr);
extern IRTEXT_CONST_PTR(kArreb1eStr); extern IRTEXT_CONST_PTR(kArreb1eStr);
@ -57,6 +59,7 @@ extern IRTEXT_CONST_PTR(kCelsiusFahrenheitStr);
extern IRTEXT_CONST_PTR(kCelsiusStr); extern IRTEXT_CONST_PTR(kCelsiusStr);
extern IRTEXT_CONST_PTR(kCentreStr); extern IRTEXT_CONST_PTR(kCentreStr);
extern IRTEXT_CONST_PTR(kChangeStr); extern IRTEXT_CONST_PTR(kChangeStr);
extern IRTEXT_CONST_PTR(kChStr);
extern IRTEXT_CONST_PTR(kCirculateStr); extern IRTEXT_CONST_PTR(kCirculateStr);
extern IRTEXT_CONST_PTR(kCkpStr); extern IRTEXT_CONST_PTR(kCkpStr);
extern IRTEXT_CONST_PTR(kCleanStr); extern IRTEXT_CONST_PTR(kCleanStr);
@ -66,6 +69,8 @@ extern IRTEXT_CONST_PTR(kColonSpaceStr);
extern IRTEXT_CONST_PTR(kComfortStr); extern IRTEXT_CONST_PTR(kComfortStr);
extern IRTEXT_CONST_PTR(kCommaSpaceStr); extern IRTEXT_CONST_PTR(kCommaSpaceStr);
extern IRTEXT_CONST_PTR(kCommandStr); extern IRTEXT_CONST_PTR(kCommandStr);
extern IRTEXT_CONST_PTR(kConfigCommandStr);
extern IRTEXT_CONST_PTR(kControlCommandStr);
extern IRTEXT_CONST_PTR(kCoolStr); extern IRTEXT_CONST_PTR(kCoolStr);
extern IRTEXT_CONST_PTR(kCoolingStr); extern IRTEXT_CONST_PTR(kCoolingStr);
extern IRTEXT_CONST_PTR(kDashStr); extern IRTEXT_CONST_PTR(kDashStr);
@ -109,6 +114,7 @@ extern IRTEXT_CONST_PTR(kHoldStr);
extern IRTEXT_CONST_PTR(kHourStr); extern IRTEXT_CONST_PTR(kHourStr);
extern IRTEXT_CONST_PTR(kHoursStr); extern IRTEXT_CONST_PTR(kHoursStr);
extern IRTEXT_CONST_PTR(kHumidStr); extern IRTEXT_CONST_PTR(kHumidStr);
extern IRTEXT_CONST_PTR(kIFeelReportStr);
extern IRTEXT_CONST_PTR(kIFeelStr); extern IRTEXT_CONST_PTR(kIFeelStr);
extern IRTEXT_CONST_PTR(kISeeStr); extern IRTEXT_CONST_PTR(kISeeStr);
extern IRTEXT_CONST_PTR(kIdStr); extern IRTEXT_CONST_PTR(kIdStr);
@ -116,6 +122,7 @@ extern IRTEXT_CONST_PTR(kIndirectStr);
extern IRTEXT_CONST_PTR(kInsideStr); extern IRTEXT_CONST_PTR(kInsideStr);
extern IRTEXT_CONST_PTR(kIonStr); extern IRTEXT_CONST_PTR(kIonStr);
extern IRTEXT_CONST_PTR(kJkeStr); extern IRTEXT_CONST_PTR(kJkeStr);
extern IRTEXT_CONST_PTR(kKeyStr);
extern IRTEXT_CONST_PTR(kKkg29ac1Str); extern IRTEXT_CONST_PTR(kKkg29ac1Str);
extern IRTEXT_CONST_PTR(kKkg9ac1Str); extern IRTEXT_CONST_PTR(kKkg9ac1Str);
extern IRTEXT_CONST_PTR(kLastStr); extern IRTEXT_CONST_PTR(kLastStr);
@ -139,6 +146,7 @@ extern IRTEXT_CONST_PTR(kMaxRightNoSpaceStr);
extern IRTEXT_CONST_PTR(kMaxRightStr); extern IRTEXT_CONST_PTR(kMaxRightStr);
extern IRTEXT_CONST_PTR(kMaxStr); extern IRTEXT_CONST_PTR(kMaxStr);
extern IRTEXT_CONST_PTR(kMaximumStr); extern IRTEXT_CONST_PTR(kMaximumStr);
extern IRTEXT_CONST_PTR(kMedHighStr);
extern IRTEXT_CONST_PTR(kMedStr); extern IRTEXT_CONST_PTR(kMedStr);
extern IRTEXT_CONST_PTR(kMediumStr); extern IRTEXT_CONST_PTR(kMediumStr);
extern IRTEXT_CONST_PTR(kMidStr); extern IRTEXT_CONST_PTR(kMidStr);
@ -188,8 +196,10 @@ extern IRTEXT_CONST_PTR(kRlt0541htaaStr);
extern IRTEXT_CONST_PTR(kRlt0541htabStr); extern IRTEXT_CONST_PTR(kRlt0541htabStr);
extern IRTEXT_CONST_PTR(kRoomStr); extern IRTEXT_CONST_PTR(kRoomStr);
extern IRTEXT_CONST_PTR(kSaveStr); extern IRTEXT_CONST_PTR(kSaveStr);
extern IRTEXT_CONST_PTR(kScheduleStr);
extern IRTEXT_CONST_PTR(kSecondStr); extern IRTEXT_CONST_PTR(kSecondStr);
extern IRTEXT_CONST_PTR(kSecondsStr); extern IRTEXT_CONST_PTR(kSecondsStr);
extern IRTEXT_CONST_PTR(kSensorReportStr);
extern IRTEXT_CONST_PTR(kSensorStr); extern IRTEXT_CONST_PTR(kSensorStr);
extern IRTEXT_CONST_PTR(kSensorTempStr); extern IRTEXT_CONST_PTR(kSensorTempStr);
extern IRTEXT_CONST_PTR(kSetStr); extern IRTEXT_CONST_PTR(kSetStr);
@ -213,7 +223,9 @@ extern IRTEXT_CONST_PTR(kTempDownStr);
extern IRTEXT_CONST_PTR(kTempStr); extern IRTEXT_CONST_PTR(kTempStr);
extern IRTEXT_CONST_PTR(kTempUpStr); extern IRTEXT_CONST_PTR(kTempUpStr);
extern IRTEXT_CONST_PTR(kThreeLetterDayOfWeekStr); extern IRTEXT_CONST_PTR(kThreeLetterDayOfWeekStr);
extern IRTEXT_CONST_PTR(kTimerActiveDaysStr);
extern IRTEXT_CONST_PTR(kTimerModeStr); extern IRTEXT_CONST_PTR(kTimerModeStr);
extern IRTEXT_CONST_PTR(kSetTimerCommandStr);
extern IRTEXT_CONST_PTR(kTimerStr); extern IRTEXT_CONST_PTR(kTimerStr);
extern IRTEXT_CONST_PTR(kToggleStr); extern IRTEXT_CONST_PTR(kToggleStr);
extern IRTEXT_CONST_PTR(kTopStr); extern IRTEXT_CONST_PTR(kTopStr);
@ -224,6 +236,8 @@ extern IRTEXT_CONST_PTR(kTypeStr);
extern IRTEXT_CONST_PTR(kUnknownStr); extern IRTEXT_CONST_PTR(kUnknownStr);
extern IRTEXT_CONST_PTR(kUpStr); extern IRTEXT_CONST_PTR(kUpStr);
extern IRTEXT_CONST_PTR(kUpperStr); extern IRTEXT_CONST_PTR(kUpperStr);
extern IRTEXT_CONST_PTR(kUpperMiddleStr);
extern IRTEXT_CONST_PTR(kValueStr);
extern IRTEXT_CONST_PTR(kV9014557AStr); extern IRTEXT_CONST_PTR(kV9014557AStr);
extern IRTEXT_CONST_PTR(kV9014557BStr); extern IRTEXT_CONST_PTR(kV9014557BStr);
extern IRTEXT_CONST_PTR(kVaneStr); extern IRTEXT_CONST_PTR(kVaneStr);

View File

@ -6,6 +6,7 @@
#endif #endif
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
#include <math.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
@ -173,6 +174,7 @@ bool hasACState(const decode_type_t protocol) {
case AMCOR: case AMCOR:
case ARGO: case ARGO:
case BOSCH144: case BOSCH144:
case CARRIER_AC84:
case CARRIER_AC128: case CARRIER_AC128:
case CORONA_AC: case CORONA_AC:
case DAIKIN: case DAIKIN:
@ -224,6 +226,7 @@ bool hasACState(const decode_type_t protocol) {
case TROTEC_3550: case TROTEC_3550:
case VOLTAS: case VOLTAS:
case WHIRLPOOL_AC: case WHIRLPOOL_AC:
case YORK:
return true; return true;
default: default:
return false; return false;
@ -304,7 +307,7 @@ String resultToSourceCode(const decode_results * const results) {
if (results->decode_type != UNKNOWN) { if (results->decode_type != UNKNOWN) {
if (hasState) { if (hasState) {
#if DECODE_AC #if DECODE_AC
uint16_t nbytes = results->bits / 8; uint16_t nbytes = ceil(static_cast<float>(results->bits) / 8.0);
output += F("uint8_t state["); output += F("uint8_t state[");
output += uint64ToString(nbytes); output += uint64ToString(nbytes);
output += F("] = {"); output += F("] = {");
@ -695,6 +698,13 @@ namespace irutils {
default: return kUnknownStr; default: return kUnknownStr;
} }
break; break;
case decode_type_t::ARGO:
switch (model) {
case argo_ac_remote_model_t::SAC_WREM2: return kArgoWrem2Str;
case argo_ac_remote_model_t::SAC_WREM3: return kArgoWrem3Str;
default: return kUnknownStr;
}
break;
default: return kUnknownStr; default: return kUnknownStr;
} }
} }
@ -722,10 +732,12 @@ namespace irutils {
/// @param[in] celsius Is the temp Celsius or Fahrenheit. /// @param[in] celsius Is the temp Celsius or Fahrenheit.
/// true is C, false is F /// true is C, false is F
/// @param[in] precomma Should the output string start with ", " or not? /// @param[in] precomma Should the output string start with ", " or not?
/// @param[in] isSensorTemp Is the value a room (ambient) temp. or target?
/// @return The resulting String. /// @return The resulting String.
String addTempToString(const uint16_t degrees, const bool celsius, String addTempToString(const uint16_t degrees, const bool celsius,
const bool precomma) { const bool precomma, const bool isSensorTemp) {
String result = addIntToString(degrees, kTempStr, precomma); String result = addIntToString(degrees, (isSensorTemp)?
kSensorTempStr : kTempStr, precomma);
result += celsius ? 'C' : 'F'; result += celsius ? 'C' : 'F';
return result; return result;
} }
@ -736,12 +748,14 @@ namespace irutils {
/// @param[in] celsius Is the temp Celsius or Fahrenheit. /// @param[in] celsius Is the temp Celsius or Fahrenheit.
/// true is C, false is F /// true is C, false is F
/// @param[in] precomma Should the output string start with ", " or not? /// @param[in] precomma Should the output string start with ", " or not?
/// @param[in] isSensorTemp Is the value a room (ambient) temp. or target?
/// @return The resulting String. /// @return The resulting String.
String addTempFloatToString(const float degrees, const bool celsius, String addTempFloatToString(const float degrees, const bool celsius,
const bool precomma) { const bool precomma, const bool isSensorTemp) {
String result = ""; String result = "";
result.reserve(14); // Assuming ", Temp: XXX.5F" is the largest. result.reserve(21); // Assuming ", Sensor Temp: XXX.5F" is the largest.
result += addIntToString(degrees, kTempStr, precomma); result += addIntToString(degrees, (isSensorTemp)?
kSensorTempStr : kTempStr, precomma);
// Is it a half degree? // Is it a half degree?
if (((uint16_t)(2 * degrees)) & 1) result += F(".5"); if (((uint16_t)(2 * degrees)) & 1) result += F(".5");
result += celsius ? 'C' : 'F'; result += celsius ? 'C' : 'F';
@ -788,43 +802,57 @@ namespace irutils {
result.reserve(19); // ", Day: N (UNKNOWN)" result.reserve(19); // ", Day: N (UNKNOWN)"
result += addIntToString(day_of_week, kDayStr, precomma); result += addIntToString(day_of_week, kDayStr, precomma);
result += kSpaceLBraceStr; result += kSpaceLBraceStr;
result += dayToString(day_of_week, offset);
return result + ')';
}
/// Create a String of the 3-letter day of the week from a numerical day of
/// the week. e.g. "Mon"
/// @param[in] day_of_week A numerical version of the sequential day of the
/// week. e.g. Sunday = 1, Monday = 2, ..., Saturday = 7
/// @param[in] offset Days to offset by.
/// e.g. For different day starting the week.
/// @return The resulting String.
String dayToString(const uint8_t day_of_week, const int8_t offset) {
if ((uint8_t)(day_of_week + offset) < 7) if ((uint8_t)(day_of_week + offset) < 7)
#if UNIT_TEST #if UNIT_TEST
result += String(kThreeLetterDayOfWeekStr).substr( return String(kThreeLetterDayOfWeekStr).substr(
(day_of_week + offset) * 3, 3); (day_of_week + offset) * 3, 3);
#else // UNIT_TEST #else // UNIT_TEST
result += String(kThreeLetterDayOfWeekStr).substring( return String(kThreeLetterDayOfWeekStr).substring(
(day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3); (day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3);
#endif // UNIT_TEST #endif // UNIT_TEST
else else
result += kUnknownStr; return kUnknownStr;
return result + ')';
} }
/// Create a String of human output for the given fan speed. /// Create a String of human output for the given fan speed.
/// e.g. "Fan: 0 (Auto)" /// e.g. "Fan: 0 (Auto)"
/// @param[in] speed The numeric speed of the fan to display. /// @param[in] speed The numeric speed of the fan to display.
/// @param[in] high The numeric value for High speed. /// @param[in] high The numeric value for High speed. (second highest)
/// @param[in] low The numeric value for Low speed. /// @param[in] low The numeric value for Low speed.
/// @param[in] automatic The numeric value for Auto speed. /// @param[in] automatic The numeric value for Auto speed.
/// @param[in] quiet The numeric value for Quiet speed. /// @param[in] quiet The numeric value for Quiet speed.
/// @param[in] medium The numeric value for Medium speed. /// @param[in] medium The numeric value for Medium speed.
/// @param[in] maximum The numeric value for Highest speed. (if > high) /// @param[in] maximum The numeric value for Highest speed. (if > high)
/// @param[in] medium_high The numeric value for third-highest speed.
/// (if > medium)
/// @return The resulting String. /// @return The resulting String.
String addFanToString(const uint8_t speed, const uint8_t high, String addFanToString(const uint8_t speed, const uint8_t high,
const uint8_t low, const uint8_t automatic, const uint8_t low, const uint8_t automatic,
const uint8_t quiet, const uint8_t medium, const uint8_t quiet, const uint8_t medium,
const uint8_t maximum) { const uint8_t maximum, const uint8_t medium_high) {
String result = ""; String result = "";
result.reserve(21); // ", Fan: NNN (UNKNOWN)" result.reserve(21); // ", Fan: NNN (UNKNOWN)"
result += addIntToString(speed, kFanStr); result += addIntToString(speed, kFanStr);
result += kSpaceLBraceStr; result += kSpaceLBraceStr;
if (speed == high) result += kHighStr; if (speed == high) result += kHighStr;
else if (speed == low) result += kLowStr; else if (speed == low) result += kLowStr;
else if (speed == automatic) result += kAutoStr; else if (speed == automatic) result += kAutoStr;
else if (speed == quiet) result += kQuietStr; else if (speed == quiet) result += kQuietStr;
else if (speed == medium) result += kMediumStr; else if (speed == medium) result += kMediumStr;
else if (speed == maximum) result += kMaximumStr; else if (speed == maximum) result += kMaximumStr;
else if (speed == medium_high) result += kMedHighStr;
else else
result += kUnknownStr; result += kUnknownStr;
return result + ')'; return result + ')';
@ -950,6 +978,106 @@ namespace irutils {
return result + ')'; return result + ')';
} }
/// @brief Create a String of human output for the given timer setting.
/// e.g. "Timer Mode: 2 (Schedule 1)"
/// @param[in] timerMode The numeric value of the timer mode to display.
/// @param[in] noTimer The numeric value for no timer (off)
/// @param[in] delayTimer The numeric value for delay (sleep) timer
/// @param[in] schedule1 The numeric value for schedule timer #1
/// @param[in] schedule2 The numeric value for schedule timer #2
/// @param[in] schedule3 The numeric value for schedule timer #3
/// @param[in] precomma Should the output string start with ", " or not?
/// @return String representation
String addTimerModeToString(const uint8_t timerMode, const uint8_t noTimer,
const uint8_t delayTimer, const uint8_t schedule1,
const uint8_t schedule2, const uint8_t schedule3,
const bool precomma) {
String result = "";
result.reserve(28); // ", Timer Mode: 2 (Schedule 1)"
result += addIntToString(timerMode, kTimerModeStr, precomma);
result += kSpaceLBraceStr;
if (timerMode == noTimer) {
result += kOffStr;
} else if (timerMode == delayTimer) {
result += kSleepTimerStr;
} else if (timerMode == schedule1) {
result += kScheduleStr;
result += '1';
} else if (timerMode == schedule2) {
result += kScheduleStr;
result += '2';
} else if (timerMode == schedule3) {
result += kScheduleStr;
result += '3';
} else {
result += kUnknownStr;
}
return result + ')';
}
/// @brief Create a String of human output for the given channel
/// e.g. "[CH#0]"
/// @param channel The numeric value of the channel to display.
/// @return String representation
String channelToString(const uint8_t channel) {
String result = "";
result.reserve(6); // "[CH#4]"
result += "[";
result += kChStr;
result += uint64ToString(channel);
result += "]";
return result;
}
/// @brief Create a String of human output for the given command type
/// e.g. "IFeel Report"
/// @param irCommandType The numeric value of the command type to display.
/// @param acControlCmd The numeric value of the "control" (default) command
/// @param iFeelReportCmd The numeric value of the sensor temperature command
/// @param timerCmd The numeric value of the timer config IR command
/// @param configCmd The numeric value of the config param set IR command
/// @return String representation
String irCommandTypeToString(uint8_t irCommandType, uint8_t acControlCmd,
uint8_t iFeelReportCmd, uint8_t timerCmd,
uint8_t configCmd) {
String result = "";
result.reserve(12); // "IFeel Report"
if (irCommandType == acControlCmd) {
result += kCommandStr;
} else if (irCommandType == iFeelReportCmd) {
result += kIFeelReportStr;
} else if (irCommandType == timerCmd) {
result += kTimerStr;
} else if (irCommandType == configCmd) {
result += kConfigCommandStr;
} else {
result += kUnknownStr;
}
return result;
}
/// @brief Create a String of the 3-letter day of the week bitmap
// e.g. 0b0000101 is "Sun | Tue"
/// @param[in] daysBitmap The bitmap representing days of week to represent
/// e.g bit[0]=Sunday, bit[1]=Monday, ...
/// @param[in] offset Days to offset by.
/// e.g. For different day starting the week.
/// @return String representation.
String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset) {
String result = "";
result.reserve(27); // Sun|Mon|Tue|Wed|Thu|Fri|Sat
for (uint8_t i = 0; i < 7; ++i) {
if (((daysBitmap >> i) & 0b1) == 0b1) {
if (result.length() > 0) {
result += "|";
}
result += irutils::dayToString(i, offset);
}
}
return result;
}
/// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS. /// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS.
/// @param[in] unescaped A String containing text to make HTML safe. /// @param[in] unescaped A String containing text to make HTML safe.
/// @return A string that is HTML safe. /// @return A string that is HTML safe.

View File

@ -60,16 +60,19 @@ namespace irutils {
String addLabeledString(const String value, const String label, String addLabeledString(const String value, const String label,
const bool precomma = true); const bool precomma = true);
String addTempToString(const uint16_t degrees, const bool celsius = true, String addTempToString(const uint16_t degrees, const bool celsius = true,
const bool precomma = true); const bool precomma = true,
const bool isSensorTemp = false);
String addTempFloatToString(const float degrees, const bool celsius = true, String addTempFloatToString(const float degrees, const bool celsius = true,
const bool precomma = true); const bool precomma = true,
const bool isSensorTemp = false);
String addModeToString(const uint8_t mode, const uint8_t automatic, String addModeToString(const uint8_t mode, const uint8_t automatic,
const uint8_t cool, const uint8_t heat, const uint8_t cool, const uint8_t heat,
const uint8_t dry, const uint8_t fan); const uint8_t dry, const uint8_t fan);
String addFanToString(const uint8_t speed, const uint8_t high, String addFanToString(const uint8_t speed, const uint8_t high,
const uint8_t low, const uint8_t automatic, const uint8_t low, const uint8_t automatic,
const uint8_t quiet, const uint8_t medium, const uint8_t quiet, const uint8_t medium,
const uint8_t maximum = 0xFF); const uint8_t maximum = 0xFF,
const uint8_t medium_high = 0xFF);
String addSwingHToString(const uint8_t position, const uint8_t automatic, String addSwingHToString(const uint8_t position, const uint8_t automatic,
const uint8_t maxleft, const uint8_t left, const uint8_t maxleft, const uint8_t left,
const uint8_t middle, const uint8_t middle,
@ -87,6 +90,19 @@ namespace irutils {
const uint8_t breeze, const uint8_t circulate); const uint8_t breeze, const uint8_t circulate);
String addDayToString(const uint8_t day_of_week, const int8_t offset = 0, String addDayToString(const uint8_t day_of_week, const int8_t offset = 0,
const bool precomma = true); const bool precomma = true);
String addTimerModeToString(const uint8_t timerType, const uint8_t noTimer,
const uint8_t delayTimer,
const uint8_t schedule1 = 0xFF,
const uint8_t schedule2 = 0xFF,
const uint8_t schedule3 = 0xFF,
const bool precomma = true);
String irCommandTypeToString(uint8_t commandType, uint8_t acControlCmd,
uint8_t iFeelReportCmd = 0xFF,
uint8_t timerCmd = 0xFF,
uint8_t configCmd = 0xFF);
String dayToString(const uint8_t day_of_week, const int8_t offset = 0);
String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset = 0);
String channelToString(const uint8_t channel);
String htmlEscape(const String unescaped); String htmlEscape(const String unescaped);
String msToString(uint32_t const msecs); String msToString(uint32_t const msecs);
String minsToString(const uint16_t mins); String minsToString(const uint16_t mins);

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,18 @@
// Copyright 2017 Schmolders // Copyright 2017 Schmolders
// Copyright 2022 crankyoldgit
// Copyright 2022 Mateusz Bronk (mbronk)
/// @file /// @file
/// @brief Support for Argo Ulisse 13 DCI Mobile Split ACs. /// @brief Support for Argo Ulisse 13 DCI Mobile Split ACs.
// Supports: // Supports:
// Brand: Argo, Model: Ulisse 13 DCI Mobile Split A/C // Brand: Argo, Model: Ulisse 13 DCI Mobile Split A/C [WREM2 remote]
// Brand: Argo, Model: Ulisse Eco Mobile Split A/C (Wifi) [WREM3 remote]
#ifndef IR_ARGO_H_ #ifndef IR_ARGO_H_
#define IR_ARGO_H_ #define IR_ARGO_H_
#include <set>
#include <utility>
#ifndef UNIT_TEST #ifndef UNIT_TEST
#include <Arduino.h> #include <Arduino.h>
#endif #endif
@ -20,14 +25,14 @@
// ARGO Ulisse DCI // ARGO Ulisse DCI
/// Native representation of a Argo A/C message. /// Native representation of a Argo A/C message for WREM-2 remote.
union ArgoProtocol { union ArgoProtocol {
uint8_t raw[kArgoStateLength]; ///< The state in native IR code form uint8_t raw[kArgoStateLength]; ///< The state in native IR code form
struct { struct {
// Byte 0 // Byte 0
uint64_t :8; // Typically 0b00110101 uint64_t Pre1 :8; // Typically 0b00110101
// Byte 1 // Byte 1
uint64_t :8; // Typically 0b10101111 uint64_t Pre2 :8; // Typically 0b10101111
// Byte 2~4 // Byte 2~4
uint64_t :3; uint64_t :3;
uint64_t Mode :3; uint64_t Mode :3;
@ -57,17 +62,143 @@ union ArgoProtocol {
uint32_t :1; // const 0 uint32_t :1; // const 0
uint32_t iFeel :1; uint32_t iFeel :1;
// Byte 10~11 // Byte 10~11
uint32_t :2; // const 01 uint32_t Post :2;
uint32_t Sum :8; // straddle byte 10 and 11 uint32_t Sum :8; // straddle byte 10 and 11
uint32_t :6; uint32_t :6;
}; };
struct {
// Byte 0-1
uint8_t :8;
uint8_t :8;
// Byte 2-3
uint8_t CheckHi :3;
uint8_t SensorT :5;
uint8_t Fixed :3; // Typically 0b011
uint8_t CheckLo :5;
};
}; };
// Constants. Store MSB left. /// Native representation of A/C IR message for WREM-3 remote
/// @note The remote sends 4 different IR command types, varying in length
/// and methods of checksum calculation
/// - [0b00] Regular A/C command (change operation mode) - 6-byte
/// - [0b01] iFeel Temperature report - 2-byte
/// - [0b10] Timer command - 9-byte
/// - [0b11] Config command - 4-byte
/// @note The 1st 2 structures are unnamed for compat. with @c ArgoProtocol
/// 1st byte definition is a header common across all commands though
union ArgoProtocolWREM3 {
uint8_t raw[kArgoStateLength]; ///< The state in native IR code form
struct {
// Byte 0 (same definition across the union)
uint8_t Pre1 :4; /// Preamble: 0b1011 @ref kArgoWrem3Preamble
uint8_t IrChannel :2; /// 0..3 range
uint8_t IrCommandType :2; /// @ref argoIrMessageType_t
// Byte 1
uint8_t RoomTemp :5; // in Celsius, range: 4..35 (offset by -4[*C])
uint8_t Mode :3; /// @ref argoMode_t
// Byte 2
uint8_t Temp :5; // in Celsius, range: 10..32 (offset by -4[*C])
uint8_t Fan :3; /// @ref argoFan_t
// Byte3
uint8_t Flap :3; /// SwingV @ref argoFlap_t
uint8_t Power :1;
uint8_t iFeel :1;
uint8_t Night :1;
uint8_t Eco :1;
uint8_t Max :1; ///< a.k.a. Turbo
// Byte4
uint8_t Filter :1;
uint8_t Light :1;
uint8_t Post1 :6; /// Unknown, always 0b110000 (TempScale?)
// Byte5
uint8_t Sum :8; /// Checksum
};
struct {
// Byte 0 (same definition across the union)
uint8_t :8; // {Pre1 | IrChannel | IrCommandType}
// Byte 1
uint8_t SensorT :5; // in Celsius, range: 4..35 (offset by -4[*C])
uint8_t CheckHi :3; // Checksum (short)
};
struct Timer {
// Byte 0 (same definition across the union)
uint8_t : 8; // {Pre1 | IrChannel | IrCommandType}
// Byte 1
uint8_t IsOn : 1;
uint8_t TimerType : 3;
uint8_t CurrentTimeLo : 4;
// Byte 2
uint8_t CurrentTimeHi : 7;
uint8_t CurrentWeekdayLo : 1;
// Byte 3
uint8_t CurrentWeekdayHi : 2;
uint8_t DelayTimeLo : 6;
// Byte 4
uint8_t DelayTimeHi : 5;
uint8_t TimerStartLo : 3;
// Byte 5
uint8_t TimerStartHi : 8;
// Byte 6
uint8_t TimerEndLo : 8;
// Byte 7
uint8_t TimerEndHi : 3;
uint8_t TimerActiveDaysLo : 5; // Bitmap (LSBit is Sunday)
// Byte 8
uint8_t TimerActiveDaysHi : 2; // Bitmap (LSBit is Sunday)
uint8_t Post1 : 1; // Unknown, always 1
uint8_t Checksum : 5;
} timer;
struct Config {
uint8_t :8; // Byte 0 {Pre1 | IrChannel | IrCommandType}
uint8_t Key :8; // Byte 1
uint8_t Value :8; // Byte 2
uint8_t Checksum :8; // Byte 3
} config;
};
const uint8_t kArgoHeatBit = 0b00100000; // Constants (WREM-2). Store MSB left.
const uint8_t kArgoHeatBit = 0b00100000;
const uint8_t kArgoPreamble1 = 0b10101100;
const uint8_t kArgoPreamble2 = 0b11110101;
const uint8_t kArgoPost = 0b00000010;
// Mode 0b00111000 // Constants (generic)
const uint16_t kArgoFrequency = 38000; // Hz
// Temp
const uint8_t kArgoTempDelta = 4;
const uint8_t kArgoMaxRoomTemp = 35; // Celsius
const uint8_t kArgoMinTemp = 10; // Celsius delta +4
const uint8_t kArgoMaxTemp = 32; // Celsius
const uint8_t kArgoMaxChannel = 3;
/// @brief IR message type (determines the payload part of IR command)
/// @note Raw values match WREM-3 protocol, but the enum is used in generic
/// context
/// @note WREM-3 remote supports all commands separately, whereas
/// WREM-2 (allegedly) only has the @c AC_CONTROL and @c IFEEL_TEMP_REPORT
/// (timers are part of @c AC_CONTROL command), and there's no config.
enum class argoIrMessageType_t : uint8_t {
AC_CONTROL = 0b00,
IFEEL_TEMP_REPORT = 0b01,
TIMER_COMMAND = 0b10, // WREM-3 only (WREM-2 has it under AC_CONTROL)
CONFIG_PARAM_SET = 0b11 // WREM-3 only
};
/// @brief A/C operation mode
/// @note Raw values match WREM-3 protocol, but the enum is used in generic
/// context
enum class argoMode_t : uint8_t {
COOL = 0b001,
DRY = 0b010,
HEAT = 0b011,
FAN = 0b100,
AUTO = 0b101
};
// Raw mode definitions for WREM-2 remote
// (not wraped into a ns nor enum for backwards-compat.)
const uint8_t kArgoCool = 0b000; const uint8_t kArgoCool = 0b000;
const uint8_t kArgoDry = 0b001; const uint8_t kArgoDry = 0b001;
const uint8_t kArgoAuto = 0b010; const uint8_t kArgoAuto = 0b010;
@ -77,19 +208,42 @@ const uint8_t kArgoHeatAuto = 0b101;
// ?no idea what mode that is // ?no idea what mode that is
const uint8_t kArgoHeatBlink = 0b110; const uint8_t kArgoHeatBlink = 0b110;
// Fan 0b00011000 /// @brief Fan speed
/// @note Raw values match WREM-3 protocol, but the enum is used in generic
/// context
enum class argoFan_t : uint8_t {
FAN_AUTO = 0b000,
FAN_LOWEST = 0b001,
FAN_LOWER = 0b010,
FAN_LOW = 0b011,
FAN_MEDIUM = 0b100,
FAN_HIGH = 0b101,
FAN_HIGHEST = 0b110
};
// Raw fan speed definitions for WREM-2 remote
// (not wraped into a ns nor enum for backwards-compat.)
const uint8_t kArgoFanAuto = 0; // 0b00 const uint8_t kArgoFanAuto = 0; // 0b00
const uint8_t kArgoFan1 = 1; // 0b01 const uint8_t kArgoFan1 = 1; // 0b01
const uint8_t kArgoFan2 = 2; // 0b10 const uint8_t kArgoFan2 = 2; // 0b10
const uint8_t kArgoFan3 = 3; // 0b11 const uint8_t kArgoFan3 = 3; // 0b11
// Temp /// @brief Flap position (swing-V)
const uint8_t kArgoTempDelta = 4; /// @note Raw values match WREM-3 protocol, but the enum is used in generic
const uint8_t kArgoMaxRoomTemp = 35; // Celsius /// context
const uint8_t kArgoMinTemp = 10; // Celsius delta +4 enum class argoFlap_t : uint8_t {
const uint8_t kArgoMaxTemp = 32; // Celsius FLAP_AUTO = 0,
FLAP_1 = 1, // Highest
FLAP_2 = 2,
FLAP_3 = 3,
FLAP_4 = 4,
FLAP_5 = 5,
FLAP_6 = 6, // Lowest
FLAP_FULL = 7
};
// Flap/SwingV // Raw Flap/SwingV definitions for WREM-2 remote
// (not wraped into a ns nor enum for backwards-compat.)
const uint8_t kArgoFlapAuto = 0; const uint8_t kArgoFlapAuto = 0;
const uint8_t kArgoFlap1 = 1; const uint8_t kArgoFlap1 = 1;
const uint8_t kArgoFlap2 = 2; const uint8_t kArgoFlap2 = 2;
@ -123,22 +277,61 @@ const uint8_t kArgoFlapFull = 7;
#define ARGO_FLAP_FULL kArgoFlapFull #define ARGO_FLAP_FULL kArgoFlapFull
/// Class for handling detailed Argo A/C messages. /// @brief Timer type to set (for @c argoIrMessageType_t::TIMER_COMMAND)
class IRArgoAC { /// @note Raw values match WREM-3 protocol
enum class argoTimerType_t : uint8_t {
NO_TIMER = 0b000,
DELAY_TIMER = 0b001,
SCHEDULE_TIMER_1 = 0b010,
SCHEDULE_TIMER_2 = 0b011,
SCHEDULE_TIMER_3 = 0b100
};
/// @brief Day type to set (for @c argoIrMessageType_t::TIMER_COMMAND)
/// @note Raw values match WREM-3 protocol
enum class argoWeekday : uint8_t {
SUNDAY = 0b000,
MONDAY = 0b001,
TUESDAY = 0b010,
WEDNESDAY = 0b011,
THURSDAY = 0b100,
FRIDAY = 0b101,
SATURDAY = 0b110
};
/// @brief Base class for handling *common* support for Argo remote protocols
/// (functionality is shared across WREM-2 and WREM-3 IR protocols)
/// @note This class uses static polymorphism and full template specializations
/// when required, to avoid a performance penalty of doing v-table lookup.
/// 2 instantiations are forced in impl. file: for @c ArgoProtocol and
/// @c ArgoProtocolWREM3
/// @note This class is abstract (though does not declare a pure-virtual fn.
/// for abovementioned reasons), and instead declares protected c-tor
/// @tparam ARGO_PROTOCOL_T The Raw device protocol/message used
template <typename ARGO_PROTOCOL_T>
class IRArgoACBase {
#ifndef UNIT_TEST // A less cloggy way of expressing FRIEND_TEST(...)
protected:
#else
public: public:
explicit IRArgoAC(const uint16_t pin, const bool inverted = false, #endif
explicit IRArgoACBase(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true); const bool use_modulation = true);
public:
#if SEND_ARGO #if SEND_ARGO
void send(const uint16_t repeat = kArgoDefaultRepeat); void send(const uint16_t repeat = kArgoDefaultRepeat);
void sendSensorTemp(const uint8_t temp,
const uint16_t repeat = kArgoDefaultRepeat);
/// Run the calibration to calculate uSec timing offsets for this platform. /// Run the calibration to calculate uSec timing offsets for this platform.
/// @return The uSec timing offset needed per modulation of the IR Led. /// @return The uSec timing offset needed per modulation of the IR Led.
/// @note This will produce a 65ms IR signal pulse at 38kHz. /// @note This will produce a 65ms IR signal pulse at 38kHz.
/// Only ever needs to be run once per object instantiation, if at all. /// Only ever needs to be run once per object instantiation, if at all.
int8_t calibrate(void) { return _irsend.calibrate(); } int8_t calibrate(void) { return _irsend.calibrate(); }
#endif // SEND_ARGO #endif // SEND_ARGO
void begin(void); void begin(void);
void on(void); void on(void);
void off(void); void off(void);
@ -149,14 +342,20 @@ class IRArgoAC {
void setTemp(const uint8_t degrees); void setTemp(const uint8_t degrees);
uint8_t getTemp(void) const; uint8_t getTemp(void) const;
void setFan(const uint8_t fan); void setSensorTemp(const uint8_t degrees);
uint8_t getFan(void) const; uint8_t getSensorTemp(void) const;
void setFlap(const uint8_t flap); void setFan(const argoFan_t fan);
uint8_t getFlap(void) const; void setFanEx(const argoFan_t fan) { setFan(fan); }
argoFan_t getFanEx(void) const; ///< `-Ex` for backw. compat w/ @c IRArgoAC
void setMode(const uint8_t mode); void setFlap(const argoFlap_t flap);
uint8_t getMode(void) const; void setFlapEx(const argoFlap_t flap) { setFlap(flap); }
argoFlap_t getFlapEx(void) const; ///< `-Ex` for backw. compat w/ @c IRArgoAC
void setMode(const argoMode_t mode);
void setModeEx(const argoMode_t mode) { setMode(mode); }
argoMode_t getModeEx(void) const; ///< `-Ex` for backw. compat w/ @c IRArgoAC
void setMax(const bool on); void setMax(const bool on);
bool getMax(void) const; bool getMax(void) const;
@ -167,41 +366,156 @@ class IRArgoAC {
void setiFeel(const bool on); void setiFeel(const bool on);
bool getiFeel(void) const; bool getiFeel(void) const;
void setTime(void); void setMessageType(const argoIrMessageType_t msgType);
void setRoomTemp(const uint8_t degrees); argoIrMessageType_t getMessageType(void) const;
uint8_t getRoomTemp(void) const; static argoIrMessageType_t getMessageType(const uint8_t state[],
const uint16_t length);
uint8_t* getRaw(void); uint8_t* getRaw(void);
void setRaw(const uint8_t state[]); uint16_t getRawByteLength() const;
static uint8_t calcChecksum(const uint8_t state[], static uint16_t getStateLengthForIrMsgType(argoIrMessageType_t type);
const uint16_t length = kArgoStateLength); void setRaw(const uint8_t state[], const uint16_t length);
static bool validChecksum(const uint8_t state[],
const uint16_t length = kArgoStateLength); static bool validChecksum(const uint8_t state[], const uint16_t length);
static uint8_t convertMode(const stdAc::opmode_t mode);
static uint8_t convertFan(const stdAc::fanspeed_t speed); static argoMode_t convertMode(const stdAc::opmode_t mode);
static uint8_t convertSwingV(const stdAc::swingv_t position); static argoFan_t convertFan(const stdAc::fanspeed_t speed);
static stdAc::opmode_t toCommonMode(const uint8_t mode); static argoFlap_t convertSwingV(const stdAc::swingv_t position);
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); static argoIrMessageType_t convertCommand(const stdAc::ac_command_t command);
stdAc::state_t toCommon(void) const;
String toString(void) const; protected:
void _stateReset(ARGO_PROTOCOL_T *state, argoIrMessageType_t messageType
= argoIrMessageType_t::AC_CONTROL);
void stateReset(argoIrMessageType_t messageType
= argoIrMessageType_t::AC_CONTROL);
void _checksum(ARGO_PROTOCOL_T *state);
void checksum(void);
static uint16_t getRawByteLength(const ARGO_PROTOCOL_T& raw,
argoIrMessageType_t messageTypeHint = argoIrMessageType_t::AC_CONTROL);
static uint8_t calcChecksum(const uint8_t state[], const uint16_t length);
static uint8_t getChecksum(const uint8_t state[], const uint16_t length);
static stdAc::opmode_t toCommonMode(const argoMode_t mode);
static stdAc::fanspeed_t toCommonFanSpeed(const argoFan_t speed);
static stdAc::swingv_t toCommonSwingV(const uint8_t position);
static stdAc::ac_command_t toCommonCommand(const argoIrMessageType_t command);
// Attributes
ARGO_PROTOCOL_T _; ///< The raw protocol data
uint16_t _length = kArgoStateLength;
argoIrMessageType_t _messageType = argoIrMessageType_t::AC_CONTROL;
#ifndef UNIT_TEST #ifndef UNIT_TEST
private: protected:
IRsend _irsend; ///< instance of the IR send class IRsend _irsend; ///< instance of the IR send class
#else #else
public:
/// @cond IGNORE /// @cond IGNORE
IRsendTest _irsend; ///< instance of the testing IR send class IRsendTest _irsend; ///< instance of the testing IR send class
/// @endcond /// @endcond
#endif #endif
// # of bytes per command };
ArgoProtocol _;
void stateReset(void);
void checksum(void);
// Attributes /// @brief Supports Argo A/C SAC-WREM2 IR remote protocol
uint8_t flap_mode; class IRArgoAC : public IRArgoACBase<ArgoProtocol> {
uint8_t heat_mode; public:
uint8_t cool_mode; explicit IRArgoAC(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);
#if SEND_ARGO
void sendSensorTemp(const uint8_t degrees,
const uint16_t repeat = kArgoDefaultRepeat);
#endif // SEND_ARGO
String toString(void) const;
stdAc::state_t toCommon(void) const;
using IRArgoACBase<ArgoProtocol>::setMode;
void setMode(const uint8_t mode); /// @deprecated, for backwards-compat.
uint8_t getMode(void) const; /// @deprecated, for backwards-compat.
using IRArgoACBase<ArgoProtocol>::setFan;
void setFan(const uint8_t fan); /// @deprecated, for backwards-compat.
uint8_t getFan(void) const; /// @deprecated, for backwards-compat.
using IRArgoACBase<ArgoProtocol>::setFlap;
void setFlap(const uint8_t flap); /// @deprecated, for backwards-compat.
uint8_t getFlap(void) const; /// @deprecated, for backwards-compat.
};
/// @brief Supports Argo A/C SAC-WREM3 IR remote protocol
class IRArgoAC_WREM3 : public IRArgoACBase<ArgoProtocolWREM3> {
public:
explicit IRArgoAC_WREM3(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);
#if SEND_ARGO
void sendSensorTemp(const uint8_t degrees,
const uint16_t repeat = kArgoDefaultRepeat);
#endif // SEND_ARGO
argo_ac_remote_model_t getModel(void) const;
argoFan_t getFan(void) const;
argoFlap_t getFlap(void) const;
argoMode_t getMode(void) const;
void setEco(const bool on);
bool getEco(void) const;
void setFilter(const bool on);
bool getFilter(void) const;
void setLight(const bool on);
bool getLight(void) const;
void setChannel(const uint8_t channel);
uint8_t getChannel(void) const;
void setConfigEntry(const uint8_t paramId, const uint8_t value);
std::pair<uint8_t, uint8_t> getConfigEntry(void) const;
void setCurrentTimeMinutes(uint16_t currentTimeMinutes);
uint16_t getCurrentTimeMinutes(void) const;
void setCurrentDayOfWeek(argoWeekday dayOfWeek);
argoWeekday getCurrentDayOfWeek(void) const;
void setTimerType(const argoTimerType_t timerType);
argoTimerType_t getTimerType(void) const;
void setDelayTimerMinutes(const uint16_t delayMinutes);
uint16_t getDelayTimerMinutes(void) const;
void setScheduleTimerStartMinutes(const uint16_t startTimeMinutes);
uint16_t getScheduleTimerStartMinutes(void) const;
// uint16_t getTimerXStartMinutes(void) const
void setScheduleTimerStopMinutes(const uint16_t stopTimeMinutes);
uint16_t getScheduleTimerStopMinutes(void) const;
// uint16_t getTimerXStopMinutes(void) const;
void setScheduleTimerActiveDays(const std::set<argoWeekday>& days);
std::set<argoWeekday> getScheduleTimerActiveDays(void) const;
uint8_t getTimerActiveDaysBitmap(void) const;
using IRArgoACBase<ArgoProtocolWREM3>::getMessageType;
static argoIrMessageType_t getMessageType(const ArgoProtocolWREM3& raw);
String toString(void) const;
stdAc::state_t toCommon(void) const;
static bool hasValidPreamble(const uint8_t state[], const uint16_t length);
public:
#if DECODE_ARGO
static bool isValidWrem3Message(const uint8_t state[], const uint16_t nbits,
bool verifyChecksum = true);
#endif
}; };
#endif // IR_ARGO_H_ #endif // IR_ARGO_H_

View File

@ -46,6 +46,15 @@ const uint16_t kCarrierAc64OneSpace = 1736;
const uint16_t kCarrierAc64ZeroSpace = 615; const uint16_t kCarrierAc64ZeroSpace = 615;
const uint32_t kCarrierAc64Gap = kDefaultMessageGap; // A guess. const uint32_t kCarrierAc64Gap = kDefaultMessageGap; // A guess.
//< @see: https://github.com/crankyoldgit/IRremoteESP8266/issues/1943#issue-1519570772
const uint16_t kCarrierAc84HdrMark = 5850;
const uint16_t kCarrierAc84Zero = 1175;
const uint16_t kCarrierAc84One = 430;
const uint16_t kCarrierAc84HdrSpace = kCarrierAc84Zero;
const uint32_t kCarrierAc84Gap = kDefaultMessageGap; // A guess.
const uint8_t kCarrierAc84ExtraBits = 4;
const uint8_t kCarrierAc84ExtraTolerance = 5;
const uint16_t kCarrierAc128HdrMark = 4600; const uint16_t kCarrierAc128HdrMark = 4600;
const uint16_t kCarrierAc128HdrSpace = 2600; const uint16_t kCarrierAc128HdrSpace = 2600;
const uint16_t kCarrierAc128Hdr2Mark = 9300; const uint16_t kCarrierAc128Hdr2Mark = 9300;
@ -645,3 +654,94 @@ bool IRrecv::decodeCarrierAC128(decode_results *results, uint16_t offset,
return true; return true;
} }
#endif // DECODE_CARRIER_AC128 #endif // DECODE_CARRIER_AC128
#if SEND_CARRIER_AC84
/// Send a Carroer A/C 84 Bit formatted message.
/// Status: BETA / Untested but probably works.
/// @param[in] data The message to be sent.
/// @param[in] nbytes The byte size of the message being sent.
/// @param[in] repeat The number of times the command is to be repeated.
void IRsend::sendCarrierAC84(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
// Protocol uses a constant bit time encoding.
for (uint16_t r = 0; r <= repeat; r++) {
if (nbytes) {
// The least significant `kCarrierAc84ExtraBits` bits of the first byte
sendGeneric(kCarrierAc84HdrMark, kCarrierAc84HdrSpace, // Header
kCarrierAc84Zero, kCarrierAc84One, // Data
kCarrierAc84One, kCarrierAc84Zero,
0, 0, // No footer
GETBITS64(data[0], 0, kCarrierAc84ExtraBits),
kCarrierAc84ExtraBits,
38000, false, 0, 33);
// The rest of the data.
sendGeneric(0, 0, // No Header
kCarrierAc84Zero, kCarrierAc84One, // Data
kCarrierAc84One, kCarrierAc84Zero,
kCarrierAc84Zero, kDefaultMessageGap, // Footer
data + 1, nbytes - 1, 38000, false, 0, 33);
}
}
}
#endif // SEND_CARRIER_AC84
#if DECODE_CARRIER_AC84
/// Decode the supplied Carroer A/C 84 Bit formatted message.
/// Status: STABLE / Confirmed Working.
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// result.
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
/// @return A boolean. True if it can decode it, false if it can't.
bool IRrecv::decodeCarrierAC84(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
// Check if we have enough data to even possibly match.
if (results->rawlen < 2 * nbits + kHeader + kFooter - 1 + offset)
return false; // Can't possibly be a valid Carrier message.
// Compliance check.
if (strict && nbits != kCarrierAc84Bits) return false;
// This decoder expects to decode an unusual number of bits. Check before we
// start.
if (nbits % 8 != kCarrierAc84ExtraBits) return false;
uint64_t data = 0;
uint16_t used = 0;
// Header + Data (kCarrierAc84ExtraBits only)
used = matchGenericConstBitTime(results->rawbuf + offset, &data,
results->rawlen - offset,
kCarrierAc84ExtraBits,
// Header (None)
kCarrierAc84HdrMark, kCarrierAc84HdrSpace,
// Data
kCarrierAc84Zero, kCarrierAc84One,
// No Footer
0, 0,
false,
_tolerance + kCarrierAc84ExtraTolerance,
kMarkExcess, false);
if (!used) return false;
// Stuff the captured data so far into the first byte of the state.
*results->state = data;
offset += used;
// Capture the rest of the data as normal as we should be on a byte boundary.
// Data + Footer
if (!matchGeneric(results->rawbuf + offset, results->state + 1,
results->rawlen - offset, nbits - kCarrierAc84ExtraBits,
0, 0, // No Header expected.
kCarrierAc84Zero, kCarrierAc84One, // Data
kCarrierAc84One, kCarrierAc84Zero,
kCarrierAc84Zero, kDefaultMessageGap, true,
_tolerance + kCarrierAc84ExtraTolerance,
kMarkExcess, false)) return false;
// Success
results->decode_type = decode_type_t::CARRIER_AC84;
results->bits = nbits;
results->repeat = false;
return true;
}
#endif // DECODE_CARRIER_AC84

View File

@ -4,6 +4,7 @@
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1127 /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1127
/// @see https://docs.google.com/spreadsheets/d/1EZy78L0cn1KDIX1aKq2biptejFqCjD5HO3tLiRvXf48/edit#gid=0 /// @see https://docs.google.com/spreadsheets/d/1EZy78L0cn1KDIX1aKq2biptejFqCjD5HO3tLiRvXf48/edit#gid=0
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1797 /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1797
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1943
// Supports: // Supports:
// Brand: Carrier/Surrey, Model: 42QG5A55970 remote // Brand: Carrier/Surrey, Model: 42QG5A55970 remote
@ -13,6 +14,8 @@
// Brand: Carrier/Surrey, Model: 619EGX0220E0 A/C // Brand: Carrier/Surrey, Model: 619EGX0220E0 A/C
// Brand: Carrier/Surrey, Model: 53NGK009/012 Inverter // Brand: Carrier/Surrey, Model: 53NGK009/012 Inverter
// Brand: Carrier, Model: 40GKX0E2006 remote (CARRIER_AC128) // Brand: Carrier, Model: 40GKX0E2006 remote (CARRIER_AC128)
// Brand: Carrier, Model: 3021203 RR03-S-Remote (CARRIER_AC84)
// Brand: Carrier, Model: 342WM100CT A/C (CARRIER_AC84)
#ifndef IR_CARRIER_H_ #ifndef IR_CARRIER_H_
#define IR_CARRIER_H_ #define IR_CARRIER_H_

View File

@ -548,6 +548,8 @@ stdAc::state_t IRCoolixAC::toCommon(const stdAc::state_t *prev) const {
// Back to "normal" stateful messages. // Back to "normal" stateful messages.
result.mode = toCommonMode(getMode()); result.mode = toCommonMode(getMode());
result.degrees = getTemp(); result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.iFeel = getZoneFollow();
result.fanspeed = toCommonFanSpeed(getFan()); result.fanspeed = toCommonFanSpeed(getFan());
return result; return result;
} }

View File

@ -165,6 +165,7 @@ class IRCoolixAC {
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const; stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const;
String toString(void) const; String toString(void) const;
void setZoneFollow(const bool on);
#ifndef UNIT_TEST #ifndef UNIT_TEST
private: private:
@ -189,7 +190,6 @@ class IRCoolixAC {
void setTempRaw(const uint8_t code); void setTempRaw(const uint8_t code);
uint8_t getTempRaw(void) const; uint8_t getTempRaw(void) const;
void setSensorTempRaw(const uint8_t code); void setSensorTempRaw(const uint8_t code);
void setZoneFollow(const bool on);
bool isSpecialState(void) const; bool isSpecialState(void) const;
bool handleSpecialState(const uint32_t data); bool handleSpecialState(const uint32_t data);
void updateAndSaveState(const uint32_t raw_state); void updateAndSaveState(const uint32_t raw_state);

View File

@ -365,6 +365,7 @@ stdAc::state_t IREcoclimAc::toCommon(void) const {
result.mode = toCommonMode(getMode()); result.mode = toCommonMode(getMode());
result.celsius = true; result.celsius = true;
result.degrees = getTemp(); result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(_.Fan); result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = (getMode() == kEcoclimSleep) ? 0 : -1; result.sleep = (getMode() == kEcoclimSleep) ? 0 : -1;
result.clock = getClock(); result.clock = getClock();

View File

@ -365,6 +365,7 @@ stdAc::state_t IRElectraAc::toCommon(void) const {
result.mode = toCommonMode(_.Mode); result.mode = toCommonMode(_.Mode);
result.celsius = true; result.celsius = true;
result.degrees = getTemp(); result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(_.Fan); result.fanspeed = toCommonFanSpeed(_.Fan);
result.swingv = getSwingV() ? stdAc::swingv_t::kAuto result.swingv = getSwingV() ? stdAc::swingv_t::kAuto
: stdAc::swingv_t::kOff; : stdAc::swingv_t::kOff;
@ -373,6 +374,7 @@ stdAc::state_t IRElectraAc::toCommon(void) const {
result.light = getLightToggle(); result.light = getLightToggle();
result.turbo = _.Turbo; result.turbo = _.Turbo;
result.clean = _.Clean; result.clean = _.Clean;
result.iFeel = getIFeel();
// Not supported. // Not supported.
result.model = -1; // No models used. result.model = -1; // No models used.
result.quiet = false; result.quiet = false;

View File

@ -14,6 +14,7 @@
// Brand: Centek, Model: SCT-65Q09 A/C // Brand: Centek, Model: SCT-65Q09 A/C
// Brand: Centek, Model: YKR-P/002E remote // Brand: Centek, Model: YKR-P/002E remote
// Brand: AEG, Model: Chillflex Pro AXP26U338CW A/C // Brand: AEG, Model: Chillflex Pro AXP26U338CW A/C
// Brand: Electrolux, Model: YKR-H/531E A/C
#ifndef IR_ELECTRA_H_ #ifndef IR_ELECTRA_H_
#define IR_ELECTRA_H_ #define IR_ELECTRA_H_

View File

@ -0,0 +1,71 @@
// Copyright 2022 Mateusz Bronk (mbronk)
/// @file
/// @brief Support for the Gorenje cooker hood IR protocols.
/// @see https://techfresh.pl/wp-content/uploads/2017/08/Gorenje-DKF-2600-MWT.pdf
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1887
// Supports:
// Brand: Gorenje, Model: DKF 2600 MWT Cooker Hood
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
const uint32_t kGorenjeMinGap = 100000U; // 0.1s
const uint16_t kGorenjeHdrMark = 0;
const uint32_t kGorenjeHdrSpace = 0;
const uint16_t kGorenjeBitMark = 1300;
const uint32_t kGorenjeOneSpace = 5700;
const uint32_t kGorenjeZeroSpace = 1700;
const uint16_t kGorenjeFreq = 38000; // Hz
const uint16_t kGorenjeTolerance = 7; // %
#if SEND_GORENJE
/// Send a Gorenje Cooker Hood formatted message.
/// Status: STABLE / Known working.
/// @param[in] data containing the IR command to be sent.
/// @param[in] nbits Nr. of bits of the message to send. usually kGorenjeBits
/// @param[in] repeat Nr. of times the message is to be repeated.
void IRsend::sendGorenje(const uint64_t data, const uint16_t nbits,
const uint16_t repeat) {
sendGeneric(kGorenjeHdrMark, kGorenjeHdrSpace,
kGorenjeBitMark, kGorenjeOneSpace,
kGorenjeBitMark, kGorenjeZeroSpace,
kGorenjeBitMark, kGorenjeMinGap,
data, nbits, kGorenjeFreq, true, repeat, kDutyDefault);
}
#endif // SEND_GORENJE
#if DECODE_GORENJE
/// Decode the supplied Gorenje Cooker Hood message.
/// Status: STABLE / Known working.
/// @param[in,out] results Ptr to the data to decode & where to store the
/// decoded result
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
/// @return A boolean. True if it can decode it, false if it can't.
bool IRrecv::decodeGorenje(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kGorenjeBits)
return false; // We expect Gorenje to be a certain sized message.
uint64_t data = 0;
if (!matchGeneric(results->rawbuf + offset, &data,
results->rawlen - offset, nbits,
kGorenjeHdrMark, kGorenjeHdrSpace,
kGorenjeBitMark, kGorenjeOneSpace,
kGorenjeBitMark, kGorenjeZeroSpace,
kGorenjeBitMark, kGorenjeMinGap,
true, kGorenjeTolerance)) return false;
// Matched!
results->bits = nbits;
results->value = data;
results->decode_type = decode_type_t::GORENJE;
results->command = 0;
results->address = 0;
return true;
}
#endif // DECODE_GORENJE

View File

@ -591,6 +591,8 @@ stdAc::state_t IRGreeAC::toCommon(void) {
result.mode = toCommonMode(_.Mode); result.mode = toCommonMode(_.Mode);
result.celsius = !_.UseFahrenheit; result.celsius = !_.UseFahrenheit;
result.degrees = getTemp(); result.degrees = getTemp();
// no support for Sensor temp.
result.iFeel = getIFeel();
result.fanspeed = toCommonFanSpeed(_.Fan); result.fanspeed = toCommonFanSpeed(_.Fan);
if (_.SwingAuto) if (_.SwingAuto)
result.swingv = stdAc::swingv_t::kAuto; result.swingv = stdAc::swingv_t::kAuto;

View File

@ -679,6 +679,7 @@ stdAc::state_t IRMideaAC::toCommon(const stdAc::state_t *prev) {
result.mode = toCommonMode(_.Mode); result.mode = toCommonMode(_.Mode);
result.celsius = !_.useFahrenheit; result.celsius = !_.useFahrenheit;
result.degrees = getTemp(result.celsius); result.degrees = getTemp(result.celsius);
result.sensorTemperature = getSensorTemp(result.celsius);
result.fanspeed = toCommonFanSpeed(_.Fan); result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = _.Sleep ? 0 : -1; result.sleep = _.Sleep ? 0 : -1;
result.econo = getEconoToggle(); result.econo = getEconoToggle();

View File

@ -740,6 +740,7 @@ stdAc::state_t IRMirageAc::toCommon(void) const {
result.mode = toCommonMode(_.Mode); result.mode = toCommonMode(_.Mode);
result.celsius = true; result.celsius = true;
result.degrees = getTemp(); result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(getFan(), _model); result.fanspeed = toCommonFanSpeed(getFan(), _model);
result.swingv = toCommonSwingV(getSwingV()); result.swingv = toCommonSwingV(getSwingV());
result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff; result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff;
@ -750,6 +751,7 @@ stdAc::state_t IRMirageAc::toCommon(void) const {
result.sleep = getSleep() ? 0 : -1; result.sleep = getSleep() ? 0 : -1;
result.quiet = getQuiet(); result.quiet = getQuiet();
result.clock = getClock() / 60; result.clock = getClock() / 60;
result.iFeel = getIFeel();
// Not supported. // Not supported.
result.econo = false; result.econo = false;
result.beep = false; result.beep = false;
@ -775,10 +777,14 @@ void IRMirageAc::fromCommon(const stdAc::state_t state) {
setFilter(state.filter); setFilter(state.filter);
// setClock() expects seconds, not minutes. // setClock() expects seconds, not minutes.
setClock((state.clock > 0) ? state.clock * 60 : 0); setClock((state.clock > 0) ? state.clock * 60 : 0);
setIFeel(state.iFeel);
if (state.sensorTemperature != kNoTempValue) {
setSensorTemp(state.celsius ? state.sensorTemperature
: fahrenheitToCelsius(state.sensorTemperature));
}
// Non-common settings. // Non-common settings.
setOnTimer(0); setOnTimer(0);
setOffTimer(0); setOffTimer(0);
setIFeel(false);
} }
/// Convert the internal state into a human readable string. /// Convert the internal state into a human readable string.

View File

@ -36,6 +36,7 @@
// Brand: Mitsubishi Electric, Model: MSZ-ZW4017S A/C (MITSUBISHI_AC) // Brand: Mitsubishi Electric, Model: MSZ-ZW4017S A/C (MITSUBISHI_AC)
// Brand: Mitsubishi Electric, Model: MSZ-FHnnVE A/C (MITSUBISHI_AC) // Brand: Mitsubishi Electric, Model: MSZ-FHnnVE A/C (MITSUBISHI_AC)
// Brand: Mitsubishi Electric, Model: RH151 remote (MITSUBISHI_AC) // Brand: Mitsubishi Electric, Model: RH151 remote (MITSUBISHI_AC)
// Brand: Mitsubishi Electric, Model: PAR-FA32MA remote (MITSUBISHI136)
#ifndef IR_MITSUBISHI_H_ #ifndef IR_MITSUBISHI_H_
#define IR_MITSUBISHI_H_ #define IR_MITSUBISHI_H_

View File

@ -128,8 +128,15 @@ uint64_t IRsend::encodePanasonic(const uint16_t manufacturer,
bool IRrecv::decodePanasonic(decode_results *results, uint16_t offset, bool IRrecv::decodePanasonic(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict, const uint16_t nbits, const bool strict,
const uint32_t manufacturer) { const uint32_t manufacturer) {
if (strict && nbits != kPanasonicBits) if (strict) { // Compliance checks
return false; // Request is out of spec. switch (nbits) {
case kPanasonic40Bits:
case kPanasonicBits:
break;
default:
return false; // Request is out of spec.
}
}
uint64_t data = 0; uint64_t data = 0;
@ -147,8 +154,10 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t offset,
if (address != manufacturer) // Verify the Manufacturer code. if (address != manufacturer) // Verify the Manufacturer code.
return false; return false;
// Verify the checksum. // Verify the checksum.
uint8_t checksumOrig = data; const uint8_t checksumOrig = data;
uint8_t checksumCalc = (data >> 24) ^ (data >> 16) ^ (data >> 8); uint8_t checksumCalc = (data >> 16) ^ (data >> 8);
if (nbits != kPanasonic40Bits)
checksumCalc ^= (data >> 24);
if (checksumOrig != checksumCalc) return false; if (checksumOrig != checksumCalc) return false;
} }

View File

@ -622,10 +622,12 @@ stdAc::state_t IRSanyoAc::toCommon(void) const {
result.mode = toCommonMode(_.Mode); result.mode = toCommonMode(_.Mode);
result.celsius = true; result.celsius = true;
result.degrees = getTemp(); result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(_.Fan); result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = _.Sleep ? 0 : -1; result.sleep = _.Sleep ? 0 : -1;
result.swingv = toCommonSwingV(_.SwingV); result.swingv = toCommonSwingV(_.SwingV);
result.beep = _.Beep; result.beep = _.Beep;
result.iFeel = !getSensor();
// Not supported. // Not supported.
result.swingh = stdAc::swingh_t::kOff; result.swingh = stdAc::swingh_t::kOff;
result.turbo = false; result.turbo = false;
@ -762,13 +764,13 @@ void IRSanyoAc88::stateReset(void) {
/// Set up hardware to be able to send a message. /// Set up hardware to be able to send a message.
void IRSanyoAc88::begin(void) { _irsend.begin(); } void IRSanyoAc88::begin(void) { _irsend.begin(); }
#if SEND_SANYO_AC #if SEND_SANYO_AC88
/// Send the current internal state as IR messages. /// Send the current internal state as IR messages.
/// @param[in] repeat Nr. of times the message will be repeated. /// @param[in] repeat Nr. of times the message will be repeated.
void IRSanyoAc88::send(const uint16_t repeat) { void IRSanyoAc88::send(const uint16_t repeat) {
_irsend.sendSanyoAc88(getRaw(), kSanyoAc88StateLength, repeat); _irsend.sendSanyoAc88(getRaw(), kSanyoAc88StateLength, repeat);
} }
#endif // SEND_SANYO_AC #endif // SEND_SANYO_AC88
/// Get a PTR to the internal state/code for this protocol with all integrity /// Get a PTR to the internal state/code for this protocol with all integrity
/// checks passing. /// checks passing.

View File

@ -0,0 +1,91 @@
// Copyright 2022 David Conran
/// @file
/// @brief Support for WowWee RoboRapter protocol
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues1938
// Supports:
// Brand: WowWee, Model: RoboRapter-X
// WowWee RoboRapter-X messages
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1938#issuecomment-1367968228
//
// Button Code
// ====== =====
// Left 0x180
// Forward 0x186
// Backward 0x187
// Right 0x188
// Stop 0x18E
// Head Counterclockwise 0x191
// Tail Left 0x192
// Tail Right 0x193
// Head Clockwise 0x194
// Guard Mode 0x1B0
// Roam 0x1B1
// Cautious Mood 0x1B2
// Playful Mood 0x1B3
// Hunting Mood 0x1B4
// Demo 0x1D0
// Bite 0x1D1
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"
// Constants
const uint16_t kWowweeHdrMark = 6684;
const uint16_t kWowweeHdrSpace = 723;
const uint16_t kWowweeBitMark = 912;
const uint16_t kWowweeOneSpace = 3259;
const uint16_t kWowweeZeroSpace = kWowweeHdrSpace;
const uint16_t kWowweeFreq = 38000; // Hz. (Just a guess)
#if SEND_WOWWEE
/// Send a WowWee formatted message.
/// Status: STABLE / Confirmed working with real device.
/// @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.
void IRsend::sendWowwee(uint64_t data, uint16_t nbits, uint16_t repeat) {
sendGeneric(kWowweeHdrMark, kWowweeHdrSpace,
kWowweeBitMark, kWowweeOneSpace,
kWowweeBitMark, kWowweeZeroSpace,
kWowweeBitMark, kDefaultMessageGap, data,
nbits, kWowweeFreq, true, repeat, 33);
}
#endif // SEND_WOWWEE
#if DECODE_WOWWEE
/// Decode the supplied WowWee message.
/// Status: STABLE / Confirmed working with real device.
/// @param[in,out] results Ptr to the data to decode & where to store the result
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
bool IRrecv::decodeWowwee(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kWowweeBits)
return false; // We expect Wowwee to be a certain sized message.
uint64_t data = 0;
// Match Header + Data + Footer
if (!matchGeneric(results->rawbuf + offset, &data,
results->rawlen - offset, nbits,
kWowweeHdrMark, kWowweeHdrSpace,
kWowweeBitMark, kWowweeOneSpace,
kWowweeBitMark, kWowweeZeroSpace,
kWowweeBitMark, kDefaultMessageGap, true)) return false;
// Success
results->bits = nbits;
results->value = data;
results->decode_type = WOWWEE;
results->command = 0;
results->address = 0;
return true;
}
#endif // DECODE_WOWWEE

View File

@ -115,7 +115,7 @@ using IRXmpUtils::adjustRepeat;
#if SEND_XMP #if SEND_XMP
/// Send a XMP packet. /// Send a XMP packet.
/// Status: Beta / Untested against a real device. /// Status: STABLE / Confirmed working against a real device.
/// @param[in] data The message to be sent. /// @param[in] data The message to be sent.
/// @param[in] nbits The number of bits of 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. /// @param[in] repeat The number of times the command is to be repeated.
@ -150,7 +150,7 @@ void IRsend::sendXmp(const uint64_t data, const uint16_t nbits,
#if DECODE_XMP #if DECODE_XMP
/// Decode the supplied XMP packet/message. /// Decode the supplied XMP packet/message.
/// Status: BETA / Probably works. /// Status: STABLE / Confirmed working against a real device.
/// @param[in,out] results Ptr to the data to decode & where to store the result /// @param[in,out] results Ptr to the data to decode & where to store the result
/// @param[in] offset The starting index to use when attempting to decode the /// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset. /// raw data. Typically/Defaults to kStartOffset.

View File

@ -0,0 +1,357 @@
// Copyright 2022 Daniele Gobbetti
/// @file
/// @brief Support for the York AC protocol (remote GRYLH2A)
// Note: Most of the code is autogenerated by the provided tools or assembled
// from other support classes
#include "ir_York.h"
#include <algorithm>
#include <cstring>
#ifndef ARDUINO
#include <string>
#endif
#include "IRrecv.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#ifdef UNIT_TEST
#include "IRsend_test.h"
#endif
#include "IRtext.h"
#include "IRutils.h"
using irutils::addBoolToString;
using irutils::addModeToString;
using irutils::addFanToString;
using irutils::addTempToString;
using irutils::addLabeledString;
using irutils::minsToString;
// Constants
const uint16_t kYorkHdrMark = 4887;
const uint16_t kYorkBitMark = 612;
const uint16_t kYorkHdrSpace = 2267;
const uint16_t kYorkOneSpace = 1778;
const uint16_t kYorkZeroSpace = 579;
const uint16_t kYorkFreq = 38000; // Hz. (Guessing the most common frequency.)
#if SEND_YORK
/// Send a 17 Byte / 136 bit York A/C message.
/// Status: ALPHA / Untested.
/// @param[in] data An array of bytes containing the IR command.
/// @param[in] nbytes Nr. of bytes of data in the array. (>=kStateLength)
/// @param[in] repeat Nr. of times the message is to be repeated.
void IRsend::sendYork(const uint8_t data[], const uint16_t nbytes,
const uint16_t repeat) {
if (nbytes < kYorkStateLength)
return;
sendGeneric(kYorkHdrMark, kYorkHdrSpace,
kYorkBitMark, kYorkOneSpace,
kYorkBitMark, kYorkZeroSpace,
kYorkBitMark, kDefaultMessageGap,
data, nbytes, kYorkFreq,
false, repeat, kDutyDefault); // false == LSB
}
#endif // SEND_YORK
#if DECODE_YORK
/// Decode the supplied message.
/// Status: ALPHA / Tested, some values still are not mapped to the internal
/// state of AC
/// @param[in,out] results Ptr to the data to decode & where to store the decode
/// @param[in] offset The starting index to use when attempting to decode the
/// raw data. Typically/Defaults to kStartOffset.
/// @param[in] nbits The number of data bits to expect.
/// @param[in] strict Flag indicating if we should perform strict matching.
/// @return A boolean. True if it can decode it, false if it can't.
bool IRrecv::decodeYork(decode_results *results, uint16_t offset,
const uint16_t nbits, const bool strict) {
if (strict && nbits != kYorkBits)
return false;
uint16_t used = 0;
used = matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, nbits,
kYorkHdrMark, kYorkHdrSpace,
kYorkBitMark, kYorkOneSpace,
kYorkBitMark, kYorkZeroSpace,
kYorkBitMark, kDefaultMessageGap,
false, _tolerance, kMarkExcess,
false); // LSB
if (used == 0) return false; // We failed to find any data.
// Succes
results->decode_type = decode_type_t::YORK;
results->bits = nbits;
return true;
}
#endif // DECODE_YORK
//
//
/// 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?
IRYorkAc::IRYorkAc(const uint16_t pin, const bool inverted,
const bool use_modulation)
: _irsend(pin, inverted, use_modulation) {
stateReset();
}
// Reset the internal state to a fixed known good state.
void IRYorkAc::stateReset() {
// This resets to a known-good state.
setRaw(kYorkKnownGoodState);
}
/// Set up hardware to be able to send a message.
void IRYorkAc::begin(void) { _irsend.begin(); }
/// Get the raw state of the object, suitable to be sent with the appropriate
/// IRsend object method.
/// @return A copy of the internal state.
uint8_t *IRYorkAc::getRaw(void) {
calcChecksum();
return _.raw;
}
/// Set the internal state from a valid code for this protocol.
/// @param[in] new_code A valid code for this protocol.
/// @param[in] length Length of the code in bytes.
void IRYorkAc::setRaw(const uint8_t new_code[], const uint16_t length) {
std::memcpy(_.raw, new_code, length);
}
#if SEND_YORK
/// Send the current internal state as an IR message.
/// @param[in] repeat Nr. of times the message will be repeated.
void IRYorkAc::send(const uint16_t repeat) {
_irsend.sendYork(getRaw(), kYorkStateLength, repeat);
}
#endif // SEND_YORK
/// Get the current operation mode setting.
/// @return The current operation mode.
uint8_t IRYorkAc::getMode(void) const {
return _.Mode;
}
/// Set the desired operation mode.
/// @param[in] mode The desired operation mode.
void IRYorkAc::setMode(const uint8_t mode) {
switch (mode) {
case kYorkFan:
case kYorkCool:
case kYorkHeat:
case kYorkDry:
_.Mode = mode;
break;
default:
_.Mode = kYorkAuto;
}
setFan(getFan()); // Ensure the fan is at the correct speed for the new mode.
}
/// 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 IRYorkAc::convertMode(const stdAc::opmode_t mode) {
switch (mode) {
case stdAc::opmode_t::kCool: return kYorkCool;
case stdAc::opmode_t::kHeat: return kYorkHeat;
case stdAc::opmode_t::kDry: return kYorkDry;
case stdAc::opmode_t::kFan: return kYorkFan;
default: return kYorkAuto;
}
}
/// 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 IRYorkAc::toCommonMode(const uint8_t mode) {
switch (mode) {
case kYorkCool: return stdAc::opmode_t::kCool;
case kYorkHeat: return stdAc::opmode_t::kHeat;
case kYorkDry: return stdAc::opmode_t::kDry;
case kYorkFan: return stdAc::opmode_t::kFan;
default: return stdAc::opmode_t::kAuto;
}
}
/// Set the speed of the fan.
/// @param[in] speed The desired setting.
/// @note The fan speed is locked to Low when in Dry mode, to auto when in auto
/// mode. "Fan" mode has no support for "auto" speed.
void IRYorkAc::setFan(const uint8_t speed) {
switch (getMode()) {
case kYorkDry:
_.Fan = kYorkFanLow;
break;
case kYorkFan:
_.Fan = std::min(speed, kYorkFanHigh);
break;
case kYorkAuto:
_.Fan = kYorkFanAuto;
break;
default:
_.Fan = std::min(speed, kYorkFanAuto);
}
}
/// Get the current fan speed setting.
/// @return The current fan speed.
uint8_t IRYorkAc::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 IRYorkAc::convertFan(const stdAc::fanspeed_t speed) {
switch (speed) {
case stdAc::fanspeed_t::kMin:
case stdAc::fanspeed_t::kLow:
return kYorkFanLow;
case stdAc::fanspeed_t::kMedium:
return kYorkFanMedium;
case stdAc::fanspeed_t::kHigh:
case stdAc::fanspeed_t::kMax:
return kYorkFanHigh;
default:
return kYorkFanAuto;
}
}
/// 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 IRYorkAc::toCommonFanSpeed(const uint8_t speed) {
switch (speed) {
case kYorkFanHigh: return stdAc::fanspeed_t::kMax;
case kYorkFanMedium: return stdAc::fanspeed_t::kMedium;
case kYorkFanLow: return stdAc::fanspeed_t::kMin;
default: return stdAc::fanspeed_t::kAuto;
}
}
/// Set the temperature.
/// @param[in] degrees The temperature in degrees celsius.
void IRYorkAc::setTemp(const uint8_t degrees) {
_.Temp = std::min(kYorkMaxTemp, std::max(kYorkMinTemp, degrees));
}
/// Get the current temperature setting.
/// @return Get current setting for temp. in degrees celsius.
uint8_t IRYorkAc::getTemp(void) const {
return _.Temp;
}
/// Set the On Timer value of the A/C.
/// @param[in] nr_of_mins The number of minutes the timer should be.
/// @note The timer time only has a resolution of 10 mins.
/// @note Setting the On Timer active will cancel the Sleep timer/setting.
void IRYorkAc::setOnTimer(const uint16_t nr_of_mins) {
_.OnTimer = nr_of_mins / 10;
}
/// Set the Off Timer value of the A/C.
/// @param[in] nr_of_mins The number of minutes the timer should be.
/// @note The timer time only has a resolution of 10 mins.
/// @note Setting the Off Timer active will cancel the Sleep timer/setting.
void IRYorkAc::setOffTimer(const uint16_t nr_of_mins) {
_.OffTimer = nr_of_mins / 10;
}
/// Get the On Timer setting of the A/C.
/// @return The Nr. of minutes the On Timer is set for.
uint16_t IRYorkAc::getOnTimer(void) const {
return _.OnTimer * 10;
}
/// Get the Off Timer setting of the A/C.
/// @return The Nr. of minutes the Off Timer is set for.
/// @note Sleep & Off Timer share the same timer.
uint16_t IRYorkAc::getOffTimer(void) const {
return _.OffTimer * 10;
}
/// CRC16-16 (a.k.a. CRC-16-IBM)
void IRYorkAc::calcChecksum() {
uint8_t length = 14;
uint16_t reg_crc = 0x0000;
uint8_t* data = _.raw;
while (length--) {
reg_crc ^= *data++;
for (uint16_t index = 0; index < 8; index++) {
if (reg_crc & 0x01) {
reg_crc = (reg_crc>>1) ^ 0xA001;
} else {
reg_crc = reg_crc >>1;
}
}
}
_.Chk1 = (reg_crc & 0xff);
_.Chk2 = ((reg_crc >> 8) & 0x00ff);
}
/// Convert the current internal state into its stdAc::state_t equivalent.
/// @param[in] prev Ptr to the previous state if required.
/// @return The stdAc equivalent of the native settings.
stdAc::state_t IRYorkAc::toCommon(const stdAc::state_t *prev) const {
stdAc::state_t result{};
// Start with the previous state if given it.
if (prev != NULL) {
result = *prev;
} else {
// Set defaults for non-zero values that are not implicitly set for when
// there is no previous state.
// e.g. Any setting that toggles should probably go here.
result.power = false;
}
result.protocol = decode_type_t::YORK;
result.mode = toCommonMode(_.Mode);
result.celsius = true;
result.degrees = getTemp();
result.fanspeed = toCommonFanSpeed(_.Fan);
result.swingv = _.SwingV ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
result.sleep = getOffTimer();
// Not supported.
result.model = -1;
result.turbo = false;
result.swingh = stdAc::swingh_t::kOff;
result.light = false;
result.filter = false;
result.econo = false;
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 IRYorkAc::toString(void) const {
String result = "";
result.reserve(70); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(_.Power, kPowerStr, false);
result += addModeToString(_.Mode, kYorkAuto, kYorkCool,
kYorkHeat, kYorkDry, kYorkFan);
result += addFanToString(_.Fan, kYorkFanHigh, kYorkFanLow,
kYorkFanAuto, kYorkFanAuto,
kYorkFanMedium);
result += addTempToString(getTemp(), true);
result += addBoolToString(_.SwingV, kSwingVStr);
result += addLabeledString(minsToString(getOnTimer()), kOnTimerStr);
result += addLabeledString(minsToString(getOffTimer()), kOffTimerStr);
return result;
}

View File

@ -0,0 +1,137 @@
// Copyright 2022 Daniele Gobbetti
/// @file
/// @brief Support for the York AC protocol (remote GRYLH2A)
// Supports:
// Brand: York, Model: MHH07P17 A/C
// Brand: York, Model: GRYLH2A remote
#ifndef IR_YORK_H_
#define IR_YORK_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include "IRremoteESP8266.h"
#include "IRsend.h"
#ifdef UNIT_TEST
#include "IRsend_test.h"
#endif
/// Native representation of a York A/C message.
union YorkProtocol{
uint8_t raw[kYorkStateLength]; ///< The state of the IR remote.
struct {
// byte 0-5
uint8_t preamble[6]; // unknown, fixed 0x08, 0x10, 0x07, 0x02, 0x40, 0x08
// byte 6
uint8_t Key1 :4; // key pressed on the remote: 1 power, 2 temp up, 3
// temp down...
uint8_t Key2 :4; // only set when setting ontime/offtime:
// Key1 value is 0x6 (enter key) and Key2 is 0x3 for
// "start" and 0x2 for "stop"
// byte 7
uint8_t Fan :4; // Fan speed: 1 low, 2 mid, 3 max, 8 auto
uint8_t Power :1; // main unit power: 1 on, 0 off
uint8_t :3;
// byte 8
uint8_t Mode :4; // 1 heat, 2 cool, 3 dry, 4 fan, 8 auto
uint8_t :4;
// byte 9
uint8_t :2;
uint8_t Temp :6; // Degrees Celsius
// byte 10
uint8_t OffTimer :8; // Power off time: 10s of minutes from now
// byte 11
uint8_t OnTimer :8; // Power on time: 10s of minutes from now
// byte 12
uint8_t :8; // unknown, normally 0x00, could be 0x08 when ontime
// set, 0x88 if both on and offtime set, 0x60 if
// sleep mode set
// byte 13
uint8_t SwingV :1; // 0 off, 1 on
uint8_t :7;
// byte 14
uint8_t :8; // checksum preamble, fixed 0xEC
// byte 15-16
uint8_t Chk1 :8; // checksum, algorithm CRC-16/ARC, first byte
uint8_t Chk2 :8; // checksum, algorithm CRC-16/ARC, second byte
};
};
// Constants
const uint8_t kYorkKnownGoodState[kYorkStateLength] = {
0x08, 0x10, 0x07, 0x02, 0x40, 0x08,
0x03, 0x18, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00,
0xEC,
0xF5, 0xF2}; // Mode "Heat", Fan Speed "auto", Temp: 24, Power: on
// Temperature
const uint8_t kYorkMinTemp = 18; // Celsius
const uint8_t kYorkMaxTemp = 32; // Celsius
// Fan
const uint8_t kYorkFanLow = 1;
const uint8_t kYorkFanMedium = 2;
const uint8_t kYorkFanHigh = 3;
const uint8_t kYorkFanAuto = 8;
// Modes
const uint8_t kYorkHeat = 1;
const uint8_t kYorkCool = 2;
const uint8_t kYorkDry = 3;
const uint8_t kYorkFan = 4;
const uint8_t kYorkAuto = 8;
// Classes
/// Class for handling detailed York A/C messages.
class IRYorkAc {
public:
explicit IRYorkAc(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);
void stateReset();
#if SEND_YORK
void send(const uint16_t repeat = kNoRepeat);
/// Run the calibration to calculate uSec timing offsets for this platform.
/// @return The uSec timing offset needed per modulation of the IR Led.
/// @note This will produce a 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_YORK
void begin();
void setPowerToggle(const bool on);
bool getPowerToggle() const;
void setTemp(const uint8_t temp);
uint8_t getTemp() const;
void setFan(const uint8_t speed);
uint8_t getFan() const;
void setMode(const uint8_t mode);
uint8_t getMode() const;
uint16_t getOnTimer(void) const;
uint16_t getOffTimer(void) const;
void setOnTimer(const uint16_t mins);
void setOffTimer(const uint16_t mins);
uint8_t* getRaw();
void setRaw(const uint8_t new_code[],
const uint16_t length = kYorkStateLength);
static uint8_t convertMode(const stdAc::opmode_t mode);
static uint8_t convertFan(const stdAc::fanspeed_t speed);
void calcChecksum();
static stdAc::opmode_t toCommonMode(const uint8_t mode);
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const;
String toString() const;
#ifndef UNIT_TEST
private:
IRsend _irsend; ///< Instance of the IR send class
#else
/// @cond IGNORE
IRsendTest _irsend; ///< Instance of the testing IR send class
/// @endcond
#endif
YorkProtocol _;
};
#endif // IR_YORK_H_

View File

@ -310,6 +310,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_LOCK #ifndef D_STR_LOCK
#define D_STR_LOCK "Lock" #define D_STR_LOCK "Lock"
#endif // D_STR_LOCK #endif // D_STR_LOCK
#ifndef D_STR_REPORT
#define D_STR_REPORT "Report"
#endif // D_STR_REPORT
#ifndef D_STR_AUTO #ifndef D_STR_AUTO
#define D_STR_AUTO "Auto" #define D_STR_AUTO "Auto"
@ -378,6 +381,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_MEDIUM #ifndef D_STR_MEDIUM
#define D_STR_MEDIUM "Medium" #define D_STR_MEDIUM "Medium"
#endif // D_STR_MEDIUM #endif // D_STR_MEDIUM
#ifndef D_STR_MED_HIGH
#define D_STR_MED_HIGH D_STR_MED "-" D_STR_HIGH
#endif // D_STR_MED_HIGH
#ifndef D_STR_HIGHEST #ifndef D_STR_HIGHEST
#define D_STR_HIGHEST "Highest" #define D_STR_HIGHEST "Highest"
@ -445,6 +451,33 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_BOTTOM #ifndef D_STR_BOTTOM
#define D_STR_BOTTOM "Bottom" #define D_STR_BOTTOM "Bottom"
#endif // D_STR_BOTTOM #endif // D_STR_BOTTOM
#ifndef D_STR_UPPER_MIDDLE
#define D_STR_UPPER_MIDDLE D_STR_UPPER "-" D_STR_MIDDLE
#endif // D_STR_UPPER_MIDDLE
#ifndef D_STR_CONFIG
#define D_STR_CONFIG "Config"
#endif // D_STR_CONFIG
#ifndef D_STR_CONTROL
#define D_STR_CONTROL "Control"
#endif // D_STR_CONTROL
#ifndef D_STR_SET_TIMER
#define D_STR_SET_TIMER D_STR_SET " " D_STR_TIMER
#endif // D_STR_AC_TIMER
#ifndef D_STR_SCHEDULE
#define D_STR_SCHEDULE "Schedule"
#endif // D_STR_SCHEDULE
#ifndef D_STR_CH
#define D_STR_CH "CH#"
#endif // D_STR_CH
#ifndef D_STR_TIMER_ACTIVE_DAYS
#define D_STR_TIMER_ACTIVE_DAYS "TimerActiveDays"
#endif // D_STR_TIMER_ACTIVE_DAYS
#ifndef D_STR_KEY
#define D_STR_KEY "Key"
#endif // D_STR_KEY
#ifndef D_STR_VALUE
#define D_STR_VALUE "Value"
#endif // D_STR_VALUE
// Compound words/phrases/descriptions from pre-defined words. // Compound words/phrases/descriptions from pre-defined words.
// Note: Obviously these need to be defined *after* their component words. // Note: Obviously these need to be defined *after* their component words.
@ -472,6 +505,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_DISPLAYTEMP #ifndef D_STR_DISPLAYTEMP
#define D_STR_DISPLAYTEMP D_STR_DISPLAY " " D_STR_TEMP #define D_STR_DISPLAYTEMP D_STR_DISPLAY " " D_STR_TEMP
#endif // D_STR_DISPLAYTEMP #endif // D_STR_DISPLAYTEMP
#ifndef D_STR_IFEELREPORT
#define D_STR_IFEELREPORT D_STR_IFEEL " " D_STR_REPORT
#endif // D_STR_IFEELREPORT
#ifndef D_STR_SENSORTEMP #ifndef D_STR_SENSORTEMP
#define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP #define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP
#endif // D_STR_SENSORTEMP #endif // D_STR_SENSORTEMP
@ -689,6 +725,12 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_DG11J191 #ifndef D_STR_DG11J191
#define D_STR_DG11J191 "DG11J191" #define D_STR_DG11J191 "DG11J191"
#endif // D_STR_DG11J191 #endif // D_STR_DG11J191
#ifndef D_STR_ARGO_WREM2
#define D_STR_ARGO_WREM2 "WREM2"
#endif // D_STR_ARGO_WREM2
#ifndef D_STR_ARGO_WREM3
#define D_STR_ARGO_WREM3 "WREM3"
#endif // D_STR_ARGO_WREM3
// Protocols Names // Protocols Names
#ifndef D_STR_AIRTON #ifndef D_STR_AIRTON
@ -727,6 +769,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_CARRIER_AC64 #ifndef D_STR_CARRIER_AC64
#define D_STR_CARRIER_AC64 D_STR_CARRIER_AC "64" #define D_STR_CARRIER_AC64 D_STR_CARRIER_AC "64"
#endif // D_STR_CARRIER_AC64 #endif // D_STR_CARRIER_AC64
#ifndef D_STR_CARRIER_AC84
#define D_STR_CARRIER_AC84 D_STR_CARRIER_AC "84"
#endif // D_STR_CARRIER_AC84
#ifndef D_STR_CARRIER_AC128 #ifndef D_STR_CARRIER_AC128
#define D_STR_CARRIER_AC128 D_STR_CARRIER_AC "128" #define D_STR_CARRIER_AC128 D_STR_CARRIER_AC "128"
#endif // D_STR_CARRIER_AC128 #endif // D_STR_CARRIER_AC128
@ -808,6 +853,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_GOODWEATHER #ifndef D_STR_GOODWEATHER
#define D_STR_GOODWEATHER "GOODWEATHER" #define D_STR_GOODWEATHER "GOODWEATHER"
#endif // D_STR_GOODWEATHER #endif // D_STR_GOODWEATHER
#ifndef D_STR_GORENJE
#define D_STR_GORENJE "GORENJE"
#endif // D_STR_GORENJE
#ifndef D_STR_GREE #ifndef D_STR_GREE
#define D_STR_GREE "GREE" #define D_STR_GREE "GREE"
#endif // D_STR_GREE #endif // D_STR_GREE
@ -1060,9 +1108,15 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_WHYNTER #ifndef D_STR_WHYNTER
#define D_STR_WHYNTER "WHYNTER" #define D_STR_WHYNTER "WHYNTER"
#endif // D_STR_WHYNTER #endif // D_STR_WHYNTER
#ifndef D_STR_WOWWEE
#define D_STR_WOWWEE "WOWWEE"
#endif // D_STR_WOWWEE
#ifndef D_STR_XMP #ifndef D_STR_XMP
#define D_STR_XMP "XMP" #define D_STR_XMP "XMP"
#endif // D_STR_XMP #endif // D_STR_XMP
#ifndef D_STR_YORK
#define D_STR_YORK "YORK"
#endif // D_STR_YORK
#ifndef D_STR_ZEPEAL #ifndef D_STR_ZEPEAL
#define D_STR_ZEPEAL "ZEPEAL" #define D_STR_ZEPEAL "ZEPEAL"
#endif // D_STR_ZEPEAL #endif // D_STR_ZEPEAL

View File

@ -0,0 +1,136 @@
// Copyright 2022 - Stijn (@stijnb1234)
// Locale/language file for Dutch / The Netherlands.
// This file will override the default values located in `defaults.h`.
#ifndef LOCALE_NL_NL_H_
#define LOCALE_NL_NL_H_
#define D_STR_UNKNOWN "ONBEKEND"
#define D_STR_POWER "Stroom"
#define D_STR_PREVIOUS "Vorige"
#define D_STR_ON "Aan"
#define D_STR_OFF "Uit"
#define D_STR_MODE "Modus"
#define D_STR_TOGGLE "Omschakelen"
#define D_STR_SLEEP "Slaap"
#define D_STR_LIGHT "Licht"
#define D_STR_POWERFUL "Sterk"
#define D_STR_QUIET "Rustig"
#define D_STR_ECONO "Eco"
#define D_STR_SWING "Zwaai"
#define D_STR_BEEP "Piep"
#define D_STR_MOULD "Schimmel"
#define D_STR_CLEAN "Reinigen"
#define D_STR_PURIFY "Zuiver"
#define D_STR_TIMER "Timer"
#define D_STR_ONTIMER D_STR_TIMER " " D_STR_ON
#define D_STR_OFFTIMER D_STR_TIMER " " D_STR_OFF
#define D_STR_CLOCK "Klok"
#define D_STR_COMMAND "Commando"
#define D_STR_XFAN "XVentilator"
#define D_STR_HEALTH "Gezondheid"
#define D_STR_IFEEL "IkVoel"
#define D_STR_ISEE "IkZie"
#define D_STR_HUMID "Vochtigheid"
#define D_STR_SAVE "Opslaan"
#define D_STR_EYE "Ogen"
#define D_STR_FOLLOW "Volgen"
#define D_STR_FRESH "Fris"
#define D_STR_HOLD "Houd"
#define D_STR_BUTTON "Knop"
#define D_STR_NIGHT "Nacht"
#define D_STR_SILENT "Stil"
#define D_STR_UP "Omhoog"
#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP
#define D_STR_DOWN "Omlaag"
#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN
#define D_STR_CHANGE "Wisselen"
#define D_STR_MOVE "Verplaatsen"
#define D_STR_SET "Instellen"
#define D_STR_CANCEL "Annuleren"
#define D_STR_COMFORT "Comfortabel"
#define D_STR_WEEKLY "Weekelijks"
#define D_STR_WEEKLYTIMER D_STR_TIMER " " D_STR_WEEKLY
#define D_STR_FAST "Snel"
#define D_STR_SLOW "Langzaam"
#define D_STR_AIRFLOW "Luchtstroom"
#define D_STR_STEP "Stap"
#define D_STR_NA "N/A"
#define D_STR_OUTSIDE "Buiten"
#define D_STR_LOUD "Luid"
#define D_STR_UPPER "Boven"
#define D_STR_LOWER "Beneden"
#define D_STR_BREEZE "Wind"
#define D_STR_CIRCULATE "Circulatie"
#define D_STR_CEILING "Plafond"
#define D_STR_WALL "Muur"
#define D_STR_ROOM "Kamer"
#define D_STR_6THSENSE "6e Zintuig"
#define D_STR_FIXED "Vast"
#define D_STR_AUTOMATIC "Automatisch"
#define D_STR_MANUAL "Handmatig"
#define D_STR_COOL "Koelen"
#define D_STR_HEAT "Verwarmen"
#define D_STR_FAN "Venilator"
#define D_STR_FANONLY "alleen_fan"
#define D_STR_DRY "Drogen"
#define D_STR_MED "Mid"
#define D_STR_MEDIUM "Medium"
#define D_STR_HIGHEST "Hoogste"
#define D_STR_HIGH "Hoog"
#define D_STR_HI "H"
#define D_STR_MID "M"
#define D_STR_MIDDLE "Medium"
#define D_STR_LOW "Laag"
#define D_STR_LO "L"
#define D_STR_LOWEST "Laagste"
#define D_STR_RIGHT "Rechts"
#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT
#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX
#define D_STR_LEFT "Links"
#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT
#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX
#define D_STR_WIDE "Breed"
#define D_STR_CENTRE "Midden"
#define D_STR_TOP "Boven"
#define D_STR_BOTTOM "Onder"
#define D_STR_DAY "Dag"
#define D_STR_DAYS D_STR_DAY "en"
#define D_STR_HOUR "Uur"
#define D_STR_HOURS D_STR_HOUR
#define D_STR_MINUTE "Minuut"
#define D_STR_MINUTES "Minuten"
#define D_STR_SECOND "Seconde"
#define D_STR_SECONDS D_STR_SECOND "n"
#define D_STR_NOW "Nu"
#define D_STR_THREELETTERDAYS "ZonMaaDinWoeDonVriZat"
#define D_STR_YES "Ja"
#define D_STR_NO "Nee"
#define D_STR_TRUE "Waar"
#define D_STR_FALSE "Niet Waar"
#define D_STR_REPEAT "Herhalen"
#define D_STR_PREVIOUS "Vorige"
#define D_STR_DISPLAY "Display"
#define D_STR_INSIDE "Binnen"
#define D_STR_POWERBUTTON "Hoofdschakelaar"
#define D_STR_PREVIOUSPOWER "Vorige inschakelstatus"
#define D_STR_DISPLAYTEMP "Temperatuurweergave"
// IRrecvDumpV2+
#define D_STR_TIMESTAMP "Tijdsaanduiding"
#define D_STR_LIBRARY "Bibliotheek"
#define D_STR_TOLERANCE "Tolerantie"
#define D_STR_MESGDESC "Beschrijving"
#define D_STR_IRRECVDUMP_STARTUP \
"IRrecvDump draait en wacht op IR-signaal op pin %d"
#define D_WARN_BUFFERFULL \
"WAARSCHUWING: IR-code is te groot voor buffer (>= %d). " \
"Het resultaat kan niet worden vertrouwd totdat het is verholpen. " \
"Wijzig & vergroot `kCaptureBufferSize`."
#endif // LOCALE_NL_NL_H_

View File

@ -73,6 +73,7 @@ TEST(TestIRac, Airton) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Airwell) { TEST(TestIRac, Airwell) {
@ -96,6 +97,7 @@ TEST(TestIRac, Airwell) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Amcor) { TEST(TestIRac, Amcor) {
@ -119,6 +121,7 @@ TEST(TestIRac, Amcor) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Argo) { TEST(TestIRac, Argo) {
@ -130,16 +133,19 @@ TEST(TestIRac, Argo) {
true, // Power true, // Power
stdAc::opmode_t::kHeat, // Mode stdAc::opmode_t::kHeat, // Mode
21, // Celsius 21, // Celsius
22, // Sensor Temp.
stdAc::fanspeed_t::kHigh, // Fan speed stdAc::fanspeed_t::kHigh, // Fan speed
stdAc::swingv_t::kOff, // Vertical swing stdAc::swingv_t::kOff, // Vertical swing
false, // iFeel
false, // Turbo false, // Turbo
-1); // Sleep -1); // Sleep
EXPECT_TRUE(ac.getPower()); EXPECT_TRUE(ac.getPower());
EXPECT_EQ(kArgoHeat, ac.getMode()); EXPECT_EQ(kArgoHeat, ac.getMode());
EXPECT_EQ(21, ac.getTemp()); EXPECT_EQ(21, ac.getTemp());
EXPECT_EQ(kArgoFlapAuto, ac.getFlap()); EXPECT_EQ(kArgoFlapFull, ac.getFlap());
EXPECT_FALSE(ac.getMax()); // Turbo EXPECT_FALSE(ac.getMax()); // Turbo
EXPECT_FALSE(ac.getNight()); // Sleep EXPECT_FALSE(ac.getNight()); // Sleep
EXPECT_EQ(argoIrMessageType_t::AC_CONTROL, ac.getMessageType());
} }
TEST(TestIRac, Carrier64) { TEST(TestIRac, Carrier64) {
@ -174,6 +180,7 @@ TEST(TestIRac, Carrier64) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Coolix) { TEST(TestIRac, Coolix) {
@ -189,9 +196,11 @@ TEST(TestIRac, Coolix) {
true, // Power true, // Power
stdAc::opmode_t::kHeat, // Mode stdAc::opmode_t::kHeat, // Mode
21, // Celsius 21, // Celsius
kNoTempValue, // Sensor Temp
stdAc::fanspeed_t::kHigh, // Fan speed stdAc::fanspeed_t::kHigh, // Fan speed
stdAc::swingv_t::kOff, // Vertical swing stdAc::swingv_t::kOff, // Vertical swing
stdAc::swingh_t::kOff, // Horizontal swing stdAc::swingh_t::kOff, // Horizontal swing
false, // iFeel
false, // Turbo false, // Turbo
false, // Light false, // Light
false, // Clean false, // Clean
@ -235,6 +244,7 @@ TEST(TestIRac, Coolix) {
// End of message #2 (i.e. Repeat '1') // End of message #2 (i.e. Repeat '1')
// Note: the two messages (#1 & #2) are identical. // Note: the two messages (#1 & #2) are identical.
ac._irsend.outputStr()); ac._irsend.outputStr());
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Corona) { TEST(TestIRac, Corona) {
@ -277,6 +287,7 @@ TEST(TestIRac, Corona) {
ASSERT_EQ(expectedCapture, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expectedCapture, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin) { TEST(TestIRac, Daikin) {
@ -310,6 +321,7 @@ TEST(TestIRac, Daikin) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin128) { TEST(TestIRac, Daikin128) {
@ -343,6 +355,7 @@ TEST(TestIRac, Daikin128) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin152) { TEST(TestIRac, Daikin152) {
@ -371,6 +384,7 @@ TEST(TestIRac, Daikin152) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin160) { TEST(TestIRac, Daikin160) {
@ -396,6 +410,7 @@ TEST(TestIRac, Daikin160) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin176) { TEST(TestIRac, Daikin176) {
@ -421,6 +436,7 @@ TEST(TestIRac, Daikin176) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin2) { TEST(TestIRac, Daikin2) {
@ -460,6 +476,7 @@ TEST(TestIRac, Daikin2) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin216) { TEST(TestIRac, Daikin216) {
@ -488,6 +505,7 @@ TEST(TestIRac, Daikin216) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Daikin64) { TEST(TestIRac, Daikin64) {
@ -548,7 +566,7 @@ TEST(TestIRac, Ecoclim) {
IRac irac(kGpioUnused); IRac irac(kGpioUnused);
IRrecv capture(kGpioUnused); IRrecv capture(kGpioUnused);
char expected[] = char expected[] =
"Power: On, Mode: 1 (Cool), Temp: 26C, SensorTemp: 26C, Fan: 2 (High), " "Power: On, Mode: 1 (Cool), Temp: 26C, SensorTemp: 27C, Fan: 2 (High), "
"Clock: 12:34, On Timer: Off, Off Timer: Off, Type: 0"; "Clock: 12:34, On Timer: Off, Off Timer: Off, Type: 0";
ac.begin(); ac.begin();
@ -556,6 +574,7 @@ TEST(TestIRac, Ecoclim) {
true, // Power true, // Power
stdAc::opmode_t::kCool, // Mode stdAc::opmode_t::kCool, // Mode
26, // Celsius 26, // Celsius
27, // Sensor Temp.
stdAc::fanspeed_t::kHigh, // Fan speed stdAc::fanspeed_t::kHigh, // Fan speed
-1, // Sleep -1, // Sleep
12 * 60 + 34); // Clock 12 * 60 + 34); // Clock
@ -567,7 +586,7 @@ TEST(TestIRac, Ecoclim) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
char expected_sleep[] = char expected_sleep[] =
"Power: On, Mode: 7 (Sleep), Temp: 21C, SensorTemp: 21C, Fan: 0 (Low), " "Power: On, Mode: 7 (Sleep), Temp: 21C, SensorTemp: 22C, Fan: 0 (Low), "
"Clock: 17:17, On Timer: Off, Off Timer: Off, Type: 0"; "Clock: 17:17, On Timer: Off, Off Timer: Off, Type: 0";
ac._irsend.reset(); ac._irsend.reset();
@ -575,6 +594,7 @@ TEST(TestIRac, Ecoclim) {
true, // Power true, // Power
stdAc::opmode_t::kCool, // Mode stdAc::opmode_t::kCool, // Mode
21, // Celsius 21, // Celsius
22, // Sensor Temp.
stdAc::fanspeed_t::kLow, // Fan speed stdAc::fanspeed_t::kLow, // Fan speed
8 * 60, // Sleep 8 * 60, // Sleep
17 * 60 + 17); // Clock 17 * 60 + 17); // Clock
@ -600,9 +620,11 @@ TEST(TestIRac, Electra) {
true, // Power true, // Power
stdAc::opmode_t::kFan, // Mode stdAc::opmode_t::kFan, // Mode
26, // Celsius 26, // Celsius
27, // Sensor Temp.
stdAc::fanspeed_t::kHigh, // Fan speed stdAc::fanspeed_t::kHigh, // Fan speed
stdAc::swingv_t::kAuto, // Vertical swing stdAc::swingv_t::kAuto, // Vertical swing
stdAc::swingh_t::kLeft, // Horizontal swing stdAc::swingh_t::kLeft, // Horizontal swing
false, // iFeel
true, // Turbo true, // Turbo
true, // Light (toggle) true, // Light (toggle)
true); // Clean true); // Clean
@ -656,6 +678,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(ardb1_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(ardb1_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
// Try to set the device to 10C Heat mode. // Try to set the device to 10C Heat mode.
@ -681,6 +704,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits); ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
ASSERT_EQ(arrah2e_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(arrah2e_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
irac.fujitsu(&ac, irac.fujitsu(&ac,
fujitsu_ac_remote_model_t::ARRY4, // Model fujitsu_ac_remote_model_t::ARRY4, // Model
@ -703,6 +727,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits); ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
ASSERT_EQ(arry4_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(arry4_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
irac.fujitsu(&ac, irac.fujitsu(&ac,
@ -753,6 +778,7 @@ TEST(TestIRac, Goodweather) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Gree) { TEST(TestIRac, Gree) {
@ -761,7 +787,7 @@ TEST(TestIRac, Gree) {
IRrecv capture(kGpioUnused); IRrecv capture(kGpioUnused);
char expected[] = char expected[] =
"Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 71F, " "Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 71F, "
"Fan: 2 (Medium), Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, " "Fan: 2 (Medium), Turbo: Off, Econo: Off, IFeel: On, WiFi: Off, "
"XFan: On, Light: On, Sleep: On, Swing(V) Mode: Manual, " "XFan: On, Light: On, Sleep: On, Swing(V) Mode: Manual, "
"Swing(V): 3 (UNKNOWN), Swing(H): 5 (Right), Timer: Off, " "Swing(V): 3 (UNKNOWN), Swing(H): 5 (Right), Timer: Off, "
"Display Temp: 0 (Off)"; "Display Temp: 0 (Off)";
@ -776,6 +802,7 @@ TEST(TestIRac, Gree) {
stdAc::fanspeed_t::kMedium, // Fan speed stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kHigh, // Vertical swing stdAc::swingv_t::kHigh, // Vertical swing
stdAc::swingh_t::kRight, // Horizontal swing stdAc::swingh_t::kRight, // Horizontal swing
true, // iFeel
false, // Turbo false, // Turbo
false, // Econo false, // Econo
true, // Light true, // Light
@ -789,6 +816,7 @@ TEST(TestIRac, Gree) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Haier) { TEST(TestIRac, Haier) {
@ -818,6 +846,7 @@ TEST(TestIRac, Haier) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Haier160) { TEST(TestIRac, Haier160) {
@ -853,6 +882,7 @@ TEST(TestIRac, Haier160) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Haier176) { TEST(TestIRac, Haier176) {
@ -886,6 +916,7 @@ TEST(TestIRac, Haier176) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, HaierYrwo2) { TEST(TestIRac, HaierYrwo2) {
@ -919,6 +950,7 @@ TEST(TestIRac, HaierYrwo2) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Hitachi) { TEST(TestIRac, Hitachi) {
@ -946,6 +978,7 @@ TEST(TestIRac, Hitachi) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Hitachi1) { TEST(TestIRac, Hitachi1) {
@ -978,6 +1011,7 @@ TEST(TestIRac, Hitachi1) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Hitachi264) { TEST(TestIRac, Hitachi264) {
@ -1003,6 +1037,7 @@ TEST(TestIRac, Hitachi264) {
ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
EXPECT_EQ(decode_type_t::HITACHI_AC264, r.protocol); EXPECT_EQ(decode_type_t::HITACHI_AC264, r.protocol);
EXPECT_TRUE(r.power); EXPECT_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode); EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
@ -1031,6 +1066,7 @@ TEST(TestIRac, Hitachi296) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
EXPECT_EQ(decode_type_t::HITACHI_AC296, r.protocol); EXPECT_EQ(decode_type_t::HITACHI_AC296, r.protocol);
EXPECT_TRUE(r.power); EXPECT_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode); EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
@ -1062,6 +1098,7 @@ TEST(TestIRac, Hitachi344) {
ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
EXPECT_EQ(decode_type_t::HITACHI_AC344, r.protocol); EXPECT_EQ(decode_type_t::HITACHI_AC344, r.protocol);
EXPECT_TRUE(r.power); EXPECT_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode); EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
@ -1082,6 +1119,7 @@ TEST(TestIRac, Hitachi344) {
ASSERT_EQ(expected_swingoff, ac.toString()); ASSERT_EQ(expected_swingoff, ac.toString());
ac._irsend.makeDecodeResult(); ac._irsend.makeDecodeResult();
EXPECT_TRUE(capture.decode(&ac._irsend.capture)); EXPECT_TRUE(capture.decode(&ac._irsend.capture));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ASSERT_EQ(HITACHI_AC344, ac._irsend.capture.decode_type); ASSERT_EQ(HITACHI_AC344, ac._irsend.capture.decode_type);
ASSERT_EQ(kHitachiAc344Bits, ac._irsend.capture.bits); ASSERT_EQ(kHitachiAc344Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected_swingoff, ASSERT_EQ(expected_swingoff,
@ -1115,6 +1153,7 @@ TEST(TestIRac, Hitachi424) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
irac.hitachi424(&ac, irac.hitachi424(&ac,
@ -1131,6 +1170,7 @@ TEST(TestIRac, Hitachi424) {
ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits); ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected_swingv, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_swingv, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Kelvinator) { TEST(TestIRac, Kelvinator) {
@ -1164,6 +1204,7 @@ TEST(TestIRac, Kelvinator) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, LG) { TEST(TestIRac, LG) {
@ -1196,6 +1237,7 @@ TEST(TestIRac, LG) {
ASSERT_EQ(61, ac._irsend.capture.rawlen); ASSERT_EQ(61, ac._irsend.capture.rawlen);
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, LG2) { TEST(TestIRac, LG2) {
@ -1228,6 +1270,7 @@ TEST(TestIRac, LG2) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
// Message #2 - SwingV Low // Message #2 - SwingV Low
EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61)); EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61));
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); ASSERT_EQ(LG2, ac._irsend.capture.decode_type);
@ -1443,6 +1486,7 @@ TEST(TestIRac, LG2_AKB73757604) {
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); ASSERT_EQ(LG2, ac._irsend.capture.decode_type);
ASSERT_EQ(kLgBits, ac._irsend.capture.bits); ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
ASSERT_EQ(kLgAcSwingHAuto, ac._irsend.capture.value); ASSERT_EQ(kLgAcSwingHAuto, ac._irsend.capture.value);
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Midea) { TEST(TestIRac, Midea) {
@ -1461,8 +1505,10 @@ TEST(TestIRac, Midea) {
stdAc::opmode_t::kDry, // Mode stdAc::opmode_t::kDry, // Mode
true, // Celsius true, // Celsius
27, // Degrees 27, // Degrees
28, // Sensor Temp.
stdAc::fanspeed_t::kMedium, // Fan speed stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kOff, // Swing(V) stdAc::swingv_t::kOff, // Swing(V)
false, // iFeel
false, // Silent/Quiet false, // Silent/Quiet
false, // Previous Silent/Quiet setting false, // Previous Silent/Quiet setting
false, // Turbo false, // Turbo
@ -1479,6 +1525,7 @@ TEST(TestIRac, Midea) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Mirage) { TEST(TestIRac, Mirage) {
@ -1518,6 +1565,7 @@ TEST(TestIRac, Mirage) {
ASSERT_EQ(kMirageBits, ac._irsend.capture.bits); ASSERT_EQ(kMirageBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_KKG9AC1, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_KKG9AC1, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
const char expected_KKG29AC1[] = const char expected_KKG29AC1[] =
"Model: 2 (KKG29AC1), Power: On, Mode: 3 (Dry), Temp: 27C, " "Model: 2 (KKG29AC1), Power: On, Mode: 3 (Dry), Temp: 27C, "
@ -1535,6 +1583,7 @@ TEST(TestIRac, Mirage) {
ASSERT_EQ(expected_KKG29AC1, ASSERT_EQ(expected_KKG29AC1,
IRAcUtils::resultAcToString(&ac._irsend.capture)); IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Mitsubishi) { TEST(TestIRac, Mitsubishi) {
@ -1567,6 +1616,7 @@ TEST(TestIRac, Mitsubishi) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Mitsubishi136) { TEST(TestIRac, Mitsubishi136) {
@ -1593,6 +1643,7 @@ TEST(TestIRac, Mitsubishi136) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, MitsubishiHeavy88) { TEST(TestIRac, MitsubishiHeavy88) {
@ -1623,6 +1674,7 @@ TEST(TestIRac, MitsubishiHeavy88) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, MitsubishiHeavy152) { TEST(TestIRac, MitsubishiHeavy152) {
@ -1656,6 +1708,7 @@ TEST(TestIRac, MitsubishiHeavy152) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Neoclima) { TEST(TestIRac, Neoclima) {
@ -1690,6 +1743,7 @@ TEST(TestIRac, Neoclima) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Panasonic) { TEST(TestIRac, Panasonic) {
@ -1722,6 +1776,7 @@ TEST(TestIRac, Panasonic) {
ASSERT_EQ(expected_nke, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_nke, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
char expected_dke[] = char expected_dke[] =
"Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (Maximum), " "Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (Maximum), "
@ -1748,6 +1803,7 @@ TEST(TestIRac, Panasonic) {
ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits); ASSERT_EQ(kPanasonicAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_dke, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_dke, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Panasonic32) { TEST(TestIRac, Panasonic32) {
@ -1774,6 +1830,7 @@ TEST(TestIRac, Panasonic32) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Samsung) { TEST(TestIRac, Samsung) {
@ -1813,6 +1870,7 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
irac.samsung(&ac, irac.samsung(&ac,
@ -1841,6 +1899,7 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
const char sleep[] = const char sleep[] =
@ -1874,6 +1933,7 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
ASSERT_EQ(sleep, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(sleep, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Sanyo) { TEST(TestIRac, Sanyo) {
@ -1890,8 +1950,10 @@ TEST(TestIRac, Sanyo) {
true, // Power true, // Power
stdAc::opmode_t::kCool, // Mode stdAc::opmode_t::kCool, // Mode
28, // Celsius 28, // Celsius
kNoTempValue, // SensorTemp
stdAc::fanspeed_t::kMedium, // Fan speed stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kHighest, // Vertical Swing stdAc::swingv_t::kHighest, // Vertical Swing
false, // iFeel
true, // Beep true, // Beep
17); // Sleep 17); // Sleep
ASSERT_EQ(expected, ac.toString()); ASSERT_EQ(expected, ac.toString());
@ -1902,6 +1964,7 @@ TEST(TestIRac, Sanyo) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Sanyo88) { TEST(TestIRac, Sanyo88) {
@ -1931,6 +1994,7 @@ TEST(TestIRac, Sanyo88) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Sharp) { TEST(TestIRac, Sharp) {
@ -1963,6 +2027,7 @@ TEST(TestIRac, Sharp) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Tcl112) { TEST(TestIRac, Tcl112) {
@ -1997,6 +2062,7 @@ TEST(TestIRac, Tcl112) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
// Test the quiet mode, which should generate two messages. // Test the quiet mode, which should generate two messages.
ac._irsend.reset(); ac._irsend.reset();
irac.tcl112(&ac, irac.tcl112(&ac,
@ -2052,6 +2118,7 @@ TEST(TestIRac, Technibel) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Teco) { TEST(TestIRac, Teco) {
@ -2079,6 +2146,7 @@ TEST(TestIRac, Teco) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Toshiba) { TEST(TestIRac, Toshiba) {
@ -2108,6 +2176,7 @@ TEST(TestIRac, Toshiba) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
EXPECT_EQ( EXPECT_EQ(
"f38000d50" "f38000d50"
"m4400s4300" "m4400s4300"
@ -2183,6 +2252,7 @@ TEST(TestIRac, Transcold) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Trotec) { TEST(TestIRac, Trotec) {
@ -2212,6 +2282,7 @@ TEST(TestIRac, Trotec) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Trotec3550) { TEST(TestIRac, Trotec3550) {
@ -2242,6 +2313,7 @@ TEST(TestIRac, Trotec3550) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Truma) { TEST(TestIRac, Truma) {
@ -2271,6 +2343,7 @@ TEST(TestIRac, Truma) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, Vestel) { TEST(TestIRac, Vestel) {
@ -2300,6 +2373,7 @@ TEST(TestIRac, Vestel) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
char expected_clocks[] = char expected_clocks[] =
@ -2325,6 +2399,7 @@ TEST(TestIRac, Vestel) {
ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits); ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_clocks, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_clocks, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
// Now check it sends both messages during normal operation when the // Now check it sends both messages during normal operation when the
// clock is set. // clock is set.
@ -2404,6 +2479,7 @@ TEST(TestIRac, Voltas) {
ASSERT_EQ(expected_unknown, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected_unknown, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset(); ac._irsend.reset();
// Test the UNKNOWN model type // Test the UNKNOWN model type
@ -2470,6 +2546,7 @@ TEST(TestIRac, Whirlpool) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
TEST(TestIRac, cmpStates) { TEST(TestIRac, cmpStates) {
@ -2507,6 +2584,21 @@ TEST(TestIRac, cmpStates) {
// Now make them different. // Now make them different.
b.power = false; b.power = false;
ASSERT_TRUE(IRac::cmpStates(a, b)); ASSERT_TRUE(IRac::cmpStates(a, b));
b = a;
ASSERT_FALSE(IRac::cmpStates(a, b));
b.command = stdAc::ac_command_t::kTimerCommand;
ASSERT_TRUE(IRac::cmpStates(a, b));
b = a;
ASSERT_FALSE(IRac::cmpStates(a, b));
b.iFeel = true;
ASSERT_TRUE(IRac::cmpStates(a, b));
b = a;
ASSERT_FALSE(IRac::cmpStates(a, b));
b.sensorTemperature = 12.5;
ASSERT_TRUE(IRac::cmpStates(a, b));
} }
TEST(TestIRac, handleToggles) { TEST(TestIRac, handleToggles) {
@ -2610,6 +2702,7 @@ TEST(TestIRac, strToFanspeed) {
EXPECT_EQ(stdAc::fanspeed_t::kMin, IRac::strToFanspeed("MIN")); EXPECT_EQ(stdAc::fanspeed_t::kMin, IRac::strToFanspeed("MIN"));
EXPECT_EQ(stdAc::fanspeed_t::kLow, IRac::strToFanspeed("LOW")); EXPECT_EQ(stdAc::fanspeed_t::kLow, IRac::strToFanspeed("LOW"));
EXPECT_EQ(stdAc::fanspeed_t::kMedium, IRac::strToFanspeed("MEDIUM")); EXPECT_EQ(stdAc::fanspeed_t::kMedium, IRac::strToFanspeed("MEDIUM"));
EXPECT_EQ(stdAc::fanspeed_t::kMediumHigh, IRac::strToFanspeed("MED-HIGH"));
EXPECT_EQ(stdAc::fanspeed_t::kHigh, IRac::strToFanspeed("HIGH")); EXPECT_EQ(stdAc::fanspeed_t::kHigh, IRac::strToFanspeed("HIGH"));
EXPECT_EQ(stdAc::fanspeed_t::kMax, IRac::strToFanspeed("MAX")); EXPECT_EQ(stdAc::fanspeed_t::kMax, IRac::strToFanspeed("MAX"));
EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("FOOBAR")); EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("FOOBAR"));
@ -2622,6 +2715,7 @@ TEST(TestIRac, strToSwingV) {
EXPECT_EQ(stdAc::swingv_t::kLowest, IRac::strToSwingV("LOWEST")); EXPECT_EQ(stdAc::swingv_t::kLowest, IRac::strToSwingV("LOWEST"));
EXPECT_EQ(stdAc::swingv_t::kLow, IRac::strToSwingV("LOW")); EXPECT_EQ(stdAc::swingv_t::kLow, IRac::strToSwingV("LOW"));
EXPECT_EQ(stdAc::swingv_t::kMiddle, IRac::strToSwingV("MIDDLE")); EXPECT_EQ(stdAc::swingv_t::kMiddle, IRac::strToSwingV("MIDDLE"));
EXPECT_EQ(stdAc::swingv_t::kUpperMiddle, IRac::strToSwingV("UPPER-MIDDLE"));
EXPECT_EQ(stdAc::swingv_t::kHigh, IRac::strToSwingV("HIGH")); EXPECT_EQ(stdAc::swingv_t::kHigh, IRac::strToSwingV("HIGH"));
EXPECT_EQ(stdAc::swingv_t::kHighest, IRac::strToSwingV("HIGHEST")); EXPECT_EQ(stdAc::swingv_t::kHighest, IRac::strToSwingV("HIGHEST"));
EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("OFF")); EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("OFF"));
@ -2652,6 +2746,10 @@ TEST(TestIRac, strToModel) {
IRac::strToModel("ARRAH2E")); IRac::strToModel("ARRAH2E"));
EXPECT_EQ(whirlpool_ac_remote_model_t::DG11J13A, EXPECT_EQ(whirlpool_ac_remote_model_t::DG11J13A,
IRac::strToModel("DG11J13A")); IRac::strToModel("DG11J13A"));
EXPECT_EQ(argo_ac_remote_model_t::SAC_WREM2,
IRac::strToModel("WREM2"));
EXPECT_EQ(argo_ac_remote_model_t::SAC_WREM3,
IRac::strToModel("WREM3"));
EXPECT_EQ(1, IRac::strToModel("1")); EXPECT_EQ(1, IRac::strToModel("1"));
EXPECT_EQ(10, IRac::strToModel("10")); EXPECT_EQ(10, IRac::strToModel("10"));
EXPECT_EQ(-1, IRac::strToModel("0")); EXPECT_EQ(-1, IRac::strToModel("0"));
@ -2659,6 +2757,26 @@ TEST(TestIRac, strToModel) {
EXPECT_EQ(0, IRac::strToModel("FOOBAR", 0)); EXPECT_EQ(0, IRac::strToModel("FOOBAR", 0));
} }
TEST(TestIRac, strToCommandType) {
EXPECT_EQ(stdAc::ac_command_t::kControlCommand,
IRac::strToCommandType("Control"));
EXPECT_EQ(stdAc::ac_command_t::kSensorTempReport,
IRac::strToCommandType("IFeel Report"));
EXPECT_EQ(stdAc::ac_command_t::kSensorTempReport,
IRac::strToCommandType("IFeel"));
EXPECT_EQ(stdAc::ac_command_t::kTimerCommand,
IRac::strToCommandType("Set Timer"));
EXPECT_EQ(stdAc::ac_command_t::kTimerCommand,
IRac::strToCommandType("Timer"));
EXPECT_EQ(stdAc::ac_command_t::kConfigCommand,
IRac::strToCommandType("Config"));
EXPECT_EQ(stdAc::ac_command_t::kControlCommand,
IRac::strToCommandType("FOOBAR"));
EXPECT_EQ(stdAc::ac_command_t::kTimerCommand,
IRac::strToCommandType("FOOBAR",
stdAc::ac_command_t::kTimerCommand));
}
TEST(TestIRac, boolToString) { TEST(TestIRac, boolToString) {
EXPECT_EQ("On", IRac::boolToString(true)); EXPECT_EQ("On", IRac::boolToString(true));
EXPECT_EQ("Off", IRac::boolToString(false)); EXPECT_EQ("Off", IRac::boolToString(false));
@ -2678,6 +2796,7 @@ TEST(TestIRac, opmodeToString) {
TEST(TestIRac, fanspeedToString) { TEST(TestIRac, fanspeedToString) {
EXPECT_EQ("Low", IRac::fanspeedToString(stdAc::fanspeed_t::kLow)); EXPECT_EQ("Low", IRac::fanspeedToString(stdAc::fanspeed_t::kLow));
EXPECT_EQ("Auto", IRac::fanspeedToString(stdAc::fanspeed_t::kAuto)); EXPECT_EQ("Auto", IRac::fanspeedToString(stdAc::fanspeed_t::kAuto));
EXPECT_EQ("Med-High", IRac::fanspeedToString(stdAc::fanspeed_t::kMediumHigh));
EXPECT_EQ("UNKNOWN", IRac::fanspeedToString((stdAc::fanspeed_t)500)); EXPECT_EQ("UNKNOWN", IRac::fanspeedToString((stdAc::fanspeed_t)500));
} }
@ -2685,6 +2804,8 @@ TEST(TestIRac, swingvToString) {
EXPECT_EQ("Off", IRac::swingvToString(stdAc::swingv_t::kOff)); EXPECT_EQ("Off", IRac::swingvToString(stdAc::swingv_t::kOff));
EXPECT_EQ("Low", IRac::swingvToString(stdAc::swingv_t::kLow)); EXPECT_EQ("Low", IRac::swingvToString(stdAc::swingv_t::kLow));
EXPECT_EQ("Auto", IRac::swingvToString(stdAc::swingv_t::kAuto)); EXPECT_EQ("Auto", IRac::swingvToString(stdAc::swingv_t::kAuto));
EXPECT_EQ("Upper-Middle", IRac::swingvToString(
stdAc::swingv_t::kUpperMiddle));
EXPECT_EQ("UNKNOWN", IRac::swingvToString((stdAc::swingv_t)500)); EXPECT_EQ("UNKNOWN", IRac::swingvToString((stdAc::swingv_t)500));
} }
@ -2696,6 +2817,17 @@ TEST(TestIRac, swinghToString) {
EXPECT_EQ("UNKNOWN", IRac::swinghToString((stdAc::swingh_t)500)); EXPECT_EQ("UNKNOWN", IRac::swinghToString((stdAc::swingh_t)500));
} }
TEST(TestIRac, commandTypeToString) {
EXPECT_EQ("Control",
IRac::commandTypeToString(stdAc::ac_command_t::kControlCommand));
EXPECT_EQ("IFeel Report",
IRac::commandTypeToString(stdAc::ac_command_t::kSensorTempReport));
EXPECT_EQ("Set Timer",
IRac::commandTypeToString(stdAc::ac_command_t::kTimerCommand));
EXPECT_EQ("Config",
IRac::commandTypeToString(stdAc::ac_command_t::kConfigCommand));
}
// Check that we keep the previous state info if the message is a special // Check that we keep the previous state info if the message is a special
// state-less command. // state-less command.
TEST(TestIRac, CoolixDecodeToState) { TEST(TestIRac, CoolixDecodeToState) {
@ -2714,6 +2846,7 @@ TEST(TestIRac, CoolixDecodeToState) {
ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_TRUE(irrecv.decode(&irsend.capture));
stdAc::state_t result; stdAc::state_t result;
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command);
ASSERT_EQ(decode_type_t::COOLIX, result.protocol); ASSERT_EQ(decode_type_t::COOLIX, result.protocol);
ASSERT_FALSE(result.power); ASSERT_FALSE(result.power);
ASSERT_EQ(stdAc::opmode_t::kHeat, result.mode); ASSERT_EQ(stdAc::opmode_t::kHeat, result.mode);
@ -2762,9 +2895,11 @@ TEST(TestIRac, Issue821) {
result.power, // Power result.power, // Power
result.mode, // Mode result.mode, // Mode
result.degrees, // Celsius result.degrees, // Celsius
kNoTempValue, // Sensor Temp
result.fanspeed, // Fan speed result.fanspeed, // Fan speed
result.swingv, // Vertical swing result.swingv, // Vertical swing
result.swingh, // Horizontal swing result.swingh, // Horizontal swing
result.iFeel, // iFeel
result.turbo, // Turbo result.turbo, // Turbo
result.light, // Light result.light, // Light
result.clean, // Clean result.clean, // Clean
@ -2877,6 +3012,7 @@ TEST(TestIRac, Issue1001) {
IRAcUtils::resultAcToString(&ac._irsend.capture)); IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
// Now check if the mode is set to "Off" instead of just change to power off. // Now check if the mode is set to "Off" instead of just change to power off.
// i.e. How Home Assistant expects things to work. // i.e. How Home Assistant expects things to work.
@ -2907,6 +3043,7 @@ TEST(TestIRac, Issue1001) {
"Command: 1 (Power)", "Command: 1 (Power)",
IRAcUtils::resultAcToString(&ac._irsend.capture)); IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
} }
// Check power switching in Daikin2 common a/c handling when from an IR message. // Check power switching in Daikin2 common a/c handling when from an IR message.
@ -2956,6 +3093,7 @@ TEST(TestIRac, Issue1035) {
ASSERT_FALSE(prev.power); ASSERT_FALSE(prev.power);
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev));
ASSERT_TRUE(result.power); ASSERT_TRUE(result.power);
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command);
prev = result; prev = result;
@ -2967,6 +3105,7 @@ TEST(TestIRac, Issue1035) {
ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type); ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
ASSERT_TRUE(prev.power); ASSERT_TRUE(prev.power);
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command);
ASSERT_FALSE(result.power); ASSERT_FALSE(result.power);
} }
@ -3138,4 +3277,26 @@ TEST(TestIRac, initState) {
EXPECT_EQ(-1, builtin_init.model); EXPECT_EQ(-1, builtin_init.model);
EXPECT_EQ(stdAc::swingv_t::kOff, builtin_init.swingv); EXPECT_EQ(stdAc::swingv_t::kOff, builtin_init.swingv);
EXPECT_EQ(decode_type_t::UNKNOWN, no_init.protocol); EXPECT_EQ(decode_type_t::UNKNOWN, no_init.protocol);
EXPECT_EQ(stdAc::ac_command_t::kControlCommand, no_init.command);
EXPECT_FALSE(no_init.iFeel);
EXPECT_EQ(kNoTempValue, no_init.sensorTemperature);
}
TEST(TestIRac, cleanState) {
IRac irac(kGpioUnused);
stdAc::state_t s = {};
s.mode = stdAc::opmode_t::kFan;
s.power = true;
s.sensorTemperature = 20.5;
s.degrees = 22.3;
auto clean = irac.cleanState(s);
EXPECT_TRUE(clean.power);
EXPECT_EQ(s.mode, clean.mode);
EXPECT_EQ(s.sensorTemperature, clean.sensorTemperature);
EXPECT_EQ(s.degrees, clean.degrees);
s.mode = stdAc::opmode_t::kOff;
clean = irac.cleanState(s);
EXPECT_FALSE(clean.power);
} }

View File

@ -3,15 +3,16 @@
#ifndef TEST_IRRECV_TEST_H_ #ifndef TEST_IRRECV_TEST_H_
#define TEST_IRRECV_TEST_H_ #define TEST_IRRECV_TEST_H_
#include <math.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include "IRutils.h" #include "IRutils.h"
#define EXPECT_STATE_EQ(a, b, c) \ #define EXPECT_STATE_EQ(a, b, c) \
for (uint8_t i = 0; i < c / 8; ++i) { \ for (uint8_t i = 0; i < ceil((c) / 8.0); ++i) { \
EXPECT_EQ(a[i], b[i]) << "Expected state " \ EXPECT_EQ((a)[i], (b)[i]) << "Expected state " \
"differs at i = " \ "differs at i = " \
<< uint64ToString(i); \ << uint64ToString(i); \
} }
#endif // TEST_IRRECV_TEST_H_ #endif // TEST_IRRECV_TEST_H_

View File

@ -16,6 +16,7 @@
# Points to the root of Google Test, relative to where this file is. # Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file. # Remember to tweak this if you move this file.
GTEST_DIR = ../lib/googletest/googletest GTEST_DIR = ../lib/googletest/googletest
GMOCK_DIR = ../lib/googletest/googlemock
# Where to find user code. # Where to find user code.
USER_DIR = ../src USER_DIR = ../src
@ -24,11 +25,14 @@ INCLUDES = -I$(USER_DIR) -I.
# Flags passed to the preprocessor. # Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that # Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers. # the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -isystem $(GTEST_DIR)/include -DUNIT_TEST -D_IR_LOCALE_=en-AU CPPFLAGS += -isystem $(GTEST_DIR)/include -isystem $(GMOCK_DIR)/include -DUNIT_TEST -D_IR_LOCALE_=en-AU
# Flags passed to the C++ compiler. # Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -Werror -pthread -std=gnu++11 CXXFLAGS += -g -Wall -Wextra -Werror -pthread -std=gnu++11
# Google Test libraries
GTEST_LIBS = gtest.a gtest_main.a gmock.a gmock_main.a
# All tests produced by this Makefile. generated from all *_test.cpp files # All tests produced by this Makefile. generated from all *_test.cpp files
TESTS = $(patsubst %.cpp,%,$(wildcard *_test.cpp)) TESTS = $(patsubst %.cpp,%,$(wildcard *_test.cpp))
@ -37,12 +41,19 @@ TESTS = $(patsubst %.cpp,%,$(wildcard *_test.cpp))
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h $(GTEST_DIR)/include/gtest/internal/*.h
# All Google Mock headers. Note that all Google Test headers are
# included here too, as they are #included by Google Mock headers.
# Usually you shouldn't change this definition.
GMOCK_HEADERS = $(GMOCK_DIR)/include/gmock/*.h \
$(GMOCK_DIR)/include/gmock/internal/*.h \
$(GTEST_HEADERS)
# House-keeping build targets. # House-keeping build targets.
all : $(TESTS) all : $(GTEST_LIBS) $(TESTS)
clean : clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o rm -f $(GTEST_LIBS) $(TESTS) *.o
# Build and run all the tests. # Build and run all the tests.
run : all run : all
@ -65,13 +76,14 @@ run-% : %_test
install-googletest : install-googletest :
rm -rf ../lib/googletest rm -rf ../lib/googletest
git clone -b v1.8.x https://github.com/google/googletest.git ../lib/googletest git clone -b v1.12.x https://github.com/google/googletest.git ../lib/googletest
# Builds gtest.a and gtest_main.a. # Builds gtest.a, gtest_main.a, gmock.a, gmock_main.a.
# Usually you shouldn't tweak such internal variables, indicated by a # Usually you shouldn't tweak such internal variables, indicated by a
# trailing _. # trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
GMOCK_SRCS_ = $(GMOCK_DIR)/src/*.cc $(GMOCK_HEADERS)
# All the IR protocol object files. # All the IR protocol object files.
PROTOCOL_OBJS = $(patsubst %.cpp,%.o,$(wildcard $(USER_DIR)/ir_*.cpp)) PROTOCOL_OBJS = $(patsubst %.cpp,%.o,$(wildcard $(USER_DIR)/ir_*.cpp))
@ -82,7 +94,7 @@ PROTOCOLS_H = $(wildcard $(USER_DIR)/ir_*.h)
# Common object files # Common object files
COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRac.o ir_GlobalCache.o \ COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRac.o ir_GlobalCache.o \
IRtext.o $(PROTOCOLS) gtest_main.a IRtext.o $(PROTOCOLS) gtest_main.a gmock_main.a
# Common dependencies # Common dependencies
COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \ COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \
$(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \ $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \
@ -90,26 +102,41 @@ COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \
$(PROTOCOLS_H) $(PROTOCOLS_H)
# Common test dependencies # Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) IRrecv_test.h IRsend_test.h COMMON_TEST_DEPS = $(COMMON_DEPS) IRrecv_test.h IRsend_test.h ut_utils.h
# For simplicity and to avoid depending on Google Test's # For simplicity and to avoid depending on implementation details of
# implementation details, the dependencies specified below are # Google Mock and Google Test, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test # conservative and not optimized. This is fine as Google Mock and
# compiles fast and for ordinary users its source rarely changes. # Google Test compile fast and for ordinary users their source rarely
# changes.
gtest-all.o : $(GTEST_SRCS_) gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_) gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc $(GTEST_DIR)/src/gtest_main.cc
gmock-all.o : $(GMOCK_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \
-c $(GMOCK_DIR)/src/gmock-all.cc
gmock_main.o : $(GMOCK_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \
-c $(GMOCK_DIR)/src/gmock_main.cc
gtest.a : gtest-all.o gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^ $(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^ $(AR) $(ARFLAGS) $@ $^
gmock.a : gmock-all.o
$(AR) $(ARFLAGS) $@ $^
gmock_main.a : gmock_main.o
$(AR) $(ARFLAGS) $@ $^
# Keep all intermediate files. # Keep all intermediate files.
.SECONDARY: .SECONDARY:
@ -123,10 +150,10 @@ IRtext.o : $(USER_DIR)/IRtext.cpp $(USER_DIR)/IRtext.h $(USER_DIR)/IRremoteESP82
IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h $(USER_DIR)/i18n.h $(USER_DIR)/IRtext.cpp $(USER_DIR)/IRtext.h $(USER_DIR)/locale/*.h IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h $(USER_DIR)/i18n.h $(USER_DIR)/IRtext.cpp $(USER_DIR)/IRtext.h $(USER_DIR)/locale/*.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRutils.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRutils.cpp
IRutils_test.o : IRutils_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) IRutils_test.o : IRutils_test.cpp $(COMMON_TEST_DEPS) $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRutils_test.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRutils_test.cpp
IRutils_test : IRutils_test.o ir_NEC.o ir_Nikai.o ir_Toshiba.o IRtext.o $(COMMON_OBJ) gtest_main.a IRutils_test : IRutils_test.o ir_NEC.o ir_Nikai.o ir_Toshiba.o IRtext.o $(COMMON_OBJ) $(GTEST_LIBS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
IRtimer.o : $(USER_DIR)/IRtimer.cpp $(USER_DIR)/IRtimer.h IRtimer.o : $(USER_DIR)/IRtimer.cpp $(USER_DIR)/IRtimer.h
@ -135,19 +162,19 @@ IRtimer.o : $(USER_DIR)/IRtimer.cpp $(USER_DIR)/IRtimer.h
IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP8266.h IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP8266.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRsend.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRsend.cpp
IRsend_test.o : IRsend_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS) IRsend_test.o : IRsend_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRsend_test.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRsend_test.cpp
IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP8266.h $(GTEST_HEADERS) IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP8266.h $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp
IRrecv_test.o : IRrecv_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS) IRrecv_test.o : IRrecv_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRrecv_test.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRrecv_test.cpp
IRac.o : $(USER_DIR)/IRac.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS) IRac.o : $(USER_DIR)/IRac.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRac.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRac.cpp
IRac_test.o : IRac_test.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS) IRac_test.o : IRac_test.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRac_test.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRac_test.cpp
# new specific targets goes above this line # new specific targets goes above this line
@ -158,11 +185,11 @@ ir_%.o : $(USER_DIR)/ir_%.h $(USER_DIR)/ir_%.cpp $(COMMON_DEPS)
ir_%.o : $(USER_DIR)/ir_%.cpp $(COMMON_DEPS) ir_%.o : $(USER_DIR)/ir_%.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_$*.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_$*.cpp
ir_%_test.o : ir_%_test.cpp $(USER_DIR)/ir_$%.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS) ir_%_test.o : ir_%_test.cpp $(USER_DIR)/ir_$%.h $(COMMON_TEST_DEPS) $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_$*_test.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_$*_test.cpp
ir_%_test.o : ir_%_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) ir_%_test.o : ir_%_test.cpp $(COMMON_TEST_DEPS) $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_$*_test.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_$*_test.cpp
%_test : $(COMMON_OBJ) %_test.o %_test : $(COMMON_OBJ) %_test.o $(GTEST_LIBS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

View File

@ -264,6 +264,16 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ(kCarrierAc64MinRepeat, ASSERT_EQ(kCarrierAc64MinRepeat,
IRsend::minRepeats(decode_type_t::CARRIER_AC64)); IRsend::minRepeats(decode_type_t::CARRIER_AC64));
// CARRIER_AC84
ASSERT_EQ("CARRIER_AC84", typeToString(decode_type_t::CARRIER_AC84));
ASSERT_EQ(decode_type_t::CARRIER_AC84, strToDecodeType("CARRIER_AC84"));
ASSERT_TRUE(hasACState(decode_type_t::CARRIER_AC84));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::CARRIER_AC84));
ASSERT_EQ(kCarrierAc84Bits,
IRsend::defaultBits(decode_type_t::CARRIER_AC84));
ASSERT_EQ(kNoRepeat,
IRsend::minRepeats(decode_type_t::CARRIER_AC84));
// CARRIER_AC128 // CARRIER_AC128
ASSERT_EQ("CARRIER_AC128", typeToString(decode_type_t::CARRIER_AC128)); ASSERT_EQ("CARRIER_AC128", typeToString(decode_type_t::CARRIER_AC128));
ASSERT_EQ(decode_type_t::CARRIER_AC128, strToDecodeType("CARRIER_AC128")); ASSERT_EQ(decode_type_t::CARRIER_AC128, strToDecodeType("CARRIER_AC128"));
@ -693,3 +703,113 @@ TEST(TestDecodeCarrierAC128, SyntheticExample) {
stdAc::state_t r, p; stdAc::state_t r, p;
ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
} }
// Decode a "real" Carrier 84bit example message.
TEST(TestDecodeCarrierAC84, RealExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint8_t expected_state[kCarrierAc84StateLength] = {
0x03, 0x00, 0x93, 0x31, 0x00, 0x12, 0x00, 0x12, 0x54, 0x21, 0xE8};
irsend.begin();
irsend.reset();
// Data from:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1943#issue-1519570772
const uint16_t rawData[171] = {
5844, 1152,
1154, 462, 1152, 462, 418, 1194, 418, 1194, 420, 1194, 416, 1198,
418, 1196, 416, 1196, 418, 1194, 420, 1192, 420, 1194, 420, 1194,
1152, 460, 1152, 460, 420, 1192, 418, 1194, 1154, 458, 418, 1194,
420, 1192, 1154, 460, 1152, 458, 420, 1194, 418, 1194, 418, 1194,
1152, 460, 1154, 458, 418, 1196, 416, 1194, 418, 1194, 418, 1196,
420, 1194, 418, 1192, 420, 1194, 420, 1192, 418, 1196, 416, 1194,
416, 1196, 1152, 462, 416, 1194, 422, 1192, 1154, 458, 420, 1192,
418, 1194, 418, 1194, 418, 1196, 420, 1194, 418, 1192, 420, 1194,
418, 1192, 420, 1194, 418, 1194, 420, 1194, 418, 1194, 1154, 458,
418, 1194, 418, 1192, 1154, 458, 418, 1196, 416, 1194, 420, 1194,
416, 1192, 418, 1194, 1152, 462, 416, 1196, 1152, 458, 418, 1196,
1152, 458, 418, 1194, 1154, 460, 418, 1194, 418, 1196, 418, 1196,
418, 1194, 1154, 460, 420, 1192, 418, 1194, 420, 1194, 418, 1194,
418, 1196, 1152, 460, 418, 1194, 1154, 458, 1154, 460, 1152, 458,
1152}; // UNKNOWN E366A1BC
irsend.sendRaw(rawData, 171, 38000);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(CARRIER_AC84, irsend.capture.decode_type);
EXPECT_EQ(kCarrierAc84Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
EXPECT_EQ(
"Protocol : CARRIER_AC84\n"
"Code : 0x03009331001200125421E8 (84 Bits)\n",
resultToHumanReadableBasic(&irsend.capture));
}
// Decode a synthetic Carrier AC 84-bit message.
TEST(TestDecodeCarrierAC84, SyntheticExample) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
const uint8_t expected_state[kCarrierAc84StateLength] = {
0x0C, 0x00, 0xC9, 0x8C, 0x00, 0x48, 0x00, 0x48, 0x2A, 0x84, 0x17};
irsend.sendCarrierAC84(expected_state);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(CARRIER_AC84, irsend.capture.decode_type);
ASSERT_EQ(kCarrierAc84Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_FALSE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// Decode a "real" troublesome Carrier 84bit example message.
TEST(TestDecodeCarrierAC84, RealExample2) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
const uint8_t expected_state[kCarrierAc84StateLength] = {
0x03, 0x00, 0x03, 0x32, 0x00, 0x12, 0x00, 0x12, 0x33, 0x11, 0xDC};
irsend.begin();
irsend.reset();
// Data from:
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1943#issuecomment-1374434085
const uint16_t rawData[171] = {
5828, 1158, 1148, 464, 1148, 494, 384, 1200, 414, 1202, 412, 1202, 410,
1204, 408, 1204, 408, 1206, 408, 1228, 386, 1202, 408, 1232, 386, 1202,
1148, 464, 1146, 468, 412, 1200, 384, 1230, 412, 1200, 412, 1200, 410,
1204, 412, 1200, 412, 1202, 1146, 468, 410, 1202, 410, 1204, 1146, 466,
1146, 464, 410, 1230, 386, 1198, 414, 1200, 412, 1202, 410, 1202, 410,
1200, 410, 1204, 408, 1204, 410, 1202, 412, 1226, 386, 1202, 1144, 468,
408, 1204, 410, 1200, 1146, 468, 412, 1198, 410, 1206, 408, 1202, 410,
1228, 384, 1228, 386, 1202, 410, 1202, 412, 1202, 408, 1202, 410, 1202,
408, 1202, 410, 1204, 1146, 464, 412, 1202, 412, 1200, 1146, 468, 408,
1202, 412, 1200, 382, 1232, 1146, 488, 1122, 466, 410, 1228, 386, 1200,
1146, 492, 1118, 466, 412, 1202, 410, 1204, 1146, 464, 414, 1198, 410,
1204, 410, 1202, 1150, 464, 410, 1202, 412, 1202, 410, 1226, 386, 1200,
410, 1228, 1148, 440, 1148, 466, 1144, 468, 408, 1202, 1144, 470, 1144,
492, 1120}; // UNKNOWN 4CC7BE54
irsend.sendRaw(rawData, 171, 38000);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(CARRIER_AC84, irsend.capture.decode_type);
EXPECT_EQ(kCarrierAc84Bits, irsend.capture.bits);
EXPECT_STATE_EQ(expected_state, irsend.capture.state, irsend.capture.bits);
EXPECT_EQ(
"",
IRAcUtils::resultAcToString(&irsend.capture));
EXPECT_EQ(
"Protocol : CARRIER_AC84\n"
"Code : 0x03000332001200123311DC (84 Bits)\n",
resultToHumanReadableBasic(&irsend.capture));
}

View File

@ -0,0 +1,203 @@
// Copyright 2022 Mateusz Bronk (mbronk)
#include "IRac.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
class TestDecodeGorenjeSyntheticSendTestFixture
: public ::testing::TestWithParam<uint64_t> {};
class TestDecodeGorenjeReceiveTestFixture
: public ::testing::TestWithParam<std::tuple<std::vector<uint16_t>,
uint64_t>> {};
TEST(TestGorenje, Settings) {
ASSERT_EQ("GORENJE", typeToString(decode_type_t::GORENJE));
ASSERT_EQ(decode_type_t::GORENJE, strToDecodeType("GORENJE"));
ASSERT_FALSE(hasACState(decode_type_t::GORENJE));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::GORENJE));
ASSERT_EQ(kGorenjeBits,
IRsendTest::defaultBits(decode_type_t::GORENJE));
}
// Test sending typical data (cooker hood light toggle)
TEST(TestSendGorenje, SendLightToggle) {
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendGorenje(0x10); // Light toggle
EXPECT_EQ(
"f38000d50"
"m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000",
irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendGorenje, SendWithRepeats) {
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendGorenje(0x8, kGorenjeBits, 0); // 0 repeats.
EXPECT_EQ(
"f38000d50"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000",
irsend.outputStr());
irsend.sendGorenje(0x8, kGorenjeBits, 2); // 2 repeats.
EXPECT_EQ(
"f38000d50"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000"
"m1300s1700m1300s1700m1300s1700m1300s1700m1300s5700m1300s1700m1300s1700"
"m1300s1700"
"m1300s100000",
irsend.outputStr());
}
// Decode a Synthetic example
TEST_P(TestDecodeGorenjeSyntheticSendTestFixture, SyntheticExample) {
uint64_t commandToTest = GetParam();
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendGorenje(commandToTest);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(GORENJE, irsend.capture.decode_type);
EXPECT_EQ(kGorenjeBits, irsend.capture.bits);
EXPECT_EQ(commandToTest, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
INSTANTIATE_TEST_CASE_P(
TestDecodeGorenje,
TestDecodeGorenjeSyntheticSendTestFixture,
::testing::Values(0x2, 0x8, 0x4, 0x10, 0x20, 0x1));
// Decode a real example (codes captured from original remote)
TEST_P(TestDecodeGorenjeReceiveTestFixture, RealExample) {
const std::vector<uint16_t> rawDataInput = std::get<0>(GetParam());
const uint64_t expectedValue = std::get<1>(GetParam());
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendRaw(&rawDataInput[0], rawDataInput.size(), 38000);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::GORENJE, irsend.capture.decode_type);
EXPECT_EQ(kGorenjeBits, irsend.capture.bits);
EXPECT_EQ(expectedValue, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
INSTANTIATE_TEST_CASE_P(
TestDecodeGorenje,
TestDecodeGorenjeReceiveTestFixture,
::testing::Values(
// POWER
std::make_tuple(std::vector<uint16_t> {
1292, 1716, 1300, 1708, 1296, 1712,
1294, 1714, 1302, 1708, 1298, 1710,
1294, 5752, 1294, 1714, 1302
},
0x2),
std::make_tuple(std::vector<uint16_t> {
1302, 1706, 1298, 1710, 1294, 1714,
1292, 1716, 1300, 1708, 1296, 1712,
1294, 5754, 1292, 1716, 1300
},
0x2),
// FAN-
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1324, 1684, 1320, 1688,
1328, 1680, 1324, 5724, 1322, 1684,
1330, 1678, 1326, 1682, 1324
},
0x8),
std::make_tuple(std::vector<uint16_t> {
1296, 1712, 1292, 1718, 1298, 1710,
1294, 1714, 1292, 5756, 1300, 1708,
1296, 1712, 1294, 1714, 1300
},
0x8),
// FAN+
std::make_tuple(std::vector<uint16_t> {
1324, 1684, 1320, 1688, 1328, 1680,
1324, 1684, 1322, 1688, 1328, 5718,
1326, 1682, 1322, 1686, 1352
},
0x4),
std::make_tuple(std::vector<uint16_t> {
1296, 1714, 1292, 1716, 1298, 1710,
1296, 1714, 1292, 1716, 1300, 5748,
1296, 1712, 1292, 1716, 1300
},
0x4),
// Light toggle
std::make_tuple(std::vector<uint16_t> {
1326, 1682, 1322, 1686, 1328, 1680,
1324, 5722, 1322, 1686, 1330, 1680,
1326, 1682, 1322, 1686, 1328
},
0x10),
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1324, 1684, 1330, 1678,
1326, 5722, 1324, 1684, 1330, 1678,
1326, 1682, 1322, 1686, 1330
},
0x10),
// Light-
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1324, 1686, 1330, 5716,
1328, 1680, 1324, 1684, 1330, 1678,
1326, 1682, 1354, 1654, 1328
},
0x20),
std::make_tuple(std::vector<uint16_t> {
1322, 1686, 1318, 1690, 1326, 5722,
1322, 1686, 1330, 1678, 1326, 1682,
1322, 1686, 1328, 1680, 1324
},
0x20),
// Light+
std::make_tuple(std::vector<uint16_t> {
1328, 1680, 1326, 1682, 1322, 1688,
1328, 1680, 1324, 1686, 1330, 1678,
1326, 1682, 1322, 5724, 1330
},
0x1),
std::make_tuple(std::vector<uint16_t> {
1298, 1710, 1294, 1714, 1302, 1708,
1298, 1710, 1294, 1716, 1300, 1708,
1296, 1712, 1292, 5756, 1300
},
0x1)
)
);

View File

@ -13,7 +13,7 @@
// Tests for encodePanasonic(). // Tests for encodePanasonic().
TEST(TestEncodePanasonic, General) { TEST(TestEncodePanasonic, General) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
EXPECT_EQ(0x0, irsend.encodePanasonic(0, 0, 0, 0)); EXPECT_EQ(0x0, irsend.encodePanasonic(0, 0, 0, 0));
EXPECT_EQ(0x101010101, irsend.encodePanasonic(1, 1, 1, 1)); EXPECT_EQ(0x101010101, irsend.encodePanasonic(1, 1, 1, 1));
EXPECT_EQ(0xFFFF, irsend.encodePanasonic(0, 0, 0, 0xFF)); EXPECT_EQ(0xFFFF, irsend.encodePanasonic(0, 0, 0, 0xFF));
@ -28,7 +28,7 @@ TEST(TestEncodePanasonic, General) {
// Test sending typical data only. // Test sending typical data only.
TEST(TestSendPanasonic64, SendDataOnly) { TEST(TestSendPanasonic64, SendDataOnly) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -76,7 +76,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
// Test sending with different repeats. // Test sending with different repeats.
TEST(TestSendPanasonic64, SendWithRepeats) { TEST(TestSendPanasonic64, SendWithRepeats) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -147,7 +147,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
// Test sending an atypical data size. // Test sending an atypical data size.
TEST(TestSendPanasonic64, SendUnusualSize) { TEST(TestSendPanasonic64, SendUnusualSize) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -213,8 +213,8 @@ TEST(TestSendPanasonic, CompareToSendPanasonic64) {
// Decode normal Panasonic messages. // Decode normal Panasonic messages.
TEST(TestDecodePanasonic, NormalDecodeWithStrict) { TEST(TestDecodePanasonic, NormalDecodeWithStrict) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
// Normal Panasonic 48-bit message. // Normal Panasonic 48-bit message.
@ -259,8 +259,8 @@ TEST(TestDecodePanasonic, NormalDecodeWithStrict) {
// Decode normal repeated Panasonic messages. // Decode normal repeated Panasonic messages.
TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) { TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
// Normal Panasonic 48-bit message with 2 repeats. // Normal Panasonic 48-bit message with 2 repeats.
@ -293,8 +293,8 @@ TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) {
// Decode Panasonic messages with unsupported values. // Decode Panasonic messages with unsupported values.
TEST(TestDecodePanasonic, DecodeWithNonStrictValues) { TEST(TestDecodePanasonic, DecodeWithNonStrictValues) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -331,8 +331,8 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictValues) {
// Decode Panasonic messages with unsupported size/lengths. // Decode Panasonic messages with unsupported size/lengths.
TEST(TestDecodePanasonic, DecodeWithNonStrictSize) { TEST(TestDecodePanasonic, DecodeWithNonStrictSize) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -375,8 +375,8 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictSize) {
// Decode (non-standard) 64-bit messages. // Decode (non-standard) 64-bit messages.
TEST(TestDecodePanasonic, Decode64BitMessages) { TEST(TestDecodePanasonic, Decode64BitMessages) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -395,8 +395,8 @@ TEST(TestDecodePanasonic, Decode64BitMessages) {
// Decode a 'real' example via GlobalCache // Decode a 'real' example via GlobalCache
TEST(TestDecodePanasonic, DecodeGlobalCacheExample) { TEST(TestDecodePanasonic, DecodeGlobalCacheExample) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -432,8 +432,8 @@ TEST(TestDecodePanasonic, DecodeGlobalCacheExample) {
// Fail to decode a non-Panasonic example via GlobalCache // Fail to decode a non-Panasonic example via GlobalCache
TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) { TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -452,8 +452,8 @@ TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) {
// Failing to decode Panasonic in Issue #245 // Failing to decode Panasonic in Issue #245
TEST(TestDecodePanasonic, DecodeIssue245) { TEST(TestDecodePanasonic, DecodeIssue245) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
irsend.reset(); irsend.reset();
@ -813,8 +813,8 @@ TEST(TestIRPanasonicAcClass, HumanReadable) {
// Decode normal Panasonic AC messages. // Decode normal Panasonic AC messages.
TEST(TestDecodePanasonicAC, RealExample) { TEST(TestDecodePanasonicAC, RealExample) {
IRsendTest irsend(4); IRsendTest irsend(kGpioUnused);
IRrecv irrecv(4); IRrecv irrecv(kGpioUnused);
irsend.begin(); irsend.begin();
// Data from Issue #525 // Data from Issue #525
@ -1586,3 +1586,73 @@ TEST(TestIRPanasonicAc32Class, HumanReadable) {
"Swing(H): Off, Swing(V): 5 (Lowest)", "Swing(H): Off, Swing(V): 5 (Lowest)",
ac.toString()); ac.toString());
} }
// Decode a 'real' example of a captured 40 bit panasonic message
TEST(TestDecodePanasonic, RealPanasonic40BitMesg) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
// Panasonic 40 bit code https://github.com/crankyoldgit/IRremoteESP8266/issues/1976#issue-1660147581
const uint16_t rawData1[83] = {
3486, 1742,
432, 456, 406, 456, 406, 1336, 406, 1312, 430, 456, 406, 1334, 408, 456,
406, 456, 408, 456, 406, 1334, 408, 456, 408, 454, 408, 1334, 408, 456,
406, 1336, 406, 456, 408, 1334, 408, 456, 406, 456, 408, 1336, 406, 456,
408, 454, 406, 456, 406, 454, 408, 1332, 410, 1332, 408, 1334, 408, 1336,
406, 1334, 410, 1332, 410, 454, 406, 456, 406, 456, 406, 1332, 410, 1334,
408, 454, 406, 1336, 406, 1336, 406, 454, 410, 454, 408}; // UKN 1D41D404
irsend.sendRaw(rawData1, 83, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(kPanasonic40Bits, irsend.capture.bits);
EXPECT_EQ(0x344A90FC6C, irsend.capture.value);
EXPECT_EQ(0x34, irsend.capture.address);
EXPECT_EQ(0x4A90FC6C, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// night ch3 from https://github.com/crankyoldgit/IRremoteESP8266/issues/1976#issuecomment-1501736104
const uint16_t rawData2[83] = {
3490, 1734,
440, 426, 460, 400, 438, 1304, 438, 1302, 440, 426, 436, 1302, 464, 400,
462, 400, 462, 402, 462, 1278, 438, 426, 438, 426, 460, 1282, 434, 428,
434, 1308, 460, 402, 460, 1280, 440, 422, 438, 426, 436, 1306, 438, 424,
462, 402, 436, 426, 462, 400, 438, 426, 436, 1304, 434, 1308, 438, 1304,
464, 1278, 436, 1306, 466, 398, 464, 398, 466, 1276, 466, 1274, 464, 1280,
462, 402, 436, 1304, 466, 1276, 440, 422, 440, 424, 460}; // UKN DAE32FFC
irsend.reset();
irsend.sendRaw(rawData2, 83, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(kPanasonic40Bits, irsend.capture.bits);
EXPECT_EQ(0x344A907CEC, irsend.capture.value);
EXPECT_EQ(0x34, irsend.capture.address);
EXPECT_EQ(0x4A907CEC, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// recreate the above real message, synthetically.
TEST(TestDecodePanasonic, SynthticPanasonic40BitMesg) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x344A90FC6C, kPanasonic40Bits);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(kPanasonic40Bits, irsend.capture.bits);
EXPECT_EQ(0x344A90FC6C, irsend.capture.value);
EXPECT_EQ(0x34, irsend.capture.address);
EXPECT_EQ(0x4A90FC6C, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}

View File

@ -0,0 +1,103 @@
// Copyright 2022 David Conran
#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
TEST(TestUtils, Housekeeping) {
ASSERT_EQ("WOWWEE", typeToString(decode_type_t::WOWWEE));
ASSERT_EQ(decode_type_t::WOWWEE, strToDecodeType("WOWWEE"));
ASSERT_FALSE(hasACState(decode_type_t::WOWWEE));
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::WOWWEE));
ASSERT_EQ(kWowweeBits, IRsend::defaultBits(decode_type_t::WOWWEE));
ASSERT_EQ(kWowweeDefaultRepeat, IRsend::minRepeats(decode_type_t::WOWWEE));
}
// Tests for sendWowwee().
// Test sending typical data only.
TEST(TestSendWowwee, SendDataOnly) {
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
irsend.sendWowwee(0x186); // Nikai TV Power Off.
EXPECT_EQ(
"f38000d33"
"m6684s723"
"m912s723m912s723m912s3259m912s3259m912s723m912s723m912s723m912s723"
"m912s3259m912s3259m912s723m912s100000",
irsend.outputStr());
irsend.reset();
}
// Tests for decodeWowwee().
// Decode normal Wowwee messages.
TEST(TestDecodeWowwee, RealDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1938#issue-1513240242
const uint16_t rawForward[25] = {
6684, 740, 918, 724, 942, 724, 918, 3250, 870, 3268, 872, 770, 940, 690,
942, 688, 942, 738, 942, 3250, 868, 3268, 872, 732, 918
}; // UNKNOWN 7469BF81
irsend.reset();
irsend.sendRaw(rawForward, 25, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x186, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1938#issue-1513240242
const uint16_t rawLeft[25] = {
6630, 764, 868, 762, 892, 788, 866, 3324, 792, 3348, 818, 760, 866, 788,
894, 772, 892, 750, 870, 786, 920, 750, 864, 776, 868
}; // UNKNOWN 28A1120F
irsend.reset();
irsend.sendRaw(rawLeft, 25, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x180, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
}
// Decode normal repeated Wowwee messages.
TEST(TestDecodeWowwee, SyntheticDecode) {
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Normal Wowwee 11-bit message.
irsend.reset();
irsend.sendWowwee(0x186);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x186, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
// Normal Wowwee 11-bit message.
irsend.reset();
irsend.sendWowwee(0x180);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(decode_type_t::WOWWEE, irsend.capture.decode_type);
EXPECT_EQ(kWowweeBits, irsend.capture.bits);
EXPECT_EQ(0x180, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_EQ(0x0, irsend.capture.address);
}

View File

@ -0,0 +1,96 @@
// Copyright 2023 Daniele Gobbetti
#include "ir_York.h"
#include "IRac.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// General housekeeping
TEST(TestYork, Housekeeping) {
ASSERT_EQ("YORK", typeToString(decode_type_t::YORK));
ASSERT_EQ(typeToString(decode_type_t::YORK), "YORK");
ASSERT_TRUE(hasACState(YORK));
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::YORK));
ASSERT_EQ(kYorkBits, IRsend::defaultBits(decode_type_t::YORK));
}
// Tests for sendYork().
// Test sending typical data only.
TEST(TestSendYork, SendDataOnly) {
IRsendTest irsend(0);
irsend.begin();
uint8_t data[kYorkStateLength] = {
0x08, 0x10, 0x07, 0x02, 0x40, 0x08,
0x03, 0x18, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00,
0xEC, 0xF5, 0xF2};
irsend.reset();
irsend.sendYork(data);
EXPECT_EQ(
"f38000d50"
"m4887s2267m612s579m612s579m612s579m612s1778m612s579m612s579m612s579"
"m612s579m612s579m612s579m612s579m612s579m612s1778m612s579m612s579"
"m612s579m612s1778m612s1778m612s1778m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s1778m612s579m612s579m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s579m612s579m612s579m612s579m612s1778m612s579m612s579"
"m612s579m612s579m612s1778m612s579m612s579m612s579m612s579m612s1778"
"m612s1778m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579"
"m612s579m612s1778m612s1778m612s579m612s579m612s579m612s1778m612s579"
"m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s1778m612s1778m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579m612s579"
"m612s579m612s579m612s579m612s579m612s1778m612s1778m612s579m612s1778"
"m612s1778m612s1778m612s1778m612s579m612s1778m612s579m612s1778m612s1778"
"m612s1778m612s1778m612s579m612s1778m612s579m612s579m612s1778m612s1778"
"m612s1778m612s1778m612s100000",
irsend.outputStr());
irsend.reset();
}
// Decode normal York messages.
TEST(TestDecodeYork, SyntheticDecode) {
IRsendTest irsend(0);
IRrecv irrecv(0);
irsend.begin();
// Synthesised Normal York message.
irsend.reset();
uint8_t kYorkKnownGoodState[kYorkStateLength] = {
0x08, 0x10, 0x07, 0x02, 0x40, 0x08,
0x03, 0x18, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00,
0xEC, 0xF5, 0xF2};
irsend.sendYork(kYorkKnownGoodState);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(YORK, irsend.capture.decode_type);
EXPECT_EQ(kYorkBits, irsend.capture.bits);
EXPECT_STATE_EQ(kYorkKnownGoodState, irsend.capture.state,
irsend.capture.bits);
EXPECT_EQ(
"Power: On, Mode: 1 (Heat), Fan: 8 (Auto), Temp: 24C, Swing(V): Off"
", On Timer: 00:00, Off Timer: 00:00",
IRAcUtils::resultAcToString(&irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
}
// test checksum calculation
TEST(TestYorkClass, SetAndGetTemp) {
IRYorkAc ac(kGpioUnused);
EXPECT_NE(23, ac.getTemp()); // default state is 24 deegrees Celsius
ac.setTemp(23);
EXPECT_EQ(23, ac.getTemp());
uint8_t expectedState[kYorkStateLength] = {
0x08, 0x10, 0x07, 0x02, 0x40, 0x08,
0x03, 0x18, 0x01, 0x5C, 0x00, 0x00, 0x00, 0x00,
0xEC, 0xA5, 0xF7};
EXPECT_STATE_EQ(expectedState, ac.getRaw(), kYorkBits);
}

View File

@ -0,0 +1,35 @@
// Copyright 2022 Mateusz Bronk
#ifndef TEST_UT_UTILS_H_
#define TEST_UT_UTILS_H_
#include <sstream>
#include <string>
#include <iomanip>
#include <vector>
#include <algorithm>
std::string bytesToHexString(const std::vector<uint8_t>& value) {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
std::for_each(std::begin(value), std::end(value), [&oss] (uint8_t i) {
oss << std::setw(2) << std::uppercase << static_cast<uint16_t>(i);
});
return oss.str();
}
std::vector<uint8_t> hexStringToBytes(const std::string& hex) {
std::vector<uint8_t> bytes;
bytes.reserve(hex.length() / 2);
for (size_t i = 0; i < hex.length(); i += 2) {
std::string nextByte = hex.substr(i, 2);
uint8_t byte = static_cast<uint8_t>(strtol(nextByte.c_str(), nullptr, 16));
bytes.emplace_back(byte);
}
return bytes;
}
#endif // TEST_UT_UTILS_H_

View File

@ -1,6 +1,6 @@
{ {
"name": "IRremoteESP8266", "name": "IRremoteESP8266",
"version": "2.8.4", "version": "2.8.5",
"keywords": "infrared, ir, remote, esp8266, esp32", "keywords": "infrared, ir, remote, esp8266, esp32",
"description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)",
"repository": "repository":

View File

@ -115,7 +115,6 @@ lib_extra_dirs = lib/libesp32, lib/libesp32_lvgl, lib/lib_basic, lib/li
[env:tasmota32-ir] [env:tasmota32-ir]
extends = env:tasmota32_base extends = env:tasmota32_base
build_flags = ${env:tasmota32_base.build_flags} build_flags = ${env:tasmota32_base.build_flags}
-DUSE_IR_REMOTE_FULL
-DFIRMWARE_IR -DFIRMWARE_IR
-DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-ir.bin"' -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-ir.bin"'
lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_ssl lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_ssl