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 ]
jobs:
Build_Examples:
Gen_Matrix:
outputs:
matrix: ${{ steps.files.outputs.matrix }}
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:
- uses: actions/checkout@v2
@ -24,14 +46,29 @@ jobs:
uses: actions/cache@v2
with:
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
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Build all the examples
- name: Build example
env:
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
- name: Check all the version numbers match.
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)"
grep -q "^version=${LIB_VERSION}$" library.properties
examples-have-platformio_ini:

View File

@ -3,21 +3,28 @@ name: Tests
on: [push, pull_request]
jobs:
Unit_Tests:
Tools_Tests:
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:
- uses: actions/checkout@v2
- name: Install the Google test suite
env:
MAKEFLAGS: "-j 2"
run: (cd test; make install-googletest)
- name: Build and run the library unit tests.
env:
MAKEFLAGS: "-j 2"
- name: Build base unit test
run: (cd test; make IRac_test)
- name: Build library unit tests
run: (cd test; make all)
- name: Run library unit tests
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/gc_decode
tools/mode2_decode
tools/code_to_raw
.pioenvs
.piolibdeps
@ -51,3 +52,4 @@ tools/mode2_decode
# Mac extended attributes
.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
[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
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.
## v2.8.5 Now Available
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
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
[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
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.
## v2.8.5 jetzt verfügbar
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
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
[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
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.
## v2.8.5 disponible
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
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
## _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)_
**[Bug Fixes]**

View File

@ -1,6 +1,6 @@
<!--- WARNING: Do NOT edit this file directly.
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
| 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 |
| [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 |
| [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 | | - |
| [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 | | - |
| [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 |
| [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 |
@ -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) | **[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) | **[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) | **[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 | | - |
@ -46,6 +47,7 @@
| [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **G.I. Cable** | XRC-200 remote | | - |
| [GlobalCache](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Global Cache** | Control Tower IR DB | | - |
| [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes |
| [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) | **[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 |
@ -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) | **[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 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 |
| [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 | | - |
@ -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 |
| [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 | | - |
| [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 | | - |
| [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 | | - |
@ -164,6 +168,7 @@
- CARRIER_AC128
- CARRIER_AC40
- CARRIER_AC64
- CARRIER_AC84
- CLIMABUTLER
- COOLIX
- COOLIX48
@ -189,6 +194,7 @@
- FUJITSU_AC
- GICABLE
- GOODWEATHER
- GORENJE
- GREE
- HAIER_AC
- HAIER_AC160
@ -267,5 +273,7 @@
- VOLTAS
- WHIRLPOOL_AC
- WHYNTER
- WOWWEE
- XMP
- YORK
- 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_CMND "cmnd" // Sub-topic for the climate command 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.
#define MQTT_CLIMATE_JSON false
@ -221,6 +223,25 @@ const uint16_t kMinUnknownSize = 2 * 10;
// actual a/c unit.
#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 --------------------------------
// 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_MODE "mode"
#define KEY_TEMP "temp"
#define KEY_HUMIDITY "humidity"
#define KEY_FANSPEED "fanspeed"
#define KEY_SWINGV "swingv"
#define KEY_SWINGH "swingh"
@ -253,6 +275,9 @@ const uint16_t kMinUnknownSize = 2 * 10;
#define KEY_JSON "json"
#define KEY_RESEND "resend"
#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.
#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_REPEAT "repeats"
#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
#define KEY_TX_GPIO "tx"
#define KEY_RX_GPIO "rx"
// Miscellaneous constants
#define TOGGLE_JS_FN_NAME "ToggleInputBasedOnCheckbox"
// Text for Last Will & Testament status messages.
const char* const kLwtOnline = "Online";
const char* const kLwtOffline = "Offline";
@ -290,7 +321,7 @@ const uint16_t kJsonAcStateMaxSize = 1024; // Bytes
// ----------------- End of User Configuration Section -------------------------
// Constants
#define _MY_VERSION_ "v1.7.0"
#define _MY_VERSION_ "v1.8.2"
const uint8_t kRebootTime = 15; // 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_FANSPEED "|" 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_FILTER "|" KEY_CLEAN "|" KEY_CELSIUS "|" KEY_RESEND "|" KEY_COMMAND "|"
"|" KEY_SENSORTEMP "|" KEY_IFEEL
#if MQTT_CLIMATE_JSON
"|" KEY_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_SWINGV, KEY_SWINGH, KEY_QUIET, KEY_TURBO, KEY_LIGHT, KEY_BEEP,
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.
@ -410,7 +443,8 @@ int8_t getDefaultTxGpio(void);
String genStatTopic(const uint16_t channel = 0);
String listOfTxGpios(void);
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 htmlButton(const String url, const String button,
const String text = "");
@ -418,9 +452,13 @@ String htmlMenu(void);
void handleRoot(void);
String addJsReloadUrl(const String url, const uint16_t timeout_s,
const bool notify);
String getJsToggleCheckbox(const String functionName = TOGGLE_JS_FN_NAME);
void handleExamples(void);
String htmlOptionItem(const String value, const String text, bool selected);
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 htmlSelectAcStateProtocol(const String name, const decode_type_t def,
const bool simple);
@ -449,6 +487,9 @@ bool parseStringAndSendPronto(IRsend *irsend, const String str,
#if SEND_RAW
bool parseStringAndSendRaw(IRsend *irsend, const String str);
#endif // SEND_RAW
#if SHT3X_SUPPORT
void sendMQTTDiscoverySensor(const char *topic, String type);
#endif // SH3X_SUPPORT
void handleIr(void);
void handleNotFound(void);
void setup_wifi(void);

View File

@ -231,6 +231,49 @@
*
* 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:
* - platform: mqtt
* name: Living Room Aircon
@ -256,8 +299,7 @@
* - "Middle"
* - "Low"
* - "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_state_topic: "ir_server/ac/stat/mode"
* temperature_command_topic: "ir_server/ac/cmnd/temp"
@ -377,6 +419,10 @@ using irutils::msToString;
ADC_MODE(ADC_VCC);
#endif // REPORT_VCC
#ifdef SHT3X_SUPPORT
#include <WEMOS_SHT3X.h>
#endif
// Globals
uint8_t _sanity = 0;
#if defined(ESP8266)
@ -453,9 +499,15 @@ String MqttClimateCmnd; // Sub-topic for the climate command topics.
#if MQTT_DISCOVERY_ENABLE
String MqttDiscovery;
String MqttUniqueId;
#if SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
String MqttDiscoverySensor;
#endif // SHT3X_SUPPORT && SHT3X_MQTT_DISCOVERY_ENABLE
#endif // MQTT_DISCOVERY_ENABLE
String MqttHAName;
String MqttClientId;
#if SHT3X_SUPPORT
String MqttSensorStat;
#endif // SHT3X_SUPPORT
// Primative lock file for gating MQTT state broadcasts.
bool lockMqttBroadcast = true;
@ -495,6 +547,11 @@ bool isSerialGpioUsedByIr(void) {
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.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
@ -905,7 +962,7 @@ void handleExamples(void) {
#endif // EXAMPLES_ENABLE
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++)
html += htmlOptionItem(IRac::boolToString(i), IRac::boolToString(i),
i == def);
@ -913,8 +970,20 @@ String htmlSelectBool(const String name, const bool def) {
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 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++) {
if (IRac::isProtocolSupported((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 html = F("<select name='") + name + F("'>");
String html = String(F("<select name='")) + name + F("'>");
for (int16_t i = -1; i <= 6; i++) {
String num = String(i);
String text;
@ -942,9 +1011,21 @@ String htmlSelectModel(const String name, const int16_t def) {
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,
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++) {
String num = String(i);
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,
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++) {
String num = String(list[i]);
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 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++) {
String mode = IRac::opmodeToString((stdAc::opmode_t)i);
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 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++) {
String speed = IRac::fanspeedToString((stdAc::fanspeed_t)i);
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 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++) {
String swing = IRac::swingvToString((stdAc::swingv_t)i);
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 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++) {
String swing = IRac::swinghToString((stdAc::swingh_t)i);
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;
}
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>");
html += title;
html += F("</title><meta http-equiv=\"Content-Type\" "
"content=\"text/html;charset=utf-8\">"
"<meta name=\"viewport\" content=\"width=device-width,"
"initial-scale=1.0,minimum-scale=1.0,maximum-scale=5.0\">"
"</head><body><center><h1>");
"initial-scale=1.0,minimum-scale=1.0,maximum-scale=5.0\">");
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())
html += h1_text;
else
@ -1036,15 +1123,26 @@ String htmlButton(const String url, const String button, const String text) {
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
void handleAirCon(void) {
String html = htmlHeader(F("Air Conditioner Control"));
String html = htmlHeader(F("Air Conditioner Control"), "",
getJsToggleCheckbox());
html += htmlMenu();
if (kNrOfIrTxGpios > 1) {
html += F("<form method='POST' action='/aircon/set'"
html += String(F("<form method='POST' action='/aircon/set'"
" enctype='multipart/form-data'>"
"<table>"
"<tr><td><b>Climate #</b></td><td>") +
"<tr><td><b>Climate #</b></td><td>")) +
htmlSelectUint(KEY_CHANNEL, kNrOfIrTxGpios, chan) +
F("<input type='submit' value='Change'>"
"</td></tr>"
@ -1053,11 +1151,12 @@ void handleAirCon(void) {
"<hr>");
}
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'"
" enctype='multipart/form-data'>"
"<input type='hidden' name='" KEY_CHANNEL "' value='") + String(chan) +
F("'>") +
"<input type='hidden' name='" KEY_CHANNEL "' value='")) + String(chan)
+ F("'>") +
F("<table style='width:33%'>"
"<tr><td>" D_STR_PROTOCOL "</td><td>") +
htmlSelectClimateProtocol(KEY_PROTOCOL,
@ -1066,6 +1165,9 @@ void handleAirCon(void) {
"<tr><td>" D_STR_MODEL "</td><td>") +
htmlSelectModel(KEY_MODEL, climate[chan]->next.model) +
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>") +
htmlSelectBool(KEY_POWER, climate[chan]->next.power) +
F("</td></tr>"
@ -1084,6 +1186,16 @@ void handleAirCon(void) {
(!climate[chan]->next.celsius ? " selected='selected'" : "") +
F(">F</option>"
"</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>") +
htmlSelectFanspeed(KEY_FANSPEED, climate[chan]->next.fanspeed) +
F("</td></tr>"
@ -1096,6 +1208,9 @@ void handleAirCon(void) {
"<tr><td>" D_STR_QUIET "</td><td>") +
htmlSelectBool(KEY_QUIET, climate[chan]->next.quiet) +
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>") +
htmlSelectBool(KEY_TURBO, climate[chan]->next.turbo) +
F("</td></tr>"
@ -1190,7 +1305,13 @@ void handleAdmin(void) {
#if MQTT_DISCOVERY_ENABLE
html += htmlButton(
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
#if MQTT_CLEAR_ENABLE
html += htmlButton(
@ -1244,8 +1365,8 @@ void handleInfo(void) {
String html = htmlHeader(F("IR MQTT server info"));
html += htmlMenu();
html +=
F("<h3>General</h3>"
"<p>Hostname: ") + String(Hostname) + F("<br>"
String(F("<h3>General</h3>"
"<p>Hostname: ")) + String(Hostname) + F("<br>"
"IP address: ") + WiFi.localIP().toString() + F("<br>"
"MAC address: ") + WiFi.macAddress() + F("<br>"
"Booted: ") + timeSince(1) + F("<br>") +
@ -1392,6 +1513,10 @@ bool clearMqttSavedStates(const String topic_base) {
#if MQTT_DISCOVERY_ENABLE
// Clear the HA climate discovery message.
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
for (size_t channel = 0;
channel <= kNrOfIrTxGpios;
@ -2106,13 +2231,20 @@ void init_vars(void) {
MqttClimateCmnd = MqttClimate + '/' + MQTT_CLIMATE_CMND + '/';
// Sub-topic for the climate stat topics.
#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.replace(":", "");
#endif // MQTT_DISCOVERY_ENABLE
MqttHAName = String(Hostname) + "_aircon";
// Create a unique MQTT client id.
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
}
@ -2418,6 +2550,9 @@ void handleSendMqttDiscovery(void) {
htmlMenu() +
F("<p>The Home Assistant MQTT Discovery message is being sent to topic: ")
+ 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."
"</p>"
"<h3>Warning!</h3>"
@ -2425,7 +2560,15 @@ void handleSendMqttDiscovery(void) {
" is sent.</p>") +
addJsReloadUrl(kUrlRoot, kRebootTime, true) +
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
@ -2598,12 +2741,13 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
}
#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(
topic, String(
pub_topic.c_str(), String(
F("{"
"\"~\":\"") + MqttClimate + F("\","
"\"name\":\"") + MqttHAName + F("\","
"\"~\":\"") + MqttClimate + channel_id + F("\","
"\"name\":\"") + MqttHAName + channel_id + F("\","
#if (!MQTT_CLIMATE_HA_MODE)
// 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
@ -2629,9 +2773,12 @@ void sendMQTTDiscovery(const char *topic) {
"\"swing_modes\":[\"" D_STR_OFF "\",\"" D_STR_AUTO "\",\"" D_STR_HIGHEST
"\",\"" D_STR_HIGH "\",\"" D_STR_MIDDLE "\",\""
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\":{"
"\"identifiers\":[\"") + MqttUniqueId + F("\"],"
"\"identifiers\":[\"") + MqttUniqueId + channel_id + F("\"],"
"\"connections\":[[\"mac\",\"") + WiFi.macAddress() + F("\"]],"
"\"manufacturer\":\"IRremoteESP8266\","
"\"model\":\"IRMQTTServer\","
@ -2647,6 +2794,47 @@ void sendMQTTDiscovery(const char *topic) {
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_ENABLE
@ -2678,8 +2866,8 @@ void loop(void) {
boot = false;
} else {
mqttLog(String(
F("IRMQTTServer just (re)connected to MQTT. "
"Lost connection about ")
String(F("IRMQTTServer just (re)connected to MQTT. "
"Lost connection about "))
+ timeSince(lastConnectedTime)).c_str());
}
lastConnectedTime = now;
@ -2715,6 +2903,29 @@ void loop(void) {
}
// Periodically send all of the climate state via MQTT.
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
#if IR_RX
@ -2934,6 +3145,7 @@ void sendJsonState(const stdAc::state_t state, const String topic,
DynamicJsonDocument json(kJsonAcStateMaxSize);
json[KEY_PROTOCOL] = typeToString(state.protocol);
json[KEY_MODEL] = state.model;
json[KEY_COMMAND] = IRac::commandToString(state.command);
json[KEY_POWER] = IRac::boolToString(state.power);
json[KEY_MODE] = IRac::opmodeToString(state.mode, ha_mode);
// 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_TEMP] = state.degrees;
json[KEY_SENSORTEMP] = state.sensorTemperature;
json[KEY_FANSPEED] = IRac::fanspeedToString(state.fanspeed);
json[KEY_SWINGV] = IRac::swingvToString(state.swingv);
json[KEY_SWINGH] = IRac::swinghToString(state.swingh);
json[KEY_QUIET] = IRac::boolToString(state.quiet);
json[KEY_IFEEL] = IRac::boolToString(state.iFeel);
json[KEY_TURBO] = IRac::boolToString(state.turbo);
json[KEY_ECONO] = IRac::boolToString(state.econo);
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*>());
else if (validJsonInt(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))
result.mode = IRac::strToOpmode(json[KEY_MODE]);
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]);
if (json.containsKey(KEY_TEMP))
result.degrees = json[KEY_TEMP];
if (json.containsKey(KEY_SENSORTEMP))
result.sensorTemperature = json[KEY_SENSORTEMP];
if (validJsonInt(json, KEY_SLEEP))
result.sleep = json[KEY_SLEEP];
if (validJsonStr(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))
result.quiet = IRac::strToBool(json[KEY_QUIET]);
if (validJsonStr(json, KEY_TURBO))
@ -3029,6 +3251,8 @@ void updateClimate(stdAc::state_t *state, const String str,
state->protocol = strToDecodeType(payload.c_str());
} else if (str.equals(prefix + F(KEY_MODEL))) {
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))) {
state->power = IRac::strToBool(payload.c_str());
#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());
#if MQTT_CLIMATE_HA_MODE
// 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
} else if (str.equals(prefix + F(KEY_TEMP))) {
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))) {
state->fanspeed = IRac::strToFanspeed(payload.c_str());
} else if (str.equals(prefix + F(KEY_SWINGV))) {
state->swingv = IRac::strToSwingV(payload.c_str());
} else if (str.equals(prefix + F(KEY_SWINGH))) {
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))) {
state->quiet = IRac::strToBool(payload.c_str());
} else if (str.equals(prefix + F(KEY_TURBO))) {
@ -3086,14 +3326,16 @@ bool sendClimate(const String topic_prefix, const bool retain,
diff = true;
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
String mode_str = IRac::opmodeToString(next.mode, MQTT_CLIMATE_HA_MODE);
#else // MQTT_CLIMATE_HA_MODE
String mode_str = IRac::opmodeToString(next.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
// Home Assistant want's these two bound together.
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) {
#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);
diff = true;
}
@ -3118,6 +3364,11 @@ bool sendClimate(const String topic_prefix, const bool retain,
diff = true;
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) {
diff = true;
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,
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) {
diff = true;
success &= sendBool(topic_prefix + KEY_QUIET, next.quiet, retain);

View File

@ -15,6 +15,8 @@ lib_deps_builtin =
lib_deps_external =
PubSubClient@>=2.8.0
ArduinoJson@>=6.0
# Uncomment the following to enable SHT-3x support.
# https://github.com/wemos/WEMOS_SHT3x_Arduino_Library.git
[common_esp8266]
lib_deps_external =
@ -36,6 +38,14 @@ lib_deps = ${common_esp8266.lib_deps_external}
board = d1_mini
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]
board = d1_mini
build_flags =

View File

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

View File

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

View File

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

View File

@ -12,6 +12,7 @@
#ifndef ARDUINO
#include <string>
#endif
#include <cmath>
#include "IRsend.h"
#include "IRremoteESP8266.h"
#include "IRtext.h"
@ -64,6 +65,36 @@
#endif // ESP8266
#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
/// @param[in] pin Gpio pin to use when transmitting IR messages.
/// @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
#if SEND_VOLTAS
case decode_type_t::VOLTAS:
#endif
#if SEND_YORK
case decode_type_t::YORK:
#endif
case decode_type_t::WHIRLPOOL_AC:
return true;
@ -439,19 +473,27 @@ void IRac::amcor(IRAmcorAc *ac,
/// @param[in] on The power setting.
/// @param[in] mode The operation mode setting.
/// @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] 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] sleep Nr. of minutes for sleep mode.
/// @note -1 is Off, >= 0 is on.
void IRac::argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const float sensorTemp, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool iFeel,
const bool turbo, const int16_t sleep) {
ac->begin();
ac->setPower(on);
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->setFlap(ac->convertSwingV(swingv));
// No Quiet setting available.
@ -464,6 +506,121 @@ void IRac::argo(IRArgoAC *ac,
ac->setNight(sleep >= 0); // Convert to a boolean.
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
#if SEND_BOSCH144
@ -546,9 +703,12 @@ void IRac::carrier64(IRCarrierAc64 *ac,
/// @param[in] on The power setting.
/// @param[in] mode The operation mode setting.
/// @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] swingv The vertical swing setting.
/// @param[in] swingh The horizontal swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful 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
@ -556,10 +716,11 @@ void IRac::carrier64(IRCarrierAc64 *ac,
/// @note -1 is Off, >= 0 is on.
void IRac::coolix(IRCoolixAC *ac,
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 bool turbo, const bool light, const bool clean,
const int16_t sleep) {
const bool iFeel, const bool turbo, const bool light,
const bool clean, const int16_t sleep) {
ac->begin();
ac->setPower(on);
if (!on) {
@ -576,6 +737,12 @@ void IRac::coolix(IRCoolixAC *ac,
// No Clock setting available.
// No Econo 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.
// 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
@ -940,13 +1107,16 @@ void IRac::delonghiac(IRDelonghiAc *ac,
/// @param[in] on The power setting.
/// @param[in] mode The operation mode setting.
/// @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] 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.
void IRac::ecoclim(IREcoclimAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const int16_t sleep, const int16_t clock) {
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const int16_t sleep,
const int16_t clock) {
ac->begin();
ac->setPower(on);
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.
ac->setMode(new_mode);
ac->setTemp(degrees);
ac->setSensorTemp(degrees); //< Set to the desired temp until we cab disable.
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 SwingH setting available
// No Quiet setting available.
@ -979,22 +1154,28 @@ void IRac::ecoclim(IREcoclimAc *ac,
/// @param[in] on The power setting.
/// @param[in] mode The operation mode setting.
/// @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] swingv The vertical swing setting.
/// @param[in] swingh The horizontal swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] lighttoggle Should we toggle the LED/Display?
/// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc
void IRac::electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh, const bool turbo,
const bool lighttoggle, const bool clean) {
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh, const bool iFeel,
const bool turbo, const bool lighttoggle, const bool clean) {
ac->begin();
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(static_cast<uint8_t>(std::round(sensorTemp)));
}
ac->setFan(ac->convertFan(fan));
ac->setSwingV(swingv != stdAc::swingv_t::kOff);
ac->setSwingH(swingh != stdAc::swingh_t::kOff);
@ -1007,6 +1188,7 @@ void IRac::electra(IRElectraAc *ac,
// No Beep setting available.
// No Sleep setting available.
// No Clock setting available.
ac->setIFeel(iFeel);
ac->send();
}
#endif // SEND_ELECTRA_AC
@ -1132,6 +1314,7 @@ void IRac::goodweather(IRGoodweatherAc *ac,
/// @param[in] fan The speed setting for the fan.
/// @param[in] swingv The vertical swing setting.
/// @param[in] swingh The horizontal swing setting.
/// @param[in] iFeel Whether to enable iFeel (remote temp) mode on the A/C unit.
/// @param[in] turbo Run the device in turbo/powerful mode.
/// @param[in] econo Toggle the device's economical 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 float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool econo, const bool light,
const bool clean, const int16_t sleep) {
const bool iFeel, const bool turbo, const bool econo,
const bool light, const bool clean, const int16_t sleep) {
ac->begin();
ac->setModel(model);
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->convertSwingV(swingv));
ac->setSwingHorizontal(ac->convertSwingH(swingh));
ac->setIFeel(iFeel);
ac->setLight(light);
ac->setTurbo(turbo);
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] celsius Temperature units. True is Celsius, False is Fahrenheit.
/// @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] 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_prev The device's previous quiet/silent 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.
void IRac::midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const bool quiet, const bool quiet_prev,
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool iFeel, const bool quiet, const bool quiet_prev,
const bool turbo, const bool econo, const bool light,
const bool clean, const int16_t sleep) {
ac->begin();
@ -1683,6 +1870,10 @@ void IRac::midea(IRMideaAC *ac,
ac->setMode(ac->convertMode(mode));
ac->setUseCelsius(celsius);
ac->setTemp(degrees, celsius);
if (sensorTemp != kNoTempValue) {
ac->setSensorTemp(sensorTemp, celsius);
}
ac->setEnableSensorTemp(iFeel);
ac->setFan(ac->convertFan(fan));
ac->setSwingVToggle(swingv != stdAc::swingv_t::kOff);
// No Horizontal swing setting available.
@ -2080,19 +2271,29 @@ void IRac::samsung(IRSamsungAc *ac,
/// @param[in] on The power setting.
/// @param[in] mode The operation mode setting.
/// @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] 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] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on.
void IRac::sanyo(IRSanyoAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool beep,
const int16_t sleep) {
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool iFeel, const bool beep, const int16_t sleep) {
ac->begin();
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
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->setSwingV(ac->convertSwingV(swingv));
// No Horizontal swing setting available.
@ -2105,10 +2306,6 @@ void IRac::sanyo(IRSanyoAc *ac,
ac->setBeep(beep);
ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean.
// 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();
}
#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.
float degC __attribute__((unused)) =
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.
stdAc::state_t send = this->handleToggles(this->cleanState(desired), prev);
// 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
case ARGO:
{
IRArgoAC ac(_pin, _inverted, _modulation);
argo(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.turbo, send.sleep);
if (send.model == argo_ac_remote_model_t::SAC_WREM3) {
IRArgoAC_WREM3 ac(_pin, _inverted, _modulation);
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;
}
#endif // SEND_ARGO
@ -2877,8 +3106,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case COOLIX:
{
IRCoolixAC ac(_pin, _inverted, _modulation);
coolix(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.swingh, send.turbo, send.light, send.clean, send.sleep);
coolix(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.swingv, send.swingh, send.iFeel, send.turbo, send.light,
send.clean, send.sleep);
break;
}
#endif // SEND_COOLIX
@ -2976,7 +3206,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case ECOCLIM:
{
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;
}
#endif // SEND_ECOCLIM
@ -2984,8 +3215,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case ELECTRA_AC:
{
IRElectraAc ac(_pin, _inverted, _modulation);
electra(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.swingh, send.turbo, send.light, send.clean);
electra(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.swingv, send.swingh, send.iFeel, send.turbo, send.light,
send.clean);
break;
}
#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);
midea(&ac, send.power, send.mode, send.celsius, send.degrees,
send.fanspeed, send.swingv, send.quiet, prev_quiet, send.turbo,
send.econo, send.light, send.sleep);
send.sensorTemperature, send.fanspeed, send.swingv, send.iFeel,
send.quiet, prev_quiet, send.turbo, send.econo, send.light,
send.clean, send.sleep);
break;
}
#endif // SEND_MIDEA
@ -3263,8 +3496,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
case SANYO_AC:
{
IRSanyoAc ac(_pin, _inverted, _modulation);
sanyo(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv,
send.beep, send.sleep);
sanyo(&ac, send.power, send.mode, degC, sensorTempC, send.fanspeed,
send.swingv, send.iFeel, send.beep, send.sleep);
break;
}
#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.swingh != b.swingh || a.quiet != b.quiet || a.turbo != b.turbo ||
a.econo != b.econo || a.light != b.light || a.filter != b.filter ||
a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep;
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.
@ -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.
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.
/// @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.
@ -3492,6 +3747,8 @@ stdAc::fanspeed_t IRac::strToFanspeed(const char *str,
!STRCASECMP(str, kMaximumStr) ||
!STRCASECMP(str, kHighestStr))
return stdAc::fanspeed_t::kMax;
else if (!STRCASECMP(str, kMedHighStr))
return stdAc::fanspeed_t::kMediumHigh;
else
return def;
}
@ -3524,6 +3781,8 @@ stdAc::swingv_t IRac::strToSwingV(const char *str,
!STRCASECMP(str, kMediumStr) ||
!STRCASECMP(str, kCentreStr))
return stdAc::swingv_t::kMiddle;
else if (!STRCASECMP(str, kUpperMiddleStr))
return stdAc::swingv_t::kUpperMiddle;
else if (!STRCASECMP(str, kHighStr) ||
!STRCASECMP(str, kHiStr))
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;
} else if (!STRCASECMP(str, kDg11j191Str)) {
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 {
int16_t number = atoi(str);
if (number > 0)
@ -3701,6 +3965,19 @@ String IRac::boolToString(const bool value) {
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.
/// @param[in] mode The enum to be converted.
/// @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.
String IRac::fanspeedToString(const stdAc::fanspeed_t speed) {
switch (speed) {
case stdAc::fanspeed_t::kAuto: return kAutoStr;
case stdAc::fanspeed_t::kMax: return kMaxStr;
case stdAc::fanspeed_t::kHigh: return kHighStr;
case stdAc::fanspeed_t::kMedium: return kMediumStr;
case stdAc::fanspeed_t::kLow: return kLowStr;
case stdAc::fanspeed_t::kMin: return kMinStr;
default: return kUnknownStr;
case stdAc::fanspeed_t::kAuto: return kAutoStr;
case stdAc::fanspeed_t::kMax: return kMaxStr;
case stdAc::fanspeed_t::kHigh: return kHighStr;
case stdAc::fanspeed_t::kMedium: return kMediumStr;
case stdAc::fanspeed_t::kMediumHigh: return kMedHighStr;
case stdAc::fanspeed_t::kLow: return kLowStr;
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.
String IRac::swingvToString(const stdAc::swingv_t swingv) {
switch (swingv) {
case stdAc::swingv_t::kOff: return kOffStr;
case stdAc::swingv_t::kAuto: return kAutoStr;
case stdAc::swingv_t::kHighest: return kHighestStr;
case stdAc::swingv_t::kHigh: return kHighStr;
case stdAc::swingv_t::kMiddle: return kMiddleStr;
case stdAc::swingv_t::kLow: return kLowStr;
case stdAc::swingv_t::kLowest: return kLowestStr;
default: return kUnknownStr;
case stdAc::swingv_t::kOff: return kOffStr;
case stdAc::swingv_t::kAuto: return kAutoStr;
case stdAc::swingv_t::kHighest: return kHighestStr;
case stdAc::swingv_t::kHigh: return kHighStr;
case stdAc::swingv_t::kMiddle: return kMiddleStr;
case stdAc::swingv_t::kUpperMiddle: return kUpperMiddleStr;
case stdAc::swingv_t::kLow: return kLowStr;
case stdAc::swingv_t::kLowest: return kLowestStr;
default: return kUnknownStr;
}
}
@ -3796,8 +4075,14 @@ namespace IRAcUtils {
#endif // DECODE_AMCOR
#if DECODE_ARGO
case decode_type_t::ARGO: {
if (IRArgoAC_WREM3::isValidWrem3Message(result->state, result->bits,
true)) {
IRArgoAC_WREM3 ac(kGpioUnused);
ac.setRaw(result->state, result->bits / 8);
return ac.toString();
}
IRArgoAC ac(kGpioUnused);
ac.setRaw(result->state);
ac.setRaw(result->state, result->bits / 8);
return ac.toString();
}
#endif // DECODE_ARGO
@ -4211,6 +4496,13 @@ namespace IRAcUtils {
return ac.toString();
}
#endif // DECODE_WHIRLPOOL_AC
#if DECODE_YORK
case decode_type_t::YORK: {
IRYorkAc ac(kGpioUnused);
ac.setRaw(result->state);
return ac.toString();
}
#endif // DECODE_YORK
default:
return "";
}
@ -4258,9 +4550,24 @@ namespace IRAcUtils {
#endif // DECODE_AMCOR
#if DECODE_ARGO
case decode_type_t::ARGO: {
IRArgoAC ac(kGpioUnused);
ac.setRaw(decode->state);
*result = ac.toCommon();
const uint16_t length = decode->bits / 8;
if (IRArgoAC_WREM3::isValidWrem3Message(decode->state,
decode->bits, true)) {
IRArgoAC_WREM3 ac(kGpioUnused);
ac.setRaw(decode->state, length);
*result = ac.toCommon();
} else {
IRArgoAC ac(kGpioUnused);
switch (length) {
case kArgoStateLength:
case kArgoShortStateLength:
ac.setRaw(decode->state, length);
*result = ac.toCommon();
break;
default:
return false;
}
}
break;
}
#endif // DECODE_ARGO
@ -4732,6 +5039,14 @@ namespace IRAcUtils {
break;
}
#endif // DECODE_WHIRLPOOL_AC
#if DECODE_YORK
case decode_type_t::YORK: {
IRYorkAc ac(kGpioUnused);
ac.setRaw(decode->state);
*result = ac.toCommon(prev);
break;
}
#endif // DECODE_YORK
default:
return false;
}

View File

@ -5,6 +5,8 @@
#ifndef UNIT_TEST
#include <Arduino.h>
#else
#include <memory>
#endif
#include "IRremoteESP8266.h"
#include "ir_Airton.h"
@ -47,6 +49,7 @@
#include "ir_Vestel.h"
#include "ir_Voltas.h"
#include "ir_Whirlpool.h"
#include "ir_York.h"
// Constants
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 strToBool(const char *str, const bool def = false);
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(
const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto);
static stdAc::fanspeed_t strToFanspeed(
@ -94,6 +99,7 @@ class IRac {
static stdAc::swingh_t strToSwingH(
const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff);
static String boolToString(const bool value);
static String commandTypeToString(const stdAc::ac_command_t cmdType);
static String opmodeToString(const stdAc::opmode_t mode,
const bool ha = false);
static String fanspeedToString(const stdAc::fanspeed_t speed);
@ -103,10 +109,17 @@ class IRac {
stdAc::state_t getStatePrev(void);
bool hasStateChanged(void);
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:
#endif
#endif // UNIT_TEST
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 _modulation; ///< Is frequency modulation to be used?
@ -132,15 +145,26 @@ class IRac {
#if SEND_ARGO
void argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool turbo, const int16_t sleep = -1);
const float sensorTemp, const stdAc::fanspeed_t fan,
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
#if SEND_BOSCH144
void bosch144(IRBosch144AC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const bool quiet);
#endif // SEND_COOLIX
#endif // SEND_BOSCH144
#if SEND_CARRIER_AC64
void carrier64(IRCarrierAc64 *ac,
const bool on, const stdAc::opmode_t mode,
@ -150,10 +174,10 @@ void carrier64(IRCarrierAc64 *ac,
#if SEND_COOLIX
void coolix(IRCoolixAC *ac,
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 bool turbo, const bool light, const bool clean,
const int16_t sleep = -1);
const bool iFeel, const bool turbo, const bool light,
const bool clean, const int16_t sleep = -1);
#endif // SEND_COOLIX
#if SEND_CORONA_AC
void corona(IRCoronaAc *ac,
@ -231,15 +255,16 @@ void daikin216(IRDaikin216 *ac,
#if SEND_ECOCLIM
void ecoclim(IREcoclimAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const int16_t sleep = -1, const int16_t clock = -1);
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const int16_t sleep = -1,
const int16_t clock = -1);
#endif // SEND_ECOCLIM
#if SEND_ELECTRA_AC
void electra(IRElectraAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh, const bool turbo,
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh, const bool iFeel, const bool turbo,
const bool lighttoggle, const bool clean);
#endif // SEND_ELECTRA_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 float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool econo, const bool light,
const bool clean, const int16_t sleep = -1);
const bool iFeel, const bool turbo, const bool econo,
const bool light, const bool clean, const int16_t sleep = -1);
#endif // SEND_GREE
#if SEND_HAIER_AC
void haier(IRHaierAC *ac,
@ -363,11 +388,11 @@ void electra(IRElectraAc *ac,
#if SEND_MIDEA
void midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const bool celsius,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const bool quiet, const bool quiet_prev, const bool turbo,
const bool econo, const bool light, const bool clean,
const int16_t sleep = -1);
const float degrees, const float sensorTemp,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool iFeel, const bool quiet, const bool quiet_prev,
const bool turbo, const bool econo, const bool light,
const bool clean, const int16_t sleep = -1);
#endif // SEND_MIDEA
#if SEND_MIRAGE
void mirage(IRMirageAc *ac, const stdAc::state_t state);
@ -451,8 +476,9 @@ void electra(IRElectraAc *ac,
#if SEND_SANYO_AC
void sanyo(IRSanyoAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool beep, const int16_t sleep = -1);
const float sensorTemp, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const bool iFeel, const bool beep,
const int16_t sleep = -1);
#endif // SEND_SANYO_AC
#if SEND_SANYO_AC88
void sanyo88(IRSanyoAc88 *ac,

View File

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

View File

@ -399,6 +399,7 @@ void IRrecv::disableIRIn(void) {
#endif // ESP8266
#if defined(ESP32)
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
timerEnd(timer);
#endif // ESP32
detachInterrupt(params.recvpin);
@ -709,9 +710,12 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
return true;
#endif
#if DECODE_PANASONIC
DPRINTLN("Attempting Panasonic decode");
DPRINTLN("Attempting Panasonic (48-bit) decode");
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
DPRINTLN("Attempting LG (28-bit) decode");
if (decodeLG(results, offset, kLgBits, true)) return true;
@ -951,8 +955,21 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
return true;
#endif
#if DECODE_ARGO
DPRINTLN("Attempting Argo decode");
if (decodeArgo(results, offset)) return true;
DPRINTLN("Attempting Argo WREM3 decode (AC Control)");
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
#if DECODE_SHARP_AC
DPRINTLN("Attempting SHARP_AC decode");
@ -1160,6 +1177,22 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
DPRINTLN("Attempting Daikin 312-bit decode");
if (decodeDaikin312(results, offset)) return true;
#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.
}
#if DECODE_HASH

View File

@ -294,6 +294,9 @@ class IRrecv {
#if DECODE_ARGO
bool decodeArgo(decode_results *results, uint16_t offset = kStartOffset,
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
#if DECODE_ARRIS
bool decodeArris(decode_results *results, uint16_t offset = kStartOffset,
@ -580,6 +583,12 @@ class IRrecv {
const uint16_t nbits = kCarrierAc40Bits,
const bool strict = true);
#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
bool decodeCarrierAC64(decode_results *results,
uint16_t offset = kStartOffset,
@ -598,6 +607,11 @@ class IRrecv {
const uint16_t nbits = kGoodweatherBits,
const bool strict = true);
#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
bool decodeGree(decode_results *results, uint16_t offset = kStartOffset,
const uint16_t nbits = kGreeBits,
@ -857,6 +871,18 @@ class IRrecv {
const uint16_t nbits = kBosch144Bits,
const bool strict = true);
#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_

View File

@ -58,7 +58,7 @@
// Minor version number (x.X.x)
#define _IRREMOTEESP8266_VERSION_MINOR 8
// Patch version number (x.x.X)
#define _IRREMOTEESP8266_VERSION_PATCH 4
#define _IRREMOTEESP8266_VERSION_PATCH 5
// Macro to convert version info into an integer
#define _IRREMOTEESP8266_VERSION_VAL(major, minor, patch) \
(((major) << 16) | ((minor) << 8) | (patch))
@ -924,6 +924,34 @@
#define SEND_DAIKIN312 _IR_ENABLE_DEFAULT_
#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 || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
@ -942,6 +970,7 @@
DECODE_KELON168 || DECODE_HITACHI_AC296 || DECODE_CARRIER_AC128 || \
DECODE_DAIKIN200 || DECODE_HAIER_AC160 || DECODE_TCL96AC || \
DECODE_BOSCH144 || DECODE_SANYO_AC152 || DECODE_DAIKIN312 || \
DECODE_CARRIER_AC84 || DECODE_YORK || \
false)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
@ -1104,8 +1133,12 @@ enum decode_type_t {
BOSCH144, // 120
SANYO_AC152,
DAIKIN312,
GORENJE,
WOWWEE,
CARRIER_AC84, // 125
YORK,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = DAIKIN312,
kLastDecodeType = YORK,
};
// Message lengths & required repeat values
@ -1123,7 +1156,13 @@ const uint16_t kAmcorStateLength = 8;
const uint16_t kAmcorBits = kAmcorStateLength * 8;
const uint16_t kAmcorDefaultRepeat = kSingleRepeat;
const uint16_t kArgoStateLength = 12;
const uint16_t kArgoShortStateLength = 4;
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 kArrisBits = 32;
const uint16_t kBosch144StateLength = 18;
@ -1137,6 +1176,9 @@ const uint16_t kCarrierAc40Bits = 40;
const uint16_t kCarrierAc40MinRepeat = 2;
const uint16_t kCarrierAc64Bits = 64;
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 kCarrierAc128Bits = kCarrierAc128StateLength * 8;
const uint16_t kCarrierAc128MinRepeat = kNoRepeat;
@ -1203,6 +1245,7 @@ const uint16_t kGicableBits = 16;
const uint16_t kGicableMinRepeat = kSingleRepeat;
const uint16_t kGoodweatherBits = 48;
const uint16_t kGoodweatherMinRepeat = kNoRepeat;
const uint16_t kGorenjeBits = 8;
const uint16_t kGreeStateLength = 8;
const uint16_t kGreeBits = kGreeStateLength * 8;
const uint16_t kGreeDefaultRepeat = kNoRepeat;
@ -1292,6 +1335,8 @@ const uint16_t kNeoclimaBits = kNeoclimaStateLength * 8;
const uint16_t kNeoclimaMinRepeat = kNoRepeat;
const uint16_t kPanasonicBits = 48;
const uint32_t kPanasonicManufacturer = 0x4004;
const uint32_t kPanasonic40Manufacturer = 0x34;
const uint16_t kPanasonic40Bits = 40;
const uint16_t kPanasonicAcStateLength = 27;
const uint16_t kPanasonicAcStateShortLength = 16;
const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8;
@ -1372,6 +1417,8 @@ const uint16_t kWhirlpoolAcStateLength = 21;
const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8;
const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat;
const uint16_t kWhynterBits = 32;
const uint16_t kWowweeBits = 11;
const uint16_t kWowweeDefaultRepeat = kNoRepeat;
const uint8_t kVestelAcBits = 56;
const uint16_t kXmpBits = 64;
const uint16_t kZepealBits = 16;
@ -1386,6 +1433,8 @@ const uint16_t kRhossStateLength = 12;
const uint16_t kRhossBits = kRhossStateLength * 8;
const uint16_t kRhossDefaultRepeat = 0;
const uint16_t kClimaButlerBits = 52;
const uint16_t kYorkBits = 136;
const uint16_t kYorkStateLength = 17;
// 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) {
switch (protocol) {
case MULTIBRACKETS:
case GORENJE:
return 8;
case WOWWEE:
return 11;
case RC5:
case SYMPHONY:
return 12;
@ -690,6 +693,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kBosch144Bits;
case CORONA_AC:
return kCoronaAcBits;
case CARRIER_AC84:
return kCarrierAc84Bits;
case CARRIER_AC128:
return kCarrierAc128Bits;
case DAIKIN:
@ -791,6 +796,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kWhirlpoolAcBits;
case XMP:
return kXmpBits;
case YORK:
return kYorkBits;
// No default amount of bits.
case FUJITSU_AC:
case MWM:
@ -916,6 +923,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
sendGoodweather(data, nbits, min_repeat);
break;
#endif
#if SEND_GORENJE
case GORENJE:
sendGorenje(data, nbits, min_repeat);
break;
#endif
#if SEND_GREE
case GREE:
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);
break;
#endif
#if SEND_WOWWEE
case WOWWEE:
sendWowwee(data, nbits, min_repeat);
break;
#endif // SEND_WOWWEE
#if SEND_XMP
case XMP:
sendXmp(data, nbits, min_repeat);
@ -1159,6 +1176,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendBosch144(state, nbytes);
break;
#endif // SEND_BOSCH144
#if SEND_CARRIER_AC84
case CARRIER_AC84:
sendCarrierAC84(state, nbytes);
break;
#endif // SEND_CARRIER_AC84
#if SEND_CARRIER_AC128
case CARRIER_AC128:
sendCarrierAC128(state, nbytes);
@ -1407,6 +1429,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendWhirlpoolAC(state, nbytes);
break;
#endif // SEND_WHIRLPOOL_AC
#if SEND_YORK
case YORK:
sendYork(state, nbytes);
break;
#endif // SEND_YORK
default:
return false;
}

View File

@ -39,6 +39,9 @@ const uint8_t kDutyMax = 100; // Percentage
const uint16_t kMaxAccurateUsecDelay = 16383;
// Usecs to wait between messages we don't know the proper gap time.
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.
namespace stdAc {
@ -56,14 +59,15 @@ enum class opmode_t {
/// Common A/C settings for Fan Speeds.
enum class fanspeed_t {
kAuto = 0,
kMin = 1,
kLow = 2,
kMedium = 3,
kHigh = 4,
kMax = 5,
kAuto = 0,
kMin = 1,
kLow = 2,
kMedium = 3,
kHigh = 4,
kMax = 5,
kMediumHigh = 6,
// 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.
@ -75,8 +79,21 @@ enum class swingv_t {
kMiddle = 3,
kLow = 4,
kLowest = 5,
kUpperMiddle = 6,
// 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.
@ -113,6 +130,9 @@ struct state_t {
bool beep = false;
int16_t sleep = -1; // `-1` means off.
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
@ -202,6 +222,11 @@ enum lg_ac_remote_model_t {
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
@ -519,14 +544,22 @@ class IRsend {
const uint16_t nbits = kGoodweatherBits,
const uint16_t repeat = kGoodweatherMinRepeat);
#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
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
#endif
#if SEND_ARGO
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 repeat = kArgoDefaultRepeat);
#endif
#endif // SEND_ARGO
#if SEND_TROTEC
void sendTrotec(const unsigned char data[],
const uint16_t nbytes = kTrotecStateLength,
@ -575,6 +608,11 @@ class IRsend {
void sendCarrierAC64(uint64_t data, uint16_t nbits = kCarrierAc64Bits,
uint16_t repeat = kCarrierAc64MinRepeat);
#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
void sendCarrierAC128(const uint8_t data[],
uint16_t nbytes = kCarrierAc128StateLength,
@ -837,6 +875,15 @@ class IRsend {
const uint16_t nbytes = kBosch144StateLength,
const uint16_t repeat = kNoRepeat);
#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:
#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(kClockStr, D_STR_CLOCK); ///< "Clock"
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(kHealthStr, D_STR_HEALTH); ///< "Health"
IRTEXT_CONST_STRING(kModelStr, D_STR_MODEL); ///< "Model"
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(kHumidStr, D_STR_HUMID); ///< "Humid"
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(kLowerStr, D_STR_LOWER); ///< "Lower"
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(kCirculateStr, D_STR_CIRCULATE); ///< "Circulate"
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(kMinStr, D_STR_MIN); ///< "Min"
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(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); ///<
///< "Swing(V) 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
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(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104"
IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191"
IRTEXT_CONST_STRING(kArgoWrem2Str, D_STR_ARGO_WREM2); ///< "WREM3"
IRTEXT_CONST_STRING(kArgoWrem3Str, D_STR_ARGO_WREM3); ///< "WREM3"
#define D_STR_UNSUPPORTED "?" // Unsupported protocols will be showing as
// a question mark, check for length > 1
@ -533,6 +547,14 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_SANYO_AC152, D_STR_UNSUPPORTED) "\x0"
COND(DECODE_DAIKIN312 || SEND_DAIKIN312,
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.
"\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(kAkb75215403Str);
extern IRTEXT_CONST_PTR(kArdb1Str);
extern IRTEXT_CONST_PTR(kArgoWrem2Str);
extern IRTEXT_CONST_PTR(kArgoWrem3Str);
extern IRTEXT_CONST_PTR(kArjw2Str);
extern IRTEXT_CONST_PTR(kArrah2eStr);
extern IRTEXT_CONST_PTR(kArreb1eStr);
@ -57,6 +59,7 @@ extern IRTEXT_CONST_PTR(kCelsiusFahrenheitStr);
extern IRTEXT_CONST_PTR(kCelsiusStr);
extern IRTEXT_CONST_PTR(kCentreStr);
extern IRTEXT_CONST_PTR(kChangeStr);
extern IRTEXT_CONST_PTR(kChStr);
extern IRTEXT_CONST_PTR(kCirculateStr);
extern IRTEXT_CONST_PTR(kCkpStr);
extern IRTEXT_CONST_PTR(kCleanStr);
@ -66,6 +69,8 @@ extern IRTEXT_CONST_PTR(kColonSpaceStr);
extern IRTEXT_CONST_PTR(kComfortStr);
extern IRTEXT_CONST_PTR(kCommaSpaceStr);
extern IRTEXT_CONST_PTR(kCommandStr);
extern IRTEXT_CONST_PTR(kConfigCommandStr);
extern IRTEXT_CONST_PTR(kControlCommandStr);
extern IRTEXT_CONST_PTR(kCoolStr);
extern IRTEXT_CONST_PTR(kCoolingStr);
extern IRTEXT_CONST_PTR(kDashStr);
@ -109,6 +114,7 @@ extern IRTEXT_CONST_PTR(kHoldStr);
extern IRTEXT_CONST_PTR(kHourStr);
extern IRTEXT_CONST_PTR(kHoursStr);
extern IRTEXT_CONST_PTR(kHumidStr);
extern IRTEXT_CONST_PTR(kIFeelReportStr);
extern IRTEXT_CONST_PTR(kIFeelStr);
extern IRTEXT_CONST_PTR(kISeeStr);
extern IRTEXT_CONST_PTR(kIdStr);
@ -116,6 +122,7 @@ extern IRTEXT_CONST_PTR(kIndirectStr);
extern IRTEXT_CONST_PTR(kInsideStr);
extern IRTEXT_CONST_PTR(kIonStr);
extern IRTEXT_CONST_PTR(kJkeStr);
extern IRTEXT_CONST_PTR(kKeyStr);
extern IRTEXT_CONST_PTR(kKkg29ac1Str);
extern IRTEXT_CONST_PTR(kKkg9ac1Str);
extern IRTEXT_CONST_PTR(kLastStr);
@ -139,6 +146,7 @@ extern IRTEXT_CONST_PTR(kMaxRightNoSpaceStr);
extern IRTEXT_CONST_PTR(kMaxRightStr);
extern IRTEXT_CONST_PTR(kMaxStr);
extern IRTEXT_CONST_PTR(kMaximumStr);
extern IRTEXT_CONST_PTR(kMedHighStr);
extern IRTEXT_CONST_PTR(kMedStr);
extern IRTEXT_CONST_PTR(kMediumStr);
extern IRTEXT_CONST_PTR(kMidStr);
@ -188,8 +196,10 @@ extern IRTEXT_CONST_PTR(kRlt0541htaaStr);
extern IRTEXT_CONST_PTR(kRlt0541htabStr);
extern IRTEXT_CONST_PTR(kRoomStr);
extern IRTEXT_CONST_PTR(kSaveStr);
extern IRTEXT_CONST_PTR(kScheduleStr);
extern IRTEXT_CONST_PTR(kSecondStr);
extern IRTEXT_CONST_PTR(kSecondsStr);
extern IRTEXT_CONST_PTR(kSensorReportStr);
extern IRTEXT_CONST_PTR(kSensorStr);
extern IRTEXT_CONST_PTR(kSensorTempStr);
extern IRTEXT_CONST_PTR(kSetStr);
@ -213,7 +223,9 @@ extern IRTEXT_CONST_PTR(kTempDownStr);
extern IRTEXT_CONST_PTR(kTempStr);
extern IRTEXT_CONST_PTR(kTempUpStr);
extern IRTEXT_CONST_PTR(kThreeLetterDayOfWeekStr);
extern IRTEXT_CONST_PTR(kTimerActiveDaysStr);
extern IRTEXT_CONST_PTR(kTimerModeStr);
extern IRTEXT_CONST_PTR(kSetTimerCommandStr);
extern IRTEXT_CONST_PTR(kTimerStr);
extern IRTEXT_CONST_PTR(kToggleStr);
extern IRTEXT_CONST_PTR(kTopStr);
@ -224,6 +236,8 @@ extern IRTEXT_CONST_PTR(kTypeStr);
extern IRTEXT_CONST_PTR(kUnknownStr);
extern IRTEXT_CONST_PTR(kUpStr);
extern IRTEXT_CONST_PTR(kUpperStr);
extern IRTEXT_CONST_PTR(kUpperMiddleStr);
extern IRTEXT_CONST_PTR(kValueStr);
extern IRTEXT_CONST_PTR(kV9014557AStr);
extern IRTEXT_CONST_PTR(kV9014557BStr);
extern IRTEXT_CONST_PTR(kVaneStr);

View File

@ -6,6 +6,7 @@
#endif
#define __STDC_LIMIT_MACROS
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <algorithm>
@ -173,6 +174,7 @@ bool hasACState(const decode_type_t protocol) {
case AMCOR:
case ARGO:
case BOSCH144:
case CARRIER_AC84:
case CARRIER_AC128:
case CORONA_AC:
case DAIKIN:
@ -224,6 +226,7 @@ bool hasACState(const decode_type_t protocol) {
case TROTEC_3550:
case VOLTAS:
case WHIRLPOOL_AC:
case YORK:
return true;
default:
return false;
@ -304,7 +307,7 @@ String resultToSourceCode(const decode_results * const results) {
if (results->decode_type != UNKNOWN) {
if (hasState) {
#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 += uint64ToString(nbytes);
output += F("] = {");
@ -695,6 +698,13 @@ namespace irutils {
default: return kUnknownStr;
}
break;
case decode_type_t::ARGO:
switch (model) {
case argo_ac_remote_model_t::SAC_WREM2: return kArgoWrem2Str;
case argo_ac_remote_model_t::SAC_WREM3: return kArgoWrem3Str;
default: return kUnknownStr;
}
break;
default: return kUnknownStr;
}
}
@ -722,10 +732,12 @@ namespace irutils {
/// @param[in] celsius Is the temp Celsius or Fahrenheit.
/// true is C, false is F
/// @param[in] precomma Should the output string start with ", " or not?
/// @param[in] isSensorTemp Is the value a room (ambient) temp. or target?
/// @return The resulting String.
String addTempToString(const uint16_t degrees, const bool celsius,
const bool precomma) {
String result = addIntToString(degrees, kTempStr, precomma);
const bool precomma, const bool isSensorTemp) {
String result = addIntToString(degrees, (isSensorTemp)?
kSensorTempStr : kTempStr, precomma);
result += celsius ? 'C' : 'F';
return result;
}
@ -736,12 +748,14 @@ namespace irutils {
/// @param[in] celsius Is the temp Celsius or Fahrenheit.
/// true is C, false is F
/// @param[in] precomma Should the output string start with ", " or not?
/// @param[in] isSensorTemp Is the value a room (ambient) temp. or target?
/// @return The resulting String.
String addTempFloatToString(const float degrees, const bool celsius,
const bool precomma) {
const bool precomma, const bool isSensorTemp) {
String result = "";
result.reserve(14); // Assuming ", Temp: XXX.5F" is the largest.
result += addIntToString(degrees, kTempStr, precomma);
result.reserve(21); // Assuming ", Sensor Temp: XXX.5F" is the largest.
result += addIntToString(degrees, (isSensorTemp)?
kSensorTempStr : kTempStr, precomma);
// Is it a half degree?
if (((uint16_t)(2 * degrees)) & 1) result += F(".5");
result += celsius ? 'C' : 'F';
@ -788,43 +802,57 @@ namespace irutils {
result.reserve(19); // ", Day: N (UNKNOWN)"
result += addIntToString(day_of_week, kDayStr, precomma);
result += kSpaceLBraceStr;
result += dayToString(day_of_week, offset);
return result + ')';
}
/// Create a String of the 3-letter day of the week from a numerical day of
/// the week. e.g. "Mon"
/// @param[in] day_of_week A numerical version of the sequential day of the
/// week. e.g. Sunday = 1, Monday = 2, ..., Saturday = 7
/// @param[in] offset Days to offset by.
/// e.g. For different day starting the week.
/// @return The resulting String.
String dayToString(const uint8_t day_of_week, const int8_t offset) {
if ((uint8_t)(day_of_week + offset) < 7)
#if UNIT_TEST
result += String(kThreeLetterDayOfWeekStr).substr(
(day_of_week + offset) * 3, 3);
return String(kThreeLetterDayOfWeekStr).substr(
(day_of_week + offset) * 3, 3);
#else // UNIT_TEST
result += String(kThreeLetterDayOfWeekStr).substring(
(day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3);
return String(kThreeLetterDayOfWeekStr).substring(
(day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3);
#endif // UNIT_TEST
else
result += kUnknownStr;
return result + ')';
return kUnknownStr;
}
/// Create a String of human output for the given fan speed.
/// e.g. "Fan: 0 (Auto)"
/// @param[in] speed The numeric speed of the fan to display.
/// @param[in] high The numeric value for High speed.
/// @param[in] high The numeric value for High speed. (second highest)
/// @param[in] low The numeric value for Low speed.
/// @param[in] automatic The numeric value for Auto speed.
/// @param[in] quiet The numeric value for Quiet speed.
/// @param[in] medium The numeric value for Medium speed.
/// @param[in] maximum The numeric value for Highest speed. (if > high)
/// @param[in] medium_high The numeric value for third-highest speed.
/// (if > medium)
/// @return The resulting String.
String addFanToString(const uint8_t speed, const uint8_t high,
const uint8_t low, const uint8_t automatic,
const uint8_t quiet, const uint8_t medium,
const uint8_t maximum) {
const uint8_t maximum, const uint8_t medium_high) {
String result = "";
result.reserve(21); // ", Fan: NNN (UNKNOWN)"
result += addIntToString(speed, kFanStr);
result += kSpaceLBraceStr;
if (speed == high) result += kHighStr;
else if (speed == low) result += kLowStr;
else if (speed == automatic) result += kAutoStr;
else if (speed == quiet) result += kQuietStr;
else if (speed == medium) result += kMediumStr;
else if (speed == maximum) result += kMaximumStr;
if (speed == high) result += kHighStr;
else if (speed == low) result += kLowStr;
else if (speed == automatic) result += kAutoStr;
else if (speed == quiet) result += kQuietStr;
else if (speed == medium) result += kMediumStr;
else if (speed == maximum) result += kMaximumStr;
else if (speed == medium_high) result += kMedHighStr;
else
result += kUnknownStr;
return result + ')';
@ -950,6 +978,106 @@ namespace irutils {
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.
/// @param[in] unescaped A String containing text to make 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,
const bool precomma = 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,
const bool precomma = true);
const bool precomma = true,
const bool isSensorTemp = false);
String addModeToString(const uint8_t mode, const uint8_t automatic,
const uint8_t cool, const uint8_t heat,
const uint8_t dry, const uint8_t fan);
String addFanToString(const uint8_t speed, const uint8_t high,
const uint8_t low, const uint8_t automatic,
const uint8_t quiet, const uint8_t medium,
const uint8_t maximum = 0xFF);
const uint8_t maximum = 0xFF,
const uint8_t medium_high = 0xFF);
String addSwingHToString(const uint8_t position, const uint8_t automatic,
const uint8_t maxleft, const uint8_t left,
const uint8_t middle,
@ -87,6 +90,19 @@ namespace irutils {
const uint8_t breeze, const uint8_t circulate);
String addDayToString(const uint8_t day_of_week, const int8_t offset = 0,
const bool precomma = true);
String addTimerModeToString(const uint8_t timerType, const uint8_t noTimer,
const uint8_t delayTimer,
const uint8_t schedule1 = 0xFF,
const uint8_t schedule2 = 0xFF,
const uint8_t schedule3 = 0xFF,
const bool precomma = true);
String irCommandTypeToString(uint8_t commandType, uint8_t acControlCmd,
uint8_t iFeelReportCmd = 0xFF,
uint8_t timerCmd = 0xFF,
uint8_t configCmd = 0xFF);
String dayToString(const uint8_t day_of_week, const int8_t offset = 0);
String daysBitmaskToString(uint8_t daysBitmap, uint8_t offset = 0);
String channelToString(const uint8_t channel);
String htmlEscape(const String unescaped);
String msToString(uint32_t const msecs);
String minsToString(const uint16_t mins);

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,18 @@
// Copyright 2017 Schmolders
// Copyright 2022 crankyoldgit
// Copyright 2022 Mateusz Bronk (mbronk)
/// @file
/// @brief Support for Argo Ulisse 13 DCI Mobile Split ACs.
// 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_
#define IR_ARGO_H_
#include <set>
#include <utility>
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
@ -20,14 +25,14 @@
// 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 {
uint8_t raw[kArgoStateLength]; ///< The state in native IR code form
struct {
// Byte 0
uint64_t :8; // Typically 0b00110101
uint64_t Pre1 :8; // Typically 0b00110101
// Byte 1
uint64_t :8; // Typically 0b10101111
uint64_t Pre2 :8; // Typically 0b10101111
// Byte 2~4
uint64_t :3;
uint64_t Mode :3;
@ -57,17 +62,143 @@ union ArgoProtocol {
uint32_t :1; // const 0
uint32_t iFeel :1;
// Byte 10~11
uint32_t :2; // const 01
uint32_t Post :2;
uint32_t Sum :8; // straddle byte 10 and 11
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 kArgoDry = 0b001;
const uint8_t kArgoAuto = 0b010;
@ -77,19 +208,42 @@ const uint8_t kArgoHeatAuto = 0b101;
// ?no idea what mode that is
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 kArgoFan1 = 1; // 0b01
const uint8_t kArgoFan2 = 2; // 0b10
const uint8_t kArgoFan3 = 3; // 0b11
// 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
/// @brief Flap position (swing-V)
/// @note Raw values match WREM-3 protocol, but the enum is used in generic
/// context
enum class argoFlap_t : uint8_t {
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 kArgoFlap1 = 1;
const uint8_t kArgoFlap2 = 2;
@ -123,22 +277,61 @@ const uint8_t kArgoFlapFull = 7;
#define ARGO_FLAP_FULL kArgoFlapFull
/// Class for handling detailed Argo A/C messages.
class IRArgoAC {
/// @brief Timer type to set (for @c argoIrMessageType_t::TIMER_COMMAND)
/// @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:
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);
public:
#if SEND_ARGO
void send(const uint16_t repeat = kArgoDefaultRepeat);
void sendSensorTemp(const uint8_t temp,
const uint16_t repeat = kArgoDefaultRepeat);
/// Run the calibration to calculate uSec timing offsets for this platform.
/// @return The uSec timing offset needed per modulation of the IR Led.
/// @note This will produce a 65ms IR signal pulse at 38kHz.
/// Only ever needs to be run once per object instantiation, if at all.
int8_t calibrate(void) { return _irsend.calibrate(); }
#endif // SEND_ARGO
void begin(void);
void on(void);
void off(void);
@ -149,14 +342,20 @@ class IRArgoAC {
void setTemp(const uint8_t degrees);
uint8_t getTemp(void) const;
void setFan(const uint8_t fan);
uint8_t getFan(void) const;
void setSensorTemp(const uint8_t degrees);
uint8_t getSensorTemp(void) const;
void setFlap(const uint8_t flap);
uint8_t getFlap(void) const;
void setFan(const argoFan_t fan);
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);
uint8_t getMode(void) const;
void setFlap(const argoFlap_t flap);
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);
bool getMax(void) const;
@ -167,41 +366,156 @@ class IRArgoAC {
void setiFeel(const bool on);
bool getiFeel(void) const;
void setTime(void);
void setRoomTemp(const uint8_t degrees);
uint8_t getRoomTemp(void) const;
void setMessageType(const argoIrMessageType_t msgType);
argoIrMessageType_t getMessageType(void) const;
static argoIrMessageType_t getMessageType(const uint8_t state[],
const uint16_t length);
uint8_t* getRaw(void);
void setRaw(const uint8_t state[]);
static uint8_t calcChecksum(const uint8_t state[],
const uint16_t length = kArgoStateLength);
static bool validChecksum(const uint8_t state[],
const uint16_t length = kArgoStateLength);
static uint8_t convertMode(const stdAc::opmode_t mode);
static uint8_t convertFan(const stdAc::fanspeed_t speed);
static uint8_t convertSwingV(const stdAc::swingv_t position);
static stdAc::opmode_t toCommonMode(const uint8_t mode);
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(void) const;
String toString(void) const;
uint16_t getRawByteLength() const;
static uint16_t getStateLengthForIrMsgType(argoIrMessageType_t type);
void setRaw(const uint8_t state[], const uint16_t length);
static bool validChecksum(const uint8_t state[], const uint16_t length);
static argoMode_t convertMode(const stdAc::opmode_t mode);
static argoFan_t convertFan(const stdAc::fanspeed_t speed);
static argoFlap_t convertSwingV(const stdAc::swingv_t position);
static argoIrMessageType_t convertCommand(const stdAc::ac_command_t command);
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
private:
protected:
IRsend _irsend; ///< instance of the IR send class
#else
public:
/// @cond IGNORE
IRsendTest _irsend; ///< instance of the testing IR send class
/// @endcond
#endif
// # of bytes per command
ArgoProtocol _;
void stateReset(void);
void checksum(void);
};
// Attributes
uint8_t flap_mode;
uint8_t heat_mode;
uint8_t cool_mode;
/// @brief Supports Argo A/C SAC-WREM2 IR remote protocol
class IRArgoAC : public IRArgoACBase<ArgoProtocol> {
public:
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_

View File

@ -46,6 +46,15 @@ const uint16_t kCarrierAc64OneSpace = 1736;
const uint16_t kCarrierAc64ZeroSpace = 615;
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 kCarrierAc128HdrSpace = 2600;
const uint16_t kCarrierAc128Hdr2Mark = 9300;
@ -645,3 +654,94 @@ bool IRrecv::decodeCarrierAC128(decode_results *results, uint16_t offset,
return true;
}
#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://docs.google.com/spreadsheets/d/1EZy78L0cn1KDIX1aKq2biptejFqCjD5HO3tLiRvXf48/edit#gid=0
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1797
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1943
// Supports:
// Brand: Carrier/Surrey, Model: 42QG5A55970 remote
@ -13,6 +14,8 @@
// Brand: Carrier/Surrey, Model: 619EGX0220E0 A/C
// Brand: Carrier/Surrey, Model: 53NGK009/012 Inverter
// 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_
#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.
result.mode = toCommonMode(getMode());
result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.iFeel = getZoneFollow();
result.fanspeed = toCommonFanSpeed(getFan());
return result;
}

View File

@ -165,6 +165,7 @@ class IRCoolixAC {
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const;
String toString(void) const;
void setZoneFollow(const bool on);
#ifndef UNIT_TEST
private:
@ -189,7 +190,6 @@ class IRCoolixAC {
void setTempRaw(const uint8_t code);
uint8_t getTempRaw(void) const;
void setSensorTempRaw(const uint8_t code);
void setZoneFollow(const bool on);
bool isSpecialState(void) const;
bool handleSpecialState(const uint32_t data);
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.celsius = true;
result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = (getMode() == kEcoclimSleep) ? 0 : -1;
result.clock = getClock();

View File

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

View File

@ -14,6 +14,7 @@
// Brand: Centek, Model: SCT-65Q09 A/C
// Brand: Centek, Model: YKR-P/002E remote
// Brand: AEG, Model: Chillflex Pro AXP26U338CW A/C
// Brand: Electrolux, Model: YKR-H/531E A/C
#ifndef 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.celsius = !_.UseFahrenheit;
result.degrees = getTemp();
// no support for Sensor temp.
result.iFeel = getIFeel();
result.fanspeed = toCommonFanSpeed(_.Fan);
if (_.SwingAuto)
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.celsius = !_.useFahrenheit;
result.degrees = getTemp(result.celsius);
result.sensorTemperature = getSensorTemp(result.celsius);
result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = _.Sleep ? 0 : -1;
result.econo = getEconoToggle();

View File

@ -740,6 +740,7 @@ stdAc::state_t IRMirageAc::toCommon(void) const {
result.mode = toCommonMode(_.Mode);
result.celsius = true;
result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(getFan(), _model);
result.swingv = toCommonSwingV(getSwingV());
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.quiet = getQuiet();
result.clock = getClock() / 60;
result.iFeel = getIFeel();
// Not supported.
result.econo = false;
result.beep = false;
@ -775,10 +777,14 @@ void IRMirageAc::fromCommon(const stdAc::state_t state) {
setFilter(state.filter);
// setClock() expects seconds, not minutes.
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.
setOnTimer(0);
setOffTimer(0);
setIFeel(false);
}
/// 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-FHnnVE A/C (MITSUBISHI_AC)
// Brand: Mitsubishi Electric, Model: RH151 remote (MITSUBISHI_AC)
// Brand: Mitsubishi Electric, Model: PAR-FA32MA remote (MITSUBISHI136)
#ifndef 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,
const uint16_t nbits, const bool strict,
const uint32_t manufacturer) {
if (strict && nbits != kPanasonicBits)
return false; // Request is out of spec.
if (strict) { // Compliance checks
switch (nbits) {
case kPanasonic40Bits:
case kPanasonicBits:
break;
default:
return false; // Request is out of spec.
}
}
uint64_t data = 0;
@ -147,8 +154,10 @@ bool IRrecv::decodePanasonic(decode_results *results, uint16_t offset,
if (address != manufacturer) // Verify the Manufacturer code.
return false;
// Verify the checksum.
uint8_t checksumOrig = data;
uint8_t checksumCalc = (data >> 24) ^ (data >> 16) ^ (data >> 8);
const uint8_t checksumOrig = data;
uint8_t checksumCalc = (data >> 16) ^ (data >> 8);
if (nbits != kPanasonic40Bits)
checksumCalc ^= (data >> 24);
if (checksumOrig != checksumCalc) return false;
}

View File

@ -622,10 +622,12 @@ stdAc::state_t IRSanyoAc::toCommon(void) const {
result.mode = toCommonMode(_.Mode);
result.celsius = true;
result.degrees = getTemp();
result.sensorTemperature = getSensorTemp();
result.fanspeed = toCommonFanSpeed(_.Fan);
result.sleep = _.Sleep ? 0 : -1;
result.swingv = toCommonSwingV(_.SwingV);
result.beep = _.Beep;
result.iFeel = !getSensor();
// Not supported.
result.swingh = stdAc::swingh_t::kOff;
result.turbo = false;
@ -762,13 +764,13 @@ void IRSanyoAc88::stateReset(void) {
/// Set up hardware to be able to send a message.
void IRSanyoAc88::begin(void) { _irsend.begin(); }
#if SEND_SANYO_AC
#if SEND_SANYO_AC88
/// Send the current internal state as IR messages.
/// @param[in] repeat Nr. of times the message will be repeated.
void IRSanyoAc88::send(const uint16_t 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
/// 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
/// 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] nbits The number of bits of message to be sent.
/// @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
/// 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] offset The starting index to use when attempting to decode the
/// 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
#define D_STR_LOCK "Lock"
#endif // D_STR_LOCK
#ifndef D_STR_REPORT
#define D_STR_REPORT "Report"
#endif // D_STR_REPORT
#ifndef D_STR_AUTO
#define D_STR_AUTO "Auto"
@ -378,6 +381,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_MEDIUM
#define D_STR_MEDIUM "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
#define D_STR_HIGHEST "Highest"
@ -445,6 +451,33 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_BOTTOM
#define D_STR_BOTTOM "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.
// 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
#define D_STR_DISPLAYTEMP D_STR_DISPLAY " " D_STR_TEMP
#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
#define D_STR_SENSORTEMP D_STR_SENSOR " " D_STR_TEMP
#endif // D_STR_SENSORTEMP
@ -689,6 +725,12 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_DG11J191
#define D_STR_DG11J191 "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
#ifndef D_STR_AIRTON
@ -727,6 +769,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_CARRIER_AC64
#define D_STR_CARRIER_AC64 D_STR_CARRIER_AC "64"
#endif // D_STR_CARRIER_AC64
#ifndef D_STR_CARRIER_AC84
#define D_STR_CARRIER_AC84 D_STR_CARRIER_AC "84"
#endif // D_STR_CARRIER_AC84
#ifndef D_STR_CARRIER_AC128
#define D_STR_CARRIER_AC128 D_STR_CARRIER_AC "128"
#endif // D_STR_CARRIER_AC128
@ -808,6 +853,9 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_GOODWEATHER
#define D_STR_GOODWEATHER "GOODWEATHER"
#endif // D_STR_GOODWEATHER
#ifndef D_STR_GORENJE
#define D_STR_GORENJE "GORENJE"
#endif // D_STR_GORENJE
#ifndef D_STR_GREE
#define D_STR_GREE "GREE"
#endif // D_STR_GREE
@ -1060,9 +1108,15 @@ D_STR_INDIRECT " " D_STR_MODE
#ifndef D_STR_WHYNTER
#define D_STR_WHYNTER "WHYNTER"
#endif // D_STR_WHYNTER
#ifndef D_STR_WOWWEE
#define D_STR_WOWWEE "WOWWEE"
#endif // D_STR_WOWWEE
#ifndef D_STR_XMP
#define D_STR_XMP "XMP"
#endif // D_STR_XMP
#ifndef D_STR_YORK
#define D_STR_YORK "YORK"
#endif // D_STR_YORK
#ifndef D_STR_ZEPEAL
#define D_STR_ZEPEAL "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));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Airwell) {
@ -96,6 +97,7 @@ TEST(TestIRac, Airwell) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Amcor) {
@ -119,6 +121,7 @@ TEST(TestIRac, Amcor) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Argo) {
@ -130,16 +133,19 @@ TEST(TestIRac, Argo) {
true, // Power
stdAc::opmode_t::kHeat, // Mode
21, // Celsius
22, // Sensor Temp.
stdAc::fanspeed_t::kHigh, // Fan speed
stdAc::swingv_t::kOff, // Vertical swing
false, // iFeel
false, // Turbo
-1); // Sleep
EXPECT_TRUE(ac.getPower());
EXPECT_EQ(kArgoHeat, ac.getMode());
EXPECT_EQ(21, ac.getTemp());
EXPECT_EQ(kArgoFlapAuto, ac.getFlap());
EXPECT_EQ(kArgoFlapFull, ac.getFlap());
EXPECT_FALSE(ac.getMax()); // Turbo
EXPECT_FALSE(ac.getNight()); // Sleep
EXPECT_EQ(argoIrMessageType_t::AC_CONTROL, ac.getMessageType());
}
TEST(TestIRac, Carrier64) {
@ -174,6 +180,7 @@ TEST(TestIRac, Carrier64) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Coolix) {
@ -189,9 +196,11 @@ TEST(TestIRac, Coolix) {
true, // Power
stdAc::opmode_t::kHeat, // Mode
21, // Celsius
kNoTempValue, // Sensor Temp
stdAc::fanspeed_t::kHigh, // Fan speed
stdAc::swingv_t::kOff, // Vertical swing
stdAc::swingh_t::kOff, // Horizontal swing
false, // iFeel
false, // Turbo
false, // Light
false, // Clean
@ -235,6 +244,7 @@ TEST(TestIRac, Coolix) {
// End of message #2 (i.e. Repeat '1')
// Note: the two messages (#1 & #2) are identical.
ac._irsend.outputStr());
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Corona) {
@ -277,6 +287,7 @@ TEST(TestIRac, Corona) {
ASSERT_EQ(expectedCapture, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin) {
@ -310,6 +321,7 @@ TEST(TestIRac, Daikin) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin128) {
@ -343,6 +355,7 @@ TEST(TestIRac, Daikin128) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin152) {
@ -371,6 +384,7 @@ TEST(TestIRac, Daikin152) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin160) {
@ -396,6 +410,7 @@ TEST(TestIRac, Daikin160) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin176) {
@ -421,6 +436,7 @@ TEST(TestIRac, Daikin176) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin2) {
@ -460,6 +476,7 @@ TEST(TestIRac, Daikin2) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin216) {
@ -488,6 +505,7 @@ TEST(TestIRac, Daikin216) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Daikin64) {
@ -548,7 +566,7 @@ TEST(TestIRac, Ecoclim) {
IRac irac(kGpioUnused);
IRrecv capture(kGpioUnused);
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";
ac.begin();
@ -556,6 +574,7 @@ TEST(TestIRac, Ecoclim) {
true, // Power
stdAc::opmode_t::kCool, // Mode
26, // Celsius
27, // Sensor Temp.
stdAc::fanspeed_t::kHigh, // Fan speed
-1, // Sleep
12 * 60 + 34); // Clock
@ -567,7 +586,7 @@ TEST(TestIRac, Ecoclim) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
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";
ac._irsend.reset();
@ -575,6 +594,7 @@ TEST(TestIRac, Ecoclim) {
true, // Power
stdAc::opmode_t::kCool, // Mode
21, // Celsius
22, // Sensor Temp.
stdAc::fanspeed_t::kLow, // Fan speed
8 * 60, // Sleep
17 * 60 + 17); // Clock
@ -600,9 +620,11 @@ TEST(TestIRac, Electra) {
true, // Power
stdAc::opmode_t::kFan, // Mode
26, // Celsius
27, // Sensor Temp.
stdAc::fanspeed_t::kHigh, // Fan speed
stdAc::swingv_t::kAuto, // Vertical swing
stdAc::swingh_t::kLeft, // Horizontal swing
false, // iFeel
true, // Turbo
true, // Light (toggle)
true); // Clean
@ -656,6 +678,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(ardb1_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
// 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(arrah2e_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
irac.fujitsu(&ac,
fujitsu_ac_remote_model_t::ARRY4, // Model
@ -703,6 +727,7 @@ TEST(TestIRac, Fujitsu) {
ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits);
ASSERT_EQ(arry4_expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
irac.fujitsu(&ac,
@ -753,6 +778,7 @@ TEST(TestIRac, Goodweather) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Gree) {
@ -761,7 +787,7 @@ TEST(TestIRac, Gree) {
IRrecv capture(kGpioUnused);
char expected[] =
"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, "
"Swing(V): 3 (UNKNOWN), Swing(H): 5 (Right), Timer: Off, "
"Display Temp: 0 (Off)";
@ -776,6 +802,7 @@ TEST(TestIRac, Gree) {
stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kHigh, // Vertical swing
stdAc::swingh_t::kRight, // Horizontal swing
true, // iFeel
false, // Turbo
false, // Econo
true, // Light
@ -789,6 +816,7 @@ TEST(TestIRac, Gree) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Haier) {
@ -818,6 +846,7 @@ TEST(TestIRac, Haier) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Haier160) {
@ -853,6 +882,7 @@ TEST(TestIRac, Haier160) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Haier176) {
@ -886,6 +916,7 @@ TEST(TestIRac, Haier176) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, HaierYrwo2) {
@ -919,6 +950,7 @@ TEST(TestIRac, HaierYrwo2) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Hitachi) {
@ -946,6 +978,7 @@ TEST(TestIRac, Hitachi) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Hitachi1) {
@ -978,6 +1011,7 @@ TEST(TestIRac, Hitachi1) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Hitachi264) {
@ -1003,6 +1037,7 @@ TEST(TestIRac, Hitachi264) {
ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t 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_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
@ -1031,6 +1066,7 @@ TEST(TestIRac, Hitachi296) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t 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_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
@ -1062,6 +1098,7 @@ TEST(TestIRac, Hitachi344) {
ASSERT_EQ(expected_swingon, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t 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_TRUE(r.power);
EXPECT_EQ(stdAc::opmode_t::kHeat, r.mode);
@ -1082,6 +1119,7 @@ TEST(TestIRac, Hitachi344) {
ASSERT_EQ(expected_swingoff, ac.toString());
ac._irsend.makeDecodeResult();
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(kHitachiAc344Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected_swingoff,
@ -1115,6 +1153,7 @@ TEST(TestIRac, Hitachi424) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
irac.hitachi424(&ac,
@ -1131,6 +1170,7 @@ TEST(TestIRac, Hitachi424) {
ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits);
ASSERT_EQ(expected_swingv, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Kelvinator) {
@ -1164,6 +1204,7 @@ TEST(TestIRac, Kelvinator) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, LG) {
@ -1196,6 +1237,7 @@ TEST(TestIRac, LG) {
ASSERT_EQ(61, ac._irsend.capture.rawlen);
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, LG2) {
@ -1228,6 +1270,7 @@ TEST(TestIRac, LG2) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
// Message #2 - SwingV Low
EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61));
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(kLgBits, ac._irsend.capture.bits);
ASSERT_EQ(kLgAcSwingHAuto, ac._irsend.capture.value);
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Midea) {
@ -1461,8 +1505,10 @@ TEST(TestIRac, Midea) {
stdAc::opmode_t::kDry, // Mode
true, // Celsius
27, // Degrees
28, // Sensor Temp.
stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kOff, // Swing(V)
false, // iFeel
false, // Silent/Quiet
false, // Previous Silent/Quiet setting
false, // Turbo
@ -1479,6 +1525,7 @@ TEST(TestIRac, Midea) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Mirage) {
@ -1518,6 +1565,7 @@ TEST(TestIRac, Mirage) {
ASSERT_EQ(kMirageBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_KKG9AC1, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
const char expected_KKG29AC1[] =
"Model: 2 (KKG29AC1), Power: On, Mode: 3 (Dry), Temp: 27C, "
@ -1535,6 +1583,7 @@ TEST(TestIRac, Mirage) {
ASSERT_EQ(expected_KKG29AC1,
IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Mitsubishi) {
@ -1567,6 +1616,7 @@ TEST(TestIRac, Mitsubishi) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Mitsubishi136) {
@ -1593,6 +1643,7 @@ TEST(TestIRac, Mitsubishi136) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, MitsubishiHeavy88) {
@ -1623,6 +1674,7 @@ TEST(TestIRac, MitsubishiHeavy88) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, MitsubishiHeavy152) {
@ -1656,6 +1708,7 @@ TEST(TestIRac, MitsubishiHeavy152) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Neoclima) {
@ -1690,6 +1743,7 @@ TEST(TestIRac, Neoclima) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Panasonic) {
@ -1722,6 +1776,7 @@ TEST(TestIRac, Panasonic) {
ASSERT_EQ(expected_nke, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
char expected_dke[] =
"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(expected_dke, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Panasonic32) {
@ -1774,6 +1830,7 @@ TEST(TestIRac, Panasonic32) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Samsung) {
@ -1813,6 +1870,7 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
irac.samsung(&ac,
@ -1841,6 +1899,7 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
const char sleep[] =
@ -1874,6 +1933,7 @@ TEST(TestIRac, Samsung) {
ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
ASSERT_EQ(sleep, IRAcUtils::resultAcToString(&ac._irsend.capture));
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Sanyo) {
@ -1890,8 +1950,10 @@ TEST(TestIRac, Sanyo) {
true, // Power
stdAc::opmode_t::kCool, // Mode
28, // Celsius
kNoTempValue, // SensorTemp
stdAc::fanspeed_t::kMedium, // Fan speed
stdAc::swingv_t::kHighest, // Vertical Swing
false, // iFeel
true, // Beep
17); // Sleep
ASSERT_EQ(expected, ac.toString());
@ -1902,6 +1964,7 @@ TEST(TestIRac, Sanyo) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Sanyo88) {
@ -1931,6 +1994,7 @@ TEST(TestIRac, Sanyo88) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Sharp) {
@ -1963,6 +2027,7 @@ TEST(TestIRac, Sharp) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Tcl112) {
@ -1997,6 +2062,7 @@ TEST(TestIRac, Tcl112) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t 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.
ac._irsend.reset();
irac.tcl112(&ac,
@ -2052,6 +2118,7 @@ TEST(TestIRac, Technibel) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Teco) {
@ -2079,6 +2146,7 @@ TEST(TestIRac, Teco) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Toshiba) {
@ -2108,6 +2176,7 @@ TEST(TestIRac, Toshiba) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
EXPECT_EQ(
"f38000d50"
"m4400s4300"
@ -2183,6 +2252,7 @@ TEST(TestIRac, Transcold) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Trotec) {
@ -2212,6 +2282,7 @@ TEST(TestIRac, Trotec) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Trotec3550) {
@ -2242,6 +2313,7 @@ TEST(TestIRac, Trotec3550) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Truma) {
@ -2271,6 +2343,7 @@ TEST(TestIRac, Truma) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, Vestel) {
@ -2300,6 +2373,7 @@ TEST(TestIRac, Vestel) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
char expected_clocks[] =
@ -2325,6 +2399,7 @@ TEST(TestIRac, Vestel) {
ASSERT_EQ(kVestelAcBits, ac._irsend.capture.bits);
ASSERT_EQ(expected_clocks, IRAcUtils::resultAcToString(&ac._irsend.capture));
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
// clock is set.
@ -2404,6 +2479,7 @@ TEST(TestIRac, Voltas) {
ASSERT_EQ(expected_unknown, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
ac._irsend.reset();
// Test the UNKNOWN model type
@ -2470,6 +2546,7 @@ TEST(TestIRac, Whirlpool) {
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t r, p;
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, r.command);
}
TEST(TestIRac, cmpStates) {
@ -2507,6 +2584,21 @@ TEST(TestIRac, cmpStates) {
// Now make them different.
b.power = false;
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) {
@ -2610,6 +2702,7 @@ TEST(TestIRac, strToFanspeed) {
EXPECT_EQ(stdAc::fanspeed_t::kMin, IRac::strToFanspeed("MIN"));
EXPECT_EQ(stdAc::fanspeed_t::kLow, IRac::strToFanspeed("LOW"));
EXPECT_EQ(stdAc::fanspeed_t::kMedium, IRac::strToFanspeed("MEDIUM"));
EXPECT_EQ(stdAc::fanspeed_t::kMediumHigh, IRac::strToFanspeed("MED-HIGH"));
EXPECT_EQ(stdAc::fanspeed_t::kHigh, IRac::strToFanspeed("HIGH"));
EXPECT_EQ(stdAc::fanspeed_t::kMax, IRac::strToFanspeed("MAX"));
EXPECT_EQ(stdAc::fanspeed_t::kAuto, IRac::strToFanspeed("FOOBAR"));
@ -2622,6 +2715,7 @@ TEST(TestIRac, strToSwingV) {
EXPECT_EQ(stdAc::swingv_t::kLowest, IRac::strToSwingV("LOWEST"));
EXPECT_EQ(stdAc::swingv_t::kLow, IRac::strToSwingV("LOW"));
EXPECT_EQ(stdAc::swingv_t::kMiddle, IRac::strToSwingV("MIDDLE"));
EXPECT_EQ(stdAc::swingv_t::kUpperMiddle, IRac::strToSwingV("UPPER-MIDDLE"));
EXPECT_EQ(stdAc::swingv_t::kHigh, IRac::strToSwingV("HIGH"));
EXPECT_EQ(stdAc::swingv_t::kHighest, IRac::strToSwingV("HIGHEST"));
EXPECT_EQ(stdAc::swingv_t::kOff, IRac::strToSwingV("OFF"));
@ -2652,6 +2746,10 @@ TEST(TestIRac, strToModel) {
IRac::strToModel("ARRAH2E"));
EXPECT_EQ(whirlpool_ac_remote_model_t::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(10, IRac::strToModel("10"));
EXPECT_EQ(-1, IRac::strToModel("0"));
@ -2659,6 +2757,26 @@ TEST(TestIRac, strToModel) {
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) {
EXPECT_EQ("On", IRac::boolToString(true));
EXPECT_EQ("Off", IRac::boolToString(false));
@ -2678,6 +2796,7 @@ TEST(TestIRac, opmodeToString) {
TEST(TestIRac, fanspeedToString) {
EXPECT_EQ("Low", IRac::fanspeedToString(stdAc::fanspeed_t::kLow));
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));
}
@ -2685,6 +2804,8 @@ TEST(TestIRac, swingvToString) {
EXPECT_EQ("Off", IRac::swingvToString(stdAc::swingv_t::kOff));
EXPECT_EQ("Low", IRac::swingvToString(stdAc::swingv_t::kLow));
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));
}
@ -2696,6 +2817,17 @@ TEST(TestIRac, swinghToString) {
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
// state-less command.
TEST(TestIRac, CoolixDecodeToState) {
@ -2714,6 +2846,7 @@ TEST(TestIRac, CoolixDecodeToState) {
ASSERT_TRUE(irrecv.decode(&irsend.capture));
stdAc::state_t result;
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_FALSE(result.power);
ASSERT_EQ(stdAc::opmode_t::kHeat, result.mode);
@ -2762,9 +2895,11 @@ TEST(TestIRac, Issue821) {
result.power, // Power
result.mode, // Mode
result.degrees, // Celsius
kNoTempValue, // Sensor Temp
result.fanspeed, // Fan speed
result.swingv, // Vertical swing
result.swingh, // Horizontal swing
result.iFeel, // iFeel
result.turbo, // Turbo
result.light, // Light
result.clean, // Clean
@ -2877,6 +3012,7 @@ TEST(TestIRac, Issue1001) {
IRAcUtils::resultAcToString(&ac._irsend.capture));
stdAc::state_t 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.
// i.e. How Home Assistant expects things to work.
@ -2907,6 +3043,7 @@ TEST(TestIRac, Issue1001) {
"Command: 1 (Power)",
IRAcUtils::resultAcToString(&ac._irsend.capture));
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.
@ -2956,6 +3093,7 @@ TEST(TestIRac, Issue1035) {
ASSERT_FALSE(prev.power);
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev));
ASSERT_TRUE(result.power);
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command);
prev = result;
@ -2967,6 +3105,7 @@ TEST(TestIRac, Issue1035) {
ASSERT_EQ(DAIKIN2, ac._irsend.capture.decode_type);
ASSERT_TRUE(prev.power);
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &result, &prev));
ASSERT_EQ(stdAc::ac_command_t::kControlCommand, result.command);
ASSERT_FALSE(result.power);
}
@ -3138,4 +3277,26 @@ TEST(TestIRac, initState) {
EXPECT_EQ(-1, builtin_init.model);
EXPECT_EQ(stdAc::swingv_t::kOff, builtin_init.swingv);
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_
#define TEST_IRRECV_TEST_H_
#include <math.h>
#include <iostream>
#include <sstream>
#include <string>
#include "IRutils.h"
#define EXPECT_STATE_EQ(a, b, c) \
for (uint8_t i = 0; i < c / 8; ++i) { \
EXPECT_EQ(a[i], b[i]) << "Expected state " \
"differs at i = " \
<< uint64ToString(i); \
#define EXPECT_STATE_EQ(a, b, c) \
for (uint8_t i = 0; i < ceil((c) / 8.0); ++i) { \
EXPECT_EQ((a)[i], (b)[i]) << "Expected state " \
"differs at i = " \
<< uint64ToString(i); \
}
#endif // TEST_IRRECV_TEST_H_

View File

@ -16,6 +16,7 @@
# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = ../lib/googletest/googletest
GMOCK_DIR = ../lib/googletest/googlemock
# Where to find user code.
USER_DIR = ../src
@ -24,11 +25,14 @@ INCLUDES = -I$(USER_DIR) -I.
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -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.
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
TESTS = $(patsubst %.cpp,%,$(wildcard *_test.cpp))
@ -37,12 +41,19 @@ TESTS = $(patsubst %.cpp,%,$(wildcard *_test.cpp))
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.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.
all : $(TESTS)
all : $(GTEST_LIBS) $(TESTS)
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o
rm -f $(GTEST_LIBS) $(TESTS) *.o
# Build and run all the tests.
run : all
@ -65,13 +76,14 @@ run-% : %_test
install-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
# trailing _.
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.
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_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_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.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)
# 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
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
# For simplicity and to avoid depending on implementation details of
# Google Mock and Google Test, the dependencies specified below are
# conservative and not optimized. This is fine as Google Mock and
# Google Test compile fast and for ordinary users their source rarely
# changes.
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_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
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
$(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^
gmock.a : gmock-all.o
$(AR) $(ARFLAGS) $@ $^
gmock_main.a : gmock_main.o
$(AR) $(ARFLAGS) $@ $^
# Keep all intermediate files.
.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
$(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
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 $@
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
$(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
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
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
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
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
# 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)
$(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
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
%_test : $(COMMON_OBJ) %_test.o
%_test : $(COMMON_OBJ) %_test.o $(GTEST_LIBS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

View File

@ -264,6 +264,16 @@ TEST(TestUtils, Housekeeping) {
ASSERT_EQ(kCarrierAc64MinRepeat,
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
ASSERT_EQ("CARRIER_AC128", typeToString(decode_type_t::CARRIER_AC128));
ASSERT_EQ(decode_type_t::CARRIER_AC128, strToDecodeType("CARRIER_AC128"));
@ -693,3 +703,113 @@ TEST(TestDecodeCarrierAC128, SyntheticExample) {
stdAc::state_t 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().
TEST(TestEncodePanasonic, General) {
IRsendTest irsend(4);
IRsendTest irsend(kGpioUnused);
EXPECT_EQ(0x0, irsend.encodePanasonic(0, 0, 0, 0));
EXPECT_EQ(0x101010101, irsend.encodePanasonic(1, 1, 1, 1));
EXPECT_EQ(0xFFFF, irsend.encodePanasonic(0, 0, 0, 0xFF));
@ -28,7 +28,7 @@ TEST(TestEncodePanasonic, General) {
// Test sending typical data only.
TEST(TestSendPanasonic64, SendDataOnly) {
IRsendTest irsend(4);
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
@ -76,7 +76,7 @@ TEST(TestSendPanasonic64, SendDataOnly) {
// Test sending with different repeats.
TEST(TestSendPanasonic64, SendWithRepeats) {
IRsendTest irsend(4);
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
@ -147,7 +147,7 @@ TEST(TestSendPanasonic64, SendWithRepeats) {
// Test sending an atypical data size.
TEST(TestSendPanasonic64, SendUnusualSize) {
IRsendTest irsend(4);
IRsendTest irsend(kGpioUnused);
irsend.begin();
irsend.reset();
@ -213,8 +213,8 @@ TEST(TestSendPanasonic, CompareToSendPanasonic64) {
// Decode normal Panasonic messages.
TEST(TestDecodePanasonic, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Normal Panasonic 48-bit message.
@ -259,8 +259,8 @@ TEST(TestDecodePanasonic, NormalDecodeWithStrict) {
// Decode normal repeated Panasonic messages.
TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Normal Panasonic 48-bit message with 2 repeats.
@ -293,8 +293,8 @@ TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) {
// Decode Panasonic messages with unsupported values.
TEST(TestDecodePanasonic, DecodeWithNonStrictValues) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
@ -331,8 +331,8 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictValues) {
// Decode Panasonic messages with unsupported size/lengths.
TEST(TestDecodePanasonic, DecodeWithNonStrictSize) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
@ -375,8 +375,8 @@ TEST(TestDecodePanasonic, DecodeWithNonStrictSize) {
// Decode (non-standard) 64-bit messages.
TEST(TestDecodePanasonic, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
@ -395,8 +395,8 @@ TEST(TestDecodePanasonic, Decode64BitMessages) {
// Decode a 'real' example via GlobalCache
TEST(TestDecodePanasonic, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
@ -432,8 +432,8 @@ TEST(TestDecodePanasonic, DecodeGlobalCacheExample) {
// Fail to decode a non-Panasonic example via GlobalCache
TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
@ -452,8 +452,8 @@ TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) {
// Failing to decode Panasonic in Issue #245
TEST(TestDecodePanasonic, DecodeIssue245) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
irsend.reset();
@ -813,8 +813,8 @@ TEST(TestIRPanasonicAcClass, HumanReadable) {
// Decode normal Panasonic AC messages.
TEST(TestDecodePanasonicAC, RealExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
IRsendTest irsend(kGpioUnused);
IRrecv irrecv(kGpioUnused);
irsend.begin();
// Data from Issue #525
@ -1586,3 +1586,73 @@ TEST(TestIRPanasonicAc32Class, HumanReadable) {
"Swing(H): Off, Swing(V): 5 (Lowest)",
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",
"version": "2.8.4",
"version": "2.8.5",
"keywords": "infrared, ir, remote, esp8266, esp32",
"description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)",
"repository":

View File

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